隧道源码示例
// Tunnel.cpp
// Demonstrates mipmapping and using texture objects
// OpenGL SuperBible
// Richard S. Wright Jr.
#include
#include
#include
#include
#include
#include
#include
#ifdef __APPLE__ #include
#else #define FREEGLUT_STATIC #include
#endif GLShaderManager shaderManager; // Shader Manager GLMatrixStack modelViewMatrix; // Modelview Matrix GLMatrixStack projectionMatrix; // Projection Matrix GLFrustum viewFrustum; // View Frustum GLGeometryTransform transformPipeline; // Geometry Transform Pipeline GLBatch floorBatch; GLBatch ceilingBatch; GLBatch leftWallBatch; GLBatch rightWallBatch; GLfloat viewZ = -65.0f; // Texture objects #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" }; /// // Change texture filter for each texture object void ProcessMenu(int value) { GLint iLoop; for(iLoop = 0; iLoop < TEXTURE_COUNT; iLoop++) { glBindTexture(GL_TEXTURE_2D, textures[iLoop]); switch(value) { case 0: glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); break; case 1: glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); break; case 2: glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST); break; case 3: glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR); break; case 4: glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); break; case 5: glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); break; } } // Trigger Redraw glutPostRedisplay(); } // // This function does any needed initialization on the rendering // context. Here it sets up and initializes the texture objects. void SetupRC() { GLbyte *pBytes; GLint iWidth, iHeight, iComponents; GLenum eFormat; GLint iLoop; // Black background glClearColor(0.0f, 0.0f, 0.0f,1.0f); shaderManager.InitializeStockShaders(); // Load textures glGenTextures(TEXTURE_COUNT, textures); for(iLoop = 0; iLoop < TEXTURE_COUNT; iLoop++) { // Bind to next texture object glBindTexture(GL_TEXTURE_2D, textures[iLoop]); // Load texture, set filter and wrap modes pBytes = gltReadTGABits(szTextureFiles[iLoop],&iWidth, &iHeight, &iComponents, &eFormat); // Load texture, set filter and wrap modes 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); glGenerateMipmap(GL_TEXTURE_2D); // Don't need original texture data any more free(pBytes); } // Build Geometry 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.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.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.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(); } /// // Shutdown the rendering context. Just deletes the // texture objects void ShutdownRC(void) { glDeleteTextures(TEXTURE_COUNT, textures); } /// // Respond to arrow keys, move the viewpoint back // and forth void SpecialKeys(int key, int x, int y) { if(key == GLUT_KEY_UP) viewZ += 0.5f; if(key == GLUT_KEY_DOWN) viewZ -= 0.5f; // Refresh the Window glutPostRedisplay(); } / // Change viewing volume and viewport. Called when window is resized void ChangeSize(int w, int h) { GLfloat fAspect; // Prevent a divide by zero if(h == 0) h = 1; // Set Viewport to window dimensions glViewport(0, 0, w, h); fAspect = (GLfloat)w/(GLfloat)h; // Produce the perspective projection viewFrustum.SetPerspective(80.0f,fAspect,1.0,120.0); projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix()); transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix); } /// // Called to draw scene void RenderScene(void) { // Clear the window with current clearing color glClear(GL_COLOR_BUFFER_BIT); modelViewMatrix.PushMatrix(); modelViewMatrix.Translate(0.0f, 0.0f, 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(); // Buffer swap glutSwapBuffers(); } // // Program entry point int main(int argc, char *argv[]) { gltSetWorkingDirectory(argv[0]); // Standard initialization stuff glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB); glutInitWindowSize(800, 600); glutCreateWindow("Tunnel"); glutReshapeFunc(ChangeSize); glutSpecialFunc(SpecialKeys); glutDisplayFunc(RenderScene); // Add menu entries to change filter 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); glutAttachMenu(GLUT_RIGHT_BUTTON); GLenum err = glewInit(); if (GLEW_OK != err) { fprintf(stderr, "GLEW Error: %s\n", glewGetErrorString(err)); return 1; } // Startup, loop, shutdown SetupRC(); glutMainLoop(); ShutdownRC(); return 0; }
运行时,按下前后方向键可前后行进。右键鼠标,有6个选项菜单,可以选择纹理贴图的过滤方式和Mip纹理贴图过滤方式。
通过上一个源码示例的学习,我们已经熟悉了纹理的一些应用的知识,着了解析学习一下新的渲染知识。
一、源码解析
1、全局变量定义
//上下左右墙壁的批次图元的定义
GLBatch floorBatch;
GLBatch ceilingBatch;
GLBatch leftWallBatch;
GLBatch rightWallBatch;
//视坐标Z轴平移的的像素值
GLfloat viewZ = -65.0f;
// 定义纹理标识和执行纹理贴图文件的指针
#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" };
2、函数解析
1)void SetupRC()
GLbyte *pBytes; //声明指向纹理数据的指针,
GLint iWidth, iHeight, iComponents; //返回的指向新的缓冲区、纹理的高低各宽度。
GLenum eFormat; //OpenGL图像数据格式
GLint iLoop; //循环加载纹理的局部变量
......
glGenTextures(TEXTURE_COUNT, textures); //生成纹理,注意是三个纹理标识符(数组)//循环绑定纹理标识符,并读取纹理贴图文件的数据
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);
// 建立天花板的墙体图形
GLfloat z; //z轴的坐标值
floorBatch.Begin(GL_TRIANGLE_STRIP, 28, 1); //绘制线带(顶点连成线)//指定Mip贴图纹理层次,纹理坐标。以视坐标的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();
//左右和下面的墙体按照以上同样的方式建立图元
2)void RenderScene(void)
modelViewMatrix.PushMatrix(); //默认压栈单位矩阵到模型视图矩阵堆栈中
modelViewMatrix.Translate(0.0f, 0.0f, viewZ);//创建一个沿Z轴的平移矩阵再与模型视图矩阵堆栈顶部的矩阵相乘,再压栈到堆栈
//选择使用纹理提到换着色器,使用绑定到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();
3)void SpecialKeys
//设置上下键时,视坐标的z轴进行改变
{
if(key == GLUT_KEY_UP)
viewZ += 0.5f;
if(key == GLUT_KEY_DOWN)
viewZ -= 0.5f;
// Refresh the Window
glutPostRedisplay();
}
4)void ProcessMenu(int value) //创建菜单的回调函数
GLint iLoop;
//循环依次绑定纹理单元标识符,右键出现菜单栏后选择不同的菜单后,设置不同的过滤方式。
for(iLoop = 0; iLoop < TEXTURE_COUNT; iLoop++)
{
glBindTexture(GL_TEXTURE_2D, textures[iLoop]);
switch(value)
{
case 0:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
break;
case 1:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
break;
case 2:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
break;
case 3:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR);
break;
case 4:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
break;
case 5:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
break;
}
// Trigger Redraw
glutPostRedisplay();
}
二、小结
此源码示例,与上一个纹理的示例不同点再与在SetupRC一次性设置,使用一个循环一对一一次绑定纹理标识并读取和载入纹理数据,并且生成了Mip贴图层。添加了一个菜单栏,右键鼠标后出现单击选择不同的栏,可以选择不同的过滤方式,再刷新渲染。