对于SkyBox,首先得准备一张CubeMap,常规有三种方法:
方法1,画一个在远剪裁面上的矩形,然后根据NDC坐标反求World Space坐标,用这个坐标作为纹理坐标去采样CubeMap。
方法2,画一个Cube,直接把CubeMap纹理贴上去。
方法3, 画一个Sphere,直接把CubeMap纹理贴上去。
需要注意到是,三种方法都必需以通过将天空盒移动到相机位置而使相机总保持处在天空盒中心。方法2和方法3其实相同。
下面的源代码是方法3的实现。
1 ////////////////////////////// 2 skyBox.h 3 ////////////////////////////// 4 #pragma once 5 #include "d3dx9.h" 6 #include "DXUTcamera.h" 7 #define V_RETURN(x) { hr = (x); if( FAILED(hr) ) { return hr; } } 8 struct SkyBoxVertex 9 { 10 float x,y,z; 11 }; 12 13 class SkyBox 14 { 15 public: 16 SkyBox(LPDIRECT3DDEVICE9 pDevice); 17 ~SkyBox(void); 18 HRESULT InitSkyBox(); 19 HRESULT RenderSkybox(const CModelViewerCamera &camera); 20 private: 21 HRESULT InitCubeTexture(); 22 HRESULT InitEffect(); 23 LPDIRECT3DDEVICE9 myD3dDevice; 24 IDirect3DCubeTexture9 * myCubeTexture; 25 IDirect3DVertexDeclaration9 *myVertexDecl; 26 ID3DXEffect* myFX; 27 D3DXHANDLE myTech; 28 D3DXHANDLE myEnvMap; 29 D3DXHANDLE myWVP; 30 const CModelViewerCamera *myCamera; 31 ID3DXMesh* mySphere; 32 33 };
1 ////////////////////////////////////// 2 SkyBox.cpp 3 ///////////////////////////////////// 4 #include "DXUT.h" 5 #include "SDKmisc.h" 6 #include "SkyBox.h" 7 SkyBox::SkyBox(LPDIRECT3DDEVICE9 pDevice) 8 { 9 myD3dDevice = pDevice; 10 myCubeTexture = NULL; 11 12 } 13 SkyBox::~SkyBox(void) 14 { 15 myCubeTexture->Release(); 16 myFX->Release(); 17 mySphere->Release(); 18 } 19 HRESULT SkyBox::InitSkyBox() 20 { 21 HRESULT hr = S_OK; 22 D3DVERTEXELEMENT9 SkyBoxVertexDecl[] = 23 { 24 {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0}, 25 D3DDECL_END() 26 }; 27 V_RETURN(D3DXCreateSphere(myD3dDevice, 100, 30, 30, &mySphere, 0)); 28 V_RETURN( InitCubeTexture() ); 29 V_RETURN( InitEffect() ); 30 return hr; 31 } 32 HRESULT SkyBox::InitCubeTexture() 33 { 34 HRESULT hr = S_OK; 35 WCHAR cubeTextruePath[MAX_PATH]; 36 V_RETURN( DXUTFindDXSDKMediaFileCch( cubeTextruePath, MAX_PATH, L"grassenvmap1024.dds" ) ); 37 V_RETURN( D3DXCreateCubeTextureFromFile(myD3dDevice,cubeTextruePath, &myCubeTexture) ); 38 return hr; 39 } 40 HRESULT SkyBox::InitEffect() 41 { 42 HRESULT hr = S_OK; 43 V_RETURN(D3DXCreateEffectFromFile(myD3dDevice, L"sky.fx", 0, 0, 0, 44 0, &myFX, 0)); 45 myTech = myFX->GetTechniqueByName("SkyTech"); 46 myWVP = myFX->GetParameterByName(0, "gWVP"); 47 myEnvMap = myFX->GetParameterByName(0, "gEnvMap"); 48 // Set effect parameters that do not vary. 49 V_RETURN(myFX->SetTechnique(myTech)); 50 V_RETURN(myFX->SetTexture(myEnvMap, myCubeTexture)); 51 return hr; 52 } 53 HRESULT SkyBox::RenderSkybox(const CModelViewerCamera &camera) 54 { 55 HRESULT hr = S_OK; 56 //// Sky always centered about camera's position. 57 D3DXMATRIX mWorld; 58 D3DXMATRIX mView; 59 D3DXMATRIX mProj; 60 const D3DXVECTOR3 p = *camera.GetEyePt(); 61 D3DXMatrixTranslation(&mWorld, p.x, p.y, p.z); 62 mView = *camera.GetViewMatrix(); 63 mProj = *camera.GetProjMatrix(); 64 D3DXMATRIX mWVP = mWorld*mView*mProj; 65 V_RETURN(myFX->SetMatrix(myWVP, &mWVP)); 66 UINT numPasses = 0; 67 V_RETURN(myFX->Begin(&numPasses, 0)); 68 V_RETURN(myFX->BeginPass(0)); 69 V_RETURN(mySphere->DrawSubset(0)); 70 V_RETURN(myFX->EndPass()); 71 V_RETURN(myFX->End()); 72 }
1 //////////////////////////////// 2 Sky.fx 3 /////////////////////////////// 4 5 uniform extern float4x4 gWVP; 6 uniform extern texture gEnvMap; 7 sampler EnvMapS = sampler_state 8 { 9 Texture = <gEnvMap>; 10 MinFilter = LINEAR; 11 MagFilter = LINEAR; 12 MipFilter = LINEAR; 13 AddressU = Clamp; 14 AddressV = Clamp; 15 }; 16 void SkyVS(float3 posL : POSITION0, 17 out float4 oPosH : POSITION0, 18 out float3 oEnvTex : TEXCOORD0) 19 { 20 // Set z = w so that z/w = 1 (i.e., skydome always on far plane). 21 oPosH = mul(float4(posL, 1.0f), gWVP).xyww; 22 23 // Use skymesh vertex position, in local space, as index into cubemap. 24 oEnvTex = posL; 25 } 26 float4 SkyPS(float3 envTex : TEXCOORD0) : COLOR 27 { 28 return texCUBE(EnvMapS, envTex); 29 } 30 technique SkyTech 31 { 32 pass P0 33 { 34 vertexShader = compile vs_2_0 SkyVS(); 35 pixelShader = compile ps_2_0 SkyPS(); 36 CullMode = None; 37 ZFunc = Always; // Always write sky to depth buffer 38 StencilEnable = true; 39 StencilFunc = Always; 40 StencilPass = Replace; 41 StencilRef = 0; // clear to zero 42 } 43 }