天空盒
天空盒
就是圍繞攝像機的360°的風景照。實質其實就是圍繞著攝像機的立方體,而攝像機就在這個立方體的里面。可以用來模擬無限的天空,山脈等現象。
為什么要使用天空盒
在3D游戲中,一般來說要渲染的東西會比較多,而使用天空盒會節約部分渲染的時間;而且如果不采用“天空盒”技術,或者其他技術,而直接進行渲染天空,地面以及周圍場景,那么可能會因為距離把握不當,造成“露餡”。
除了在游戲中使用“天空盒”技術較多,在一些二次元動畫中也會經常使用到,如MMD(miku miku dance)。
? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? ???
天空盒的結構
就如同一個立方體一樣
? ? ? ? ? ? ? ? ? ? ? ? ?
顯然可知,該立方體共有8個頂點,6個面,因此最多需要6張紋理圖,這6張紋理圖分別覆蓋該立方體的不同面。
//SkyBox's FVFstruct SKYBOXVERTEX{float x, y, z;float u, v;}; #define D3DFVF_SKYBOX D3DFVF_XYZ|D3DFVF_TEX1 class CSkyModel{public:CSkyModel(LPDIRECT3DDEVICE9 pDevice);virtual ~CSkyModel();//Data types & constantsenum ModelType{k_box,k_hemisphere,k_sphere,k_dome};bool Init_SkyBox(float Length); //Initialize the sky boxbool Load_SkyTextureFromFile(wchar_t *pFrontTextureFile, wchar_t *pBackTextureFile, wchar_t *pLeftTextureFile, \wchar_t *pRightTextureFile, wchar_t *pTopTextureFile, wchar_t *pBottomTextureFile);void Render_SkyBox(D3DXMATRIX *pMatWorld, bool bRenderFrame); //the first parameter is the sky box's world matrix,//the second parameter is doing or not doing render the line (ê?·???è?3????ò)bool Init_Floor(float length);void Render_Floor(bool bRenderFrame);private:ModelType m_type;LPD3DXMESH m_pMesh;D3DXHANDLE m_hUVSettings;LPDIRECT3DDEVICE9 m_pd3dDevice; //D3D Device objectLPDIRECT3DVERTEXBUFFER9 m_pVertexBuffer; //the vertex buffer objectLPDIRECT3DVERTEXBUFFER9 m_pFloorVerBuffer; //the floor's vertex bufferLPDIRECT3DTEXTURE9 m_pTexture[6];float m_Length; //the length of skybox};首先是定義天空盒的頂點格式,x,y,z分別代表坐標位置,u,v代表紋理坐標。
然后再定義其靈活頂點格式。
在類中,我聲明了關于立方體長度的變量,以及存儲6個紋理的數組;也聲明了關于天空盒的類型,是天空盒還是天空球,或還是其他類型。在Demo中只實現了天空盒一種,且用旋轉的方式進行模擬天空移動。
該類的定義:
// //Name: CSkyModel Class // CSkyModel::CSkyModel(LPDIRECT3DDEVICE9 pDevice) {m_pd3dDevice = pDevice;m_pVertexBuffer = NULL;for (size_t i = 0; i != 6; i++){m_pTexture[i] = NULL;}m_Length = 0.0f; }CSkyModel::~CSkyModel() {SAFE_RELEASE(m_pd3dDevice);SAFE_RELEASE(m_pVertexBuffer);SAFE_RELEASE(m_pFloorVerBuffer);for (size_t i = 0; i != 6; ++i){SAFE_RELEASE(m_pTexture[i]);} }bool CSkyModel::Init_SkyBox(float Length) {m_Length = Length;//1.創建。創建頂點緩存m_pd3dDevice->CreateVertexBuffer(24 * sizeof(SKYBOXVERTEX), 0,D3DFVF_SKYBOX, D3DPOOL_MANAGED, &m_pVertexBuffer, 0);//用一個結構體把頂點數據先準備好SKYBOXVERTEX vertices[] ={//前面的四個頂點{ -m_Length / 2, 0.0f, m_Length / 2, 0.0f, 1.0f, },{ -m_Length / 2, m_Length / 2, m_Length / 2, 0.0f, 0.0f, },{ m_Length / 2, 0.0f, m_Length / 2, 1.0f, 1.0f, },{ m_Length / 2, m_Length / 2, m_Length / 2, 1.0f, 0.0f, },//背面的四個頂點{ m_Length / 2, 0.0f, -m_Length / 2, 0.0f, 1.0f, },{ m_Length / 2, m_Length / 2, -m_Length / 2, 0.0f, 0.0f, },{ -m_Length / 2, 0.0f, -m_Length / 2, 1.0f, 1.0f, },{ -m_Length / 2, m_Length / 2, -m_Length / 2, 1.0f, 0.0f, },//左面的四個頂點{ -m_Length / 2, 0.0f, -m_Length / 2, 0.0f, 1.0f, },{ -m_Length / 2, m_Length / 2, -m_Length / 2, 0.0f, 0.0f, },{ -m_Length / 2, 0.0f, m_Length / 2, 1.0f, 1.0f, },{ -m_Length / 2, m_Length / 2, m_Length / 2, 1.0f, 0.0f, },//右面的四個頂點{ m_Length / 2, 0.0f, m_Length / 2, 0.0f, 1.0f, },{ m_Length / 2, m_Length / 2, m_Length / 2, 0.0f, 0.0f, },{ m_Length / 2, 0.0f, -m_Length / 2, 1.0f, 1.0f, },{ m_Length / 2, m_Length / 2, -m_Length / 2, 1.0f, 0.0f, },//上面的四個頂點{ m_Length / 2, m_Length / 2, -m_Length / 2, 1.0f, 0.0f, },{ m_Length / 2, m_Length / 2, m_Length / 2, 1.0f, 1.0f, },{ -m_Length / 2, m_Length / 2, -m_Length / 2, 0.0f, 0.0f, },{ -m_Length / 2, m_Length / 2, m_Length / 2, 0.0f, 1.0f, },//bottom{-m_Length / 2,0,m_Length / 2,0,0},{-m_Length / 2,0,-m_Length / 2,0,1},{m_Length / 2,0,m_Length / 2,1,0},{m_Length / 2,0,-m_Length / 2,1,1},};//準備填充頂點數據void *pVertices;//Lockm_pVertexBuffer->Lock(0, 0, (void**)&pVertices, 0);//access 把結構體中的數據直接拷到頂點緩沖區中memcpy(pVertices, vertices, sizeof(vertices));//UnLockm_pVertexBuffer->Unlock();//Floorfloat _length = 5000.0f;this->Init_Floor(_length);return true; }bool CSkyModel::Init_Floor(float tLength) {//1.創建。創建頂點緩存m_pd3dDevice->CreateVertexBuffer(4 * sizeof(SKYBOXVERTEX), 0,D3DFVF_SKYBOX, D3DPOOL_MANAGED, &m_pFloorVerBuffer, 0);//用一個結構體把頂點數據先準備好SKYBOXVERTEX vertices[] ={//底部{ -tLength,0.0f,-tLength,0.0f,30.0f },{ -tLength,0.0f,tLength,0.0f,0.0f },{ tLength,0.0f,-tLength,30.0f,30.0f },{ tLength,0.0f,tLength,30.0f,0.0f },};//準備填充頂點數據void *pVertices;//Lockm_pFloorVerBuffer->Lock(0, 0, (void**)&pVertices, 0);//access 把結構體中的數據直接拷到頂點緩沖區中memcpy(pVertices, vertices, sizeof(vertices));//UnLockm_pVertexBuffer->Unlock();return true; }bool CSkyModel::Load_SkyTextureFromFile(wchar_t *pFrontTextureFile, wchar_t *pBackTextureFile, wchar_t *pLeftTextureFile, \wchar_t *pRightTextureFile, wchar_t *pTopTextureFile, wchar_t *pBottomTextureFile) {//從文件加載五張紋理D3DXCreateTextureFromFileW(m_pd3dDevice, pFrontTextureFile, &m_pTexture[0]); //前面D3DXCreateTextureFromFileW(m_pd3dDevice, pBackTextureFile, &m_pTexture[1]); //后面D3DXCreateTextureFromFileW(m_pd3dDevice, pLeftTextureFile, &m_pTexture[2]); //左面D3DXCreateTextureFromFileW(m_pd3dDevice, pRightTextureFile, &m_pTexture[3]); //右面D3DXCreateTextureFromFileW(m_pd3dDevice, pTopTextureFile, &m_pTexture[4]); //上面D3DXCreateTextureFromFileW(m_pd3dDevice, pBottomTextureFile, &m_pTexture[5]); //底部return TRUE; }//-------------------------------------------------------------------------------------- // Name: SkyBoxClass::RenderSkyBox() // Desc: 繪制出天空盒,可以通過第二個參數選擇是否繪制出線框 //-------------------------------------------------------------------------------------- void CSkyModel::Render_SkyBox(D3DXMATRIX *pMatWorld, bool bRenderFrame) {m_pd3dDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1); //將紋理顏色混合的第一個參數的顏色值用于輸出m_pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); //紋理顏色混合的第一個參數的值就取紋理顏色值m_pd3dDevice->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_MIRROR);m_pd3dDevice->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_MIRROR);m_pd3dDevice->SetTransform(D3DTS_WORLD, pMatWorld); //設置世界矩陣m_pd3dDevice->SetStreamSource(0, m_pVertexBuffer, 0, sizeof(SKYBOXVERTEX)); //把包含的幾何體信息的頂點緩存和渲染流水線相關聯 m_pd3dDevice->SetFVF(D3DFVF_SKYBOX); //設置FVF靈活頂點格式//一個for循環,將6個面繪制出來for (int i = 0; i != 6; i++){m_pd3dDevice->SetTexture(0, m_pTexture[i]);m_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, i * 4, 2);}//對是否渲染線框的處理代碼if (bRenderFrame) //如果要渲染出線框的話{m_pd3dDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME); //把填充模式設為線框填充//一個for循環,將5個面的線框繪制出來for (int i = 0; i != 6; i++){m_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, i * 4, 2); //繪制頂點 }m_pd3dDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID); //把填充模式調回實體填充} }void CSkyModel::Render_Floor(bool bRenderFrame) {m_pd3dDevice->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP);m_pd3dDevice->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP);m_pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);m_pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);m_pd3dDevice->SetRenderState(D3DRS_LIGHTING, FALSE);m_pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);D3DXMATRIX matWorld;D3DXMatrixTranslation(&matWorld, 0.0f, 0.0f, 0.0f);m_pd3dDevice->SetTransform(D3DTS_WORLD, &matWorld);m_pd3dDevice->SetStreamSource(0, m_pFloorVerBuffer, 0, sizeof(SKYBOXVERTEX));m_pd3dDevice->SetFVF(D3DFVF_SKYBOX);m_pd3dDevice->SetTexture(0, m_pTexture[5]);m_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);//對是否渲染線框的處理代碼if (bRenderFrame) //如果要渲染出線框的話{m_pd3dDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME); //把填充模式設為線框填充m_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); //繪制頂點 m_pd3dDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID); //把填充模式調回實體填充} }最后演示結果
? ? ? ? ? ? ? ? ? ??
源代碼
CSDN內進行下載? 當前CSDN已改版,無法進行調整積分值,所以不是很推薦。
天空盒實現還有其他辦法,不用手動進行設置立方體的大小,可以通過導入一個立方體的模型,如.X文件,然后通過HLSL進行頂點著色器的編寫,也可以實現。
如果想多了解關于3D場景以及地形渲染可以參考
Real Time 3D Terrain Engines Using C++ And Dx9
總結
- 上一篇: javaweb框架
- 下一篇: php openssl 处理pkcs8,