
案例分析
-
一定要注意,搞清楚各个顶点对应的顶点坐标和纹理坐标
顶点坐标和纹理坐标
流程图

我们可以将隧道拆分成3个部分:地面、天花板、墙面(左墙和右墙)
。分别用4个三角形批次类来装载。
//4个批次容器类
GLBatch floorBatch;//地面
GLBatch ceilingBatch;//天花板
GLBatch leftWallBatch;//左墙面
GLBatch rightWallBatch;//右墙面
地面
如图所示,地面是由一个一个的三角形拼接而成

-
拼接方式
我们使用GL_TRIANGLE_STRIP的方式来链接每个顶点,即从第三个点开始,每点与前面的两个点组合画一个三角形,即线性连续三角形串:图元类型参数。
//参数1:代表点的连接方式,GL_TRIANGLE_STRIP
//参数2:代表点的个数
//参数3:代表这个批次类中会使用1个批次类
floorBatch.Begin(GL_TRIANGLE_STRIP, 28, 1);
- 绘制顶点坐标和纹理坐标
这步操作就是讲纹理跟顶点坐标进行一个映射操作
for(z = 60.0f; z >= 0.0f; z -=10.0f)
{
//绘制纹理坐标
//参数1:texture,纹理层次,对于存储着色器来进行渲染,一般为0。
//参数2:s,对应顶点坐标中的x坐标
//参数3:t,对应顶点坐标中的y坐标
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);
}
天花板
天花板的构造方式和地板一样。

- 拼接方式
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);
}
左墙

- 拼接方式
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);
}
右墙

