環境映射(EnvironmentMapping)

環境映射是一種用來模擬光滑表面對周圍環境的反射的技術,常見的如鏡子、光亮漆面的金屬等等。

這種技術的實現主要通過將一張帶有周圍環境的貼圖附在所需要表現的多邊形表面來實現的。目前在實時3D遊戲畫面渲染中經常使用的有兩種環境映射。

球形環境映射是模擬在球體表面產生環境映射的技術,通過對普通貼圖的UV坐標進行調整計算來產生在球體表面應產生的扭曲。

UV的計算利用球體表面的法線來計算。

基本介紹

  • 中文名:環境映射
  • 外文名:EnvironmentMapping
  • 屬於:模擬反射的技術
  • 分類:一項技術
  • 計算公式:  u=Nx/2+0.5v=Ny/2+0.5
簡介,立方映射,

簡介

計算公式中的Nx和Ny是表面法線的x和y分量,除以2將區間限制在[-0.5,0.5],+0.5將區間調整至UV坐標應在的[0,1]區間。在這個公式的計算下,當球體正中表面法線正對攝像機的地方,坐標不會有任何扭曲;周圍點依次隨著Nx和Ny分量的增大而產生扭曲。
球體背面的剔除面可以根據法線Z分量的正負來判斷。

立方映射

立方環境映射(Cubic Environment Mapping)
立方環境映射是現在常用環境映射技術。我們知道遊戲場景中經常通過在一個正方體上的六個面貼上前後左右上下六個貼圖來模擬天空、宇宙等環境,稱為Cubemap有的引擎中成為Skybox,立方環境映射的原理就是在遊戲中所需要產生映射的物體的位置動態生成一套Cubemap,再對Cubemap進行採樣生成物體表面應該反射出的周遭環境。
具體的採樣方法是利用物體表面的法線來計算的,我們假設動態生成的Cubemap的正方體剛剛好包圍住需要產生環境映射效果的物體,我們從攝像機也就是觀察點出發同物體表面產生出的反射向量(同Phong光照模型的鏡面反射中的反射向量是相同的,計算方法也相同R=2(E*N)*N-E),這個反射向量同正方體相交於一點,得到了這個點的所在面及UV坐標,採樣,得到的顏色值就是我們應當看到。
立方環境映射的原理就是這樣的,但是這些計算步驟並不需要我們在使用的時候過多考慮,因為從Cubemap的生成,到採樣的計算,圖形API已經都為我們封裝好了,下面記錄了在DirectX中簡單的API調用流程,權作筆記。
首先需要聲明Cubemap的貼圖
環境映射(EnvironmentMapping)
LPDIRECT3DCUBETEXTURE9 m_pCubeMap = NULL;
然後創建Cubemap貼圖
pd3dDevice->CreateCubeTexture(256,1,D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8,D3DPOOL_DEFAULT , &m_pCubeMap,NULL );
注意這裡用到了D3DUSAGE_RENDERTARGET,也就是說我們的Cubemap需要靠RenderTarget繪製。
如果需要的話,深度緩衝也可以考慮在內。
IDirect3DSurface9* g_pDepthCube = NULL;
DXUTDeviceSettings d3dSettings = DXUTGetDeviceSettings();
pd3dDevice->CreateDepthStencilSurface( 256, 256, d3dSettings.pp.AutoDepthStencilFormat,D3DMULTISAMPLE_NONE,0,TRUE,&g_pDepthCube, NULL );
繪製函式
void RenderSceneIntoCubeMap( IDirect3DDevice9 *pd3dDevice, double fTime )
{
HRESULT hr;
// Cubemap使用的投影矩陣
D3DXMATRIXA16 mProj;
D3DXMatrixPerspectiveFovLH( &mProj, D3DX_PI * 0.5f, 1.0f, 0.01f, 100.0f );
LPDIRECT3DSURFACE9 pRTOld = NULL;
V( pd3dDevice->GetRenderTarget( 0, &pRTOld ) );
LPDIRECT3DSURFACE9 pDSOld = NULL;
//if( SUCCEEDED( pd3dDevice->GetDepthStencilSurface( &pDSOld ) ) )
//{
// // 如果使用深度緩衝
// V( pd3dDevice->SetDepthStencilSurface( g_pDepthCube ) );
//}
for( int nFace = 0; nFace < 6; ++nFace ) //依次完成Cubemap中的六個面的繪製
{
LPDIRECT3DSURFACE9 pSurf;
V( m_pCubeMap->GetCubeMapSurface( (D3DCUBEMAP_FACES)nFace, 0, &pSurf ) );
V( pd3dDevice->SetRenderTarget( 0, pSurf ) );
SAFE_RELEASE( pSurf );
D3DXMATRIXA16 mView = DXUTGetCubeMapViewMatrix( nFace );
V( pd3dDevice->Clear( 0L, NULL, D3DCLEAR_ZBUFFER,0x000000ff, 1.0f, 0L ) );
pd3dDevice->SetTransform(D3DTS_VIEW,&mView);
pd3dDevice->SetTransform(D3DTS_PROJECTION,&mProj);
if( SUCCEEDED( pd3dDevice->BeginScene() ) )
{
//在這裡繪製環境
pd3dDevice->EndScene();
}
}
// Restore depth-stencil buffer and render target
/*if( pDSOld )//如果使用深度緩衝
{
V( pd3dDevice->SetDepthStencilSurface( pDSOld ) );
SAFE_RELEASE( pDSOld );
}*/
V( pd3dDevice->SetRenderTarget( 0, pRTOld ) );
SAFE_RELEASE( pRTOld );
}
這個繪製函式
一般在每一幀繪製場景的最開始執行,先將場景內的物體繪製在Cubemap上。
這樣我們就有了可用的Cubemap,之後我們繪製需要採用環境映射的物體時,將這個Cubemap作為Texture傳入Shader內,另外還需傳入觀察向量用於計算反射向量。
在Shader中,頂點著色器中完成反射向量的計算:
float3 vecReflect = normalize(reflect(vecEye, InNormal));
像素著色器負責採樣,HLSL中已經有現成的函式可以使用,我們只需將計算所得反射向量傳入即可。
Output.RGBColor = texCUBE(EnvironmentSampler, In.CubeTexcoord);
採樣器EnvironmentSampler並不需要特別的設定。
texture EnvironmentMap;
samplerCUBE EnvironmentSampler = sampler_state
{
Texture = (EnvironmentMap);
MipFilter = LINEAR;
MinFilter = LINEAR;
MagFilter = LINEAR;
};

相關詞條

熱門詞條

聯絡我們