使用OpenGL常用的API肚邢,繪制一個簡單的隧道模型并貼圖憎妙。最終下過如下:
完成代碼:
#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)關(guān)系如下:
總結(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