///// Dual Paraboloid Shadow Mapping ///// ///// Copyright (c) by Christoph P. - gamedevelop.eu ///// ///// All rights reserved ///// ///// allowed for non-commercial use ///// #define SHADOW_EPSILON 0.0005f texture g_DPFrontMap; texture g_DPBackMap; texture g_Terrain; float4x4 g_mDPWorldView; float4x4 g_mDPView; float4x4 g_mWorld; float4x4 g_mViewProj; float g_fFar; float g_fNear; float3 g_vLightPos; // worldspace float g_fDir; // direction of hemisphere float4 g_Material = float4(1.0f, 1.0f, 1.0f, 1.0f); float4 g_LightAmbientColor = float4(0.2f, 0.2f, 0.2f, 1.0f); float4 g_LightDiffuseColor = float4(1.0f, 1.0f, 1.0f, 1.0f); // DPDepth sampler2D DPFrontSampler = sampler_state { Texture = ; MinFilter = Linear; MagFilter = Linear; MipFilter = Linear; AddressU = Border; AddressV = Border; BorderColor = float4(0.0f, 0.0f, 0.0f, 1.0f); }; sampler2D DPBackSampler = sampler_state { Texture = ; MinFilter = Linear; MagFilter = Linear; MipFilter = Linear; AddressU = Border; AddressV = Border; BorderColor = float4(0.0f, 0.0f, 0.0f, 1.0f); }; // DPSM sampler2D TerrainSampler = sampler_state { Texture = ; MinFilter = Linear; MagFilter = Linear; MipFilter = Linear; AddressU = Wrap; AddressV = Wrap; }; // DPDepth struct VSDPDepthIn { float3 Pos : POSITION; }; struct PSDPDepthIn { float4 Pos : POSITION; float ClipDepth : TEXCOORD1; float Depth : TEXCOORD2; }; // DPSM struct VSDPSMIn { float3 Pos : POSITION; float2 TexCoord : TEXCOORD0; float3 Normal : NORMAL; }; struct PSDPSMIn { float4 Pos : POSITION; float3 PosWorld : TEXCOORD0; float2 TexCoord : TEXCOORD1; float3 Normal : TEXCOORD2; float3 Light : TEXCOORD3; }; // DPDepth-vertex-shader PSDPDepthIn DPDepthVS(VSDPDepthIn In) { PSDPDepthIn Out; // transform vertex to DP-space Out.Pos = mul(float4(In.Pos, 1.0f), g_mDPWorldView); Out.Pos /= Out.Pos.w; // for the back-map z has to be inverted Out.Pos.z *= g_fDir; // because the origin is at 0 the proj-vector // matches the vertex-position float fLength = length(Out.Pos.xyz); // normalize Out.Pos /= fLength; // save for clipping Out.ClipDepth = Out.Pos.z; // calc "normal" on intersection, by adding the // reflection-vector(0,0,1) and divide through // his z to get the texture coords Out.Pos.x /= Out.Pos.z + 1.0f; Out.Pos.y /= Out.Pos.z + 1.0f; // set z for z-buffering and neutralize w Out.Pos.z = (fLength - g_fNear) / (g_fFar - g_fNear); Out.Pos.w = 1.0f; // DP-depth Out.Depth = Out.Pos.z; return Out; } // DPDepth-pixel-shader float4 DPDepthPS(PSDPDepthIn In) : COLOR { // clipping clip(In.ClipDepth); return In.Depth; } // DPSM-vertex-shader PSDPSMIn DPSMVS(VSDPSMIn In) { PSDPSMIn Out; // world space float3 vPosWorld = mul(float4(In.Pos, 1.0f), g_mWorld); Out.Normal = normalize(mul(In.Normal, (float3x3)g_mWorld)); Out.Light = normalize(g_vLightPos - vPosWorld); Out.Pos = mul(float4(vPosWorld, 1.0f), g_mViewProj); Out.PosWorld = vPosWorld; Out.TexCoord = In.TexCoord; return Out; } // DPSM-pixel-shader float4 DPSMPS(PSDPSMIn In) : COLOR { float3 Color; // texcoord-calculation is the same calculation as in the Depth-VS, // but texcoords have to be in range [0, 1] // transform into lightspace float3 vPosDP = mul(float4(In.PosWorld, 1.0f), g_mDPView); float fLength = length(vPosDP); // normalize vPosDP /= fLength; // compute and read according depth float fDPDepth; float fSceneDepth; if(vPosDP.z >= 0.0f) { float2 vTexFront; vTexFront.x = (vPosDP.x / (1.0f + vPosDP.z)) * 0.5f + 0.5f; vTexFront.y = 1.0f - ((vPosDP.y / (1.0f + vPosDP.z)) * 0.5f + 0.5f); fSceneDepth = (fLength - g_fNear) / (g_fFar - g_fNear); fDPDepth = tex2D(DPFrontSampler, vTexFront).r; } else { // for the back the z has to be inverted float2 vTexBack; vTexBack.x = (vPosDP.x / (1.0f - vPosDP.z)) * 0.5f + 0.5f; vTexBack.y = 1.0f - ((vPosDP.y / (1.0f - vPosDP.z)) * 0.5f + 0.5f); fSceneDepth = (fLength - g_fNear) / (g_fFar - g_fNear); fDPDepth = tex2D(DPBackSampler, vTexBack).r; } // lighting and shadowing float3 vNormal = normalize(In.Normal); float3 vLight = normalize(In.Light); if((fDPDepth + SHADOW_EPSILON) < fSceneDepth) { Color = tex2D(TerrainSampler, In.TexCoord) * g_LightAmbientColor; } else { Color = tex2D(TerrainSampler, In.TexCoord) * saturate(dot(vLight, vNormal)) * g_LightDiffuseColor * g_Material + g_LightAmbientColor; } return float4(Color, 1.0f); } technique DPDepth { pass p0 { VertexShader = compile vs_2_0 DPDepthVS(); PixelShader = compile ps_2_0 DPDepthPS(); } } technique DPSM { pass p0 { VertexShader = compile vs_3_0 DPSMVS(); PixelShader = compile ps_3_0 DPSMPS(); } }