OpenGL 八 - 纹理案例
Posted zhangying-domy
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了OpenGL 八 - 纹理案例相关的知识,希望对你有一定的参考价值。
案例一、隧道
效果
1)四面:
2)主要代码:
1 // 初始化设置 2 void SetupRC() { 3 4 glClearColor(0.0f, 0.0f, 0.0f, 1.0f);// 黑色 5 shaderManager.InitializeStockShaders(); 6 7 8 GLbyte *pBytes; 9 GLint iWidth, iHeight, iComponents; 10 GLenum eFormat; 11 12 // 生成纹理标记 13 /* 分配纹理对象 glGenTextures 14 参数1:纹理对象的数量 15 参数2:纹理对象标识数组 16 */ 17 glGenTextures(TEXTURE_COUNT, textures); 18 19 20 // 设置纹理 21 for (GLint i = 0; i < TEXTURE_COUNT; i++) { 22 23 // 绑定纹理对象 24 /*绑定纹理对象 glBindTexture 25 参数1:纹理模式,GL_TEXTURE_1D,GL_TEXTURE_2D,GL_TEXTURE_3D 26 参数2:需要绑定的纹理对象id 27 */ 28 glBindTexture(GL_TEXTURE_2D, textures[i]); 29 30 31 // 加载 读取 tga 文件数据 32 /* 加载 tga 文件 33 参数1:纹理文件名称 34 参数2:文件宽度变量地址 35 参数3:文件高度变量地址 36 参数4:文件组件变量地址 37 参数5:文件格式变量地址 38 39 返回值:pBytes,指向图像数据的指针 40 */ 41 pBytes = gltReadTGABits(textureFiles[i], &iWidth, &iHeight, &iComponents, &eFormat); 42 43 44 // 设置纹理参数 45 // 设置放大缩小 过滤方式 GL_TEXTURE_MAG_FILTER(放大过滤器,GL_NEAREST(最邻近过滤);GL_TEXTURE_MIN_FILTER(缩小过滤器,GL_NEAREST(最邻近过滤) 46 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 47 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 48 49 // 设置环绕方式 50 // GL_TEXTURE_WRAP_S(2D:s、t轴环绕),GL_CLAMP_TO_EDGE --> 环绕模式强制对范围之外的纹理坐标沿着合法的纹理单元的最后一行或一列进行采样 51 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 52 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 53 54 55 // 载入纹理 56 /* 载入纹理 glTexImage2D 57 参数1:纹理维度,GL_TEXTURE_2D 58 参数2:mip贴图层次 59 参数3:纹理单元存储的颜色成分(从读取像素图中获得) 60 参数4:加载纹理宽度 61 参数5:加载纹理的高度 62 参数6:为纹理贴图指定一个边界宽度 0 63 参数7、8:像素数据的数据类型, GL_UNSIGNED_BYTE无符号整型 64 参数9:指向纹理图像数据的指针 65 */ 66 glTexImage2D(GL_TEXTURE_2D, 0, iComponents, iWidth, iHeight, 0, eFormat, GL_UNSIGNED_BYTE, pBytes); 67 // glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels) 68 69 70 // 生成纹理对象 glGenerateMipmap 71 /* 为纹理对象生成一组完整的 mipmap 72 参数1:纹理维度,GL_TEXTURE_1D,GL_TEXTURE_2D,GL_TEXTURE_2D 73 */ 74 glGenerateMipmap(GL_TEXTURE_2D); 75 76 // 释放原始纹理数据,不再需要纹理原始数据了 77 free(pBytes); 78 } 79 80 81 // 设置隧道的上下左右4个面 82 GLfloat z;// 深度,隧道的深度 83 84 // 地板 -- 图 ‘地板’ 85 /* 86 GLTools库中的容器类,GBatch --> void GLBatch::Begin(GLenum primitive,GLuint nVerts,GLuint nTextureUnits = 0); 87 参数1:图元枚举值 88 参数2:顶点数 89 参数3:纹理数 --> 1组或者2组纹理坐标 90 */ 91 floorBatch.Begin(GL_TRIANGLE_STRIP, 28, 1); 92 for(z = 60.0f; z >= 0.0f; z -=10.0f) { 93 94 // 纹理坐标与顶点的对应 95 floorBatch.MultiTexCoord2f(0, 0.0f, 0.0f);// 纹理坐标 96 floorBatch.Vertex3f(-10.0f, -10.0f, z);// 顶点 97 98 floorBatch.MultiTexCoord2f(0, 1.0f, 0.0f); 99 floorBatch.Vertex3f(10.0f, -10.0f, z); 100 101 floorBatch.MultiTexCoord2f(0, 0.0f, 1.0f); 102 floorBatch.Vertex3f(-10.0f, -10.0f, z - 10.0f); 103 104 floorBatch.MultiTexCoord2f(0, 1.0f, 1.0f); 105 floorBatch.Vertex3f(10.0f, -10.0f, z - 10.0f); 106 } 107 floorBatch.End(); 108 109 // 天花板 -- 图 ‘天花板’ 110 ceilingBatch.Begin(GL_TRIANGLE_STRIP, 28, 1); 111 for(z = 60.0f; z >= 0.0f; z -=10.0f) { 112 113 ceilingBatch.MultiTexCoord2f(0, 0.0f, 1.0f); 114 ceilingBatch.Vertex3f(-10.0f, 10.0f, z - 10.0f); 115 116 ceilingBatch.MultiTexCoord2f(0, 1.0f, 1.0f); 117 ceilingBatch.Vertex3f(10.0f, 10.0f, z - 10.0f); 118 119 ceilingBatch.MultiTexCoord2f(0, 0.0f, 0.0f); 120 ceilingBatch.Vertex3f(-10.0f, 10.0f, z); 121 122 ceilingBatch.MultiTexCoord2f(0, 1.0f, 0.0f); 123 ceilingBatch.Vertex3f(10.0f, 10.0f, z); 124 } 125 ceilingBatch.End(); 126 127 // 左侧墙面 -- 图 ‘左墙’ 128 leftWallBatch.Begin(GL_TRIANGLE_STRIP, 28, 1); 129 for(z = 60.0f; z >= 0.0f; z -=10.0f) { 130 131 leftWallBatch.MultiTexCoord2f(0, 0.0f, 0.0f); 132 leftWallBatch.Vertex3f(-10.0f, -10.0f, z); 133 134 leftWallBatch.MultiTexCoord2f(0, 0.0f, 1.0f); 135 leftWallBatch.Vertex3f(-10.0f, 10.0f, z); 136 137 leftWallBatch.MultiTexCoord2f(0, 1.0f, 0.0f); 138 leftWallBatch.Vertex3f(-10.0f, -10.0f, z - 10.0f); 139 140 leftWallBatch.MultiTexCoord2f(0, 1.0f, 1.0f); 141 leftWallBatch.Vertex3f(-10.0f, 10.0f, z - 10.0f); 142 } 143 leftWallBatch.End(); 144 145 // 右侧墙面 -- 图 ‘右墙‘ 146 rightWallBatch.Begin(GL_TRIANGLE_STRIP, 28, 1); 147 for(z = 60.0f; z >= 0.0f; z -=10.0f) { 148 149 rightWallBatch.MultiTexCoord2f(0, 0.0f, 0.0f); 150 rightWallBatch.Vertex3f(10.0f, -10.0f, z); 151 152 rightWallBatch.MultiTexCoord2f(0, 0.0f, 1.0f); 153 rightWallBatch.Vertex3f(10.0f, 10.0f, z); 154 155 rightWallBatch.MultiTexCoord2f(0, 1.0f, 0.0f); 156 rightWallBatch.Vertex3f(10.0f, -10.0f, z - 10.0f); 157 158 rightWallBatch.MultiTexCoord2f(0, 1.0f, 1.0f); 159 rightWallBatch.Vertex3f(10.0f, 10.0f, z - 10.0f); 160 } 161 rightWallBatch.End(); 162 } 163 164 // 渲染 165 void RenderScene(void) { 166 167 glClear(GL_COLOR_BUFFER_BIT); 168 169 // 压栈 170 modelViewMatix.PushMatrix(); 171 // z轴上平移 172 modelViewMatix.Translate(0.0f, 0.0f, viewZ); 173 174 // 纹理替换矩阵着色器 175 /* 176 参数1:GLT_SHADER_TEXTURE_REPLACE(着色器标签) 177 参数2:模型视图投影矩阵 178 参数3:纹理层 179 */ 180 shaderManager.UseStockShader(GLT_SHADER_TEXTURE_REPLACE, transformPipeline.GetModelViewProjectionMatrix(),0); 181 182 // 绑定纹理 183 /* 184 --> 为何又绑定一次??? 185 --> 为防止纹理 ID 绑定错误,状态机机制,在共同开发过程中,可能出现绑定的纹理出现变化 186 */ 187 // 地板 188 glBindTexture(GL_TEXTURE_2D, textures[TEXTURE_FLOOR]); 189 floorBatch.Draw(); 190 // 天花板 191 glBindTexture(GL_TEXTURE_2D, textures[TEXTURE_CEILING]); 192 ceilingBatch.Draw(); 193 // 左右墙 194 glBindTexture(GL_TEXTURE_2D, textures[TEXTURE_BRICK]); 195 leftWallBatch.Draw(); 196 rightWallBatch.Draw(); 197 198 // 出栈 199 modelViewMatix.PopMatrix(); 200 201 // 交换缓冲区 202 glutSwapBuffers(); 203 } 204 205 // 视口 窗口大小改变时接受新的宽度和高度,其中0,0代表窗口中视口的左下角坐标,w,h代表像素 206 void ChangeSize(int w,int h) { 207 // 防止h变为0 208 if(h == 0) 209 h = 1; 210 211 // 设置视口窗口尺寸 212 glViewport(0, 0, w, h); 213 214 // setPerspective 函数的参数是一个从顶点方向看去的视场角度(用角度值表示) 215 // 设置透视模式,初始化其透视矩阵 216 viewFrustum.SetPerspective(80.0f, GLfloat(w)/GLfloat(h), 1.0f, 120.0f); 217 218 //4.把 透视矩阵 加载到 透视矩阵对阵中 219 projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix()); 220 221 //5.初始化渲染管线 222 transformPipeline.SetMatrixStacks(modelViewMatix, projectionMatrix); 223 }
案例二、球体转动 添加纹理
效果
主要代码
1 // 绘制球体视图 2 void drawSpheres (GLfloat yRot) { 3 4 // 设置点光源位置 5 static GLfloat vLightPos[] = {0.0f, 3.0f, 0.0f, 1.0f}; 6 // 漫反射颜色 白色 7 static GLfloat vWhite[] = { 1.0f, 1.0f, 1.0f, 1.0f }; 8 9 10 // 绘制 小球们 11 // 绑定纹理 12 glBindTexture(GL_TEXTURE_2D, textures[2]);// 小球上贴的纹理 13 for (int i = 0; i < SPHERE_NUM; i++) { 14 15 modelViewMatix.PushMatrix(); 16 modelViewMatix.MultMatrix(spheres[i]);// 小球位置 17 modelViewMatix.Rotate(yRot, 0, 1, 0); 18 // GLT_SHADER_TEXTURE_POINT_LIGHT_DIFF:纹理点光源着色器;vLightPos:光源位置;vBigSphereColor:绘制颜色 19 shaderManager.UseStockShader(GLT_SHADER_TEXTURE_POINT_LIGHT_DIFF, 20 modelViewMatix.GetMatrix(), 21 transformPipeline.GetProjectionMatrix(), 22 vLightPos, 23 vWhite, 24 0); 25 sphereBatch.Draw(); 26 27 modelViewMatix.PopMatrix(); 28 } 29 30 31 // 绘制大球 32 modelViewMatix.Translate(0, 0.2f, -2.5f);// y轴上靠近镜面一点 Z轴距离再远一些 33 // 34 modelViewMatix.PushMatrix(); 35 // 大球沿Y轴 旋转弧度:yRot 自传 36 modelViewMatix.Rotate(yRot, 0, 1, 0); 37 // 绑定纹理 38 glBindTexture(GL_TEXTURE_2D, textures[1]); 39 shaderManager.UseStockShader(GLT_SHADER_TEXTURE_POINT_LIGHT_DIFF, 40 modelViewMatix.GetMatrix(), 41 transformPipeline.GetProjectionMatrix(), 42 vLightPos, 43 vWhite, 44 0); 45 bigSphereBatch.Draw(); 46 modelViewMatix.PopMatrix(); 47 48 49 // 绘制沿大球转的小球 50 modelViewMatix.PushMatrix(); 51 modelViewMatix.Rotate(yRot * -2, 0, 1, 0); 52 modelViewMatix.Translate(0.8f, 0.0f, 0.0f);// 小球在X方向上偏移一定位置 不然会看不见小球 53 glBindTexture(GL_TEXTURE_2D, textures[2]); 54 shaderManager.UseStockShader(GLT_SHADER_TEXTURE_POINT_LIGHT_DIFF, 55 modelViewMatix.GetMatrix(), 56 transformPipeline.GetProjectionMatrix(), 57 vLightPos, 58 vWhite, 59 0); 60 sphereBatch.Draw(); 61 modelViewMatix.PopMatrix(); 62 63 } 64 65 // 设置纹理 66 bool LoadTGATexture(const char *textureName, GLenum minFilter, GLenum magFilter, GLenum wrapModel) { 67 68 GLbyte *pBits; 69 int nWidth, nHeight, nComponents; 70 GLenum eFormat; 71 72 // 读取纹理 73 pBits = gltReadTGABits(textureName, &nWidth, &nHeight, &nComponents, &eFormat); 74 if (!pBits) { 75 return false; 76 } 77 78 // 设置过滤方式 79 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minFilter); 80 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magFilter); 81 82 // 设置环绕方式 83 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapModel); 84 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapModel); 85 86 // 载入纹理 87 glTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB, nWidth, nHeight, 0, eFormat, GL_UNSIGNED_BYTE, pBits); 88 89 // 使用完毕释放pbit 90 free(pBits); 91 92 93 // 只有minFilter 等于以下四种模式,才可以生成Mip贴图 94 // GL_NEAREST_MIPMAP_NEAREST具有非常好的性能,并且闪烁现象非常弱 95 // GL_LINEAR_MIPMAP_NEAREST常常用于对游戏进行加速,它使用了高质量的线性过滤器 96 // GL_LINEAR_MIPMAP_LINEAR 和GL_NEAREST_MIPMAP_LINEAR 过滤器在Mip层之间执行了一些额外的插值,以消除他们之间的过滤痕迹。 97 // GL_LINEAR_MIPMAP_LINEAR 三线性Mip贴图。纹理过滤的黄金准则,具有最高的精度。 98 if (minFilter == GL_LINEAR_MIPMAP_LINEAR || 99 minFilter == GL_LINEAR_MIPMAP_NEAREST || 100 minFilter == GL_NEAREST_MIPMAP_LINEAR || 101 minFilter == GL_NEAREST_MIPMAP_NEAREST) { 102 103 // 加载mip 纹理生成所有的mip 层 104 // 参数:GL_TEXTURE_1D、GL_TEXTURE_2D、GL_TEXTURE_3D 105 glGenerateMipmap(GL_TEXTURE_2D); 106 } 107 108 return true; 109 } 110 111 // 初始化 设置 112 void SetupRC() { 113 114 // 设置清屏颜色到颜色缓存区 115 glClearColor(0.0f, 0.0f, 0.0f, 1.0f); 116 117 // 初始化着色器管理器 118 shaderManager.InitializeStockShaders(); 119 120 // 开启深度测试 背面剔除 121 glEnable(GL_DEPTH_TEST); 122 glEnable(GL_CULL_FACE); 123 124 // 设置大球 125 gltMakeSphere(bigSphereBatch, 0.4f, 40, 80); 126 127 // 设置小球 128 gltMakeSphere(sphereBatch, 0.1f, 26, 13); 129 130 // 地板 纹理 --> 4个顶点对应纹理图的4个坐标 131 GLfloat texSize = 10.0f; 132 floorTriangleBatch.Begin(GL_TRIANGLE_FAN, 4,1); 133 floorTriangleBatch.MultiTexCoord2f(0, 0.0f, 0.0f); 134 floorTriangleBatch.Vertex3f(-20.f, -0.41f, 20.0f); 135 136 floorTriangleBatch.MultiTexCoord2f(0, texSize, 0.0f); 137 floorTriangleBatch.Vertex3f(20.0f, -0.41f, 20.f); 138 139 floorTriangleBatch.MultiTexCoord2f(0, texSize, texSize); 140 floorTriangleBatch.Vertex3f(20.0f, -0.41f, -20.0f); 141 142 floorTriangleBatch.MultiTexCoord2f(0, 0.0f, texSize); 143 floorTriangleBatch.Vertex3f(-20.0f, -0.41f, -20.0f); 144 floorTriangleBatch.End(); 145 146 147 // 小球们的位置 随机小球顶点坐标数据 148 for (int i = 0; i < SPHERE_NUM; i++) { 149 150 // y轴不变,X,Z产生随机值 151 GLfloat x = ((GLfloat)((rand() % 400) - 200 ) * 0.1f); 152 GLfloat z = ((GLfloat)((rand() % 400) - 200 ) * 0.1f); 153 154 // 在y方向,将球体设置为0.0的位置,这使得它们看起来是飘浮在眼睛的高度 155 // 对spheres数组中的每一个顶点,设置顶点数据 156 spheres[i].SetOrigin(x, 0.0f, z); 157 } 158 159 160 // 设置纹理 161 // 生成纹理标记 162 glGenTextures(3, textures); 163 164 // 绑定纹理 设置纹理参数 165 glBindTexture(GL_TEXTURE_2D, textures[0]); 166 LoadTGATexture("marble.tga", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR, GL_REPEAT); 167 168 // GL_CLAMP_TO_EDGE 纹理坐标约束在0~1,超出部分边缘重复(边缘拉伸效果) 169 glBindTexture(GL_TEXTURE_2D, textures[1]); 170 LoadTGATexture("marslike.tga", GL_LINEAR_MIPMAP_LINEAR, 171 GL_LINEAR, GL_CLAMP_TO_EDGE); 172 173 glBindTexture(GL_TEXTURE_2D, textures[2]); 174 LoadTGATexture("moonlike.tga", GL_LINEAR_MIPMAP_LINEAR, 175 GL_LINEAR, GL_CLAMP_TO_EDGE); 176 } 177 178 179 180 // 渲染 181 void RenderScene(void) { 182 183 // 清除窗口 颜色、深度缓冲区 184 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 185 186 // 地板颜色 --> 镜面透明效果 alpha设置一定透明度 187 static GLfloat vFloorColor[] = {1.0, 1.0, 0.0, 0.7f}; 188 189 // 定时器时间 动画 --> 大球自传 190 static CStopWatch rotTimer; 191 float yRot = rotTimer.GetElapsedSeconds() * 60.0f; 192 193 194 // 压栈 --> copy 一份栈顶矩阵 --> 单元矩阵 195 modelViewMatix.PushMatrix(); 196 197 198 // 观察者矩阵压栈 199 /* 200 观察者的移动要影响到所有绘制物体,所以要 先压栈 201 */ 202 M3DMatrix44f cameraM; 203 cameraFrame.GetCameraMatrix(cameraM); 204 modelViewMatix.MultMatrix(cameraM); 205 206 207 // 镜面内部分 208 // 压栈 --> 原因:镜面部分绘制后要继续绘制地板上面的视图 209 modelViewMatix.PushMatrix(); 210 // 镜面内的小球门 211 // 绘制镜面内部分(镜面内的小球门) 212 213 // 沿Y轴翻转 214 modelViewMatix.Scale(1.0f, -1.0f, 1.0f); 215 // 视图距离地板面设定一定间隔 -- 避免粘在一起 就不像镜面了 216 modelViewMatix.Translate(0, 0.8, 0); 217 218 // 此时绘制镜面部分为顺时针旋转,将顺时针旋转设为正面 --> 正背面 观察者只能看到正面 219 glFrontFace(GL_CW); 220 // 绘制视图 221 drawSpheres(yRot); 222 223 // 恢复逆时针转为正面 224 glFrontFace(GL_CCW); 225 // 226 modelViewMatix.PopMatrix(); 227 228 229 // 绘制镜面 230 // 开启混合 231 glEnable(GL_BLEND); 232 // 指定混合方程式 233 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 234 // 绑定地面(镜面)纹理 235 glBindTexture(GL_TEXTURE_2D, textures[0]); 236 /* 纹理调整着色器 --> 将一个基本色乘以一个取自纹理的单元nTextureUnit的纹理 237 参数1:GLT_SHADER_TEXTURE_MODULATE 238 参数2:模型视图投影矩阵 239 参数3:颜色 240 参数4:纹理单元(第0层的纹理单元) 241 */ 242 shaderManager.UseStockShader(GLT_SHADER_TEXTURE_MODULATE, 243 transformPipeline.GetModelViewProjectionMatrix(), 244 vFloorColor, 245 0); 246 floorTriangleBatch.Draw(); 247 // 取消混合 248 glDisable(GL_BLEND); 249 250 251 // 绘制镜面外的球 252 drawSpheres(yRot); 253 254 modelViewMatix.PopMatrix(); 255 256 257 // 258 glutSwapBuffers(); 259 260 // 261 glutPostRedisplay(); 262 }
以上是关于OpenGL 八 - 纹理案例的主要内容,如果未能解决你的问题,请参考以下文章