ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

OpenGL学习笔记--渲染yuv纹理

2021-07-14 13:00:38  阅读:252  来源: 互联网

标签:1.0 OpenGL -- TEXTURE yuv tex GL 着色器


 

OpenGL视频学习资料:https://pan.baidu.com/s/1muWuuuo1_89AijQRNOcJmg
提取码:xcwn

 

 

一般ffmpeg解码后的数据类型都是I420,即YUV420P,OpenGL没有提供直接渲染yuv的接口,我们可以通过可编程渲染管线,利用多重纹理将Y、U、V纹理分别传入,在片元着色器GL_FRAGMENT_SHADER中将yuv进行矩阵转化成RGB,然后进行渲染。

GLSL简单介绍
OpenGL渲染管线的知识可以参考博客http://www.cnblogs.com/yyxt/p/4056417.html
顶点着色器和片元着色器是必须的。

GLSL的语法和C语言很类似。每一个Shader程序都有一个main函数,这一点和c语言是一样的。这里的变量命名规则保持跟c一样就行了,注意gl_开头的变量名是系统内置的变量。
变量类型:
attribute:外部传入顶点着色器的变量,每一个顶点都会有这两个属性。变化率高,用于定义每个点。
varying:用于顶点着色器和片元着色器之间相互传递的参数。
uniform:外部传入片元着色器的变量,变化率较低,对于可能在整个渲染过程没有改变,只是个常量。
数据类型:
vec2:包含了2个浮点数的向量
vec3:包含了3个浮点数的向量
vec4:包含了4个浮点数的向量
sampler1D:1D纹理着色器
sampler2D:2D纹理着色器
sampler3D:3D纹理着色器
mat2:2*2维矩阵
mat3:3*3维矩阵
mat4:4*4维矩阵
全局变量:
gl_Position:原始的顶点数据在Vertex Shader中经过平移、旋转、缩放等数学变换后,生成新的顶点位置(一个四维 (vec4) 变量,包含顶点的 x、y、z 和 w 值)。新的顶点位置通过在Vertex Shader中写入gl_Position传递到渲染管线的后继阶段继续处理。
gl_FragColor:Fragment Shader的输出,它是一个四维变量(或称为 vec4)。gl_FragColor 表示在经过着色器代码处理后,正在呈现的像素的 R、G、B、A 值。
Vertex Shader是作用于每一个顶点的,如果Vertex有三个点,那么Vertex Shader会被执行三次。Fragment Shader是作用于每个像素的,一个像素运行一次。从源代码中可以看出,像素的转换在Fragment Shader中完成。

总结一句话就是顶点着色器搞定位置,片元着色器搞定颜色。

创建YUV着色器
流程图:
开始
创建顶点着色器和片元着色器 glCreateShader
设定GLSL源码 glShaderSource
编译GLSL源码 glCompileShader
创建一个新的程序 glCreateProgram
关联着色器 glAttachShader
绑定attribute变量 glBindAttribLocation
链接程序 glLinkProgram
获取uniform变量 glGetUniformLocation
结束
代码示例
GLuint prog_yuv;
GLuint texUniformY,texUniformU,texUniformV;
GLuint tex_yuv[3];
enum E_VER_ATTR{ver_attr_ver = 3, ver_attr_tex = 4, ver_attr_num};

struct Texture{
GLuint texID; // glGenTextures分配的ID
GLuint type; // 数据类型如GL_RGB
GLint width;
GLint height;
GLint bpp;
GLubyte* data; // 像素数据
};

