• 其他语言



在主流图形硬件上实现阴影贴图
页面和feed选项
打印
收藏此页
Digg此页 | 添加到您的del.icio.us帐号
目录

实现过程
阴影贴图以纹理的形式存储,因此,为可能要用作渲染目标的阴影贴图创建一个纹理。英特尔® 图形显示技术允许将多个不同的纹理格式作为渲染目标。该技术目前不支持浮点纹理,因此最合适的选择是 32 位纹理:

D3DXCreateTexture(pd3dDevice, SHADOWMAP_SIZE, SHADOWMAP_SIZE, 1,
			D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, 
D3DPOOL_DEFAULT, &g_pShadowMap);

IDirect3DSurface9* pShadowSurface;
IDirect3DSurface9* pOriginalBackBuffer;

g_pShadowMap->GetSurfaceLevel(0, &pShadowSurface);
pd3dDevice->GetRenderTarget(0, &pOriginalBackBuffer);
pd3dDevice->SetRenderTarget(0, pShadowSurface);
SAFE_RELEASE(pShadowSurface);

//渲染场景,然后存储设置

pd3dDevice->SetRenderTarget(0, &pOriginalBackBUffer);
      
着色器生成阴影贴图的过程极其简单。对于顶点着色器,将顶点位置转换成光线的视图空间。将新位置传递到像素着色器作为纹理坐标,以便针对每个像素对该位置进行插值计算。像素着色器仅需输出每个像素的预计深度值作为颜色。

void VertexGenerateShadowMap(float4 iPosition :POSITION, 
				 out float2 oDepth :TEXCOORD0, 
				 out float4 oPosition :POSITION)
{
oPosition = mul(iPosition, g_mWorldViewProjection);
oDepth.xy = oPosition.zw;
}

void PixelGenerateShadowMap(float2 Depth :TEXCOORD0, 
out float4 oColor :COLOR)
{
	oColor = Depth.x / Depth.y;
}
      


图 3:对阴影贴图的渲染。深度值的范围为 0.0 到 1.0,其中 0.0 表示离光线最近。此处,离光线越近的点颜色越深。

要使用阴影贴图进行光照计算,需要顶点着色器将顶点位置转换成光线的投影空间。然后,程序将该值传递到像素着色器作为纹理坐标。

void VertexShadowMap(float4 iPosition :POSITION,
			 float3 iNormal :NORMAL,
			 out float4 oPosition :POSITION,
			 out float4 oViewSpacePosition :TEXCOORD0,
			 out float3 oNormal :TEXCOORD1,
			 out float4 oLightSpacePosition :TEXCOORD2)
{
oViewSpacePosition = mul(iPosition, g_mWorldView);
oPosition = mul(iPosition, g_mWorldViewProjection);
	oNormal = mul( iNormal, (float3x3)g_mWorldView);
oLightSpacePosition = mul(oViewSpacePosition, 
				g_mViewToLightProjectionSpace);
}

计算每个像素的光照。在每个像素上,使用该位置在光线的投影空间中的 x 值和 y 值作为纹理坐标对阴影贴图值采样。x 值和 y 值的范围为 -1.0 到 1.0,因此需要将它们缩小为 0.0 到 1.0 进行纹理采样。对于要照亮的像素,该位置的值必须小于阴影贴图中存储的值。为了考虑位置多次转换造成的浮点错误,应包含一个额外的偏移量。

void PixelShadowMap(float4 vViewSpacePosition :TEXCOORD0,
float3 vNormal :TEXCOORD1,
float4 vLightSpacePosition :TEXCOORD2,
out float4 oColor :COLOR)
{
	// 确定阴影贴图中存储的深度值
	float2 ShadowMapCoord = 0.5 * vLightSpacePosition.xy /
				vLightSpacePosition.w 
+ float2(0.5, 0.5);
ShadowMapCoord.y = 1.0f - ShadowMapCoord.y;
	float fShadowMapDistance = tex2D(ShadowMapSampler, 
						 ShadowMapCoord);
 
	float fDistanceToLight = vLightSpacePosition.z 
					/ vLightSpacePosition.w;

	// 将到光线的距离与阴影贴图值比较
	// 偏移因子降低了浮点错误的影响
	float fShadow = fDistanceToLight - fShadowMapDistance 
> g_fShadowMapBias
				? 0.0f :1.0f;

	float3 vLight = (float3)normalize(vViewSpacePosition – 
						 g_vPositionOfLight);
float4 vDiffuse = fShadow * g_vLightDiffuse
				* dot(-vLight, normalize(vNormal));
	oColor = saturate((vDiffuse + g_vLightAmbient) 
* g_vMaterialColor);
}



图 4:使用阴影渲染的场景。

上一部分1  2  3  4  5  下一部分

第 3 页, 共 9 页