本次案例分析我们主要实现改动画
我们要实现这样的效果,需要绘制四个纹理,左右墙面纹理,隧道顶部以及底部纹理
准备工作
同样我们整体的顺序是ChangeSize函数->SetupRC函数->RenderScene函数,以及控制视图的SpecialKeys函数
ChangeSize函数
ChangeSize函数主要还是设置窗口、投影矩阵、加载投影矩阵以及设置变换管道,代码如下
void ChangeSize(int w,int h)
{
if (h == 0) {
h = 1;
}
glViewport(0,0, w, h);
//设置投影矩阵
viewFrustum.SetPerspective(100.0f, (float)w/(float)h, 1.0, 120.0);
//加载投影矩阵
projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
//设置变换管道
transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
}
复制代码
SetupRC函数
这个函数里面处理的事情主要是设置背景色、初始化着色器管理、处理三个(上、下跟左右)纹理,设置纹理跟隧道顶点的映射关系
设置背景以及初始化着色管理器
//设置背影颜色
glClearColor(0.0f,0.0f,0.0f,1.0f);
//初始化着色管理器
shaderManager.InitializeStockShaders();
复制代码
处理纹理
GLbyte *pBytes;
GLint iWidth, iHeight, iComponents;
GLenum eFormat;
GLint iLoop;
//生成纹理标记
glGenTextures(TEXTURE_COUNT, textures);
//for循环设置纹理
for (int i = 0; i<TEXTURE_COUNT; i++) {
//绑定纹理
glBindTexture(GL_TEXTURE_2D, textures[i]);
//解析tga文件
pBytes = gltReadTGABits(szTextureFiles[i], &iWidth, &iHeight, &iComponents, &eFormat);
//设置纹理过滤方式
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);//放大过滤
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);//缩小过滤
//设置环绕方式
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(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);
}
复制代码
处理地板纹理与顶点映射关系
如下图所示,地板顶点的变化主要是z轴发生了变化
//z表示隧道的深度,z的值约小距离屏幕越远
GLfloat z;
floorBatch.Begin(GL_TRIANGLE_STRIP, 28, 1);
for (z = 70.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();
复制代码
设置顶部纹理与顶点关系
同样我们从下图可以看到顶点变化的依然是z轴
//绘制天花板
ceilingBatch.Begin(GL_TRIANGLE_STRIP, 28, 1);
for(z = 70.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(z = 70.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(z = 70.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函数
主要就是根据纹理绘制隧道
void RenderScene(void)
{
//清除一个或一组特定的缓冲区
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
//模型视图压栈
modelViewMatrix.PushMatrix();
//视图平移
modelViewMatrix.Translate(0, 0, viewZ);
//设置纹理替换矩阵
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();
modelViewMatrix.PopMatrix();
//将在后台缓冲区进行渲染,然后在结束时交换到前台
glutSwapBuffers();
}
复制代码
SpecialKeys函数
主要是接手上下左右键的输入并重新绘制隧道
//前后移动视口来对方向键作出响应
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函数
程序入口
int main(int argc,char* argv[])
{
gltSetWorkingDirectory(argv[0]);
// 标准初始化
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
glutInitWindowSize(800, 600);
glutCreateWindow("Tunnel");
glutReshapeFunc(ChangeSize);
glutSpecialFunc(SpecialKeys);
glutDisplayFunc(RenderScene);
// 添加菜单入口,改变过滤器
// 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);
GLenum err = glewInit();
if (GLEW_OK != err) {
fprintf(stderr, "GLEW Error: %s\n", glewGetErrorString(err));
return 1;
}
// 启动循环,关闭纹理
SetupRC();
glutMainLoop();
ShutdownRC();
return 0;
}
复制代码