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

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