[1637] | 1 | // Percentage closer soft shadows
|
---|
| 2 | // nVidia implementation
|
---|
| 3 |
|
---|
| 4 |
|
---|
| 5 | // SHADOWMAP generation
|
---|
| 6 |
|
---|
| 7 | //-----------------------------------------------------------------------------
|
---|
| 8 | // Vertex Shader: RenderShadowMap_06_VS
|
---|
| 9 | // Desc: Process vertex for the shadow map
|
---|
| 10 | //-----------------------------------------------------------------------------
|
---|
| 11 | void RenderShadowMap_06_VS(
|
---|
| 12 | float4 Pos : POSITION,
|
---|
| 13 | out float4 oPos : POSITION,
|
---|
| 14 | out float hPos : TEXCOORD0 )
|
---|
| 15 | {
|
---|
| 16 | oPos = mul( Pos, WorldLightProj ); // Compute the projected coordinates
|
---|
| 17 | hPos = oPos.w; // Store z in our spare texcoord
|
---|
| 18 | }
|
---|
| 19 |
|
---|
| 20 | //-----------------------------------------------------------------------------
|
---|
| 21 | // Pixel Shader: RenderShadowMap_06_PS
|
---|
| 22 | // Desc: Process pixel for the shadow map
|
---|
| 23 | //-----------------------------------------------------------------------------
|
---|
| 24 | float4 RenderShadowMap_06_PS(
|
---|
| 25 | float hPos : TEXCOORD0 ):COLOR
|
---|
| 26 | {
|
---|
| 27 | return float4(hPos,0,0,0);
|
---|
| 28 | }
|
---|
| 29 |
|
---|
| 30 |
|
---|
| 31 | // SCENE RENDERING
|
---|
| 32 |
|
---|
| 33 | //-----------------------------------------------------------------------------
|
---|
| 34 | // Vertex Shader: RenderSceneWithTechnique_06_VS
|
---|
| 35 | // Desc: Process vertex for scene
|
---|
| 36 | //-----------------------------------------------------------------------------
|
---|
| 37 | VS_OUTPUT RenderSceneWithTechnique_06_VS( VS_INPUT IN )
|
---|
| 38 | {
|
---|
| 39 | VS_OUTPUT OUT = (VS_OUTPUT)0;
|
---|
| 40 | OUT.Color = IN.Color;
|
---|
| 41 | OUT.Tex = IN.Tex;
|
---|
| 42 |
|
---|
| 43 | // transform model-space vertex position to light's normalized device space:
|
---|
| 44 | OUT.ldPosition = mul(IN.Position, WorldLightProj);
|
---|
| 45 |
|
---|
| 46 | // transform model-space vertex position to normalized screen space:
|
---|
| 47 | OUT.hPosition = mul(IN.Position, WorldViewProj);
|
---|
| 48 | return OUT;
|
---|
| 49 | }
|
---|
| 50 |
|
---|
| 51 |
|
---|
| 52 | //-----------------------------------------------------------------------------
|
---|
| 53 | // Pixel Shader: RenderSceneWithTechnique_06_PS
|
---|
| 54 | // Desc: PCF soft shadow
|
---|
| 55 | //-----------------------------------------------------------------------------
|
---|
| 56 | // -------------------------------------
|
---|
| 57 | // STEP 1: Search for potential blockers
|
---|
| 58 | // -------------------------------------
|
---|
| 59 | half findBlocker(
|
---|
| 60 | half2 uv,
|
---|
| 61 | half4 LP,
|
---|
| 62 | half searchWidth )
|
---|
| 63 | {
|
---|
| 64 | // divide filter width by number of samples to use
|
---|
| 65 | half stepSize = 2 * searchWidth / g_iKernelSize;
|
---|
| 66 |
|
---|
| 67 | // compute starting point uv coordinates for search
|
---|
| 68 | uv = uv - half2(searchWidth, searchWidth);
|
---|
| 69 |
|
---|
| 70 | // reset sum to zero
|
---|
| 71 | half blockerSum = 0;
|
---|
| 72 | half receiver = LP.z;
|
---|
| 73 | half blockerCount = 0;
|
---|
| 74 | half foundBlocker = 0;
|
---|
| 75 |
|
---|
| 76 | // iterate through search region and add up depth values
|
---|
| 77 | for (int i=0; i<g_iKernelSize; i++) {
|
---|
| 78 | for (int j=0; j<g_iKernelSize; j++) {
|
---|
| 79 | half shadMapDepth = tex2D(g_ShadowMapColorSampler, uv + half2(i*stepSize,j*stepSize)).x;
|
---|
| 80 | // found a blocker
|
---|
| 81 | if (shadMapDepth < receiver) {
|
---|
| 82 | blockerSum += shadMapDepth;
|
---|
| 83 | blockerCount++;
|
---|
| 84 | foundBlocker = 1;
|
---|
| 85 | }
|
---|
| 86 | }
|
---|
| 87 | }
|
---|
| 88 |
|
---|
| 89 | half result;
|
---|
| 90 |
|
---|
| 91 | if (foundBlocker == 0) {
|
---|
| 92 | // set it to a unique number so we can check
|
---|
| 93 | // later to see if there was no blocker
|
---|
| 94 | result = 999;
|
---|
| 95 | }
|
---|
| 96 | else {
|
---|
| 97 | // return average depth of the blockers
|
---|
| 98 | result = blockerSum / blockerCount;
|
---|
| 99 | }
|
---|
| 100 |
|
---|
| 101 | return result;
|
---|
| 102 | }
|
---|
| 103 |
|
---|
| 104 | // ------------------------------------------------
|
---|
| 105 | // STEP 2: Estimate penumbra based on
|
---|
| 106 | // blocker estimate, receiver depth, and light size
|
---|
| 107 | // ------------------------------------------------
|
---|
| 108 | half estimatePenumbra(
|
---|
| 109 | half receiver, // receiver depth
|
---|
| 110 | half blocker )
|
---|
| 111 | {
|
---|
| 112 | // estimate penumbra using parallel planes approximation
|
---|
| 113 | return (receiver - blocker) * g_fLightSize / blocker;
|
---|
| 114 | }
|
---|
| 115 |
|
---|
| 116 | // ----------------------------------------------------
|
---|
| 117 | // Step 3: Percentage-closer filter implementation with
|
---|
| 118 | // variable filter width and number of samples.
|
---|
| 119 | // This assumes a square filter with the same number of
|
---|
| 120 | // horizontal and vertical samples.
|
---|
| 121 | // ----------------------------------------------------
|
---|
| 122 |
|
---|
| 123 | half PCF_Filter(
|
---|
| 124 | half2 uv,
|
---|
| 125 | half4 LP,
|
---|
| 126 | half filterWidth )
|
---|
| 127 | {
|
---|
| 128 | // compute step size for iterating through the kernel
|
---|
| 129 | half stepSize = 2 * filterWidth / g_iKernelSize;
|
---|
| 130 |
|
---|
| 131 | // compute uv coordinates for upper-left corner of the kernel
|
---|
| 132 | uv = uv - half2(filterWidth,filterWidth);
|
---|
| 133 |
|
---|
| 134 | half sum = 0; // sum of successful depth tests
|
---|
| 135 |
|
---|
| 136 | // now iterate through the kernel and filter
|
---|
| 137 | for (int i=0; i<g_iKernelSize; i++) {
|
---|
| 138 | for (int j=0; j<g_iKernelSize; j++) {
|
---|
| 139 | // get depth at current texel of the shadow map
|
---|
| 140 | half shadMapDepth = 0;
|
---|
| 141 |
|
---|
| 142 | shadMapDepth = tex2D(g_ShadowMapColorSampler, uv + half2(i*stepSize,j*stepSize)).x;
|
---|
| 143 |
|
---|
| 144 | // test if the depth in the shadow map is closer than
|
---|
| 145 | // the eye-view point
|
---|
| 146 | half shad = LP.z < shadMapDepth;
|
---|
| 147 |
|
---|
| 148 | // accumulate result
|
---|
| 149 | sum += shad;
|
---|
| 150 | }
|
---|
| 151 | }
|
---|
| 152 |
|
---|
| 153 | // return average of the samples
|
---|
| 154 | return sum / (g_iKernelSize*g_iKernelSize);
|
---|
| 155 | }
|
---|
| 156 |
|
---|
| 157 |
|
---|
| 158 | float4 RenderSceneWithTechnique_06_PS( VS_OUTPUT IN ) : COLOR
|
---|
| 159 | {
|
---|
| 160 | // Apply bias
|
---|
| 161 | IN.ldPosition.z -= g_fShadowBias;
|
---|
| 162 |
|
---|
| 163 | // The soft shadow algorithm follows:
|
---|
| 164 |
|
---|
| 165 | // Compute uv coordinates for the point being shaded
|
---|
| 166 | // Saves some future recomputation.
|
---|
| 167 | half2 uv = half2(.5,-.5)*(IN.ldPosition.xy)/IN.ldPosition.w + half2( 0.5f + HALF_TEXEL, 0.5f + HALF_TEXEL );
|
---|
| 168 |
|
---|
| 169 | // ---------------------------------------------------------
|
---|
| 170 | // Step 1: Find blocker estimate
|
---|
| 171 | half blocker = findBlocker(uv, IN.ldPosition, g_fIntensity * g_fLightSize / IN.ldPosition.z );
|
---|
| 172 |
|
---|
| 173 | // ---------------------------------------------------------
|
---|
| 174 | // Step 2: Estimate penumbra using parallel planes approximation
|
---|
| 175 | half penumbra = estimatePenumbra( IN.ldPosition.z, blocker );
|
---|
| 176 |
|
---|
| 177 | // ---------------------------------------------------------
|
---|
| 178 | // Step 3: Compute percentage-closer filter
|
---|
| 179 | // based on penumbra estimate
|
---|
| 180 |
|
---|
| 181 | // Now do a penumbra-based percentage-closer filter
|
---|
| 182 | half shadowed = PCF_Filter(uv, IN.ldPosition, penumbra );
|
---|
| 183 |
|
---|
| 184 | // If no blocker was found, just return 1.0
|
---|
| 185 | // since the point isn't occluded
|
---|
| 186 | if (blocker > 998)
|
---|
| 187 | shadowed = 1.0;
|
---|
| 188 |
|
---|
| 189 | // Visualize lighting and shadows
|
---|
| 190 | if( shadowed < 1.0 )
|
---|
| 191 | {
|
---|
| 192 | shadowed *= g_fBiasSlope;
|
---|
| 193 | if( shadowed > 1.0 )
|
---|
| 194 | {
|
---|
| 195 | shadowed = 1.0;
|
---|
| 196 | }
|
---|
| 197 | }
|
---|
| 198 | return tex2D(g_samScene, IN.Tex) * shadowed * g_vMaterial;
|
---|
| 199 | }
|
---|
| 200 |
|
---|
| 201 |
|
---|
| 202 |
|
---|
| 203 | // TECHNIQUE
|
---|
| 204 |
|
---|
| 205 | //-----------------------------------------------------------------------------
|
---|
| 206 | // Techniques: RenderShadowMap
|
---|
| 207 | // Desc: Render the shadow map
|
---|
| 208 | //-----------------------------------------------------------------------------
|
---|
| 209 |
|
---|
| 210 | technique RenderShadowMap_6
|
---|
| 211 | {
|
---|
| 212 | pass p0
|
---|
| 213 | {
|
---|
| 214 | VertexShader = compile vs_2_0 RenderShadowMap_06_VS();
|
---|
| 215 | PixelShader = compile ps_2_0 RenderShadowMap_06_PS();
|
---|
| 216 | }
|
---|
| 217 | }
|
---|
| 218 |
|
---|
| 219 |
|
---|
| 220 | technique RenderSceneWithTechnique_6
|
---|
| 221 | {
|
---|
| 222 | pass p0
|
---|
| 223 | {
|
---|
| 224 | VertexShader = compile vs_2_0 RenderSceneWithTechnique_06_VS();
|
---|
| 225 | PixelShader = compile ps_3_0 RenderSceneWithTechnique_06_PS();
|
---|
| 226 | }
|
---|
| 227 | } |
---|