opengl 高级技巧

Posted qianbo_insist

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了opengl 高级技巧相关的知识,希望对你有一定的参考价值。

1 glOrtho 投影变换,使得和uv坐标一致

在二维平面顶点坐标和uv 纹理坐标如何做到一致而不用计算?
像一下这么使用

 glOrtho(0,1,1,0,-1,100);

接下去的坐标就可以由原来的负数变成和uv 一致
//传递顶点和纹理坐标
//顶点
// static const GLfloat ver[] = {
// -1.0f,-1.0f,
// 1.0f,-1.0f,
// -1.0f, 1.0f,
// 1.0f,1.0f
// };

我们知道opengl 标准坐标是 左右 -1 到 1, 上下是 1 到 -1 ,而整个屏幕的中间才是 0,0,0,也就是原点,
但是经过 glOrtho(0,1,1,0,-1,100); 变换后,就可以变成 左右 0 到1 上下也是0 到 1 ,是不是可以和 uv 坐标一致了,是的!
上面的矩阵变成下面的
static const GLfloat ver[] = {
0.0f, 1.0f,
1.0f, 1.0f,
0.0f, 0.0f,
1.0f, 0.0f
};
这下,tex 和 ver 可以使用同一个矩阵了。

2 和glsl 兼容问题

一旦使用glOrtho 和 glPers glFrustum 等函数时, glsl 中的顶点坐标依然是 (-1 ,1) , 那么怎么和glOrtho 等投影矩阵一致呢?我们熟知的三个矩阵投影变换模型矩阵
1 变换矩阵 2 投影矩阵 3 模型观察矩阵 要做乘法和顶点相乘,也就是:

uniform mat4 projMat;
uniform mat4 viewMat;
uniform mat4 modelMat; 

三个相乘
我们来写个glsl
以下是顶点着色器

const char *vsrc =   "#version 330\\n"
                           "uniform mat4 projMat;\\n"
						   "uniform mat4 viewMat;\\n"
						   "uniform mat4 modelMat; \\n"
                           "in vec3 pos;\\n"
                           "in vec2 texin;\\n"
                           "out vec2 texCoord;\\n"
                           "void main()\\n"
                           "{\\n"
                           "    gl_Position = * vec4(pos, 1.0);\\n"
                           "    texCoord = texin;\\n"
                           "}\\n";

以下是片元着色器

    const char *fsrc =
                           "#version 330\\n"
                           "out mediump vec4 color;\\n"
                           "in vec2 texCoord;\\n"
                           "uniform sampler2D tex\\n;"
                           "void main()\\n"
                           "{\\n"
                           "    color = texture(tex, texCoord);\\n"
                           //"      color = vec4(1.0, 0.0, 0.0, 0.0);\\n"
                           "}\\n";

计算三个矩阵要传进去才能正确,为了避免使用矩阵传入,一种方法是,在glsl 语言里面依然使用原坐标,二种方法是,使用兼容glsl

 const char *vsrc =   "#version 330 compatibility\\n"
                           "in vec3 pos;\\n"
                           "in vec2 texin;\\n"
                           "out vec2 texCoord;\\n"
                           "void main()\\n"
                           "{\\n"
                           "    gl_Position = gl_ModelViewProjectionMatrix * vec4(pos, 1.0);\\n"
                           "    texCoord = texin;\\n"
                           "}\\n";

神奇的是,以前的的版本有一个全局变量叫gl_ModelViewProjectionMatrix,可以不用我们手动计算,代价是要加上compatibility 。

当然,我们可以手动获取投影矩阵的值,像以下这样:

float mat[16];
glGetFloatv(GL_PROJECTION_MATRIX, mat);

3、使用glm 计算矩阵

当然,除了使用兼容方式,可以使用glm 来计算投影变换模型矩阵
m_mat4View = glm::lookAt(glm::vec3(0, 0, -1), glm::vec3(0, 0, 0), glm::vec3(0, -1, 0));
m_mat4Projection = glm::ortho(-1.0f, 1.0f, -1.0f, 1.0f);
m_mat4Model = glm::mat4(1.0f);
m_mat4Model = glm::translate(m_mat4Model, glm::vec3(m_fXTranslate, m_fYTranslate, m_fZTranslate));
m_mat4Model = glm::rotate(m_mat4Model, glm::radians(m_fXRotateDegree), glm::vec3(1.0f, 0, 0));
m_mat4Model = glm::rotate(m_mat4Model, glm::radians(m_fYRotateDegree), glm::vec3(0, 1.0f, 0));
m_mat4Model = glm::rotate(m_mat4Model, glm::radians(m_fZRotateDegree), glm::vec3(0, 0, 1.0f));
m_mat4Model = glm::scale(m_mat4Model, glm::vec3(m_fXScale, m_fYScale, m_fZScale));
m_mat4ProjectionModelView = m_mat4Projection * m_mat4View * m_mat4Model;
glUniformMatrix4fv(m_iProjectionModelViewIDUniform, 1, GL_FALSE, &m_mat4ProjectionModelView[0][0]);

这样,把计算的m_mat4ProjectionModelView 传到glsl 中也是可以的

#version 330 core
uniform mat4 ProjectionModelView;
in vec4 vertexCoord;
in vec2 textureCoord;
out vec2 outTextureCoord;

void main(void){
gl_Position = ProjectionModelView * vertexCoord;
outTextureCoord = textureCoord;
}

#version 330 core
in vec2 outTextureCoord;
uniform sampler2D textureY;
void main(void)
{
vec3 bgr;
bgr = texture2D(textureY, outTextureCoord).rgb;
gl_FragColor = vec4(bgr, 1.0);
}

3、效率问题

使用RGBA 还是 YUV 还是 RGB
这个很是奇特,yuv数据很小,RGB, 数据翻了一倍,而RGBA 则更多,是不是yuv效率最高?不是,是RGBA。
显卡的4字节对齐就是这样的,不过可以使用glPixelStorei 来指定打包传输的字节对齐,GL_UNPACK_ALIGNMENT,是内存到显卡的传送,如下指定为1字节对齐
glPixelStorei(GL_UNPACK_ALIGNMENT,1);
这个函数在不同的操作系统和不同的驱动下表现不同,为了不用做那么多的测试,请使用RGBA方式。这种方式始终表现良好

4、 查看信息

//查看显卡、GLSL和OpenGL的信息  
	const GLubyte *vendor = glGetString(GL_VENDOR);
	const GLubyte *renderer = glGetString(GL_RENDERER);
	const GLubyte *version = glGetString(GL_VERSION);
	const GLubyte *glslVersion = glGetString(GL_SHADING_LANGUAGE_VERSION);
	cout << "显卡供应商   : " << vendor << endl;
	cout << "显卡型号     : " << renderer << endl;
	cout << "OpenGL版本   : " << version << endl;
	cout << "GLSL版本     : " << glslVersion << endl;

以上是关于opengl 高级技巧的主要内容,如果未能解决你的问题,请参考以下文章

OpenGL片段着色器不照亮场景

片段着色器中未使用纹理数据 - OpenGL

带有顶点/片段着色器的光。使用不同的变量。 (openGL)

Atom编辑器入门到精通 Atom使用进阶

Android课程---Android Studio使用小技巧:提取方法代码片段

OpenGL、GLSL 片段着色器无法读取 Sampler2D 纹理