1.加载纹理
这个案例中用到了三个纹理,所以用一个for循环来依次进行绑定加载纹理。
//分配纹理对象
glGenTextures(TEXTURE_COUNT, textures);
for (iLoop=0; iLoop<TEXTURE_COUNT; iLoop++) {
//绑定纹理对象
glBindTexture(GL_TEXTURE_2D, textures[iLoop]);
//加载tga文件
pBytes = gltReadTGABits(szTextureFiles[iLoop], &iWidth, &iHeigth, &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(GL_TEXTURE_2D, 0, iComponents, iHeigth, iHeigth, 0, eFormat, GL_UNSIGNED_BYTE, pBytes);
//为纹理对象生成一组完整的mipmap glGenerateMipmap
glGenerateMipmap(GL_TEXTURE_2D);
//释放原始纹理数据,不在需要纹理原始数据了
free(pBytes);
}
2. 确定坐标
以地板坐标为例。地板顶点坐标的绘制采用三角形带GL_TRIANGLE_STRIP
的形式来确定,两个三角形可以组成一个正方形的图形,对应的纹理坐标的确定参照下图。
实现代码:
//设置几何图形顶点
GLfloat z, x=10, y=10;
floorBatch.Begin(GL_TRIANGLE_STRIP, 28, 1);
//铺地板 z表示隧道深度
for (z=60; z>=0; z-=10) {
floorBatch.MultiTexCoord2f(0, 0.0, 0.0);
floorBatch.Vertex3f(-x, -y, z);
floorBatch.MultiTexCoord2f(0, 1.0, 0);
floorBatch.Vertex3f(x, -y, z);
floorBatch.MultiTexCoord2f(0, 0, 1.0);
floorBatch.Vertex3f(-x, -y, z-10);
floorBatch.MultiTexCoord2f(0, 1.0, 1.0);
floorBatch.Vertex3f(x, -y, z-10);
}
floorBatch.End();
其余坐标可以参照上面的设置来确定。
3.绘制
绘制就比较简单了,记得在绘制之前,先要绑定一下对应的纹理对象。
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_BRICK]);
leftWallBatch.Draw();
glBindTexture(GL_TEXTURE_2D, textures[TEXTURE_BRICK]);
rightBatch.Draw();
glBindTexture(GL_TEXTURE_2D, textures[TEXTURE_CEILING]);
ceilingBatch.Draw();
modelViewMatrix.PopMatrix();
glutSwapBuffers();
运行代码, 我们就能得到想要的效果了。
效果4. 镜头移动
上面只能展示一个静态效果,并不能移动,所以我们添加一个响应特殊键位的方法。来移动镜头。最终效果和会上面的动图效果一样。
//前后移动视口来对方向键作出响应
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();
}
5. 对比一些效果
最后我们还可以添加一个右键点击的列表,来设置不同的参数,对比一下不同参数设置的不同效果。 添加菜单入口:
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);
事件处理:
//菜单栏选择
void ProcessMenu(int value)
{
GLuint iLoop;
for (iLoop = 0; iLoop<TEXTURE_COUNT; iLoop++) {
glBindTexture(GL_TEXTURE_2D, textures[iLoop]);
switch (value) {
case 0:
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
break;
case 1:
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
break;
case 2:
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
break;
case 3:
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR);
break;
case 4:
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
case 5:
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
case 6:
GLfloat fLargest;
glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &fLargest);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, fLargest);
default:
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.0f);
break;
}
}
glutPostRedisplay();
}
网友评论