source: GTP/trunk/App/Demos/Vis/FriendlyCulling/src/shaders/ssao.cg @ 3088

Revision 3088, 11.7 KB checked in by mattausch, 16 years ago (diff)
Line 
1#include "../shaderenv.h"
2
3////////////////////
4// Screen Spaced Ambient Occlusion shader
5// based on shader of Alexander Kusternig
6
7
8#define USE_EYE_SPACE_DEPTH 1
9
10
11struct fragment
12{
13        float2 texCoord: TEXCOORD0;
14        float3 view: TEXCOORD1;
15};
16
17
18struct pixel
19{
20        float4 illum_col: COLOR0;
21};
22
23
24inline float occlusionPower(float radius, float dist)
25{
26        return 6.283185307179586476925286766559f * (1.0f - cos(asin(radius / dist)));
27}
28
29
30inline float2 myreflect(float2 pt, float2 n)
31{
32        // distance to plane
33        float d = dot(n, pt);
34        // reflect around plane
35        float2 rpt = pt - d * 2.0f * n;
36
37        return rpt;
38}
39
40
41inline float3 Interpol(float2 w, float3 bl, float3 br, float3 tl, float3 tr)
42{
43        float3 x1 = lerp(bl, tl, w.y);
44        float3 x2 = lerp(br, tr, w.y);
45        float3 v = lerp(x1, x2, w.x);
46
47        return v;
48}
49
50
51// reconstruct world space position
52inline float3 ReconstructSamplePos(uniform sampler2D tex,
53                                                                   float2 texcoord,
54                                                                   float3 bl, float3 br, float3 tl, float3 tr)
55{
56        const float eyeSpaceDepth = tex2D(tex, texcoord).w;
57        float3 viewVec = Interpol(texcoord, bl, br, tl, tr);
58        float3 samplePos = -viewVec * eyeSpaceDepth;
59
60        return samplePos;
61}
62
63#pragma position_invariant temporalSmoothing
64
65
66inline float ComputeDifference(float2 offset,
67                                                           uniform sampler2D oldTex,
68                                                           const uniform float4x4 oldModelViewProj,
69                                                           uniform sampler2D colors,
70                                                           uniform sampler2D noiseTex,
71                                                           uniform float scaleFactor,
72                                                           uniform float3 bl,
73                                                           uniform float3 br,
74                                                           uniform float3 tl,
75                                                           uniform float3 tr,
76                                                           float2 texcoord0,
77                                                           float3 eyePos,
78                                                           float3 oldEyePos,
79                                                           uniform float3 oldbl,
80                                                           uniform float3 oldbr,
81                                                           uniform float3 oldtl,
82                                                           uniform float3 oldtr
83                                                          // float dummy3
84                                                           )
85{
86        float2 mynoise = tex2D(noiseTex, texcoord0).xy;
87
88        const float2 offsetTransformed = myreflect(offset, mynoise);
89        const float2 texCoord = texcoord0 + offsetTransformed * scaleFactor;
90        const float3 samplePos = ReconstructSamplePos(colors, texCoord, bl, br, tl, tr) + eyePos;
91
92        // reproject into old frame and calculate projected depth
93        float4 projPos = mul(oldModelViewProj, float4(samplePos, 1.0f));
94        projPos /= projPos.w;
95
96        // fit from unit cube into 0 .. 1
97        const float2 oldTexCoords = projPos.xy * 0.5f + 0.5f;
98
99        // retrieve the sample from the last frame
100        float4 oldCol = tex2D(oldTex, oldTexCoords);
101
102        float oldEyeSpaceDepth = oldCol.w;// dummy3;
103        float3 viewVec = Interpol(oldTexCoords, oldbl, oldbr, oldtl, oldtr);
104        float3 oldSamplePos = oldEyePos - viewVec * oldEyeSpaceDepth;
105
106        float dDiff = length(oldSamplePos - samplePos.xyz);
107
108        return dDiff;
109}
110
111
112/** This shader computes the reprojection and stores reprojected color / depth values
113        as well as a boolean that
114*/
115float4 temporalSmoothing(float4 currentProjPos,
116                                                 float4 worldPos,
117                                                 uniform sampler2D oldTex,
118                                                 const uniform float4x4 oldModelViewProj,
119                                                 uniform float temporalCoherence,
120                                                 uniform float2 ao,
121                                                 uniform float2 samples[NUM_SAMPLES],
122                                                 uniform sampler2D colors,
123                                                 uniform sampler2D noiseTex,
124                                                 uniform float scaleFactor,
125                                                 uniform float3 bl,
126                                                 uniform float3 br,
127                                                 uniform float3 tl,
128                                                 uniform float3 tr,
129                                                 float2 texcoord0,
130                                                 float3 eyePos,
131                                                 float eyeSpaceDepth,
132                                                 float3 oldEyePos,
133                                                 uniform float3 oldbl,
134                                                 uniform float3 oldbr,
135                                                 uniform float3 oldtl,
136                                                 uniform float3 oldtr
137                                                 )
138{
139        float4 illum_col;
140
141        /////////////////
142        //-- compute reprojection for temporal smoothing
143
144        // reproject into old frame and calculate projected depth
145        float4 backProjPos = mul(oldModelViewProj, worldPos);
146        backProjPos /= backProjPos.w;
147        // fit from unit cube into 0 .. 1
148        const float2 oldTexCoords = backProjPos.xy * 0.5f + 0.5f;
149        //float2 oldTexCoords = texcoord0;
150
151        // retrieve the sample from the last frame
152        //float4 oldCol = tex2Dlod(oldTex, float4(oldTexCoords, 0, 0));
153        float4 oldCol = tex2D(oldTex, oldTexCoords);
154
155        //eyeSpaceDepth = 1e6f;
156       
157        //const float dummy3 = 1e-4f;
158        //const float oldEyeSpaceDepth = 1e5f * dummy3;
159        //const float oldEyeSpaceDepth = oldCol.z / dummy3;
160        const float oldEyeSpaceDepth = oldCol.w;
161
162        //oldTexCoords.x += 0.5f / 1024.0f; oldTexCoords.y += 0.5f / 768.0f;
163
164        float3 viewVec = Interpol(oldTexCoords, oldbl, oldbr, oldtl, oldtr);
165        //float3 oldSamplePos = -viewVec * eyeSpaceDepth + oldEyePos;
166        float3 oldSamplePos = oldEyePos - viewVec * oldEyeSpaceDepth;
167
168        //const float oldDepth = oldCol.z;
169        const float depthDif = length(oldSamplePos - worldPos.xyz);
170        //eyeSpaceDepth *= dummy3;
171       
172        //const float depthDif = abs(oldEyeSpaceDepth - eyeSpaceDepth);// * 1e4f;
173        //const float depthDif = abs(oldEyeSpaceDepth - dummy2) * 1e3f;
174
175        //const float oldNumSamples = oldCol.y;
176        const float oldWeight = clamp(oldCol.y, .0f, temporalCoherence);
177        float newWeight;
178
179        bool isValid = true;
180
181        for (int i = 0; i < NUM_SAMPLES; ++ i)
182        {
183                float sampleDif  = ComputeDifference(samples[i],
184                                          oldTex,
185                                                          oldModelViewProj,
186                                                          colors,
187                                                          noiseTex,
188                                                          scaleFactor,
189                                                          bl, br, tl, tr,
190                                                          texcoord0,
191                                                          eyePos,
192                                                          oldEyePos,
193                                                          oldbl, oldbr, oldtl, oldtr
194                                                          //,dummy3
195                                                          );
196
197                //if (sampleDif > 1e-1f) isValid = false;
198        }
199
200        // the number of valid samples in this frame
201        //const float newNumSamples = ao.y;
202
203        if ((temporalCoherence > 1e-6f)
204                && (oldTexCoords.x >= 0.0f) && (oldTexCoords.x < 1.0f)
205                && (oldTexCoords.y >= 0.0f) && (oldTexCoords.y < 1.0f)
206                && (abs(depthDif) <= MIN_DEPTH_DIFF)
207                // if visibility changed in the surrounding area we have to recompute
208                //&& (oldNumSamples > 0.8f * newNumSamples)
209                && isValid
210                )
211        {
212                // increase the weight for convergence
213                newWeight = oldWeight + 1.0f;
214                illum_col.x = (ao.x + oldCol.x * oldWeight) / newWeight;
215                //if (!(oldNumSamples > ao.y - 1.5f)) newWeight = 0;
216        }
217        else
218        {       
219                illum_col.x = ao.x;
220                newWeight = .0f;
221        }
222
223        //illum_col.x = depthDif;
224       
225        //isValid = 0.0f;
226        //illum_col.y = isValid / 16.0f;
227        illum_col.y = newWeight;
228        illum_col.w = eyeSpaceDepth;
229        //illum_col.z = dummy2;
230
231        return illum_col;
232}
233
234
235/** The ssao shader returning the an intensity value between 0 and 1
236*/
237float2 ssao(fragment IN,
238                        uniform sampler2D colors,
239                        uniform sampler2D noiseTex,
240                        uniform float2 samples[NUM_SAMPLES],
241                        uniform float3 currentNormal,
242                        uniform float3 centerPosition,
243                        uniform float scaleFactor,
244                        uniform float3 bl,
245                        uniform float3 br,
246                        uniform float3 tl,
247                        uniform float3 tr,
248                        uniform float3 viewDir
249                        )
250{
251        // Check in a circular area around the current position.
252        // Shoot vectors to the positions there, and check the angle to these positions.
253        // Summing up these angles gives an estimation of the occlusion at the current position.
254
255        float total_ao = .0f;
256        float numSamples = .0f;
257
258
259        for (int i = 0; i < NUM_SAMPLES; ++ i)
260        {
261                const float2 offset = samples[i];
262
263#if 1
264                ////////////////////
265                //-- add random noise: reflect around random normal vector (rather slow!)
266
267                float2 mynoise = tex2D(noiseTex, IN.texCoord).xy;
268                const float2 offsetTransformed = myreflect(offset, mynoise);
269#else
270                const float2 offsetTransformed = offset;
271#endif
272                // weight with projected coordinate to reach similar kernel size for near and far
273                const float2 texcoord = IN.texCoord.xy + offsetTransformed * scaleFactor;
274
275                //if ((texcoord.x <= 1.0f) && (texcoord.x >= 0.0f) && (texcoord.y <= 1.0f) && (texcoord.y >= 0.0f)) ++ numSamples;
276
277                const float3 samplePos = ReconstructSamplePos(colors, texcoord, bl, br, tl, tr);
278
279
280                ////////////////
281                //-- compute contribution of sample using the direction and angle
282
283                float3 dirSample = samplePos - centerPosition;
284                const float lengthToSample = length(dirSample);
285                // normalize
286                dirSample /= lengthToSample;
287
288                // angle between current normal and direction to sample controls AO intensity.
289                const float cosAngle = max(dot(dirSample, currentNormal), 0.0f);
290
291                // the distance_scale offset is used to avoid singularity that occurs at global illumination when
292                // the distance to a sample approaches zero
293                //const float aoContrib = (1.0f > lengthToSample) ? occlusionPower(9e-2f, DISTANCE_SCALE + lengthToSample): .0f;
294                const float aoContrib = SAMPLE_INTENSITY / (DISTANCE_SCALE + lengthToSample * lengthToSample);
295
296#if 1
297                // if surface normal perpenticular to view dir, approx. half of the samples will not count
298                // => compensate for this (on the other hand, projected sampling area could be larger!)
299                const float viewCorrection = 1.0f + VIEW_CORRECTION_SCALE * dot(viewDir, currentNormal);
300                total_ao += cosAngle * aoContrib * viewCorrection;
301#else
302                total_ao += cosAngle * intensity;
303#endif
304        }
305
306        return float2(max(0.0f, 1.0f - total_ao), numSamples);
307}
308
309//#pragma position_invariant main
310
311/** The mrt shader for screen space ambient occlusion
312*/
313pixel main(fragment IN,
314                   uniform sampler2D colors,
315                   uniform sampler2D normals,
316                   uniform sampler2D noiseTex,
317                   uniform float2 samples[NUM_SAMPLES],
318                   uniform sampler2D oldTex,
319                   uniform float4x4 modelViewProj,
320                   uniform float4x4 oldModelViewProj,
321                   uniform float temporalCoherence,
322                   uniform float3 eyePos,
323                   uniform float3 bl,
324                   uniform float3 br,
325                   uniform float3 tl,
326                   uniform float3 tr,
327                   uniform float3 oldEyePos,
328                   uniform float3 oldbl,
329                   uniform float3 oldbr,
330                   uniform float3 oldtl,
331                   uniform float3 oldtr
332                   )
333{
334        pixel OUT;
335
336        const float3 normal = normalize(tex2Dlod(normals, float4(IN.texCoord, 0 ,0)).xyz);
337
338        // reconstruct position from the eye space depth
339        const float3 viewDir = IN.view;
340        const float eyeSpaceDepth = tex2D(colors, IN.texCoord).w;
341        const float3 eyeSpacePos = -viewDir * eyeSpaceDepth;
342        const float4 worldPos = float4(eyePos + eyeSpacePos, 1.0f);
343
344
345        ////////////////
346        //-- calculcate the current projected posiion (also used for next frame)
347       
348        float4 projPos = mul(modelViewProj, worldPos);
349       
350        float w = 1.0f / projPos.w;
351        projPos *= w;
352        w *= SAMPLE_RADIUS;
353       
354        const float2 ao = ssao(IN, colors, noiseTex, samples, normal, eyeSpacePos, w, bl, br, tl, tr, normalize(viewDir));
355
356
357        /////////////////
358        //-- compute temporally smoothing
359       
360        OUT.illum_col = temporalSmoothing(projPos, worldPos, oldTex, oldModelViewProj, temporalCoherence, ao,
361                                              samples, colors, noiseTex, w, bl, br, tl, tr, IN.texCoord, eyePos, eyeSpaceDepth,
362                                                                          oldEyePos, oldbl, oldbr, oldtl, oldtr);
363
364        return OUT;
365}
366
367
368float Filter(float2 texCoord,
369                         uniform sampler2D ssaoTex,
370                         uniform float2 filterOffs[NUM_SSAO_FILTERSAMPLES],
371                         uniform float filterWeights[NUM_SSAO_FILTERSAMPLES]
372)
373{
374        float average = .0f;
375        float w = .0f;
376
377        for (int i = 0; i < NUM_SSAO_FILTERSAMPLES; ++ i)
378        {
379                average += filterWeights[i] * tex2Dlod(ssaoTex, float4(texCoord + filterOffs[i], 0, 0)).x;
380                w += filterWeights[i];
381        }
382
383        average *= 1.0f / (float)w;
384
385        return average;
386}
387
388
389pixel combine(fragment IN,
390                          uniform sampler2D colors,
391                          uniform sampler2D ssaoTex,
392                          uniform float2 filterOffs[NUM_SSAO_FILTERSAMPLES],
393                          uniform float filterWeights[NUM_SSAO_FILTERSAMPLES]
394                          )
395{
396        pixel OUT;
397
398        float4 col = tex2Dlod(colors, float4(IN.texCoord, 0, 0));
399        float3 ao = tex2Dlod(ssaoTex, float4(IN.texCoord, 0, 0));
400
401        //if (ao.y < 10.0f)
402        //      ao.x = Filter(IN.texCoord, ssaoTex, filterOffs, filterWeights);
403
404        //OUT.illum_col = col * ao.x;
405        OUT.illum_col = float4(ao.x, ao.x, ao.x, col.w);
406        //OUT.illum_col.xyz = float3(1.0f - ao.x, 1.0f - ao.y * 1e-2f, 1);
407        //OUT.illum_col.xyz = float3(1.0f - ao.x, ao.y, 0);
408        OUT.illum_col.w = col.w;
409
410        return OUT;
411}
Note: See TracBrowser for help on using the repository browser.