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