本文正在参加「金石计划」
起因
之前笔者写的Opengl入门教程都是面向Android开发者的Opengl ES方面的,总所周知,Opengl本身就是跨平台的,Opengl ES的程序只需经过稍微改动适配一下即可变成Opengl在 桌面端运行起来。
比如之前笔者写的文章 Opengl ES之YUV数据渲染 最近因为工作需要,笔者想把这部分的渲染代码适配到桌面端,
居然惊奇地发现了在Opengl 3.3中,关于颜色格式的内置变量GL_LUMINANCE和GL_LUMINANCE_ALPHA居然被删除了。那咋整?此路不通啊...
兼容性修复
在Opengl ES中GL_LUMINANCE一般表示的是亮度信息,也就是一个颜色通道,在渲染NV21数据时,就表示的是Y的数据,而GL_LUMINANCE_ALPHA则表示的是两个通道的信息,在渲染NV21数据时表示的就是UV数据。
明白了这个含义之后,其实就是一个通道和两个通道的事情。既然GL_LUMINANCE和GL_LUMINANCE_ALPHA被删除了,那我们可以再查询些资料看看Opengl中还有那些变量时可以表示一个数据通道和两个数据通道的,这样问题应该就能够解决了。
在Opengl中表示一个通道和表示两个通道的变量还是不少的,例如GL_RED、GL_RED、GL_GREEN、GL_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兼容适配完成啦...
Opengl ES系列入门介绍
Opengl ES之EGL环境搭建
Opengl ES之着色器
Opengl ES之三角形绘制
Opengl ES之四边形绘制
Opengl ES之纹理贴图
Opengl ES之VBO和VAO
Opengl ES之EBO
Opengl ES之FBO
Opengl ES之PBO
Opengl ES之YUV数据渲染
YUV转RGB的一些理论知识
Opengl ES之RGB转NV21
Opengl ES之踩坑记
Opengl ES之矩阵变换(上)
Opengl ES之矩阵变换(下)
Opengl ES之水印贴图
Opengl ES之纹理数组
OpenGL ES之多目标渲染(MRT
Opengl ES之LUT滤镜(上)
Opengl ES之LUT滤镜(下)-3DLUT
OpenglES之分屏滤镜
关注我,一起进步,人生不止coding!!!