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

Revision 3111, 13.1 KB checked in by mattausch, 16 years ago (diff)

worked on dynamic objects indexing not working yet

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