Opengl中GL_LUMINANCE被移除的兼容性问题

之前笔者写的Opengl入门教程都是面向Android开发者的Opengl ES方面的,总所周知,Opengl本身就是跨平台的,Opengl ES的程序只需经过稍微改动适配一下即可变成Opengl在 桌面端运行起来。

比如之前笔者写的文章 Opengl ES之YUV数据渲染  最近因为工作需要,笔者想把这部分的渲染代码适配到桌面端, 居然惊奇地发现了在Opengl 3.3中,关于颜色格式的内置变量GL_LUMINANCEGL_LUMINANCE_ALPHA居然被删除了。那咋整?此路不通啊…

兼容性修复

在Opengl ES中GL_LUMINANCE一般表示的是亮度信息,也就是一个颜色通道,在渲染NV21数据时,就表示的是Y的数据,而GL_LUMINANCE_ALPHA则表示的是两个通道的信息,在渲染NV21数据时表示的就是UV数据。

明白了这个含义之后,其实就是一个通道和两个通道的事情。既然GL_LUMINANCEGL_LUMINANCE_ALPHA被删除了,那我们可以再查询些资料看看Opengl中还有那些变量时可以表示一个数据通道和两个数据通道的,这样问题应该就能够解决了。

在Opengl中表示一个通道和表示两个通道的变量还是不少的,例如GL_REDGL_REDGL_GREENGL_BLUE等这些变量可以表示一个颜色通道的数据,而GL_RG可以表示两个颜色通道的数据, 同理GL_RGB则可以表示三个颜色通道的数据,GL_RGBA则是带透明度的四个颜色通道的数据。

当然,纹理的数据格式与着色器的渲染是息息相关的,我们改动了纹理数据格式的同时,着色器程序也需要作出相应的修改,否则就是白搭,总不能是我们上传的纹理数据是GL_GREEN,而在着色器中依然使用.r这样的数据通道吧?

既然原理都清楚了,那下面就是开始适配吧…

首先我们修改下纹理的数据格式,将GL_LUMINANCE改为GL_RED,将GL_LUMINANCE_ALPHA改为GL_RG,完整代码如下:


void YUVRenderOpengl::setYUVData(void *y_data, void *uv_data, int width, int height, int yuvType) {

    // 准备y数据纹理
    glGenTextures(1, &y_textureId);
    glActiveTexture(GL_TEXTURE2);
    glUniform1i(y_textureSampler, 2);

    // 绑定纹理
    glBindTexture(GL_TEXTURE_2D, y_textureId);
    // 为当前绑定的纹理对象设置环绕、过滤方式
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

    // 旧的 opengl ES使用
   //    glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, width, height, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, y_data);

   // 新的 opengl 3.3使用
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, width, height, 0, GL_RED, GL_UNSIGNED_BYTE, y_data);
    // 生成mip贴图
    glGenerateMipmap(GL_TEXTURE_2D);

    glBindTexture(GL_TEXTURE_2D, y_textureId);
    // 解绑定
    glBindTexture(GL_TEXTURE_2D, 0);

    // 准备uv数据纹理
    glGenTextures(1, &uv_textureId);
    glActiveTexture(GL_TEXTURE3);
    glUniform1i(uv_textureSampler, 3);

    // 绑定纹理
    glBindTexture(GL_TEXTURE_2D, uv_textureId);
    // 为当前绑定的纹理对象设置环绕、过滤方式
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    // 注意宽高
    // 注意要使用 GL_LUMINANCE_ALPHA
    // 旧的 opengl ES使用
//    glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, width/2, height/2, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, uv_data);

    // 新的 opengl 3.3使用
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RG, width/2, height/2, 0, GL_RG, GL_UNSIGNED_BYTE, uv_data);
    // 生成mip贴图
    glGenerateMipmap(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D, uv_textureId);
    // 解绑定
    glBindTexture(GL_TEXTURE_2D, 0);
}

相关改动部分笔者已增加注释说明。

然后我们修改下着色器部分,以下是原来的着色器代码:

static const char *fragment = "#version 300 es\n"
                              "precision mediump float;\n"
                              "out vec4 FragColor;\n"
                              "in vec2 TexCoord;\n"
                              "uniform sampler2D y_texture; \n"
                              "uniform sampler2D uv_texture;\n"
                              "void main()\n"
                              "{\n"
                              "vec3 yuv;\n"
                              "yuv.x = texture(y_texture, TexCoord).r;\n"
                              "yuv.y = texture(uv_texture, TexCoord).a-0.5;\n"
                              "yuv.z = texture(uv_texture, TexCoord).r-0.5;\n"
                              "vec3 rgb =mat3( 1.0,1.0,1.0,\n"
                              "0.0,-0.344,1.770,1.403,-0.714,0.0) * yuv;\n"
                              "FragColor = vec4(rgb, 1);\n"
                              "}";

因为我们在纹理上传时修改了Y和UV纹理数据的格式,但是Y数据我们使用的是GL_RED,因此在着色器中依然使用.r获取,者无需修改。由于UV纹理我们改为了GL_RG, 因此我们需要将yuv.y = texture(uv_texture, TexCoord).a-0.5;\n这一行的a通道改为g通道,也就是改为yuv.y = texture(uv_texture, TexCoord).g-0.5;\n

同时#version 300 es是opengl ES着色器的声明,在桌面端使用Opengl 3.3,我们需要将这个声明改为#version 330 core 。

因此完整的着色器代码是:


static const char *fragment = "#version 330 core\n"
                              "precision mediump float;\n"
                              "out vec4 FragColor;\n"
                              "in vec2 TexCoord;\n"
                              "uniform sampler2D y_texture; \n"
                              "uniform sampler2D uv_texture;\n"
                              "void main()\n"
                              "{\n"
                              "vec3 yuv;\n"
                              "yuv.x = texture(y_texture, TexCoord).r;\n"
                              "yuv.y = texture(uv_texture, TexCoord).g-0.5;\n"
                              "yuv.z = texture(uv_texture, TexCoord).r-0.5;\n"
                              "vec3 rgb =mat3( 1.0,1.0,1.0,\n"
                              "0.0,-0.344,1.770,1.403,-0.714,0.0) * yuv;\n"
                              "FragColor = vec4(rgb, 1);\n"
                              "}";

至此,NV21数据渲染就由Opengl ES向Opengl 3.3兼容适配完成啦…

关注我,一起进步,人生不止coding!!!

思想觉悟
思想觉悟

本文来自作者投稿,版权归原作者所有。如需转载,请注明出处:https://www.nxrte.com/jishu/27415.html

(0)

相关推荐

发表回复

登录后才能评论