- 拼接方式
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);
}
加载纹理
在这个项目中由于有3个纹理,所以我们用纹理数组来记录纹理。
#define TEXTURE_COUNT 3 //纹理个数
GLuint textures[TEXTURE_COUNT];//纹理标记数组
1. 生成纹理标记
/** 分配纹理对象 glGenTextures
参数1:纹理对象的数量
参数2:纹理对象标识数组
*/
glGenTextures(TEXTURE_COUNT, textures);
2. 绑定纹理
由于这个项目有多个纹理,所以我们用一个循环来进行绑定纹理以及设置纹理的参数。
// 循环设置纹理数组的纹理参数
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);
}
其中的iWidth,iHeight
等参数我们提前设置。
GLbyte *pBytes;
GLint iWidth, iHeight, iComponents;
GLenum eFormat;
GLint iLoop;
那么这些参数从哪来的呢?就是由
gltReadTGABits(szTextureFiles[iLoop],&iWidth, &iHeight, &iComponents, &eFormat);
这句代码获取,gltReadTGABits
代表的是从.tga文件读取纹理,所以iWidth,iHeight等这些参数就是从纹理数据获取而来的,其实就是指针,指向了存放这些参数的地址。
SetupRC
//在这个函数里能够在渲染环境中进行任何需要的初始化,它这里的设置并初始化纹理对象
void SetupRC()
{
//1.黑色的背景
glClearColor(0.0f, 0.0f, 0.0f,1.0f);
//2.初始化shaderManager
shaderManager.InitializeStockShaders();
GLbyte *pBytes;
GLint iWidth, iHeight, iComponents;
GLenum eFormat;
GLint iLoop;
//3.生成纹理标记
/** 分配纹理对象 glGenTextures
参数1:纹理对象的数量
参数2:纹理对象标识数组
*/
glGenTextures(TEXTURE_COUNT, textures);
//4. 循环设置纹理数组的纹理参数
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);
}
//5. 设置几何图形顶点/纹理坐标(上.下.左.右)
GLfloat z;
/*
GLTools库中的容器类,GBatch,
void GLBatch::Begin(GLenum primitive,GLuint nVerts,GLuint nTextureUnits = 0);
参数1:图元枚举值
参数2:顶点数
参数3:1组或者2组纹理坐标
*/
floorBatch.Begin(GL_TRIANGLE_STRIP, 28, 1);
//参考PPT图6-10
//Z表示深度,隧道的深度
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();
//参考PPT图6-11
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();
//参考PPT图6-12
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();
//参考PPT图6-13
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();
}
RenderScene
接下来进行纹理绘制
- 由于用到了纹理,我么我们用
GLT_SHADER_TEXTURE_REPLACE(纹理替换着色器)
这个着色器。
// 0代表从第一层绘制纹理,
shaderManager.UseStockShader(GLT_SHADER_TEXTURE_REPLACE, transformPipeline.GetModelViewProjectionMatrix(), 0);
- 绘制
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();
为什么在Draw()
之前还要进行绑定呢?这是因为我们要将纹理数据和三角形批次类进行绑定
。
所以RenderScene代码如下:
//调用,绘制场景
void RenderScene(void)
{
//1.用当前清除色,清除窗口
glClear(GL_COLOR_BUFFER_BIT);
//2.模型视图压栈
modelViewMatrix.PushMatrix();
//Z轴平移viewZ 距离
modelViewMatrix.Translate(0.0f, 0.0f, viewZ);
//3.纹理替换矩阵着色器
/*
参数1:GLT_SHADER_TEXTURE_REPLACE(着色器标签)
参数2:模型视图投影矩阵
参数3:纹理层
*/
shaderManager.UseStockShader(GLT_SHADER_TEXTURE_REPLACE, transformPipeline.GetModelViewProjectionMatrix(), 0);
//4.绑定纹理
/*
参数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();
//5.pop
modelViewMatrix.PopMatrix();
//6.缓存区交换
glutSwapBuffers();
}
移动观察者
//前后移动视口来对方向键作出响应
void SpecialKeys(int key, int x, int y)
{
if(key == GLUT_KEY_UP)
//移动的是深度值,Z
viewZ += 0.5f;
if(key == GLUT_KEY_DOWN)
viewZ -= 0.5f;
//更新窗口,即可回调到RenderScene函数里
glutPostRedisplay();
}
运行代码,得到隧道

完整代码
main:初始化入口
SetupRC:初始化背景色、着色器,生成纹理,并设置顶点及纹理坐标
ChangeSize:改变视景体和视口,在改变窗口大小或初始化窗口调用
RenderScene:清理缓存、绑定纹理并绘制隧道
ShutdownRC:关闭渲染环境
SpecialKeys:根据上下键位,记录前后移动的深度值,并重新渲染
ProcessMenu:根据选择的菜单选项,for循环更换所有纹理的过滤方式,并重新渲染
#include "GLTools.h"
#include "GLShaderManager.h"
#include "GLFrustum.h"
#include "GLBatch.h"
#include "GLFrame.h"
#include "GLMatrixStack.h"
#include "GLGeometryTransform.h"
#ifdef __APPLE__
#include <glut/glut.h>
#else
#define FREEGLUT_STATIC
#include <GL/glut.h>
#endif
GLShaderManager shaderManager; //着色器管理器
GLMatrixStack modelViewMatrix; //模型视图矩阵
GLMatrixStack projectionMatrix; //投影矩阵
GLFrustum viewFrustum; //视景体
GLGeometryTransform transformPipeline; //几何变换管线
//4个批次容器类
GLBatch floorBatch;//地面
GLBatch ceilingBatch;//天花板
GLBatch leftWallBatch;//左墙面
GLBatch rightWallBatch;//右墙面
//设置一个深度初始值,-65。
GLfloat viewZ = -65.0f;
// 纹理标识符号
#define TEXTURE_BRICK 0 //墙面
#define TEXTURE_FLOOR 1 //地板
#define TEXTURE_CEILING 2 //纹理天花板
#define TEXTURE_COUNT 3 //纹理个数
//纹理标记数组
GLuint textures[TEXTURE_COUNT];
//文件tag名字数组
const char *szTextureFiles[TEXTURE_COUNT] = { "brick.tga", "floor.tga", "ceiling.tga" };
void ChangeSize(int w, int h)
{
if (h == 0) {
h = 1;
}
glViewport(0, 0, w, h);
viewFrustum.SetPerspective(35.0f, float(w)/float(h), 1.0f, 120.0f);
projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
}
//在这个函数里能够在渲染环境中进行任何需要的初始化,它这里的设置并初始化纹理对象
void SetupRC()
{
//1、背景色
glClearColor(0, 0, 0, 1);
//2、初始化着色器
shaderManager.InitializeStockShaders();
//3、加载纹理部分
//1、分配纹理
glGenTextures(TEXTURE_COUNT, textures);
//2、初始化我们需要用的参数
//指针
GLbyte *pBytes;
//宽、高、组件
GLint iWidth,iHeight,iComponents;
//格式
GLenum eFormat;
//定义一个i
GLint iLoop;
//3、我们这次要进行4个面的纹理处理,为了方便,这里循环绑定纹理
//我们需要设置纹理的参数,就需要先确认是对哪个纹理进行设置,这时候就靠绑定纹理来搞定了
//就是我们先绑定纹理A,然后对A进行设置。之后是B、C...
//和RenderScene中一样。要先确认是哪个纹理,才开始draw
for (iLoop = 0; iLoop < TEXTURE_COUNT; iLoop++) {
//绑定纹理
glBindTexture(GL_TEXTURE_2D, textures[iLoop]);
//拿到相关的参数
pBytes = gltReadTGABits(szTextureFiles[iLoop], &iWidth, &iHeight, &iComponents, &eFormat);
//设置参数
//过滤方式
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
//环绕方式
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
//载入纹理
glTexImage2D(GL_TEXTURE_2D, 0, iComponents, iWidth, iHeight, 0, eFormat, GL_UNSIGNED_BYTE, pBytes);
//为纹理对象生成完整的mip贴图
glGenerateMipmap(GL_TEXTURE_2D);
//用完释放
free(pBytes);
}
//初始化4个墙面的顶点数据和纹理坐标
//利用三角形带的图元连接方式
//连接方式,28个顶点,1个纹理
floorBatch.Begin(GL_TRIANGLE_STRIP, 28,1);
for(GLfloat 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.Begin(GL_TRIANGLE_STRIP, 28, 1);
for(GLfloat 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.Begin(GL_TRIANGLE_STRIP, 28, 1);
for(GLfloat 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.Begin(GL_TRIANGLE_STRIP, 28, 1);
for(GLfloat 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();
}
//关闭渲染环境
void ShutdownRC(void)
{
//删除所用到的3个纹理
glDeleteTextures(3, textures);
}
//调用,绘制场景
void RenderScene(void)
{
//1
glClear(GL_COLOR_BUFFER_BIT);
//2、压栈
modelViewMatrix.PushMatrix();
//矩阵直接记录移动
modelViewMatrix.Translate(0, 0, viewZ);
//3、纹理替换矩阵着色器
shaderManager.UseStockShader(GLT_SHADER_TEXTURE_REPLACE,transformPipeline.GetModelViewProjectionMatrix(),0);
//4、绘制。
//因为我们有4个面需要绘制。为了以防万一,绑定了错误的纹理,这里重新绑定一次
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();
//出栈
modelViewMatrix.PopMatrix();
//交换缓冲区
glutSwapBuffers();
}
void SpecialKeys(int key, int x, int y)
{
if (key == GLUT_KEY_UP) {
viewZ += 0.5f;
}
if (key == GLUT_KEY_DOWN) {
viewZ -= 0.5f;
}
glutPostRedisplay();
}
void ProcessMenu(int value)
{
//这里用循环,还是因为一旦改变,4个面都需要做改变
for (GLint iLoop = 0; iLoop < TEXTURE_COUNT; iLoop++) {
//还是要先确定 改变的是哪个纹理的属性。所以先绑定
glBindTexture(GL_TEXTURE_2D, textures[iLoop]);
switch(value)
{
case 0:
//GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER(缩小过滤器),GL_NEAREST(最邻近过滤)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
break;
case 1:
//GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER(缩小过滤器),GL_LINEAR(线性过滤)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
break;
case 2:
//GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER(缩小过滤器),GL_NEAREST_MIPMAP_NEAREST(选择最邻近的Mip层,并执行最邻近过滤)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
break;
case 3:
//GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER(缩小过滤器),GL_NEAREST_MIPMAP_LINEAR(在Mip层之间执行线性插补,并执行最邻近过滤)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR);
break;
case 4:
//GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER(缩小过滤器),GL_NEAREST_MIPMAP_LINEAR(选择最邻近Mip层,并执行线性过滤)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
break;
case 5:
//GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER(缩小过滤器),GL_LINEAR_MIPMAP_LINEAR(在Mip层之间执行线性插补,并执行线性过滤,又称为三线性过滤)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
break;
case 6:
//设置各向异性过滤
GLfloat fLargest;
//获取各向异性过滤的最大数量
glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &fLargest);
//设置纹理参数(各向异性采样)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, fLargest);
break;
case 7:
//设置各向同性过滤,数量为1.0表示(各向同性采样)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.0f);
break;
}
}
//触发重画
glutPostRedisplay();
}
int main (int argc ,char *argv[]){
//一如既往的准备工作
//设置工作目录
gltSetWorkingDirectory(argv[0]);
//初始化glut库
glutInit(&argc, argv);
//初始化双缓冲区窗口
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
//设置大小
glutInitWindowSize(800, 800);
//设置名称
glutCreateWindow("隧道-Mip贴图");
//初始化GLEW库
GLenum status = glewInit();
if (GLEW_OK != status) {
printf("GLEW Error:%s\n",glewGetErrorString(status));
return 1;
}
//1
glutReshapeFunc(ChangeSize);
//2
glutDisplayFunc(RenderScene);
//3
glutSpecialFunc(SpecialKeys);
//4
glutCreateMenu(ProcessMenu);
glutAddMenuEntry("GL_NEAREST", 0);
glutAddMenuEntry("GL_LINEAR", 1);
glutAddMenuEntry("GL_NEAREST_MIPMAP_NEAREST", 2);
glutAddMenuEntry("GL_NEAREST_MIPMAP_LINEAR", 3);
glutAddMenuEntry("GL_LINEAR_MIPMAP_NEAREST", 4);
glutAddMenuEntry("GL_LINEAR_MIPMAP_LINEAR", 5);
glutAddMenuEntry("Anisotropic Filter", 6);
glutAddMenuEntry("Anisotropic Off", 7);
glutAttachMenu(GLUT_RIGHT_BUTTON);
//5
SetupRC();
glutMainLoop();
//6
ShutdownRC();
return 0;
}
网友评论