如果我们能时时刻刻都在学习,从观察、聆听、注视和行动中学习,那么你会发现,学习是不断进展,永无过去 | 学习技术不是发财之道 | 学习技术,因为崇尚科学与真理
就我所知常用的环境贴图有两种,一种是球状的环境贴图;一种是立方体的环境贴图。如果是制作水体的反射或折射效果也可以只做平面的环境贴图。 DirectX中提供了一个很方便的立方体环境贴图。立方体的六个面定义如下:
D3DCUBEMAP_FACE_FORCE_DWORD = 0x7fffffff} D3DCUBEMAP_FACES;
如下图所示: 实现原理也很简单: 1、把立方体环境贴图放到反射物体所知位置,并把该反射物体以外的东西映射到立方体环境贴图上。 2、根据摄像机到反射物体表面的点的向量a和该点的法向量n,求出a的反射向量b。 3、以反射向量b作为立方体环境贴图的寻址,把它所对应的颜色赋给反射物体上的点。 实现过程需要用到一个立方体环境贴图和一个深度表面,步骤如下:
//创建 DepthStencilSurface DXUTDeviceSettings d3dSettings = DXUTGetDeviceSettings(); hr = pDev->CreateDepthStencilSurface( ENVMAPSIZE, ENVMAPSIZE, d3dSettings.pp.AutoDepthStencilFormat, D3DMULTISAMPLE_NONE, 0, TRUE, & m_pSurfDepthCube, NULL ); if( FAILED( hr)) return hr;
//创建立方体贴图 hr = pDev->CreateCubeTexture( ENVMAPSIZE, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A16B16G16R16F, D3DPOOL_DEFAULT, & m_pReflectCubeTex, NULL ); if( FAILED( hr) ) return hr;3、把被反射物体渲染到立方体环境贴图中//------------------------------------------------------------//desc: 渲染反射场景//param: pDev 设备//return: 是否创建成功//------------------------------------------------------------HRESULT GRenderMaterialProxy::RenderReflectScene(LPDIRECT3DDEVICE9 pDev){ HRESULT hr;
if( pDev == NULL) return E_FAIL;
LPDIRECT3DSURFACE9 pSufRTBackup; //RenderTarget 备份 LPDIRECT3DSURFACE9 pSufDSBackup; //DepthStencilSurface 备份
pDev->GetRenderTarget( 0, & pSufRTBackup);
if( SUCCEEDED( pDev->GetDepthStencilSurface( & pSufDSBackup) ) ) { pDev->SetDepthStencilSurface( m_pSurfDepthCube); }
//以反射物体为中心,设置视口投影矩阵 LPDIRECT3DSURFACE9 pSurf; D3DXMATRIXA16 mView, mProj; D3DXMATRIXA16 mViewDir( * GCameraManager::GetInstance()->GetCamera()->GetViewMatrix() ); mViewDir._41 = mViewDir._42 = mViewDir._43 = 0.0f;
D3DXMatrixPerspectiveFovLH( &mProj, D3DX_PI * 0.5f, 1.0f, 0.01f, 10000.0f );
std::vector< IRenderObject *>::iterator itRenderObj;
//渲染Cube 6个表面 for( int iFace = 0; iFace < 6; ++iFace) { //获取立方体环境贴图表面,并设为设备的渲染目标 //注意:GetCubeMapSurface的第二个参数0表示获取立方体环境贴图的表面 //如果是 n则表示获取立方体环境贴图的第n层表面 V( m_pReflectCubeTex->GetCubeMapSurface( ( D3DCUBEMAP_FACES) iFace, 0, & pSurf)); V( pDev->SetRenderTarget( 0, pSurf));
mView = DXUTGetCubeMapViewMatrix( iFace); D3DXMatrixMultiply( & mView, & mViewDir, & mView);
V( pDev->Clear( 0L, NULL, D3DCLEAR_ZBUFFER, 0x000000ff, 1.0f, 0L )); //渲染被反射物体 for( itRenderObj = m_vpReflectObjects.begin(); itRenderObj != m_vpReflectObjects.end(); itRenderObj++) (*itRenderObj)->Render( pDev, & mView, & mProj);
SAFE_RELEASE( pSurf);
}
if( pSufDSBackup) { pDev->SetDepthStencilSurface( pSufDSBackup); //恢复深度表面 SAFE_RELEASE( pSufDSBackup); }
pDev->SetRenderTarget( 0, pSufRTBackup); //恢复渲染目标 SAFE_RELEASE( pSufRTBackup);
return S_OK;} 4、根据立方体环境贴图确定反射物体的颜色(用HLSL实现) //渲染环境贴图 if( m_bEnableReflect) RenderReflectScene( pDev);
D3DXMATRIXA16 mWorld, mView, mProj, mWorldView; CBaseCamera * pCamera = GCameraManager::GetInstance()->GetCamera(); D3DXVECTOR4 vEyePos = D3DXVECTOR4(* GCameraManager::GetInstance()->GetCamera()->GetEyePt(), 0.0f); D3DXMATRIXA16 mEyePos; ::D3DXMatrixTranslation( & mEyePos, vEyePos.x, vEyePos.y, vEyePos.z); ::D3DXMatrixTranslation( & mWorld, 0.0f, 0.0f, 0.0f);
mView = * pCamera->GetViewMatrix(); mProj = * pCamera->GetProjMatrix();
GVector4 * pLightDirList = G3DSceneManager::GetInstance()->GetLightDirList(); UINT iLightCount = G3DSceneManager::GetInstance()->GetLightCount();
//设置变化矩阵 m_pEffect->SetMatrix("g_mWorld", &mWorld); m_pEffect->SetMatrix("g_mProj", &mProj); m_pEffect->SetMatrix("g_mView", &mView);
m_pEffect->SetTexture("g_texReflect", m_pReflectCubeTex); //设置立方体环境贴图 m_pEffect->SetFloat("g_fReflectivity", m_fReflectivity); //设置反射率( fx文件代码如下)
extern matrix g_mWorld;extern matrix g_mView;extern matrix g_mProj;
texture g_texReflect;float g_fReflectivity = 0.9f;
samplerCUBE g_samReflect =sampler_state{ Texture = <g_texReflect>; MinFilter = Linear; MagFilter = Linear; MipFilter = Linear;};
void VS_Reflect( float4 iPos : POSITION, float3 iNor : NORMAL, out float4 oPos : POSITION, out float3 oEnvTex : TEXCOORD0 ){ matrix mWorldView = mul( g_mWorld, g_mView); oPos = mul( iPos, mWorldView); float3 vN = mul( iNor, mWorldView); vN = normalize( vN); float3 vEyeR = -normalize( oPos); float3 vRef; vRef = 2 * dot( vEyeR, vN) * vN - vEyeR; //vRef = reflect( vEyeR, vN); oEnvTex = vRef; oPos = mul( oPos, g_mProj);}
float4 PS_Reflect( float3 iTex : TEXCOORD0 ) : COLOR{ float4 fColor = texCUBE( g_samReflect, iTex); fColor.x = fColor.x * g_fReflectivity; fColor.y = fColor.y * g_fReflectivity; fColor.z = fColor.z * g_fReflectivity; return fColor; }
technique Tec_RenderMaterial{ pass p0 { vertexShader = compile vs_2_0 VS_Reflect(); pixelShader = compile ps_2_0 PS_Reflect(); }}
实现效果如下: