环境反射效果

Posted on 2009-02-11 19:39 Herbert 阅读(1385) 评论(0)  编辑 收藏 引用 所属分类: DirectX

  就我所知常用的环境贴图有两种,一种是球状的环境贴图;一种是立方体的环境贴图。如果是制作水体的反射或折射效果也可以只做平面的环境贴图。
  DirectX中提供了一个很方便的立方体环境贴图。立方体的六个面定义如下:

typedef enum _D3DCUBEMAP_FACES
{
    D3DCUBEMAP_FACE_POSITIVE_X     = 0,
    D3DCUBEMAP_FACE_NEGATIVE_X     = 1,
    D3DCUBEMAP_FACE_POSITIVE_Y     = 2,
    D3DCUBEMAP_FACE_NEGATIVE_Y     = 3,
    D3DCUBEMAP_FACE_POSITIVE_Z     = 4,
    D3DCUBEMAP_FACE_NEGATIVE_Z     = 5,

    D3DCUBEMAP_FACE_FORCE_DWORD    = 0x7fffffff
} D3DCUBEMAP_FACES;


如下图所示:


   实现原理也很简单:
   1、把立方体环境贴图放到反射物体所知位置,并把该反射物体以外的东西映射到立方体环境贴图上。
   2、根据摄像机到反射物体表面的点的向量a和该点的法向量n,求出a的反射向量b。
   3、以反射向量b作为立方体环境贴图的寻址,把它所对应的颜色赋给反射物体上的点。

   实现过程需要用到一个立方体环境贴图和一个深度表面,步骤如下:

   1、定义
    LPDIRECT3DCUBETEXTURE9 m_pReflectCubeTex;  //反射的立方贴图 
    LPDIRECT3DSURFACE9           m_pSurfDepthCube; // DepthStencilSurface

   2、初始化
    HRESULT hr;

 //创建 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(); 
 }
}


实现效果如下:


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理