【OpenGL学习】使用Shader处理纹理
使用Shader处理纹理本是件简单的事情,但是我在尝试写一个简单的例子的时候却犯了个错误,导致郁闷了一天,这个稍后再说。 先整理下怎么用Shader处理纹理吧。
1.原理:
用Shader处理纹理的原理其实很简单,将纹理通过一个uniform变量传入shader,然后对着个uniform变量进行操作,就可以直接操作纹理了。
2.参考资料
lighthouse3d上面的教程比较简略,没有列出完整的程序,我看后比较迷茫。http://www.lighthouse3d.com/tutorials/glsl-tutorial/simple-texture/ 写得比较详细的是这么一本书:OpenGL® Shading Language, Second Edition,Chapter10.2有比较详细的介绍。电子版地址:http://wiki.labomedia.org/images/1/10/Orange_Book_-_OpenGL_Shading_Language_2nd_Edition.pdf 总结下大体思路就是:生成纹理——绑定纹理——设置纹理——激活纹理——传递变量给shader
3.题外话
下面该说说我犯的这个错误了。重点在于我傻乎乎的以为纹理坐标已经不需要设置了(display函数中),Shader会智能地处理这些。仔细想想其实这种想法很不合理,因为Shader并不知道纹理坐标和顶点坐标的对应关系,比如 某个顶点应该对应纹理的左上还是左下坐标。所以当我在display函数中加上纹理坐标的设置之后一切都变得正常了。 这个故事告诉我们:写程序的时候想当然是最可怕的。。
4.代码
最后贴上代码吧,供以后查阅。
vertex shader代码:
void main() { gl_TexCoord[0] = gl_MultiTexCoord0; gl_Position = ftransform(); }
fragment shader代码:
uniform sampler2D sampler0; void main() { vec3 lightColor = vec3(texture2D(sampler0, gl_TexCoord[0].st)); gl_FragColor = vec4(1-lightColor, 0.0);//反色 }
纹理设置代码:
glClearColor (0.0, 0.0, 0.0, 0.0); glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LESS); makeImage(); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glGenTextures(1, &texName); glBindTexture(GL_TEXTURE_2D, texName); /* 定义纹理 */ glTexImage2D(GL_TEXTURE_2D, 0, 3, ImageWidth, ImageHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, &Image[0][0][0]); /* 控制滤波 */ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); /* 说明映射方式*/ glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL); /* 启动纹理映射 */ glEnable(GL_TEXTURE_2D); glShadeModel(GL_FLAT);
向shader中传递变量:
GLuint texLoc = glGetUniformLocation(p, "sampler0"); glUniform1i(texLoc,0);
显示代码:
glBegin(GL_QUADS); glTexCoord2f(0.0, 0.0); glVertex3f(-1.0, -1.0,0.0); glTexCoord2f(0.0, 1.0); glVertex3f(1.0, -1.0,0.0); glTexCoord2f(1.0, 1.0); glVertex3f(1.0, 1.0,0.0); glTexCoord2f(1.0, 0.0); glVertex3f(-1.0, 1.0,0.0); glEnd();