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 | } |
---|