OpenGL ES _ 入门_01

作者: 酷走天涯 | 来源:发表于2016-08-17 21:22 被阅读6766次

    OpenGL ES _ 入门_01
    OpenGL ES _ 入门_02
    OpenGL ES _ 入门_03
    OpenGL ES _ 入门_04
    OpenGL ES _ 入门_05
    OpenGL ES _ 入门练习_01
    OpenGL ES _ 入门练习_02
    OpenGL ES _ 入门练习_03
    OpenGL ES _ 入门练习_04
    OpenGL ES _ 入门练习_05
    OpenGL ES _ 入门练习_06
    OpenGL ES _ 着色器 _ 介绍
    OpenGL ES _ 着色器 _ 程序
    OpenGL ES _ 着色器 _ 语法
    OpenGL ES_着色器_纹理图像
    OpenGL ES_着色器_预处理
    OpenGL ES_着色器_顶点着色器详解
    OpenGL ES_着色器_片断着色器详解
    OpenGL ES_着色器_实战01
    OpenGL ES_着色器_实战02
    OpenGL ES_着色器_实战03

    学习是一件开心的额事情

    本节学习目标

    • 创建一个完整的OpenGL ES 工程代码
    • 绘制三角形
      提醒:代码你可能看不懂,因为你没学过这个东西,看完这个只要你知道是什么东西就行了,后续内容马上跟进!

    第一步.创建一个工程

    CA60DADE-C80A-4F8A-A4C2-A8771C952B8D.png ](http:https://img.haomeiwen.com/i1594482/6a9848ca8df11b95.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

    第二步:删除掉ViewController.h和ViewController.m文件


    删除自带文件

    第三步:创建继承自GLKViewController 的控制器对象,我起了一个名字叫OSViewController


    创建对象

    第四步.在OSViewController.h文件中引用框架#import <GLKit/GLKit.h>


    引用框架

    第五步,将创建的控制器和storyborad的视图进行绑定

    绑定

    完成以上几步:我们的配置算是完成了!


    第六步,创建一个EAGContext 对象,用来跟踪OpenGL 的状态和管理数据和命令

    // MARK: - 创建一个EAGContext
    -(void)createEagContext{
    self.eagcontext = [[EAGLContext alloc]initWithAPI:kEAGLRenderingAPIOpenGLES2];
    [EAGLContext setCurrentContext:self.eagcontext];
    }
    

    第七步.配置GLKView(刚才创建的控制器的view的类型就是GLKView类型)

    // MARK: - 配置GLKView
    -(void)configure{
    GLKView *view = (GLKView*)self.view;
    view.context = self.eagcontext;
    view.drawableDepthFormat = GLKViewDrawableDepthFormat24;
    }
    

    第八步.编写顶点着色器程序(Shader.vsh)

    CA60DADE-C80A-4F8A-A4C2-A8771C952B8D.png
    attribute vec4 position; // 属性,如果绑定了这个属性,
    uniform  vec4 color; // 需要从程序中传入的值,一会我们会不断改变这个值
    varying lowp vec4 colorVarying; // 这个值需要和片段着色器的声明相同
    
    void main()
    {
       gl_Position = position; // 设置顶点位置
       colorVarying = color;  // 设置顶点颜色
     }
    

    第九步.编写片段着色器程序(Shader.fsh)
    和上面的创建类似,文件名字后缀不一样

      varying lowp vec4 colorVarying;
      void main()
      {
        gl_FragColor = colorVarying; // 设置片段着色器中的颜色
      }
    

    第十步. 分别编译两个顶点着色器程序和片断着色器源代码。

     // 1.创建标示
    GLuint vertShader, fragShader;
    // 2.获取文件路径
    NSString *vertShaderPathname, *fragShaderPathname;
    vertShaderPathname = [[NSBundle mainBundle] pathForResource:@"Shader" ofType:@"vsh"];
    // 3.编译
    if (![self compileShader:&vertShader type:GL_VERTEX_SHADER file:vertShaderPathname]) {
        NSLog(@"编译失败 vertex shader");
        return NO;
    }
    
    // 创建 编译 片断着色器
    fragShaderPathname = [[NSBundle mainBundle] pathForResource:@"Shader" ofType:@"fsh"];
    if (![self compileShader:&fragShader type:GL_FRAGMENT_SHADER file:fragShaderPathname]) {
        NSLog(@"Failed to compile fragment shader");
        return NO;
    }
    

    编译代码封装了一下,具体代码如下:

    - (BOOL)compileShader:(GLuint *)shader type:(GLenum)type file:(NSString *)file
    {
    
    //1  获取文件的内容 并进行NSUTF8StringEncoding 编码
    const GLchar *source;
    source = (GLchar *)[[NSString stringWithContentsOfFile:file encoding:NSUTF8StringEncoding error:nil] UTF8String];
    if (!source) {
        NSLog(@"Failed to load vertex shader");
        return NO;
    }
    //2 根据类型创建着色器
    *shader = glCreateShader(type);
    //3. 获取着色器的数据源
    glShaderSource(*shader, 1, &source, NULL);
    //4. 开始编译
    glCompileShader(*shader);
    // 方便调试,可以不用
    #if defined(DEBUG)
    GLint logLength;
    glGetShaderiv(*shader, GL_INFO_LOG_LENGTH, &logLength);
    if (logLength > 0) {
        GLchar *log = (GLchar *)malloc(logLength);
        glGetShaderInfoLog(*shader, logLength, &logLength, log);
        NSLog(@"Shader compile log:\n%s", log);
        free(log);
    }
    #endif
    //5. 查看是否编译成功
    GLint status;
    
    glGetShaderiv(*shader, GL_COMPILE_STATUS, &status);
    if (status == 0) {
        glDeleteShader(*shader);
        return NO;
    }
    
    return YES;
    }
    

    经过上面的代码 ,我们就讲两个着色器程序编译完成


    第十一步.创建着一个空的色器程序,把刚才编译好的两个着色器目标代码,连接到这个空的程序中去

      _program = glCreateProgram();
    // 第九步 将顶点着色器加到程序中
    glAttachShader(_program, vertShader);
    
    // 将片断着色器加到程序中
    glAttachShader(_program, fragShader);
    

    第十二步.将着色器程序的属性绑定到OpenGL 中

     // 绑定着色器的属性
    glBindAttribLocation(_program, 0, "position");  // 0代表枚举位置
    

    第十三步.开始正式链接着色器程序

        if (![self linkProgram:_program]) {
        NSLog(@"Failed to link program: %d", _program);
        
        if (vertShader) {
            glDeleteShader(vertShader);
            vertShader = 0;
        }
        if (fragShader) {
            glDeleteShader(fragShader);
            fragShader = 0;
        }
        if (_program) {
            glDeleteProgram(_program);
            _program = 0;
        }
        
        return NO;
    }
    

    下面是封装的链接着色器程序

    - (BOOL)linkProgram:(GLuint)prog
    {
    // 1链接程序
    glLinkProgram(prog);
    
    #if defined(DEBUG)
    GLint logLength;
    glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &logLength);
    if (logLength > 0) {
        GLchar *log = (GLchar *)malloc(logLength);
        glGetProgramInfoLog(prog, logLength, &logLength, log);
        NSLog(@"Program link log:\n%s", log);
        free(log);
    }
    #endif
    // 2 检查链接结果
    GLint status;
    glGetProgramiv(prog, GL_LINK_STATUS, &status);
    if (status == 0) {
        return NO;
    }  
    return YES;
    

    }


    第十四步.获取着色器中输入变量的索引值

     _vertexcolor = glGetUniformLocation(_program, "color");
    

    第十五步. 将顶点数据加载到GPU 中去

     // 三角形顶点数据
    static GLfloat vertex[6] = {
    -1,-1,// 左下
    -1,1, // 左上
    1,1  // 右上
     };
    // 加载数据,具体的参数说明暂时不写了,后面会专门讲
    -(void)loadVertex{
    glGenBuffers(1, &_vertexBuffer); // 申请内存标识
    glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);// 绑定
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertex), vertex, GL_STATIC_DRAW);// 申请内存空间
    glEnableVertexAttribArray(GLKVertexAttribPosition);// 开启顶点数据
    // 设置指针
    glVertexAttribPointer(GLKVertexAttribPosition, 
    2, 
    GL_FLOAT,
    GL_FALSE, 
    8,
    0);
    } 
    

    第十六步. 绘制数据

    -(void)glkView:(GLKView *)view drawInRect:(CGRect)rect{
      static NSInteger count = 0;
     // 清除颜色缓冲区
     glClearColor(1, 1, 1, 1);
     glClear(GL_COLOR_BUFFER_BIT);
     count ++;
      if (count > 50 ) {
        count = 0;
        // 根据颜色索引值,设置颜色数据,就是刚才我们从着色器程序中获取的颜色索引值
        glUniform4f(_vertexcolor,   arc4random_uniform(255)/225.0, arc4random_uniform(255)/225.0, arc4random_uniform(255)/225.0, 1);
      }
      // 使用着色器程序
      glUseProgram(_program);
      // 绘制
      glDrawArrays(GL_TRIANGLES, 0, 3);  
     }
    

    代码有点多,请按照步骤敲打一遍。
    效果是不断变化颜色的三角形


    切图一 切图二

    总结

    OpenGL 是一个很深奥,又很神奇的东西!想学技术的加群:578734141

    代码下载

    相关文章

      网友评论

      • 哈秋呵呵:请问demo的新地址是什么啊
        搜捕儿:同问~github找不到这个文章的demo呀大佬
        哈秋呵呵:@酷走天涯 在OpenGLES_Learn目录下没有找到O pen GLES_001的代码:joy:
        酷走天涯:@哈秋呵呵 github上找找看
      • 7e70e3784a48:照着敲了一遍 运行出来的三角形一直是黑色的 请问可能哪里出了问题呢?
      • 酷走天涯:windows上我没玩过,你可能买本书看看,OpenGL 的内容还是蛮多的
      • 58d1f0e1bcc8:额,OpenGL小白路过,请问楼主,有没有在windows上的编写的案例,也希望能这么一步一步来的
      • blue_lights:群主,你这些例子的代码,github上怎么找不到了
        blue_lights:@酷走天涯 恩恩,谢了,博主思路很清晰,受教
        酷走天涯:@想象的产儿 地址改了,没有及时更新,待会发给你
      • d8a23509d4f2: if (_program) {
        glDeleteProgram(_program);
        _program = 0;
        }
        在这地方delete program不会出问题吗?
        暴走大牙:@华丽丽的outline 没问题,link失败了,link成功了也可以删shader
      • c7d69b3fd2fb:GLKViewController没有啊 GLKIt 框架 是什么框架 代码下载的地址404 找不到
      • 神经骚栋:大神 Demo的传送门是错误的~
        酷走天涯:@神经骚栋 我正在整理库,你可以到https://github.com/XJALYN/OpenGLES_Learn这里去找
      • 童冀:开篇是OpenGL ES 2 后面怎么变成1了
        童冀:@酷走天涯 api变动的多不
        酷走天涯:@童冀 之前的教程有一些是es1 要区别对待
        酷走天涯:@童冀 是opengl es2

      本文标题:OpenGL ES _ 入门_01

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