美文网首页
06 - OpenGL ES学习之绘制一个立方体

06 - OpenGL ES学习之绘制一个立方体

作者: CoderP1 | 来源:发表于2021-12-03 18:05 被阅读0次

    看过之前一系列的文章之后,我们对ES有了一个比较基础的理解了,下面我们通过绘制一个随时间旋转的立方体,来汇总前几篇文章的内容,以加深对OpenGL ES渲染过程的理解。

    示例代码在git仓库

    正如读者所知,一个正方体是由六个面组成的,那这里我们拆分需求,逐次绘制六个面,然后用时间作为输入量,改变MVP矩阵,就能最终实现我们的效果。在后续的文章中,我都是在VSCode里编写着色器,安装GLSL扩展后,可以高亮显示,比较方便。

    1.首先我们先来展示一下立方体的空间示意图

    立方体空间示意图

    绘制与X轴垂直的平面的代码:

    - (void)drawPositiveXWithColorLocation:(GLuint)colorLocation andPositionLocation:(GLuint)positionLocation {
        //每一行代表(x,y,z,r,g,b)
        static GLfloat positiveX[24] = {
            0.5f,  0.5f,  0.5f, 1.0f, 0.6f, 0.3f,
            0.5f,  -0.5f, 0.5f, 1.0f, 0.6f, 0.3f,
            0.5f, -0.5f, -0.5f, 1.0f, 0.6f, 0.3f,
            0.5f, 0.5f,  -0.5f, 1.0f, 0.6f, 0.3f,
            
        };
        
        if (self.vertexBufferId == 0) {
            glGenBuffers(1, &_vertexBufferId);
            glBindBuffer(GL_ARRAY_BUFFER, _vertexBufferId);
        }
        glBufferData(GL_ARRAY_BUFFER, sizeof(positiveX), positiveX, GL_STATIC_DRAW);
        
        GLuint offset = 3 * sizeof(float);
        glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), NULL);
        glVertexAttribPointer(colorLocation, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (const void *) offset);
        
        _esContext.drawFunc(&_esContext);
        
    }
    

    这里我们先找出与X轴垂直相交的这个面的四个顶点坐标,因为我们绘图采用的是GL_TRIANGLE_FAN模式,所以只需要四个顶点就可以了。
    其它5个面也是这样绘制的

    加载MVP矩阵的代码如下:

     [super glkView:view drawInRect:rect];
        _elapsedTime += 0.02;
        //时间系数
        float varyFactor =  (sin(self.elapsedTime) + 1.0) / 2.0; //0 ~ 1
        _esContext.width = view.drawableWidth;
        _esContext.height = view.drawableHeight;
        
        
        //开启深度测试,为了确定绘制的时候哪一个面绘制在上面
        glEnable(GL_DEPTH_TEST);
        
        glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
        
        //获取属性color和position的index
        GLint colorIndex = glGetAttribLocation(_esContext.program, "vColor");
        GLint positionIndex = glGetAttribLocation(_esContext.program, "vPosition");
        
        //创建MVP矩阵
        GLint modelIndex = glGetUniformLocation(_esContext.program, "modelTransform");
        GLint viewIndex = glGetUniformLocation(_esContext.program, "viewTransform");
        GLint projectIndex = glGetUniformLocation(_esContext.program, "projectTransform");
        
        GLKMatrix4 rotate = GLKMatrix4MakeRotation(varyFactor * M_PI * 2, 1, 1, 1);
        GLKMatrix4 translate = GLKMatrix4MakeTranslation(-0.1, -0.1, -0.1);
        
        GLKMatrix4 modelMatrix = GLKMatrix4Multiply(translate, rotate);
        
    
        GLKMatrix4 projectionMatrix = GLKMatrix4MakePerspective(GLKMathDegreesToRadians(90), view.frame.size.width / view.frame.size.height, 0.2, 10.0);
        
        
        GLKMatrix4 cameraMatrix = GLKMatrix4MakeLookAt(0, 0, 2 * (varyFactor + 1), 0, 0, 0, 0, 1, 0);
        
        //加载MVP矩阵
        glUniformMatrix4fv(modelIndex, 1, GL_FALSE, modelMatrix.m);
        glUniformMatrix4fv(viewIndex  , 1, GL_FALSE, cameraMatrix.m);
        glUniformMatrix4fv(projectIndex, 1, GL_FALSE, projectionMatrix.m);
        
        //开启顶点属性
        glEnableVertexAttribArray(colorIndex);
        glEnableVertexAttribArray(positionIndex);
        
        
        //加载顶点数据,并且依次绘制立方体的六个面
        [self drawPositiveXWithColorLocation:colorIndex andPositionLocation:positionIndex];
        [self drawNegativeXWithColorLocation:colorIndex andPositionLocation:positionIndex];
        [self drawPositiveYWithColorLocation:colorIndex andPositionLocation:positionIndex];
        [self drawNegativeYWithColorLocation:colorIndex andPositionLocation:positionIndex];
        [self drawPositiveZWithColorLocation:colorIndex andPositionLocation:positionIndex];
        [self drawNegativeZWithColorLocation:colorIndex andPositionLocation:positionIndex];
       
        //关闭顶点属性
        glDisableVertexAttribArray(colorIndex);
        glDisableVertexAttribArray(positionIndex);
    
    

    这里需要注意两点
    1.需要开启深度测试,如果没有开启深度测试的话,ES是不知道你绘制面的层次,会出现如下效果:


    未开启深度测试

    2.开启深度测试后,除了需要清除颜色缓冲区外,还需要清除深度缓冲区

    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
    

    最终正确的效果如下图:


    开启深度测试

    相关文章

      网友评论

          本文标题:06 - OpenGL ES学习之绘制一个立方体

          本文链接:https://www.haomeiwen.com/subject/hkqxxrtx.html