球體環(huán)境映射是一個(gè)創(chuàng)建快速金屬反射效果的方法,但它并不像真實(shí)世界里那么精確!我們從18課的代碼開始來(lái)創(chuàng)建這個(gè)教程,教你如何創(chuàng)建這種效果。
在我們開始之間,看一下紅寶書中的介紹。它定義球體環(huán)境映射為一幅位于無(wú)限遠(yuǎn)的圖像,把它映射到球面上。
在Photoshop中創(chuàng)建一幅球體環(huán)境映射圖。
首先,你需要一幅球體環(huán)境映射圖,用來(lái)把它映射到球體上。在Photoshop中打開一幅圖并選擇所有的像素,創(chuàng)建它的一個(gè)復(fù)制。
接著,我們把圖像變?yōu)?的冪次方大小,一般為128x128或256x256。
最后使用扭曲(distort)濾鏡,并應(yīng)用球體效果。然后把它保存為*.bmp文件。
我們并沒有添加任何全局變量,只是把紋理組的大小變?yōu)?,以保存6幅紋理。
GLuint texture[6]; // 保存6幅紋理
下面我們要做的就是載入這些紋理
int LoadGLTextures()
{
int Status=FALSE;
AUX_RGBImageRec *TextureImage[2]; // 創(chuàng)建紋理的保存空間
memset(TextureImage,0,sizeof(void *)*2); // 清空為0
// 載入*.bmp圖像
if ((TextureImage[0]=LoadBMP("Data/BG.bmp")) && // 背景圖
(TextureImage[1]=LoadBMP("Data/Reflect.bmp"))) // 反射圖(球形紋理圖)
{
Status=TRUE;
glGenTextures(6, &texture[0]); // 創(chuàng)建6個(gè)紋理
for (int loop=0; loop<=1; loop++)
{
// 創(chuàng)建臨近點(diǎn)過濾紋理圖
glBindTexture(GL_TEXTURE_2D, texture[loop]); // 創(chuàng)建紋理0和1
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[loop]->sizeX, TextureImage[loop]->sizeY,
0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[loop]->data);
// 創(chuàng)建線形過濾紋理圖
glBindTexture(GL_TEXTURE_2D, texture[loop+2]); // 創(chuàng)建紋理2,3
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[loop]->sizeX, TextureImage[loop]->sizeY,
0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[loop]->data);
// 創(chuàng)建線形Mipmap紋理圖
glBindTexture(GL_TEXTURE_2D, texture[loop+4]); // 創(chuàng)建紋理4,5
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_NEAREST);
gluBuild2DMipmaps(GL_TEXTURE_2D, 3, TextureImage[loop]->sizeX, TextureImage[loop]->sizeY,
GL_RGB, GL_UNSIGNED_BYTE, TextureImage[loop]->data);
}
for (loop=0; loop<=1; loop++)
{
if (TextureImage[loop]) // 如果圖像存在則清除
{
if (TextureImage[loop]->data)
{
free(TextureImage[loop]->data);
}
free(TextureImage[loop]);
}
}
}
return Status;
}
我們對(duì)立方體的繪制代碼做了一些小的改動(dòng),把法線的范圍從[-1,1]縮放到[-0.5,0.5]。如果法向量太大的話,會(huì)產(chǎn)生一些塊狀效果,影響視覺效果。
GLvoid glDrawCube()
{
glBegin(GL_QUADS);
// 前面
glNormal3f( 0.0f, 0.0f, 0.5f);
glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f);
glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f);
// 背面
glNormal3f( 0.0f, 0.0f,-0.5f);
glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f);
glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f);
// 上面
glNormal3f( 0.0f, 0.5f, 0.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f);
glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, 1.0f, 1.0f);
glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, 1.0f, 1.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f);
// 下面
glNormal3f( 0.0f,-0.5f, 0.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, -1.0f, -1.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, -1.0f, -1.0f);
glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f);
glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f);
// 右面
glNormal3f( 0.5f, 0.0f, 0.0f);
glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f);
glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f);
// 左面
glNormal3f(-0.5f, 0.0f, 0.0f);
glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f);
glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f);
glEnd();
}
在初始化OpenGL中,我們添加一些新的函數(shù)來(lái)使用球體紋理映射。
下面的代碼讓OpenGL自動(dòng)為我們計(jì)算使用球體映射時(shí),頂點(diǎn)的紋理坐標(biāo)。
glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); // 設(shè)置s方向的紋理自動(dòng)生成
glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); // 設(shè)置t方向的紋理自動(dòng)生成
我們幾乎完成了所有的工作!接下來(lái)要做的就是就是繪制渲染,我刪除了一些二次幾何體,因?yàn)樗鼈兊囊曈X效果并不好。當(dāng)然我們需要OpenGL為這些幾何體自動(dòng)生成坐標(biāo),接著選擇球體映射紋理并繪制幾何體。最后把OpenGL狀態(tài)設(shè)置正常模式。
int DrawGLScene(GLvoid)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity(); // 重置視口
glTranslatef(0.0f,0.0f,z);
glEnable(GL_TEXTURE_GEN_S); // 自動(dòng)生成s方向紋理坐標(biāo)
glEnable(GL_TEXTURE_GEN_T); // 自動(dòng)生成t方向紋理坐標(biāo)
glBindTexture(GL_TEXTURE_2D, texture[filter+(filter+1)]); // 綁定紋理
glPushMatrix();
glRotatef(xrot,1.0f,0.0f,0.0f);
glRotatef(yrot,0.0f,1.0f,0.0f);
switch(object)
{
case 0:
glDrawCube();
break;
case 1:
glTranslatef(0.0f,0.0f,-1.5f); // 創(chuàng)建圓柱
gluCylinder(quadratic,1.0f,1.0f,3.0f,32,32);
break;
case 2:
gluSphere(quadratic,1.3f,32,32); // 創(chuàng)建球
break;
case 3:
glTranslatef(0.0f,0.0f,-1.5f); // 創(chuàng)建圓錐
gluCylinder(quadratic,1.0f,0.0f,3.0f,32,32);
break;
};
glPopMatrix();
glDisable(GL_TEXTURE_GEN_S); // 禁止自動(dòng)生成紋理坐標(biāo)
glDisable(GL_TEXTURE_GEN_T);
xrot+=xspeed;
yrot+=yspeed;
return TRUE; // 成功返回
}
最后我們使用空格來(lái)切換各個(gè)不同的幾何體
if (keys[' '] && !sp)
{
sp=TRUE;
object++;
if(object>3)
object=0;
}
我們成功了!現(xiàn)在你可以使用環(huán)境映射紋理做一些非常棒的特效了。我想做一個(gè)立方體環(huán)境映射的例子,但我現(xiàn)在的顯卡不支持這種特效,所以只有等到以后了。
謝謝,并祝你好運(yùn)!