效果展示
绘制流程
定义变量
GLShaderManager shaderManager; // 着色器管理器
GLMatrixStack modelViewMatrix; // 模型视图矩阵
GLMatrixStack projectionMatrix; // 投影矩阵
GLFrustum viewFrustum; // 视景体
GLGeometryTransform transformPipeline; // 几何变换管线
GLBatch floorBatch; // 地面批次容器类
GLBatch ceilingBatch; // 天花板批次容器类
GLBatch leftWallBatch; // 左墙面批次容器类
GLBatch rightWallBatch; // 右墙面批次容器类
GLfloat viewZ = -65.0f; // 深度初始值,-65
#define TEXTURE_BRICK 0 // 墙面纹理标识符号
#define TEXTURE_FLOOR 1 // 地板纹理标识符号
#define TEXTURE_CEILING 2 // 天花板纹理标识符号
#define TEXTURE_COUNT 3 // 纹理个数
GLuint textures[TEXTURE_COUNT]; //纹理标记数组
const char *szTextureFiles[TEXTURE_COUNT] = { "brick.tga", "floor.tga", "ceiling.tga" }; // 文件tag名字数组
纹理坐标和几何坐标的对应绘制
设置纹理坐标使用批次类的MultiTexCoord2f,其中第一个参数是指图层,即纹理的level,一般默认设置为0,后两个参数即为纹理的坐标s、t;设置顶点坐标使用批次类的Vertex3f,传入顶点的x、y、z;
四个面均是由多个三角形使用三角形带的图元连接方式组成,所以只需要使用for循环,每次设置四个点的顶点及纹理坐标即可完成绘制;
一、floorBatch(地板)
- ⼏何坐标计算
- 纹理坐标:
// z表示隧道的深度
GLfloat z;
floorBatch.Begin(GL_TRIANGLE_STRIP, 28, 1);
for(z = 60.0f; z >= 0.0f; z -= 10.0f) {
floorBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
floorBatch.Vertex3f(-10.0f, -10.0f, z);
floorBatch.MultiTexCoord2f(0, 1.0f, 0.0f);
floorBatch.Vertex3f(10.0f, -10.0f, z);
floorBatch.MultiTexCoord2f(0, 0.0f, 1.0f);
floorBatch.Vertex3f(-10.0f, -10.0f, z - 10.0f);
floorBatch.MultiTexCoord2f(0, 1.0f, 1.0f);
floorBatch.Vertex3f(10.0f, -10.0f, z - 10.0f);
}
floorBatch.End();
二、ceilingBatch(天花板)
- 几何坐标
- 纹理坐标
ceilingBatch.Begin(GL_TRIANGLE_STRIP, 28, 1);
for(z = 60.0f; z >= 0.0f; z -= 10.0f) {
ceilingBatch.MultiTexCoord2f(0, 0.0f, 1.0f);
ceilingBatch.Vertex3f(-10.0f, 10.0f, z - 10.0f);
ceilingBatch.MultiTexCoord2f(0, 1.0f, 1.0f);
ceilingBatch.Vertex3f(10.0f, 10.0f, z - 10.0f);
ceilingBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
ceilingBatch.Vertex3f(-10.0f, 10.0f, z);
ceilingBatch.MultiTexCoord2f(0, 1.0f, 0.0f);
ceilingBatch.Vertex3f(10.0f, 10.0f, z);
}
ceilingBatch.End();
leftWallBatch(左边墙壁)
- 几何坐标
- 纹理坐标
leftWallBatch.Begin(GL_TRIANGLE_STRIP, 28, 1);
for(z = 60.0f; z >= 0.0f; z -= 10.0f) {
leftWallBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
leftWallBatch.Vertex3f(-10.0f, -10.0f, z);
leftWallBatch.MultiTexCoord2f(0, 0.0f, 1.0f);
leftWallBatch.Vertex3f(-10.0f, 10.0f, z);
leftWallBatch.MultiTexCoord2f(0, 1.0f, 0.0f);
leftWallBatch.Vertex3f(-10.0f, -10.0f, z - 10.0f);
leftWallBatch.MultiTexCoord2f(0, 1.0f, 1.0f);
leftWallBatch.Vertex3f(-10.0f, 10.0f, z - 10.0f);
}
leftWallBatch.End();
四、rightWallBatch(右边墙面)
- 几何坐标
- 纹理坐标
rightWallBatch.Begin(GL_TRIANGLE_STRIP, 28, 1);
for(z = 60.0f; z >= 0.0f; z -= 10.0f) {
rightWallBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
rightWallBatch.Vertex3f(10.0f, -10.0f, z);
rightWallBatch.MultiTexCoord2f(0, 0.0f, 1.0f);
rightWallBatch.Vertex3f(10.0f, 10.0f, z);
rightWallBatch.MultiTexCoord2f(0, 1.0f, 0.0f);
rightWallBatch.Vertex3f(10.0f, -10.0f, z - 10.0f);
rightWallBatch.MultiTexCoord2f(0, 1.0f, 1.0f);
rightWallBatch.Vertex3f(10.0f, 10.0f, z - 10.0f);
}
rightWallBatch.End();
生成纹理
一、生成纹理对象:本案例中使用了3个纹理(左右墙面纹理标识、天花板纹理标识、地板纹理标识),需要传入纹理层个数;
/* 生成纹理标记
* 分配纹理对象 glGenTextures
* 参数1:纹理对象的数量
* 参数2:纹理对象标识数组
*/
glGenTextures(TEXTURE_COUNT, textures);
二、设置纹理参数:由于使用多个纹理,因此使用循环设置纹理数组的纹理参数;
- 绑定纹理对象: glBindTexture;
- 读取TGA纹理文件:gltReadTGABits;
- 设置纹理环绕方式和过滤方式:glTexParameteri;
- 载入纹理:glTexImage2D;
- 生成Mip贴图:glGenerateMipmap(当过滤方式与Mip无关时,可以设置也可以不设置,如果使用与Mip相关的过滤方式,就必须设置);
- 释放指向纹理对象空间的指针:free;
GLbyte *pBytes;
GLint iWidth, iHeight, iComponents;
GLenum eFormat;
GLint iLoop;
/* 生成纹理标记
* 分配纹理对象 glGenTextures
* 参数1:纹理对象的数量
* 参数2:纹理对象标识数组
*/
glGenTextures(TEXTURE_COUNT, textures);
// 循环设置纹理数组的纹理参数
for(iLoop = 0; iLoop < TEXTURE_COUNT; iLoop++) {
/* 绑定纹理对象 glBindTexture
* 参数1:纹理模式,GL_TEXTURE_1D,GL_TEXTURE_2D,GL_TEXTURE_3D
* 参数2:需要绑定的纹理对象
*/
glBindTexture(GL_TEXTURE_2D, textures[iLoop]);
/* 加载tga文件
* 参数1:纹理文件名称
* 参数2:文件宽度变量地址
* 参数3:文件高度变量地址
* 参数4:文件组件变量地址
* 参数5:文件格式变量地址
* 返回值:pBytes,指向图像数据的指针
*/
pBytes = gltReadTGABits(szTextureFiles[iLoop],&iWidth, &iHeight,
&iComponents, &eFormat);
// 加载纹理、设置过滤器和包装模式
// GL_TEXTURE_MAG_FILTER(放大过滤器,GL_NEAREST(最邻近过滤)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
// GL_TEXTURE_MIN_FILTER(缩小过滤器),GL_NEAREST(最邻近过滤)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
// GL_TEXTURE_WRAP_S(s轴环绕),GL_CLAMP_TO_EDGE(环绕模式强制对范围之外的纹理坐标沿着合法的纹理单元的最后一行或一列进行采样)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
// GL_TEXTURE_WRAP_T(t轴环绕),GL_CLAMP_TO_EDGE(环绕模式强制对范围之外的纹理坐标沿着合法的纹理单元的最后一行或一列进行采样)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
/* 载入纹理 glTexImage2D
* 参数1:纹理维度,GL_TEXTURE_2D
* 参数2:mip贴图层次
* 参数3:纹理单元存储的颜色成分(从读取像素图中获得)
* 参数4:加载纹理宽度
* 参数5:加载纹理的高度
* 参数6:加载纹理的深度
* 参数7:像素数据的数据类型,GL_UNSIGNED_BYTE无符号整型
* 参数8:指向纹理图像数据的指针
*/
glTexImage2D(GL_TEXTURE_2D, 0, iComponents, iWidth, iHeight, 0, eFormat, GL_UNSIGNED_BYTE, pBytes);
/* 为纹理对象生成一组完整的mipmap glGenerateMipmap
* 参数1:纹理维度,GL_TEXTURE_1D,GL_TEXTURE_2D,GL_TEXTURE_2D
*/
glGenerateMipmap(GL_TEXTURE_2D);
// 释放原始纹理数据,不再需要纹理原始数据
free(pBytes);
}
渲染绘制场景
- 视图模型矩阵平移:需要往-z轴平移一定的矩阵,方便观察,且与矩阵栈顶相乘,将其结果覆盖栈顶矩阵;
// 轴平移viewZ 距离
modelViewMatrix.Translate(0.0f, 0.0f, viewZ);
- 使用纹理替换矩阵着色器:最后一个参数是指纹理的level,默认为0;
/* 纹理替换矩阵着色器
* 参数1:GLT_SHADER_TEXTURE_REPLACE(着色器标签)
* 参数2:模型视图投影矩阵
* 参数3:纹理层
*/
shaderManager.UseStockShader(GLT_SHADER_TEXTURE_REPLACE, transformPipeline.GetModelViewProjectionMatrix(), 0);
- 绑定纹理:由于地面、天花板、左右墙面分别使用不同的纹理,所以需要分别绑定并绘制;
/* 绑定纹理
* 参数1:纹理模式,GL_TEXTURE_1D、GL_TEXTURE_2D、GL_TEXTURE_3D
* 参数2:需要绑定的纹理
*/
glBindTexture(GL_TEXTURE_2D, textures[TEXTURE_FLOOR]);
floorBatch.Draw();
glBindTexture(GL_TEXTURE_2D, textures[TEXTURE_CEILING]);
ceilingBatch.Draw();
glBindTexture(GL_TEXTURE_2D, textures[TEXTURE_BRICK]);
leftWallBatch.Draw();
rightWallBatch.Draw();
各向异性过滤渲染效果的对比
- GL_NEAREST:GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER(缩小过滤器),GL_NEAREST(最邻近过滤)
- GL_LINEAR:GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER(缩小过滤器),GL_LINEAR(线性过滤)
- GL_NEAREST_MIPMAP_NEAREST:GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER(缩小过滤器),GL_NEAREST_MIPMAP_NEAREST(选择最邻近的Mip层,并执行最邻近过滤)
- GL_NEAREST_MIPMAP_LINEAR:GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER(缩小过滤器),GL_NEAREST_MIPMAP_LINEAR(在Mip层之间执行线性插补,并执行最邻近过滤)
- GL_LINEAR_MIPMAP_NEAREST:GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER(缩小过滤器),GL_NEAREST_MIPMAP_LINEAR(选择最邻近Mip层,并执行线性过滤)
- GL_LINEAR_MIPMAP_LINEAR:GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER(缩小过滤器),GL_LINEAR_MIPMAP_LINEAR(在Mip层之间执行线性插补,并执行线性过滤,又称为三线性过滤)
- Anisotropic Filter:
// 设置各向异性过滤
GLfloat fLargest;
// 获取各向异性过滤的最大数量
glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &fLargest);
// 设置纹理参数(各向异性采样)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, fLargest);
- Anisotropic Off:
// 设置各向同性过滤,数量为1.0表示(各向同性采样)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.0f);