使用OpenGL常用的API,繪制一個簡單的隧道模型并貼圖。最終下過如下:

1.gif
完成代碼:
#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 = -60.0f;
// 紋理標(biāo)識符號
#define TEXTURE_BRICK 0 //墻面
#define TEXTURE_FLOOR 1 //地板
#define TEXTURE_CEILING 2 //紋理天花板
#define TEXTURE_COUNT 3 //紋理個數(shù)
GLuint textures[TEXTURE_COUNT];//紋理標(biāo)記數(shù)組
//文件tag名字?jǐn)?shù)組
const char *szTextureFiles[TEXTURE_COUNT] = { "brick.tga", "floor.tga", "ceiling.tga" };
//菜單欄選擇
void ProcessMenu(int value)
{
GLint i ;
for (i = 0 ; i<TEXTURE_COUNT; i++) {
glBindTexture(GL_TEXTURE_2D, textures[i]);
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;
case 6:
//設(shè)置各向異性過濾
GLfloat fLargest;
//獲取各向異性過濾的最大數(shù)量
glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &fLargest);
//設(shè)置紋理參數(shù)(各向異性采樣)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, fLargest);
break;
case 7:
//設(shè)置各向同性過濾,數(shù)量為1.0表示(各向同性采樣)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.0f);
break;
}
}
glutPostRedisplay();
}
//在這個函數(shù)里能夠在渲染環(huán)境中進(jìn)行任何需要的初始化,它這里的設(shè)置并初始化紋理對象
void SetupRC()
{
glClearColor(0, 0, 0, 1);
shaderManager.InitializeStockShaders();
GLbyte * byte;
GLint i, width, height, iComponent;
GLenum eFormat;
glGenTextures(TEXTURE_COUNT, textures);
for (i = 0; i<TEXTURE_COUNT; i++) {
glBindTexture(GL_TEXTURE_2D, textures[i]);
byte = gltReadTGABits(szTextureFiles[i], &width, &height, &iComponent, &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, iComponent, width, height, 0, eFormat, GL_UNSIGNED_BYTE, byte);
glGenerateMipmap(GL_TEXTURE_2D);
free(byte);
}
GLfloat z;
floorBatch.Begin(GL_TRIANGLE_STRIP, 28, 1);
for (z = 60.0f; z >= 0.0f; z-= 10.0f) {
floorBatch.MultiTexCoord2f(0, 1.0f, 0.0f);
floorBatch.Vertex3f(-10.0f, -10.0f, z);
floorBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
floorBatch.Vertex3f(10.0f, -10.0f, z);
floorBatch.MultiTexCoord2f(0, 1.0f, 1.0f);
floorBatch.Vertex3f(-10.0f, -10.0f, z - 10.0f);
floorBatch.MultiTexCoord2f(0, 0.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, 0.0f);
ceilingBatch.Vertex3f(-10.0f, 10.0f, z - 10.0f);
ceilingBatch.MultiTexCoord2f(0, 1.0f, 0.0f);
ceilingBatch.Vertex3f(10.0f, 10.0f, z - 10.0f);
ceilingBatch.MultiTexCoord2f(0, 1.0f, 0.0f);
ceilingBatch.Vertex3f(-10.0f, 10.0f, z);
ceilingBatch.MultiTexCoord2f(0, 1.0f, 1.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, 1.0f, 0.0f);
leftWallBatch.Vertex3f(-10.0f, -10.0f, z);
leftWallBatch.MultiTexCoord2f(0, 1.0f, 1.0f);
leftWallBatch.Vertex3f(-10.0f, 10.0f, z);
leftWallBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
leftWallBatch.Vertex3f(-10.0f, -10.0f, z - 10.0f);
leftWallBatch.MultiTexCoord2f(0, 0.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, 1.0f, 0.0f);
rightWallBatch.Vertex3f(10.0f, -10.0f, z);
rightWallBatch.MultiTexCoord2f(0, 1.0f, 1.0f);
rightWallBatch.Vertex3f(10.0f, 10.0f, z);
rightWallBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
rightWallBatch.Vertex3f(10.0f, -10.0f, z - 10.0f);
rightWallBatch.MultiTexCoord2f(0, 0.0f, 1.0f);
rightWallBatch.Vertex3f(10.0f, 10.0f, z - 10.0f);
}
rightWallBatch.End();
}
//關(guān)閉渲染環(huán)境
void ShutdownRC(void)
{
glDeleteTextures(TEXTURE_COUNT, textures);
}
//前后移動視口來對方向鍵作出響應(yīng)
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();
}
//改變視景體和視口,在改變窗口大小或初始化窗口調(diào)用
void ChangeSize(int w, int h)
{
if (h == 0) h = 1;
glViewport(0, 0, w, h);
viewFrustum.SetPerspective(80, float(w)/float(h), 1, 120);
projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
}
//調(diào)用,繪制場景
void RenderScene(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_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();
}
int main(int argc, char *argv[])
{
gltSetWorkingDirectory(argv[0]);
// 標(biāo)準(zhǔn)初始化
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;
}
// 啟動循環(huán),關(guān)閉紋理
SetupRC();
glutMainLoop();
ShutdownRC();
return 0;
}
紋理坐標(biāo)對應(yīng)如下:

image.png
總結(jié):
1.讀取的紋理可以翻轉(zhuǎn)使用,正反面都可以用來填充。
2.繪制流程:指定生成紋理ID的數(shù)量和數(shù)組 —>綁定紋理ID—>讀取.tga文件載入紋理 —>設(shè)置過濾方式和環(huán)繞 —> 設(shè)置紋理和頂點(diǎn)對應(yīng)關(guān)系 —> 綁定相應(yīng)的紋理并用對應(yīng)的批次類繪制
3.修改紋理環(huán)繞過濾方式前,也需要綁定紋理ID