美文网首页
OpenGL ES内容(2)

OpenGL ES内容(2)

作者: ZZ_军哥 | 来源:发表于2020-09-30 18:15 被阅读0次

    废话不多说.开始写代码,用OpenGL ES加载一张图片(代码已经经过我测试)
    导入系统库

    #import <GLKit/GLKit.h> //由iOS提供,里面提供了一些对OpenGL ES封装的内容
    #import <OpenGLES/ES3/gl.h>  //OpenGL ES 系统库
    #import <OpenGLES/ES3/glext.h> //OpenGL ES 系统库
    @interface TestView ()
    @property(nonatomic,strong)CAEAGLLayer *myLayer; //显示的layer
    @property(nonatomic,strong)EAGLContext *myContext; //图形上下文
    @property(nonatomic,assign)GLuint myProgram; //链接两个shader的连接器
    @property(nonatomic,assign)GLuint frameBuffer; //帧缓冲区
    @property(nonatomic,assign)GLuint renderBuffer; //渲染缓冲区
    @end
    

    新建一个TestView类,添加到VC的View上,重写TestView 的Layer系统方法,将其替换为显示OpenGl ES的图层

    + (Class)layerClass
    {
        return [CAEAGLLayer class];
    }
    

    在layoutSubviews里分了5个阶段内容,前面4个阶段基本是固定死的,不会有啥变动
    主要是第5个阶段

    - (void)layoutSubviews
    {
        //1.设置图层
        [self setUpLayer];
        //2.设置上下文
        [self setUpContext];
        //3.设置渲染缓冲区
        [self setUpRenderBuffer];
        //4.设置帧缓冲区
        [self setUpFrameBuffer];
        //5.开始渲染
        [self render];
    }
    

    1.设置图层

    - (void)setUpLayer
    {
        //将CALayer变成CAEAGLLayer
        self.myLayer = (CAEAGLLayer *)self.layer;
      //设置View的比例系数
        [self setContentScaleFactor:[UIScreen mainScreen].scale];
      //设置CAEAGLLayer的颜色空间
        self.myLayer.drawableProperties = @{kEAGLDrawablePropertyColorFormat:kEAGLColorFormatRGBA8,kEAGLDrawablePropertyRetainedBacking:@(false)};
    }
    

    2.设置上下文

    - (void)setUpContext
    {
        //创建一个ES3.0的上下文,并将其设置为当前上下文
        self.myContext = [[EAGLContext alloc]initWithAPI:kEAGLRenderingAPIOpenGLES3];
        [EAGLContext setCurrentContext:self.myContext];
    }
    

    3.设置渲染缓冲区

    - (void)setUpRenderBuffer
    {
        //申请渲染缓存区标识
        glGenRenderbuffers(1, &_renderBuffer);
        //绑定渲染缓存区
        glBindRenderbuffer(GL_RENDERBUFFER, self.renderBuffer);
        //将标识符绑定到GL_RENDERBUFFER
        [self.myContext renderbufferStorage:GL_RENDERBUFFER fromDrawable:self.myLayer];
    }
    

    4.设置帧缓存区

    - (void)setUpFrameBuffer
    {
        //申请帧缓冲区标识
        glGenFramebuffers(1, &_frameBuffer);
        //绑定帧缓冲区
        glBindFramebuffer(GL_FRAMEBUFFER, self.frameBuffer);
        //将_renderBuffer 装配到GL_COLOR_ATTACHMENT0 附着点上
        glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, self.renderBuffer);
    }
    

    5.接下来就是在render中的代码
    第一步:

       //1.设置背景色绿色(RGBA)
        glClearColor(0, 1, 0, 1);
        //2.清理颜色缓存区
        glClear(GL_COLOR_BUFFER_BIT);
        //3.创建视口
        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);
    

    第二步.配置顶点和纹理坐标

        GLfloat vertice[] = {
            
            //下面的三角形
            -0.55,0.5,0,   1,0,  //左上角
            -0.55,-0.5,0,  0,0,  //左下角
            0.45,-0.5,0,   1,0,  //右下角
            //上面的三角形
            -0.45,0.5,0,   1,0,  //左上角
            0.55,0.5,0,    1,1,   //右上角
            0.55,-0.5,0,    1,1   //右下角
        };
    

    第三步:编写着色器,新建两个empty文件,shader.vsh和shader.fsh,文件名和后缀名按你喜好随便写.
    1.shader.vsh中的代码:注意本来这个文件中时不能有注释的,否则编译该字符串时容易失败,只是为了讲解写的注释

    //1.申明position 和 textureCoord 用来接收外部传过来的顶点坐标和纹理坐标
    attribute vec3 position;
    attribute vec2 textureCoord;
    //2.将纹理坐标从顶点着色器传入到片元着色器的通道
    varying lowp vec2 varingPosition;
    
    void main()
    {
        varingPosition = textureCoord;
        //3. gl_Position为OpenGL ES内部已经创建的变量,顶点数据一定要给它,否则无效
        gl_Position = position;
    }
    

    2.shader.fsh的代码:注意一点,片元主色器中未申明的变量不会配给精度,需要自己设置精度,否则运算会出错.而顶点着色器会配默认精度

    //由于片元着色器的没有申明精度的变量不会默认精度,如果没有精度,会出错,全局申明float类型为高精度
    precision highp float;
    //和顶点着色器中的通道必须一样
    varying lowp vec2 varingPosition;
    //纹理采样器
    uniform lowp sampler2D colorMap;
    void main()
    {
        /*gl_FragColor为内建变量,颜色赋值给该变量,OpenGL ES才能获取
         texture2D为内建函数,根据采样器和顶点获取纹理数据
        */
        gl_FragColor = texture2D(colorMap,varingPosition);
    }
    

    3.将两个shader文件字符串加载运行到program中

    - (GLuint)loadProgramVerFile:(NSString *)verFile fragFile:(NSString *)fragFile
    {
        //声明顶点,片元着色器变量
        GLuint vershader,fragmentShader;
        //创建program
        GLint program = glCreateProgram();
        //将两个着色器中的字符串编译成程序
        [self compileShader:&vershader file:verFile type:GL_VERTEX_SHADER];
        [self compileShader:&fragmentShader file:fragFile type:GL_FRAGMENT_SHADER];
        //将两个着色器程序附着在program中,后面用program对着色器进行操作
        glAttachShader(program, vershader);
        glAttachShader(program, fragmentShader);
        //删除已经附着完的shader
        glDeleteShader(vershader);
        glDeleteShader(fragmentShader);
        return program;
    }
    - (void)compileShader:(GLuint *)shader file:(NSString *)file type:(GLint)type
    {
        //获取字符串
        NSString *str = [NSString stringWithContentsOfFile:file encoding:NSUTF8StringEncoding error:nil];
        //转化为C字符串
        const GLchar *source = (GLchar *)[str UTF8String];
        //创建着色器
        *shader = glCreateShader(type);
        //将文件中的字符串载入到shader中
        glShaderSource(*shader, 1, &source, NULL);
        //编译shader生成程序
        glCompileShader(*shader);
    }
    

    第四部:render方法中

        //2.编译链接两个着色器
        NSString *verFile = [[NSBundle mainBundle]pathForResource:@"shader.vsh" ofType:nil];
        NSString *fragFile = [[NSBundle mainBundle]pathForResource:@"shader.fsh" ofType:nil];
     
        //将两个着色器文件传入链接成program
        self.myProgram = [self loadProgramVerFile:verFile fragFile:fragFile];
        //链接program(有可能失败,因为你的shader文件代码可能写错)
        glLinkProgram(self.myProgram);
        //获取连接状态
        GLint linkStatus;
        glGetProgramiv(self.myProgram, GL_LINK_STATUS, &linkStatus);
        if (linkStatus == GL_FALSE) {
            GLchar message[1000];
            //获取连接错误信息
            glGetProgramInfoLog(self.myProgram, sizeof(message), NULL, message);
            NSString *log = [[NSString alloc]initWithUTF8String:message];
            NSLog(@"链接失败:%@",log);
            return;
        }
        //开始使用program
        glUseProgram(self.myProgram);
    

    第五部,开始将顶点信息传入到着色器中,

        //将顶点数据从内存复制到现存
        GLuint buffer;
        glGenBuffers(1, &buffer);
        glBindBuffer(GL_ARRAY_BUFFER, buffer);
        glBufferData(GL_ARRAY_BUFFER, sizeof(vertice), vertice, GL_STATIC_DRAW);
        //获取顶点着色器中的 顶点属性通道 attribute vec3 position;传入的变量名和shader文件的名称一样
        GLint position = glGetAttribLocation(self.myProgram, "position");
        //开启position属性传输通道,默认是关闭的
        glEnableVertexAttribArray(position);
        //将顶点数据传入到shader中
        glVertexAttribPointer(position, 6, GL_FLOAT, GL_FALSE, sizeof(GLfloat)*5, NULL);
        //纹理坐标的传入和顶点一样
        GLint textureCoord = glGetAttribLocation(self.myProgram, "textureCoord");
        glEnableVertexAttribArray(textureCoord);
            glVertexAttribPointer(position, 6, GL_FLOAT, GL_FALSE, sizeof(GLfloat)*5, (GLfloat *)NULL+3);
        //设置纹理内容
        [self setUpTexture];
        //获取着色器
        GLint colorMap = glGetUniformLocation(self.myProgram, "colorMap");
        //第一个纹理,在设置纹理时也设置为0
        glUniform1f(colorMap, 0);
        
        //开始绘制图像 1.三角形 2.从0开始 3.6个顶点
        glDrawArrays(GL_TRIANGLES, 0, 6);
        
        //将绘制好的内容呈现到屏幕上来
        [self.myContext presentRenderbuffer:GL_RENDERBUFFER];
    

    第五步:在家纹理

    - (void)setUpTexture
    {
        //图片解压缩,变成位图,具体可以网上搜,本文不讲解
        CGImageRef imageRef = [UIImage imageNamed:@"girl"].CGImage;
        size_t width = CGImageGetWidth(imageRef);
        size_t height = CGImageGetHeight(imageRef);
        GLubyte *datas = calloc(width*height*4, sizeof(GLubyte));
        //将图片转化为位图
        CGContextRef contextRef = CGBitmapContextCreate(datas, width, height, 8, width*4, CGImageGetColorSpace(imageRef), kCGImageAlphaPremultipliedLast);
        CGRect rect = CGRectMake(0, 0, width, height);
        CGContextDrawImage(contextRef, rect, imageRef);
        
        //绑定纹理,将其设置成第0个纹理,与glUniform1f(colorMap, 0);对应
        glBindTexture(GL_TEXTURE0, 0);
        float w = width;
        float h = height;
        //设置纹理格式
        glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
        glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
        glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
        //加载纹理数据
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, datas);
        free(contextRef);
        free(datas);
    }
    
    

    相关文章

      网友评论

          本文标题:OpenGL ES内容(2)

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