今天我們使用OpenGL的紋理繪制一個(gè)隧道芥映,效果如下:
隧道案例
隧道的繪制與上一節(jié)金字塔的繪制類似莹规,主要是我們要找到各個(gè)面與對(duì)應(yīng)的紋理的坐標(biāo)點(diǎn)的對(duì)應(yīng),設(shè)置好環(huán)繞方式和過(guò)濾模式矮燎,最后添加菜單鍵來(lái)更改過(guò)濾模式鸡号,主要代碼如下:
//在這個(gè)函數(shù)里能夠在渲染環(huán)境中進(jìn)行任何需要的初始化转砖,它這里的設(shè)置并初始化紋理對(duì)象
void SetupRC()
{
//1.黑色的背景
glClearColor(0.0f, 0.0f, 0.0f,1.0f);
//2.初始化shaderManager
shaderManager.InitializeStockShaders();
GLbyte *pBytes;
GLint iWidth, iHeight, iComponents;
GLenum eFormat;
GLint iLoop;
//3.生成紋理標(biāo)記
/** 分配紋理對(duì)象 glGenTextures
參數(shù)1:紋理對(duì)象的數(shù)量
參數(shù)2:紋理對(duì)象標(biāo)識(shí)數(shù)組
*/
glGenTextures(TEXTURE_COUNT, textures);
//4. 循環(huán)設(shè)置紋理數(shù)組的紋理參數(shù)
for(iLoop = 0; iLoop < TEXTURE_COUNT; iLoop++)
{
/**綁定紋理對(duì)象 glBindTexture
參數(shù)1:紋理模式,GL_TEXTURE_1D,GL_TEXTURE_2D,GL_TEXTURE_3D
參數(shù)2:需要綁定的紋理對(duì)象
*/
glBindTexture(GL_TEXTURE_2D, textures[iLoop]);
/**加載tga文件
參數(shù)1:紋理文件名稱
參數(shù)2:文件寬度變量地址
參數(shù)3:文件高度變量地址
參數(shù)4:文件組件變量地址
參數(shù)5:文件格式變量地址
返回值:pBytes膜蠢,指向圖像數(shù)據(jù)的指針
*/
pBytes = gltReadTGABits(szTextureFiles[iLoop],&iWidth, &iHeight,
&iComponents, &eFormat);
//加載紋理堪藐、設(shè)置過(guò)濾器和包裝模式
//GL_TEXTURE_MAG_FILTER(放大過(guò)濾器,GL_NEAREST(最鄰近過(guò)濾)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
//GL_TEXTURE_MIN_FILTER(縮小過(guò)濾器),GL_NEAREST(最鄰近過(guò)濾)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
//GL_TEXTURE_WRAP_S(s軸環(huán)繞),GL_CLAMP_TO_EDGE(環(huán)繞模式強(qiáng)制對(duì)范圍之外的紋理坐標(biāo)沿著合法的紋理單元的最后一行或一列進(jìn)行采樣)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
//GL_TEXTURE_WRAP_T(t軸環(huán)繞),GL_CLAMP_TO_EDGE(環(huán)繞模式強(qiáng)制對(duì)范圍之外的紋理坐標(biāo)沿著合法的紋理單元的最后一行或一列進(jìn)行采樣)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
/**載入紋理 glTexImage2D
參數(shù)1:紋理維度挑围,GL_TEXTURE_2D
參數(shù)2:mip貼圖層次
參數(shù)3:紋理單元存儲(chǔ)的顏色成分(從讀取像素圖中獲得)
參數(shù)4:加載紋理寬度
參數(shù)5:加載紋理的高度
參數(shù)6:加載紋理的深度
參數(shù)7:像素?cái)?shù)據(jù)的數(shù)據(jù)類型,GL_UNSIGNED_BYTE無(wú)符號(hào)整型
參數(shù)8:指向紋理圖像數(shù)據(jù)的指針
*/
glTexImage2D(GL_TEXTURE_2D, 0, iComponents, iWidth, iHeight, 0, eFormat, GL_UNSIGNED_BYTE, pBytes);
/**為紋理對(duì)象生成一組完整的mipmap glGenerateMipmap
參數(shù)1:紋理維度,GL_TEXTURE_1D,GL_TEXTURE_2D,GL_TEXTURE_2D
*/
glGenerateMipmap(GL_TEXTURE_2D);
//釋放原始紋理數(shù)據(jù)糖荒,不在需要紋理原始數(shù)據(jù)了
free(pBytes);
}
//5. 設(shè)置幾何圖形頂點(diǎn)/紋理坐標(biāo)(上.下.左.右)
GLfloat z;
/*
GLTools庫(kù)中的容器類杉辙,GBatch,
void GLBatch::Begin(GLenum primitive,GLuint nVerts,GLuint nTextureUnits = 0);
參數(shù)1:圖元枚舉值
參數(shù)2:頂點(diǎn)數(shù)
參數(shù)3:1組或者2組紋理坐標(biāo)
*/
floorBatch.Begin(GL_TRIANGLE_STRIP, 28, 1);
//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();
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();
}
該方法首先加載四個(gè)面的紋理數(shù)據(jù)蜘矢,設(shè)置紋理的環(huán)繞方式和過(guò)濾方式以及包裝模式狂男,
然后把隧道的四個(gè)面根據(jù)深度Z值用相對(duì)應(yīng)的紋理數(shù)據(jù)進(jìn)行設(shè)置。
各個(gè)面的對(duì)應(yīng)紋理坐標(biāo)如下圖:
地板
左墻面
右墻面
天花板
然后在RenderScene函數(shù)中進(jìn)行繪制:
//調(diào)用品腹,繪制場(chǎng)景
void RenderScene(void)
{
//1.用當(dāng)前清除色岖食,清除窗口
glClear(GL_COLOR_BUFFER_BIT);
//2.模型視圖壓棧
modelViewMatrix.PushMatrix();
//Z軸平移viewZ 距離
modelViewMatrix.Translate(0.0f, 0.0f, viewZ);
//3.紋理替換矩陣著色器
/*
參數(shù)1:GLT_SHADER_TEXTURE_REPLACE(著色器標(biāo)簽)
參數(shù)2:模型視圖投影矩陣
參數(shù)3:紋理層
*/
shaderManager.UseStockShader(GLT_SHADER_TEXTURE_REPLACE, transformPipeline.GetModelViewProjectionMatrix(), 0);
//4.綁定紋理
/*
參數(shù)1:紋理模式,GL_TEXTURE_1D舞吭、GL_TEXTURE_2D泡垃、GL_TEXTURE_3D
參數(shù)2:需要綁定的紋理
*/
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();
//5.pop
modelViewMatrix.PopMatrix();
//6.緩存區(qū)交換
glutSwapBuffers();
}
因?yàn)槲覀兿胍c(diǎn)擊窗口右鍵彈出更改過(guò)濾方式的帶單,所以我們要做Main函數(shù)中添加一下代碼:
// 添加菜單入口羡鸥,改變過(guò)濾器
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);
最后我們通過(guò)監(jiān)聽(tīng)ProcessMenu函數(shù)來(lái)更改成對(duì)應(yīng)的過(guò)濾方式來(lái)重新渲染蔑穴,
//菜單欄選擇
void ProcessMenu(int value)
{
GLint iLoop;
for(iLoop = 0; iLoop < TEXTURE_COUNT; iLoop++)
{
/**綁定紋理 glBindTexture
參數(shù)1:GL_TEXTURE_2D
參數(shù)2:需要綁定的紋理對(duì)象
*/
glBindTexture(GL_TEXTURE_2D, textures[iLoop]);
/**配置紋理參數(shù) glTexParameteri
參數(shù)1:紋理模式
參數(shù)2:紋理參數(shù)
參數(shù)3:特定紋理參數(shù)
*/
switch(value)
{
case 0:
//GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER(縮小過(guò)濾器),GL_NEAREST(最鄰近過(guò)濾)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
break;
case 1:
//GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER(縮小過(guò)濾器)惧浴,GL_LINEAR(線性過(guò)濾)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
break;
case 2:
//GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER(縮小過(guò)濾器)存和,GL_NEAREST_MIPMAP_NEAREST(選擇最鄰近的Mip層,并執(zhí)行最鄰近過(guò)濾)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
break;
case 3:
//GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER(縮小過(guò)濾器)衷旅,GL_NEAREST_MIPMAP_LINEAR(在Mip層之間執(zhí)行線性插補(bǔ)捐腿,并執(zhí)行最鄰近過(guò)濾)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR);
break;
case 4:
//GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER(縮小過(guò)濾器),GL_NEAREST_MIPMAP_LINEAR(選擇最鄰近Mip層柿顶,并執(zhí)行線性過(guò)濾)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
break;
case 5:
//GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER(縮小過(guò)濾器)叙量,GL_LINEAR_MIPMAP_LINEAR(在Mip層之間執(zhí)行線性插補(bǔ),并執(zhí)行線性過(guò)濾九串,又稱為三線性過(guò)濾)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
break;
case 6:
//設(shè)置各向異性過(guò)濾
GLfloat fLargest;
//獲取各向異性過(guò)濾的最大數(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è)置各向同性過(guò)濾绞佩,數(shù)量為1.0表示(各向同性采樣)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.0f);
break;
}
}
//觸發(fā)重畫(huà)
glutPostRedisplay();
}