美文网首页音视频从入门到放弃音视频开发
在iOS中如何使用OpenGL画一些简单的图形

在iOS中如何使用OpenGL画一些简单的图形

作者: zhonglaoban | 来源:发表于2021-01-15 23:18 被阅读0次

    本篇文章中,主要实现的是如何使用OpenGL画一个三角形和矩形,我分为下几个步骤来说明:

    • OpenGL的语言GLSL
    • 编译OpenGL的语言
    • 创建一些顶点缓冲区
    • 设置一些顶点坐标
    • 将坐标传给OpenGL

    OpenGL的语言GLSL

    它和C语言类似,可以声明一些变量(a_Position),有一个main的入口函数,有系统内置的变量(gl_Position)。

    attribute vec3 a_Position;
    
    void main(void) {
        gl_Position = vec4(a_Position, 1.0);
    }
    

    使用OpenGL的语言

    和我们的代码一样,要使用这些GLSL,还需要编译它们,将它们加载到内存中。整个加载、编译过程有这3步:

    • 加载shader字符串
    • 根据字符串创建shader对象
    • 编译shader对象
    - (GLuint)compileShader:(NSString *)shaderName withType:(GLenum)shaderType {
        //加载shader字符串
        NSString *shaderPath = [[NSBundle mainBundle] pathForResource:shaderName ofType:nil];
        NSError *error;
        NSString *shaderString = [NSString stringWithContentsOfFile:shaderPath encoding:NSUTF8StringEncoding error:&error];
        if (!shaderString) {
            NSLog(@"Error loading shader: %@", error.localizedDescription);
            return -1;
        }
        
        //shader
        GLuint shaderHandle = glCreateShader(shaderType);
        
        //将字符串代码转为shader
        const char * shaderStringUTF8 = [shaderString UTF8String];
        int shaderStringLength = (int)[shaderString length];
        glShaderSource(shaderHandle, 1, &shaderStringUTF8, &shaderStringLength);
        
        //编译shader
        glCompileShader(shaderHandle);
        
        //检查编译结果
        GLint compileSuccess;
        glGetShaderiv(shaderHandle, GL_COMPILE_STATUS, &compileSuccess);
        if (compileSuccess == GL_FALSE) {
            GLchar messages[256];
            glGetShaderInfoLog(shaderHandle, sizeof(messages), 0, &messages[0]);
            NSString *messageString = [NSString stringWithUTF8String:messages];
            NSLog(@"%@", messageString);
            return -1;
        }
        
        return shaderHandle;
    }
    

    编译好后,我们还需要创建一个管道,将内存中的这些编译好的东西交给GPU。之后CPU中更新的数据都是通过这个管道传送给GPU的。

    - (void)compileVertexShader:(NSString *)vertexShader
                 fragmentShader:(NSString *)fragmentShader {
        GLuint vertexShaderName = [self compileShader:vertexShader
                                             withType:GL_VERTEX_SHADER];
        GLuint fragmentShaderName = [self compileShader:fragmentShader
                                               withType:GL_FRAGMENT_SHADER];
        
        //创建program
        _programHandle = glCreateProgram();
        
        //绑定着色器
        glAttachShader(_programHandle, vertexShaderName);
        glAttachShader(_programHandle, fragmentShaderName);
        
        glLinkProgram(_programHandle);
        
        //检查program结果
        GLint linkSuccess;
        glGetProgramiv(_programHandle, GL_LINK_STATUS, &linkSuccess);
        if (linkSuccess == GL_FALSE) {
            GLchar messages[256];
            glGetProgramInfoLog(_programHandle, sizeof(messages), 0, &messages[0]);
            NSString *messageString = [NSString stringWithUTF8String:messages];
            NSLog(@"%@", messageString);
        }
        
        // 删除着色器,它们已经链接到我们的程序中了,已经不再需要了
        glDeleteShader(vertexShaderName);
        glDeleteShader(fragmentShaderName);
    }
    

    创建顶点缓冲区

    我们这里画两个图形,所以创建两个顶点缓冲区,并将对应的顶点坐标存储到顶点缓冲区中。

    - (void)setupVAO {
        GLfloat triangleVertices[] = {
            -0.4, 0.0, 0.0,
             0.0, 0.4, 0.0,
             0.5, 0.0, 0.0,
        };
        glGenBuffers(1, &_triangleVAO);
        glBindBuffer(GL_ARRAY_BUFFER, _triangleVAO);
        glBufferData(GL_ARRAY_BUFFER, sizeof(triangleVertices), triangleVertices, GL_STATIC_DRAW);
        
        GLfloat rectangleVertices[] = {
            -0.4, -0.4, 0.0,
            -0.4, -0.8, 0.0,
             0.4, -0.8, 0.0,
             0.4, -0.4, 0.0,
        };
        glGenBuffers(1, &_rectangleVAO);
        glBindBuffer(GL_ARRAY_BUFFER, _rectangleVAO);
        glBufferData(GL_ARRAY_BUFFER, sizeof(rectangleVertices), rectangleVertices, GL_STATIC_DRAW);
    }
    

    将图形画出来

    我们先指定好用哪个通道,然后再通过这个通道传输数据,并将它们显示出来。
    glEnableVertexAttribArray(0) 表示绑定我们编写的GLSL中的第一个参数。
    glDrawArrays(GL_TRIANGLES, 0, 3) 以三角形的方式画3个点。
    glDrawArrays(GL_TRIANGLE_FAN, 0, 4) 以三角形射线的方式画4个点,画了两个三角形。

    几种画图方式
    - (void)glkView:(GLKView *)view drawInRect:(CGRect)rect {
        GLKView *glView = (GLKView *)self.view;
        [EAGLContext setCurrentContext:glView.context];
        glClearColor(0, 0, 0, 1);
        glClear(GL_COLOR_BUFFER_BIT);
        
        [_triangleShader prepareToDraw];
        glBindBuffer(GL_ARRAY_BUFFER, _triangleVAO);
        glEnableVertexAttribArray(GLKVertexAttribPosition);
        glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
        glDrawArrays(GL_TRIANGLES, 0, 3);
        
        [_rectangleShader prepareToDraw];
        glBindBuffer(GL_ARRAY_BUFFER, _rectangleVAO);
        glEnableVertexAttribArray(GLKVertexAttribPosition);
        glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
        glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
    }
    

    运行项目,可以看到一个三角形和一个矩形,它们都是红色的。
    Github地址

    相关文章

      网友评论

        本文标题:在iOS中如何使用OpenGL画一些简单的图形

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