OpenGL--天空盒
理論基礎(chǔ)
1,目前虛擬場(chǎng)景中天空建模常用的方法有天空頂(SkyDome:半球形)和天空盒(SkyBox:長(zhǎng)方體)兩種方法。其本質(zhì)都是攝像機(jī)處在一個(gè)盒子中間,這個(gè)盒子通過(guò)紋理貼圖形成的虛擬世界場(chǎng)景。其中天空盒繪制技術(shù)非常簡(jiǎn)單,因此被廣泛應(yīng)用。然而,有時(shí)也會(huì)存在一些問(wèn)題,例如使用霧效時(shí),如果霧被設(shè)置在觀察者的旁邊,天空盒將減淡甚至消失。另一個(gè)更坑爹的問(wèn)題是霧會(huì)聚積在天空盒的頂點(diǎn)處,從而使天空盒的多邊形暴露無(wú)遺。小心地調(diào)整霧化參數(shù)或細(xì)分天空盒的每一個(gè)面可以減少這些問(wèn)題,但這樣會(huì)大大影響性能。此時(shí),就可用天空頂來(lái)替代天空盒了。它是個(gè)半球形場(chǎng)景,因此就不會(huì)有什么邊界暴露問(wèn)題了。本節(jié)主要介紹天空盒相關(guān)技術(shù)。
2,天空盒其實(shí)就是一個(gè)覆蓋場(chǎng)景四周的長(zhǎng)方體,但它的各個(gè)面上貼有表示天空的紋理圖片,即四周的4面紋理的邊與頂面紋理的邊相連,同時(shí)四面紋理前后相連,紋理大小要是2的N次方(32,64,128,…),如下:
天空盒示例(部分輔助類見(jiàn)上一節(jié))
1,主程序:
#include "stdafx.h" #include<gl/glut.h> #include<gl/glu.h> #include<gl/gl.h> #include <gl\GLAUX.h>#include "Camera.h" #include "SkyBox.h"Camera m_Camera; CSkyBox m_SkyBox;void init(void) {/** 用戶自定義的初始化過(guò)程 */glClearColor(0.0f, 0.0f, 0.0f, 0.5f);glClearDepth(1.0f);glDepthFunc(GL_LEQUAL);glEnable(GL_DEPTH_TEST);glShadeModel(GL_SMOOTH);glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);/** 啟用紋理 */glEnable(GL_TEXTURE_2D);/** 初始化天空 */if (!m_SkyBox.Init()){MessageBox(NULL, (LPCWSTR)"初始化天空失敗!", (LPCWSTR)"錯(cuò)誤", MB_OK);exit(0);}/** 設(shè)置攝像機(jī) */m_Camera.setCamera(500, 35, 400, 501, 35, 400, 0, 1, 0); }void display(void) {/** 用戶自定義的繪制過(guò)程 */glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);glLoadIdentity();/** 放置攝像機(jī) */m_Camera.setLook();/** 繪制天空 */m_SkyBox.CreateSkyBox(0, 0, 0, 1.0, 0.5, 1.0);glFlush(); /**< 強(qiáng)制執(zhí)行所有的OpenGL命令 */ }void ChangeSize(int width, int height) {glViewport(0, 0, width, height); /**< 重新設(shè)置視口 */glMatrixMode(GL_PROJECTION);glLoadIdentity();gluPerspective(45.0f, (GLfloat)width / (GLfloat)height, 0.1f, 4000.0f);glMatrixMode(GL_MODELVIEW);glLoadIdentity(); }void motion(int x, int y) {m_Camera.setViewByMouse();glutPostRedisplay(); }void keyboard(unsigned char key, int x, int y) {switch (key) {case 27:exit(0);break;case '1':m_Camera.setSpeed(0.2f);break;case '2':m_Camera.setSpeed(1.0f);break;case 'w':m_Camera.moveCamera(m_Camera.getSpeed());break;case 's':m_Camera.moveCamera(-m_Camera.getSpeed());break;case 'a':m_Camera.yawCamera(-m_Camera.getSpeed());break;case 'd':m_Camera.yawCamera(m_Camera.getSpeed());break;}glutPostRedisplay();printf("key::%d", key); }int main(int argc, char** argv) {glutInit(&argc, argv);glutInitDisplayMode(GLUT_DEPTH | GLUT_RGB);glutInitWindowSize(800, 600);glutInitWindowPosition((GetSystemMetrics(SM_CXSCREEN) >> 1) - 400, (GetSystemMetrics(SM_CYSCREEN) >> 1) - 300);glutCreateWindow("天空盒");init();glutReshapeFunc(ChangeSize);glutDisplayFunc(display);glutMotionFunc(motion);glutKeyboardFunc(keyboard);glutMainLoop();return 0; }2,天空盒實(shí)現(xiàn)類
#ifndef __SKYBOX_H__ #define __SKYBOX_H__#include "stdafx.h" #include "CBMPLoader.h" #include "Vector.h" #include "Camera.h"#define GL_CLAMP_TO_EDGE 0x812F/** 天空盒類 */ class CSkyBox { public:/** 構(gòu)造函數(shù) */CSkyBox();~CSkyBox();/** 初始化 */bool Init();/** 渲染天空 */void CreateSkyBox(float x, float y, float z, float width, float height, float length);private:CBMPLoader m_texture[6]; /**< 天空盒紋理 */};#endif ///__SKYBOX_H__ #include "SkyBox.h"CSkyBox::CSkyBox() { }CSkyBox::~CSkyBox() {/** 刪除紋理對(duì)象及其占用的內(nèi)存 */for(int i =0 ;i< 6; i++){m_texture[i].FreeImage();glDeleteTextures(1,&m_texture[i].ID);}}/** 天空盒初始化 */ bool CSkyBox::Init() {char filename[128] ; /**< 用來(lái)保存文件名 */char *bmpName[] = { "back","front","bottom","top","left","right"};for(int i=0; i< 6; i++){sprintf(filename,"data/%s",bmpName[i]);strcat(filename,".bmp");if(!m_texture[i].LoadBitmap(filename)) /**< 載入位圖文件 */{MessageBox(NULL, (LPCWSTR)"裝載位圖文件失敗!", (LPCWSTR)"錯(cuò)誤", MB_OK); /**< 如果載入失敗則彈出對(duì)話框 */exit(0);}glGenTextures(1, &m_texture[i].ID); /**< 生成一個(gè)紋理對(duì)象名稱 */glBindTexture(GL_TEXTURE_2D, m_texture[i].ID); /**< 創(chuàng)建紋理對(duì)象 *//** 控制濾波: *//*其中GL_TEXTURE_WRAP_S,GL_TEXTURE_WRAP_T通常可設(shè)置為GL_REPEAT或GL_CLAMP兩種方式。當(dāng)待填充的多邊形大于紋理的時(shí)候,GL_REPEAT表示多余的部分用重復(fù)的方式填充;GL_CLAMP表示多余的部分用相連邊緣的相鄰像素填充。在實(shí)際繪制中,我們一般采用GL_CLAMP_EDGE來(lái)處理,這就消除了接縫處的細(xì)線,增強(qiáng)了天空盒的真實(shí)感。*/glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE);/** 創(chuàng)建紋理 */gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB, m_texture[i].imageWidth,m_texture[i].imageHeight, GL_RGB, GL_UNSIGNED_BYTE,m_texture[i].image);}return true;}/** 構(gòu)造天空盒 */ void CSkyBox::CreateSkyBox(float x, float y, float z, float box_width, float box_height,float box_length) {/** 獲得場(chǎng)景中光照狀態(tài) */GLboolean lp;glGetBooleanv(GL_LIGHTING,&lp);/** 計(jì)算天空盒長(zhǎng) 寬 高 */float width = MAP * box_width/8;float height = MAP * box_height/8;float length = MAP * box_length/8;/** 計(jì)算天空盒中心位置 */x = x+ MAP/8 - width / 2;y = y+ MAP/24 - height / 2;z = z+ MAP/8 - length / 2;glDisable(GL_LIGHTING); /**< 關(guān)閉光照 *//** 開(kāi)始繪制 */glPushMatrix();glTranslatef(-x,-y,-z);/** 繪制背面 */glBindTexture(GL_TEXTURE_2D, m_texture[0].ID);glBegin(GL_QUADS); /** 指定紋理坐標(biāo)和頂點(diǎn)坐標(biāo) */glTexCoord2f(1.0f, 0.0f); glVertex3f(x + width, y, z);glTexCoord2f(1.0f, 1.0f); glVertex3f(x + width, y + height, z); glTexCoord2f(0.0f, 1.0f); glVertex3f(x, y + height, z);glTexCoord2f(0.0f, 0.0f); glVertex3f(x, y, z);glEnd();/** 繪制前面 */glBindTexture(GL_TEXTURE_2D, m_texture[1].ID);glBegin(GL_QUADS); /** 指定紋理坐標(biāo)和頂點(diǎn)坐標(biāo) */glTexCoord2f(1.0f, 0.0f); glVertex3f(x, y, z + length);glTexCoord2f(1.0f, 1.0f); glVertex3f(x, y + height, z + length);glTexCoord2f(0.0f, 1.0f); glVertex3f(x + width, y + height, z + length); glTexCoord2f(0.0f, 0.0f); glVertex3f(x + width, y, z + length);glEnd();/** 繪制底面 */glBindTexture(GL_TEXTURE_2D, m_texture[2].ID);glBegin(GL_QUADS); /** 指定紋理坐標(biāo)和頂點(diǎn)坐標(biāo) */glTexCoord2f(1.0f, 0.0f); glVertex3f(x, y, z);glTexCoord2f(1.0f, 1.0f); glVertex3f(x, y, z + length);glTexCoord2f(0.0f, 1.0f); glVertex3f(x + width, y, z + length); glTexCoord2f(0.0f, 0.0f); glVertex3f(x + width, y, z);glEnd();/** 繪制頂面 */glBindTexture(GL_TEXTURE_2D, m_texture[3].ID);glBegin(GL_QUADS); /** 指定紋理坐標(biāo)和頂點(diǎn)坐標(biāo) */glTexCoord2f(0.0f, 1.0f); glVertex3f(x + width, y + height, z);glTexCoord2f(0.0f, 0.0f); glVertex3f(x + width, y + height, z + length); glTexCoord2f(1.0f, 0.0f); glVertex3f(x, y + height, z + length);glTexCoord2f(1.0f, 1.0f); glVertex3f(x, y + height, z);glEnd();/** 繪制左面 */glBindTexture(GL_TEXTURE_2D, m_texture[4].ID);glBegin(GL_QUADS); /** 指定紋理坐標(biāo)和頂點(diǎn)坐標(biāo) */glTexCoord2f(1.0f, 1.0f); glVertex3f(x, y + height, z); glTexCoord2f(0.0f, 1.0f); glVertex3f(x, y + height, z + length); glTexCoord2f(0.0f, 0.0f); glVertex3f(x, y, z + length);glTexCoord2f(1.0f, 0.0f); glVertex3f(x, y, z); glEnd();/** 繪制右面 */glBindTexture(GL_TEXTURE_2D, m_texture[5].ID);glBegin(GL_QUADS); /** 指定紋理坐標(biāo)和頂點(diǎn)坐標(biāo) */glTexCoord2f(0.0f, 0.0f); glVertex3f(x + width, y, z);glTexCoord2f(1.0f, 0.0f); glVertex3f(x + width, y, z + length);glTexCoord2f(1.0f, 1.0f); glVertex3f(x + width, y + height, z + length); glTexCoord2f(0.0f, 1.0f); glVertex3f(x + width, y + height, z);glEnd();glPopMatrix(); /** 繪制結(jié)束 */if(lp) /** 恢復(fù)光照狀態(tài) */ glEnable(GL_LIGHTING);}注:
/* 定義地面網(wǎng)格 /
const unsigned int MAP_WIDTH = 1024;
const unsigned int CELL_WIDTH = 16;
const unsigned int MAP = MAP_WIDTH * CELL_WIDTH / 2;
總結(jié)
以上是生活随笔為你收集整理的OpenGL--天空盒的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: node2vec算法
- 下一篇: JavaWeb开发框架——Spring