OpenGL--天空盒
生活随笔
收集整理的這篇文章主要介紹了
OpenGL--天空盒
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
理論基礎
1,目前虛擬場景中天空建模常用的方法有天空頂(SkyDome:半球形)和天空盒(SkyBox:長方體)兩種方法。其本質都是攝像機處在一個盒子中間,這個盒子通過紋理貼圖形成的虛擬世界場景。其中天空盒繪制技術非常簡單,因此被廣泛應用。然而,有時也會存在一些問題,例如使用霧效時,如果霧被設置在觀察者的旁邊,天空盒將減淡甚至消失。另一個更坑爹的問題是霧會聚積在天空盒的頂點處,從而使天空盒的多邊形暴露無遺。小心地調整霧化參數或細分天空盒的每一個面可以減少這些問題,但這樣會大大影響性能。此時,就可用天空頂來替代天空盒了。它是個半球形場景,因此就不會有什么邊界暴露問題了。本節主要介紹天空盒相關技術。
2,天空盒其實就是一個覆蓋場景四周的長方體,但它的各個面上貼有表示天空的紋理圖片,即四周的4面紋理的邊與頂面紋理的邊相連,同時四面紋理前后相連,紋理大小要是2的N次方(32,64,128,…),如下:
天空盒示例(部分輔助類見上一節)
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) {/** 用戶自定義的初始化過程 */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)"錯誤", MB_OK);exit(0);}/** 設置攝像機 */m_Camera.setCamera(500, 35, 400, 501, 35, 400, 0, 1, 0); }void display(void) {/** 用戶自定義的繪制過程 */glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);glLoadIdentity();/** 放置攝像機 */m_Camera.setLook();/** 繪制天空 */m_SkyBox.CreateSkyBox(0, 0, 0, 1.0, 0.5, 1.0);glFlush(); /**< 強制執行所有的OpenGL命令 */ }void ChangeSize(int width, int height) {glViewport(0, 0, width, height); /**< 重新設置視口 */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,天空盒實現類
#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:/** 構造函數 */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() {/** 刪除紋理對象及其占用的內存 */for(int i =0 ;i< 6; i++){m_texture[i].FreeImage();glDeleteTextures(1,&m_texture[i].ID);}}/** 天空盒初始化 */ bool CSkyBox::Init() {char filename[128] ; /**< 用來保存文件名 */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)"錯誤", MB_OK); /**< 如果載入失敗則彈出對話框 */exit(0);}glGenTextures(1, &m_texture[i].ID); /**< 生成一個紋理對象名稱 */glBindTexture(GL_TEXTURE_2D, m_texture[i].ID); /**< 創建紋理對象 *//** 控制濾波: *//*其中GL_TEXTURE_WRAP_S,GL_TEXTURE_WRAP_T通常可設置為GL_REPEAT或GL_CLAMP兩種方式。當待填充的多邊形大于紋理的時候,GL_REPEAT表示多余的部分用重復的方式填充;GL_CLAMP表示多余的部分用相連邊緣的相鄰像素填充。在實際繪制中,我們一般采用GL_CLAMP_EDGE來處理,這就消除了接縫處的細線,增強了天空盒的真實感。*/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);/** 創建紋理 */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;}/** 構造天空盒 */ void CSkyBox::CreateSkyBox(float x, float y, float z, float box_width, float box_height,float box_length) {/** 獲得場景中光照狀態 */GLboolean lp;glGetBooleanv(GL_LIGHTING,&lp);/** 計算天空盒長 寬 高 */float width = MAP * box_width/8;float height = MAP * box_height/8;float length = MAP * box_length/8;/** 計算天空盒中心位置 */x = x+ MAP/8 - width / 2;y = y+ MAP/24 - height / 2;z = z+ MAP/8 - length / 2;glDisable(GL_LIGHTING); /**< 關閉光照 *//** 開始繪制 */glPushMatrix();glTranslatef(-x,-y,-z);/** 繪制背面 */glBindTexture(GL_TEXTURE_2D, m_texture[0].ID);glBegin(GL_QUADS); /** 指定紋理坐標和頂點坐標 */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); /** 指定紋理坐標和頂點坐標 */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); /** 指定紋理坐標和頂點坐標 */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); /** 指定紋理坐標和頂點坐標 */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); /** 指定紋理坐標和頂點坐標 */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); /** 指定紋理坐標和頂點坐標 */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(); /** 繪制結束 */if(lp) /** 恢復光照狀態 */ glEnable(GL_LIGHTING);}注:
/* 定義地面網格 /
const unsigned int MAP_WIDTH = 1024;
const unsigned int CELL_WIDTH = 16;
const unsigned int MAP = MAP_WIDTH * CELL_WIDTH / 2;
總結
以上是生活随笔為你收集整理的OpenGL--天空盒的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: node2vec算法
- 下一篇: 用计算机画图软件画画教程,电脑画图软件有