// 加载YUV着色器
void loadYUVShader(){
GLuint vs = glCreateShader(GL_VERTEX_SHADER);
GLuint fs = glCreateShader(GL_FRAGMENT_SHADER);

char szVS[] = " \
attribute vec4 verIn; \
attribute vec2 texIn; \
varying vec2 texOut; \
\
void main(){ \
gl_Position = verIn; \
texOut = texIn; \
} \
";
const GLchar* pszVS = szVS;
GLint len = strlen(szVS);
glShaderSource(vs, 1, (const GLchar**)&pszVS, &len);

char szFS[] = " \
varying vec2 texOut; \
uniform sampler2D tex_y; \
uniform sampler2D tex_u; \
uniform sampler2D tex_v; \
\
void main(){ \
vec3 yuv; \
vec3 rgb; \
yuv.x = texture2D(tex_y, texOut).r; \
yuv.y = texture2D(tex_u, texOut).r - 0.5; \
yuv.z = texture2D(tex_v, texOut).r - 0.5; \
rgb = mat3( 1, 1, 1, \
0, -0.39465, 2.03211, \
1.13983, -0.58060, 0) * yuv; \
gl_FragColor = vec4(rgb, 1); \
} \
";
const GLchar* pszFS = szFS;
len = strlen(szFS);
glShaderSource(fs, 1, (const GLchar**)&pszFS, &len);

glCompileShader(vs);
glCompileShader(fs);

//#ifdef _DEBUG
GLint iRet = 0;
glGetShaderiv(vs, GL_COMPILE_STATUS, &iRet);
glGetShaderiv(fs, GL_COMPILE_STATUS, &iRet);
//#endif

prog_yuv = glCreateProgram();

glAttachShader(prog_yuv, vs);
glAttachShader(prog_yuv, fs);

glBindAttribLocation(prog_yuv, ver_attr_ver, "verIn");
glBindAttribLocation(prog_yuv, ver_attr_tex, "texIn");

glLinkProgram(prog_yuv);

//#ifdef _DEBUG
glGetProgramiv(prog_yuv, GL_LINK_STATUS, &iRet);
//#endif

glValidateProgram(prog_yuv);

texUniformY = glGetUniformLocation(prog_yuv, "tex_y");
texUniformU = glGetUniformLocation(prog_yuv, "tex_u");
texUniformV = glGetUniformLocation(prog_yuv, "tex_v");


static const GLfloat vertices[] = {
-1.0f, -1.0f,
1.0f, -1.0f,
-1.0f, 1.0f,
1.0f, 1.0f,
};

static const GLfloat textures[] = {
0.0f, 1.0f,
1.0f, 1.0f,
0.0f, 0.0f,
1.0f, 0.0f,
};

// reverse
//static const GLfloat textures[] = {
// 0.0f, 0.0f,
// 1.0f, 0.0f,
// 0.0f, 1.0f,
// 1.0f, 1.0f,
//};

glVertexAttribPointer(ver_attr_ver, 2, GL_FLOAT, GL_FALSE, 0, vertices);
glEnableVertexAttribArray(ver_attr_ver);

glVertexAttribPointer(ver_attr_tex, 2, GL_FLOAT, GL_FALSE, 0, textures);
glEnableVertexAttribArray(ver_attr_tex);

glGenTextures(3, tex_yuv);
for (int i = 0; i < 3; i++){
glBindTexture(GL_TEXTURE_2D, tex_yuv[i]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_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);
}
}

// 绘画YUV数据
void drawYUV(Texture* tex){
glUseProgram(prog_yuv);

glMatrixMode(GL_PROJECTION);
glLoadIdentity();

int w = tex->width;
int h = tex->height;
int y_size = w*h;
GLubyte* y = tex->data;
GLubyte* u = y + y_size;
GLubyte* v = u + (y_size>>2);

glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, tex_yuv[0]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, w, h, 0, GL_RED, GL_UNSIGNED_BYTE, y);
glUniform1i(texUniformY, 0);

glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, tex_yuv[1]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, w/2, h/2, 0, GL_RED, GL_UNSIGNED_BYTE, u);
glUniform1i(texUniformU, 1);

glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, tex_yuv[2]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, w/2, h/2, 0, GL_RED, GL_UNSIGNED_BYTE, v);
glUniform1i(texUniformV, 2);

glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}


这里只是贴出了关键的加载YUV着色器,和绘画YUV数据关键的代码
————————————————
版权声明:本文为CSDN博主「ithewei」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/GG_SiMiDa/article/details/74474780

标签:1.0,OpenGL,--,TEXTURE,yuv,tex,GL,着色器
来源: https://www.cnblogs.com/yyjy-edu/p/15010322.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有