OpenGL蓝宝书源码学习(二十三)第七章——MultiTexture多重纹理
来源:互联网 发布:网络语 编辑:程序博客网 时间:2024/06/10 09:21
在上一节CubeMap的基础上新增了一个纹理贴图实现多重纹理。
// MultiTexture.cpp// OpenGL SuperBible// Demonstrates applying a cube map to an object (sphere)// simultaneously with a "tarnish" texture.// Program by Richard S. Wright Jr.#include// OpenGL toolkit#include #include #include #include #include #include #include #ifdef __APPLE__#include #else#define FREEGLUT_STATIC#include #endifGLFrame viewFrame;GLFrustum viewFrustum;GLTriangleBatch sphereBatch;GLBatch cubeBatch;GLMatrixStack modelViewMatrix;GLMatrixStack projectionMatrix;GLGeometryTransform transformPipeline;GLuint cubeTexture;GLuinttarnishTexture;GLint reflectionShader;GLint skyBoxShader;GLint locMVPReflect, locMVReflect, locNormalReflect, locInvertedCamera;GLintlocCubeMap, locTarnishMap;GLintlocMVPSkyBox;// Six sides of a cube mapconst char *szCubeFaces[6] = { "pos_x.tga", "neg_x.tga", "pos_y.tga", "neg_y.tga", "pos_z.tga", "neg_z.tga" };GLenum cube[6] = { GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_X, GL_TEXTURE_CUBE_MAP_POSITIVE_Y, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, GL_TEXTURE_CUBE_MAP_POSITIVE_Z, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z }; //////////////////////////////////////////////////////////////////// This function does any needed initialization on the rendering// context. void SetupRC() { GLbyte *pBytes; GLint iWidth, iHeight, iComponents; GLenum eFormat; int i; // Cull backs of polygons glCullFace(GL_BACK); glFrontFace(GL_CCW); glEnable(GL_DEPTH_TEST); glPixelStorei(GL_UNPACK_ALIGNMENT, 1);// Load the tarnish textureglGenTextures(1, &tarnishTexture);glBindTexture(GL_TEXTURE_2D, tarnishTexture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_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);pBytes = gltReadTGABits("tarnish.tga", &iWidth, &iHeight, &iComponents, &eFormat); glTexImage2D(GL_TEXTURE_2D, 0, iComponents, iWidth, iHeight, 0, eFormat, GL_UNSIGNED_BYTE, pBytes); free(pBytes); glGenerateMipmap(GL_TEXTURE_2D); // Load the cube map glGenTextures(1, &cubeTexture); glBindTexture(GL_TEXTURE_CUBE_MAP, cubeTexture); // Set up texture maps glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); // Load Cube Map images for(i = 0; i < 6; i++) { // Load this texture map pBytes = gltReadTGABits(szCubeFaces[i], &iWidth, &iHeight, &iComponents, &eFormat); glTexImage2D(cube[i], 0, iComponents, iWidth, iHeight, 0, eFormat, GL_UNSIGNED_BYTE, pBytes); free(pBytes); } glGenerateMipmap(GL_TEXTURE_CUBE_MAP); viewFrame.MoveForward(-4.0f); gltMakeSphere(sphereBatch, 1.0f, 52, 26); gltMakeCube(cubeBatch, 20.0f); reflectionShader = gltLoadShaderPairWithAttributes("Reflection.vp", "Reflection.fp", 3, GLT_ATTRIBUTE_VERTEX, "vVertex", GLT_ATTRIBUTE_NORMAL, "vNormal",GLT_ATTRIBUTE_TEXTURE0, "vTexCoords"); locMVPReflect = glGetUniformLocation(reflectionShader, "mvpMatrix"); locMVReflect = glGetUniformLocation(reflectionShader, "mvMatrix"); locNormalReflect = glGetUniformLocation(reflectionShader, "normalMatrix");locInvertedCamera = glGetUniformLocation(reflectionShader, "mInverseCamera"); locCubeMap = glGetUniformLocation(reflectionShader, "cubeMap");locTarnishMap = glGetUniformLocation(reflectionShader, "tarnishMap"); skyBoxShader = gltLoadShaderPairWithAttributes("SkyBox.vp", "SkyBox.fp", 2, GLT_ATTRIBUTE_VERTEX, "vVertex", GLT_ATTRIBUTE_NORMAL, "vNormal");locMVPSkyBox = glGetUniformLocation(skyBoxShader, "mvpMatrix"); // Set textures to their texture unitsglActiveTexture(GL_TEXTURE1);glBindTexture(GL_TEXTURE_2D, tarnishTexture);glActiveTexture(GL_TEXTURE0);glBindTexture(GL_TEXTURE_CUBE_MAP, cubeTexture); }void ShutdownRC(void) { glDeleteTextures(1, &cubeTexture); } // Called to draw scenevoid RenderScene(void) { // Clear the window glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); M3DMatrix44f mCamera; M3DMatrix44f mCameraRotOnly;M3DMatrix44f mInverseCamera; viewFrame.GetCameraMatrix(mCamera, false); viewFrame.GetCameraMatrix(mCameraRotOnly, true);m3dInvertMatrix44(mInverseCamera, mCameraRotOnly); modelViewMatrix.PushMatrix(); // Draw the sphere modelViewMatrix.MultMatrix(mCamera); glUseProgram(reflectionShader); glUniformMatrix4fv(locMVPReflect, 1, GL_FALSE, transformPipeline.GetModelViewProjectionMatrix()); glUniformMatrix4fv(locMVReflect, 1, GL_FALSE, transformPipeline.GetModelViewMatrix()); glUniformMatrix3fv(locNormalReflect, 1, GL_FALSE, transformPipeline.GetNormalMatrix());glUniformMatrix4fv(locInvertedCamera, 1, GL_FALSE, mInverseCamera);glUniform1i(locCubeMap, 0);glUniform1i(locTarnishMap, 1);glEnable(GL_CULL_FACE); sphereBatch.Draw();glDisable(GL_CULL_FACE);modelViewMatrix.PopMatrix();modelViewMatrix.PushMatrix(); modelViewMatrix.MultMatrix(mCameraRotOnly);glUseProgram(skyBoxShader);glUniformMatrix4fv(locMVPSkyBox, 1, GL_FALSE, transformPipeline.GetModelViewProjectionMatrix());cubeBatch.Draw(); modelViewMatrix.PopMatrix(); // Do the buffer Swap glutSwapBuffers(); }// Respond to arrow keys by moving the camera frame of referencevoid SpecialKeys(int key, int x, int y) { if(key == GLUT_KEY_UP) viewFrame.MoveForward(0.1f); if(key == GLUT_KEY_DOWN) viewFrame.MoveForward(-0.1f); if(key == GLUT_KEY_LEFT) viewFrame.RotateLocalY(0.1); if(key == GLUT_KEY_RIGHT) viewFrame.RotateLocalY(-0.1); // Refresh the Window glutPostRedisplay(); }void ChangeSize(int w, int h) { // Prevent a divide by zero if(h == 0) h = 1; // Set Viewport to window dimensions glViewport(0, 0, w, h); viewFrustum.SetPerspective(35.0f, float(w)/float(h), 1.0f, 1000.0f); projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix()); transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);}int main(int argc, char* argv[]) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); glutInitWindowSize(800,600); glutCreateWindow("OpenGL MultiTexture"); glutReshapeFunc(ChangeSize); glutDisplayFunc(RenderScene); glutSpecialFunc(SpecialKeys); GLenum err = glewInit(); if (GLEW_OK != err) { fprintf(stderr, "GLEW Error: %s\n", glewGetErrorString(err)); return 1; } SetupRC(); glutMainLoop(); ShutdownRC(); return 0; }// Reflection Shader// Vertex Shader// Richard S. Wright Jr.// OpenGL SuperBible#version 130// Incoming per vertex... position and normalin vec4 vVertex;in vec3 vNormal;in vec2 vTexCoords;uniform mat4 mvpMatrix;uniform mat4 mvMatrix;uniform mat3 normalMatrix;uniform mat4 mInverseCamera;// Texture coordinate to fragment programsmooth out vec3 vVaryingTexCoord;smooth out vec2 vTarnishCoords;void main(void) { // Normal in Eye Space vec3 vEyeNormal = normalMatrix * vNormal; // Vertex position in Eye Space vec4 vVert4 = mvMatrix * vVertex; vec3 vEyeVertex = normalize(vVert4.xyz / vVert4.w); // Get reflected vector vec4 vCoords = vec4(reflect(vEyeVertex, vEyeNormal), 1.0); // Rotate by flipped camera vCoords = mInverseCamera * vCoords; vVaryingTexCoord.xyz = normalize(vCoords.xyz); vTarnishCoords = vTexCoords.st; // Don't forget to transform the geometry! gl_Position = mvpMatrix * vVertex; }// Skybox Shader// Fragment Shader// Richard S. Wright Jr.// OpenGL SuperBible#version 130out vec4 vFragColor;uniform samplerCube cubeMap;varying vec3 vVaryingTexCoord;void main(void) { vFragColor = texture(cubeMap, vVaryingTexCoord); } // Reflection Shader// Fragment Shader// Richard S. Wright Jr.// OpenGL SuperBible#version 130out vec4 vFragColor;uniform samplerCube cubeMap;uniform sampler2D tarnishMap;smooth in vec3 vVaryingTexCoord;smooth in vec2 vTarnishCoords;void main(void) { vFragColor = texture(cubeMap, vVaryingTexCoord.stp); vFragColor *= texture(tarnishMap, vTarnishCoords); } // Skybox Shader// Vertex Shader// Richard S. Wright Jr.// OpenGL SuperBible#version 130// Incoming per vertex... just the positionin vec4 vVertex;uniform mat4 mvpMatrix; // Transformation matrix// Texture Coordinate to fragment programvarying vec3 vVaryingTexCoord;void main(void) { // Pass on the texture coordinates vVaryingTexCoord = normalize(vVertex.xyz); // Don't forget to transform the geometry! gl_Position = mvpMatrix * vVertex; }
一、多重纹理基础
在之前的学习的纹理贴图都是将一个单独的纹理加载到纹理对象上。当我们要使用这个纹理时,将他绑定到选定的纹理纹理对象上,然后将片段着色器的单个统一值设置为0。为什么是0呢?因为0是我们将要绑定到纹理单元的索引。OpenGL允许我们将独立的纹理对象绑定到一些可用的纹理单元上,从而提供了将两个或更多纹理同时应用到几何图形。可以对实现进行查询,来查看支持的纹理单元数量。如下:
GLint iUnits;glGenIntegerv(GL_MAX_TEXTURE_UNITS,&Units);默认情况下,第一个纹理单元为活动的纹理单元。所有纹理绑定操作都会影响当前活动的纹理单元。我们可以通过调用以纹理单元标识为变量的glActiveTexture来改变当前纹理单元。例如,要切换到第二个纹理单元并将它绑定到指定纹理对象上:
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D,textureID);
二、多重纹理坐标
有两个函数可以提供纹理坐标。
1、CopyTexCoordData2f,它的速度是最快的,因为它会一次复制整个一组纹理坐标。
2、使用较慢的每次一个顶点的接口,与立即模式类似。可以通过两种方式指定一个二维纹理坐标,每次指定一个。
此次的源码是在上次学习的源码基础上新增了多重纹理的应用,所以只着重解析多重纹理部分源码。
三、Client程序解析
MultiTexture.cpp
1、全局变量
//声明两个纹理对象标识,对应着色器程序的统一值
GLint locCubeMap, locTarnishMap;
2、函数解析
1)void SetupRC()
.....
//生成纹理对象
glGenTextures(1, &tarnishTexture);
//绑定纹理对象
glBindTexture(GL_TEXTURE_2D, tarnishTexture);//设置纹理对象的过滤和环绕模式
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_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);//加载纹理贴图,指定宽、高、新的缓冲区和文件格式
pBytes = gltReadTGABits("tarnish.tga", &iWidth, &iHeight, &iComponents, &eFormat);
//从缓冲区载入纹理数据,一旦载入,纹理就会成为当前纹理状态(即活动的)
glTexImage2D(GL_TEXTURE_2D, 0, iComponents, iWidth, iHeight, 0, eFormat, GL_UNSIGNED_BYTE, pBytes);
//释放内存
free(pBytes);
//生成Mip贴图层
glGenerateMipmap(GL_TEXTURE_2D);
...............
//得到着色器程序中的两个贴图的统一值,赋值给纹理对象标识
locCubeMap = glGetUniformLocation(reflectionShader, "cubeMap");
locTarnishMap = glGetUniformLocation(reflectionShader, "tarnishMap");.............
//切换纹理单元。将两个纹理进行绑定,每个纹理都会绑定到自己的纹理单元上
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, tarnishTexture);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_CUBE_MAP, cubeTexture);2)void RenderScene(void)
.........
//设置着色器程序纹理对象的统一值
glUniform1i(locCubeMap, 0);
glUniform1i(locTarnishMap, 1);注:多重纹理的源码是在上一节的源码基础上新添,所以略去了全部的解析。可回顾上一节。下面着重解析着色器程序。
四、着色器程序解析
与CubeMap的源码基本一致,这里解析一下新增的代码。
Reflection.vp
// 设置第二个纹理的纹理坐标
in vec2 vTexCoords;
vTarnishCoords = vTexCoords.st;
Reflection.fp
//采样器,将要采样的纹理所绑定的纹理单元
uniform sampler2D tarnishMap;
//设置输出颜色:立方体纹理采样得到的颜色再乘等于第二个纹理采样得到的颜色值
vFragColor = texture(cubeMap, vVaryingTexCoord.stp);
vFragColor *= texture(tarnishMap, vTarnishCoords);
五、小结
此多重纹理的源码示例是在上一节的CubeMap的示例的基础上新增了多重纹理的渲染效果。需要注意的是,在客户端程序中第二个纹理对象的生成和绑定,得到着色器程序中的纹理采样器的统一值,再进行绑定设置纹理单元,在着色器程序中,得到要进行渲染的输出颜色值。
- OpenGL蓝宝书源码学习(二十三)第七章——MultiTexture多重纹理
- OpenGL蓝宝书源码学习(二十一)第七章——SphereWorld矩阵纹理
- OpenGL蓝宝书源码学习(二十二)第七章——Cubemap立方体贴图
- OpenGL蓝宝书源码学习(九)第五章——纹理基础篇
- OpenGL蓝宝书源码学习(十三)第六章——OpenGL着色器和着色语言
- OpenGL蓝宝书源码学习(二)第二章——Move.cpp
- OpenGL蓝宝书源码学习(二十)第六章——Dissolve
- OpenGL蓝宝书源码学习(十)第五章——纹理的应用、Mip贴图、各项异性过滤和纹理压缩基础
- OpenGL蓝宝书第七章:立体天空和纹理折射、双纹理(上)
- OpenGL蓝宝书第七章:立体天空和纹理折射、双纹理(下)
- OpenGL蓝宝书源码学习(一)第二章——Triangle.cpp
- OpenGL蓝宝书源码学习(五)第三章——Blending.cpp
- OpenGL蓝宝书源码学习(三)第三章——GeoTest.cpp
- OpenGL蓝宝书源码学习(四)第三章——Scissor.cpp
- OpenGL蓝宝书源码学习(六)第三章——Smoother.cpp
- OpenGL蓝宝书源码学习(七)第四章——ModelViewProjection.cpp
- OpenGL蓝宝书源码学习(八)第四章——SphereWorld.cpp
- OpenGL蓝宝书源码学习(十一)第五章——Pyramid.cpp
- 高考
- 『干货』深度强化学习与自适应在线学习的阿里实践
- [Virtualization]ESXi体系结构与内存管理(三)控制内存分配
- C语言一些最基本的排序知识
- JS知识点
- OpenGL蓝宝书源码学习(二十三)第七章——MultiTexture多重纹理
- C语言链表最全操作
- JSF
- Linux中使用SecureCRT上传、下载文件命令sz与rz用法实例
- 写作建议
- classnotfound原因分析
- jmeter压测http请求
- TypeScript 基础数据类型简介
- Matlab 视频读取报错“Unable to locate decompressor to decompress video stream”解决办法