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

看过之前一系列的文章之后,我们对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学习之绘制一个立方体)