美文网首页
OpenGL ES GLSL加载图片

OpenGL ES GLSL加载图片

作者: 大橘猪猪侠 | 来源:发表于2020-08-07 21:44 被阅读0次

    OpenGL ES需要渲染上下文和绘制表面才能完成图像的绘制。但是OpenGL的API并没有提供如何创建渲染上下文或者如何连接到原生窗口系统。EGL时Khronos渲染API和原生系统之间的接口。
    唯一支持OpenGL ES 却不支持EGL的平台时iOS。因此我们在iOS系统上使用的EGL是苹果自己定义的EGL。

    在本案例中,使用的EGL是CAEAGLLayer。

    下面介绍一下EGL的主要功能:
    1、和本地窗口系统通讯
    2、查询可用的配置
    3、创建OpenGL ES可用的“绘图表面”
    4、同步不同类别的API之间的渲染。
    5、管理“渲染资源”,比如纹理映射。

    这个案例需要实现的目标有:
    1、用EAGL创建屏幕上的渲染表面
    2、加载顶点/片元着色器
    3、创建一个程序对象,并链接顶点/片元着色器,并链接程序对象
    4、设置视口
    5、清除颜色缓冲区
    6、渲染简单图元
    7、使颜色缓冲区的内容在EAGL窗口表现呈现

    案例的最终效果:

    Simulator Screen Shot - iPhone SE -2nd generation- - 2020-07-30 at 20.52.24.png

    如何实现上面图形的效果呢?

    首先我们要去定义顶点着色器和片元着色器去加载数据
    我们定义两个空文件,一个后缀为fsh(片元着色器),一个为vsh(顶点着色器)
    片元着色器代码

    precision highp float;
    varying lowp vec2 varyTextCoord;
    uniform sampler2D colorMap;
    
    void main(){
        gl_FragColor = texture2D(colorMap,varyTextCoord);
    }
    
    

    顶点着色器代码

    attribute vec4 position;
    attribute vec2 textCoordinate;
    varying lowp vec2 varyTextCoord;
    
    void main(){
        varyTextCoord = textCoordinate;
        gl_Position = position;
    }
    
    

    在定义完着色器后,就可以实现用GLSL去加载图片
    我们分六步完成:
    第一步:设置图层
    将CAEAGLLayer替换CALayer,然后设置屏幕大小,设置描述属性。

    self.myEagLayer = (CAEAGLLayer *)self.layer;
    [self setContentScaleFactor:[[UIScreen mainScreen]scale]];
    self.myEagLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:@false,kEAGLDrawablePropertyRetainedBacking,kEAGLColorFormatRGBA8,kEAGLDrawablePropertyColorFormat, nil];
    

    第二步:设置上下文
    上下文是就是存储程序的状态
    首先确定OpenGL ES渲染API的版本,然后创建图像上下文

    EAGLRenderingAPI api = kEAGLRenderingAPIOpenGLES3;
    EAGLContext *context = [[EAGLContext alloc]initWithAPI:api];
    

    第三步:清空缓冲区

    glDeleteBuffers(1, &_myColorRenderBuffer);
    self.myColorRenderBuffer = 0;
    
    glDeleteBuffers(1, &_myColorFrameBuffer);
    self.myColorFrameBuffer = 0;
    

    第四步:设置RenderBuffer(renderbuffer 能够被⽤用来分配和存储颜⾊色、
    深度或者模板值)

    GLuint buffer;
    glGenRenderbuffers(1, &buffer);
    glBindRenderbuffer(GL_RENDERBUFFER, self.myColorRenderBuffer);
    [self.myContext renderbufferStorage:GL_RENDERBUFFER fromDrawable:self.myEagLayer];
    

    第五步:设置FrameBuffer(是⼀个收集颜⾊色、深
    度和模板缓存区的附着点。描述属性的状态,例如颜色、深度和模板
    缓存区的⼤小和格式,都关联到FBO(Frame Buffer Object))

    GLuint buffer;
    glGenFramebuffers(1, &buffer);
    glBindFramebuffer(GL_FRAMEBUFFER, self.myColorFrameBuffer);
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, self.myColorRenderBuffer);
    

    第四步和第五步代码步骤都差不多,都是创建一个缓冲区id,然后申请缓冲区标志,然后绑定,再与EAGL绑定在一起

    第六步:绘制,在这个过程中,我们需要引用我们之前写的着色器。并且加载顶点数据和纹理也是在这一步当中

    glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
        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 *verFile = [[NSBundle mainBundle]pathForResource:@"shaderv" ofType:@"vsh"];
    
    NSString *fragFile = [[NSBundle mainBundle]pathForResource:@"shaderf" ofType:@"fsh"];
    
    self.myPrograme = [self loadShaders:verFile Withfrag:fragFile];
    glLinkProgram(self.myPrograme);
    GLint linkStatus;
    glGetProgramiv(self.myPrograme, GL_LINK_STATUS, &linkStatus); 
    glUseProgram(self.myPrograme);
     GLfloat attrArr[] =
        {
            0.5f, -0.5f, -1.0f,     1.0f, 0.0f,
            -0.5f, 0.5f, -1.0f,     0.0f, 1.0f,
            -0.5f, -0.5f, -1.0f,    0.0f, 0.0f,
    
            0.5f, 0.5f, -1.0f,      1.0f, 1.0f,
            -0.5f, 0.5f, -1.0f,     0.0f, 1.0f,
            0.5f, -0.5f, -1.0f,     1.0f, 0.0f,
        };
    
        GLuint attriBuffer;
        glGenBuffers(1, &attriBuffer);
        glBindBuffer(GL_ARRAY_BUFFER, attriBuffer);
        glBufferData(GL_ARRAY_BUFFER, sizeof(attrArr), attrArr, GL_DYNAMIC_DRAW);
    
    GLuint position = glGetAttribLocation(self.myPrograme, "position");
    
    glEnableVertexAttribArray(position);
    glVertexAttribPointer(position, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat)*5, NULL);
    GLuint textCoor = glGetAttribLocation(self.myPrograme, "textCoordinate");
    
    glEnableVertexAttribArray(textCoor);
    
    glVertexAttribPointer(textCoor, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat)*5, (float *)NULL+3);
    [self setupTexture:@"fengjing"];
    glUniform1i(glGetUniformLocation(self.myPrograme, "colorMap"), 0);
    glDrawArrays(GL_TRIANGLES, 0, 6);
    [self.myContext presentRenderbuffer:GL_RENDERBUFFER];
    
    

    整个过程就此结束,从上面的图来看,它是倒着的,这又是什么原因呢?
    那是因为它开始加载的顶点是从左下角开始加载,因此图片是反的。
    那么我们如何实现它的正向显示呢?

    在案例中,我们可以在加载纹理的过程中,去对图片进行翻转,将它翻转之后,再加载上去。

        CGContextTranslateCTM(spriteContext, rect.origin.x, rect.origin.y);
        CGContextTranslateCTM(spriteContext, 0, rect.size.height);
        CGContextScaleCTM(spriteContext, 1.0, -1.0);
        CGContextTranslateCTM(spriteContext, -rect.origin.x, -rect.origin.y);
        CGContextDrawImage(spriteContext, rect, spriteImage);
    

    在加上上面的代码之后,图片就能正常显示了,当然翻转的方式有很多种,这边就使用了一种简单的方法去实现

    附上demo

    相关文章

      网友评论

          本文标题:OpenGL ES GLSL加载图片

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