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

Revision 3105, 12.8 KB checked in by mattausch, 16 years ago (diff)

now strafing up not working anymore!!!!

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