OpenGL ES 渲染立体图形

Posted lybskill

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了OpenGL ES 渲染立体图形相关的知识,希望对你有一定的参考价值。

一、理解

顶点数据存储在申请的缓冲区中,其由数据总线传递给着色器(如果是片元着色器,还须将顶点转换成片元),再由着色器最终渲染到涂层上;

二、思路

1.设置涂层;

 2.创建上下文;

 3.清空缓存区;

 4.创建渲染缓存区和帧缓存区;

 5.开始绘制;

三、核心代码

//最终渲染

- (void)renderLayer
{
    //设置窗口背景颜色
    glClearColor(0.0, 0.0, 0.0, 1.0);
    //清空颜色缓存
    glClear(GL_COLOR_BUFFER_BIT);
    //设置视口大小
    CGFloat scale = [[UIScreen mainScreen] scale];
    glViewport(self.frame.origin.x*scale, self.frame.origin.y*scale, self.frame.size.width*scale, self.frame.size.height*scale);
    
    //读取顶点和片元着色器程序
    NSString *vertFile = [[NSBundle mainBundle] pathForResource:@"shaderv" ofType:@"glsl"];
    NSString *fragFile = [[NSBundle mainBundle] pathForResource:@"shaderf" ofType:@"glsl"];
    NSLog(@"vertFile:%@", vertFile);
    NSLog(@"fragFile:%@", fragFile);
    
    //判断myProgram是否存在,存在则清空
    if (self.myProgram) {
        glDeleteProgram(self.myProgram);
        self.myProgram = 0;
    }
    
    //加载着色器到myProgram中
    self.myProgram = [self loadShader:vertFile frag:fragFile];
    
    //创建链接
    glLinkProgram(self.myProgram);
    GLint linkSuccess;
    
    //获取链接状态
    glGetProgramiv(self.myProgram, GL_LINK_STATUS, &linkSuccess);
    
    //判断链接是否成功
    if (linkSuccess == GL_FALSE) {
        //获取失败信息
        GLchar message[256];
        glGetProgramInfoLog(self.myProgram, sizeof(message), 0, &message[0]);
        //c字符串转换成oc字符串
        NSString *messageString = [NSString stringWithUTF8String:message];
        NSLog(@"error:%@", messageString);
        return;
    } else {
        //使用myProgram
        glUseProgram(self.myProgram);
    }
    
    //创建绘制索引数组
    GLuint indices[] = {
        0, 3, 2,
        0, 1, 3,
        0, 2, 4,
        0, 4, 1,
        2, 3, 4,
        1, 4, 3
    };
    
    //判断顶点缓存区是否为空,为空则申请一个缓存区标志符
    if (self.myVertices == 0) {
        glGenBuffers(1, &_myVertices);
    }
    
    //----------处理顶点坐标---------
    
    /*顶点数据
     1.前3个坐标值(x、y、z),后3个颜色值(RGB);
     2.有先后顺序,否则绘制形状完全不同
     */
    GLfloat attrArr[] =
    {
        -0.5f, 0.5f, 0.0f,      1.0f, 0.0f, 1.0f, //左上
        0.5f, 0.5f, 0.0f,       1.0f, 0.0f, 1.0f, //右上
        -0.5f, -0.5f, 0.0f,     1.0f, 1.0f, 1.0f, //左下
        0.5f, -0.5f, 0.0f,      1.0f, 1.0f, 1.0f, //右下
        0.0f, 0.0f, 1.0f,       0.0f, 1.0f, 0.0f, //顶点
    };
    
    //将_myVertices绑定到GL_ARRAY_BUFFER标志符上
    glBindBuffer(GL_ARRAY_BUFFER, _myVertices);
    //把顶点坐标数据从CPU复制到GPU上
    glBufferData(GL_ARRAY_BUFFER, sizeof(attrArr), attrArr, GL_DYNAMIC_DRAW);
    
    //将顶点坐标数据通过myProgram传递到顶点着色器程序的position
    
    //获取顶点属性入口
    GLuint position = glGetAttribLocation(self.myProgram, "position");
    /*传递数据
     1.一行6个数据,前3个为坐标,后3个为颜色;
     2.NULL开始位置:默认为0,指向数组首地址;
     */
    glVertexAttribPointer(position, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat)*6, NULL);
    //设置合适的格式从缓存区中读取数据
    glEnableVertexAttribArray(position);
    
    //处理顶点颜色数据:传递到顶点着色器的positionColor
    GLuint positionColor = glGetAttribLocation(self.myProgram, "positionColor");
    glVertexAttribPointer(positionColor, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat)*6, (float *)NULL +3);
    glEnableVertexAttribArray(positionColor);
    
    //在myProgram中找到透视投影矩阵和模型视图矩阵
    GLuint projectionMatrixSlot = glGetUniformLocation(self.myProgram, "projectionMatrix");
    GLuint modelViewMatrixSlot = glGetUniformLocation(self.myProgram, "modelViewMatrix");
    
    //创建透视投影矩阵并初始化
    float width = self.frame.size.width;
    float height = self.frame.size.height;
    KSMatrix4 _projectionMatrix;
    ksMatrixLoadIdentity(&_projectionMatrix);
    float aspect = width/height;
    ksPerspective(&_projectionMatrix, 30.0, aspect, 5.0f, 20.0f);
    
    //设置glsl里面的投影矩阵
    glUniformMatrix4fv(projectionMatrixSlot, 1, GL_FALSE, (GLfloat *)&_projectionMatrix.m[0][0]);
    
    //开启剔除功能
    glEnable(GL_CULL_FACE);
    
    //创建平移矩阵:Z轴平移-10
    KSMatrix4 _modelViewMatrix;
    ksMatrixLoadIdentity(&_modelViewMatrix);
    ksTranslate(&_modelViewMatrix, 0.0, 0.0, -10.0);
    
    //创建旋转矩阵
    KSMatrix4 _rotationMatrix;
    ksMatrixLoadIdentity(&_rotationMatrix);
    ksRotate(&_rotationMatrix, xDegree, 1.0, 0.0, 0.0);
    ksRotate(&_rotationMatrix, yDegree, 0.0, 1.0, 0.0);
    ksRotate(&_rotationMatrix, zDegree, 0.0, 0.0, 1.0);
    
    //将平移矩阵和旋转矩阵相乘,结果放到模型视图矩阵中
    ksMatrixMultiply(&_modelViewMatrix, &_rotationMatrix, &_modelViewMatrix);
    
    //设置glsl里面的模型视图矩阵
    glUniformMatrix4fv(modelViewMatrixSlot, 1, GL_FALSE, (GLfloat *)&_modelViewMatrix.m[0][0]);
    
    //设置绘制参数:片元、个数、索引数组
    glDrawElements(GL_TRIANGLES, sizeof(indices)/sizeof(indices[0]), GL_UNSIGNED_INT, indices);
    
    //由顶点着色器将缓存区中的数据渲染到显示涂层上
    [self.myContext presentRenderbuffer:GL_RENDERBUFFER];
}

四、效果

技术分享图片

技术分享图片

 

 

GitHub

以上是关于OpenGL ES 渲染立体图形的主要内容,如果未能解决你的问题,请参考以下文章

OpenGL ES 太好玩了图形渲染管线

OpenGL ES 太好玩了图形渲染管线

OpenGL ES 学习 -- 绘制平面图形

OpenGL学习随笔-- OpenGL ES 2.0渲染管线

我的OpenGL学习进阶之旅OpenGL ES 3.0实现了具有可编程着色功能的图形管线

我的OpenGL学习进阶之旅OpenGL ES 3.0实现了具有可编程着色功能的图形管线