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

Revision 3114, 13.0 KB checked in by mattausch, 16 years ago (diff)

worked on dynamic objects: now ook, but have to work on render queue

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                                                           uniform sampler2D oldTex,
69                                                           const uniform float4x4 oldModelViewProj,
70                                                           uniform sampler2D colors,
71                                                           uniform sampler2D noiseTex,
72                                                           uniform float scaleFactor,
73                                                           uniform float3 bl,
74                                                           uniform float3 br,
75                                                           uniform float3 tl,
76                                                           uniform float3 tr,
77                                                           float2 texcoord0,
78                                                           float3 oldEyePos,
79                                                           uniform float3 oldbl,
80                                                           uniform float3 oldbr,
81                                                           uniform float3 oldtl,
82                                                           uniform float3 oldtr,
83                                                           float eyeSpaceDepth
84                                                           )
85{
86        const float2 mynoise = tex2Dlod(noiseTex, texcoord0).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
96        const float3 translatedPos = samplePos - oldEyePos;
97        // reproject into old frame and calculate projected depth
98        float4 projPos = mul(oldModelViewProj, float4(translatedPos, 1.0f));
99        projPos /= projPos.w;
100
101        // fit from unit cube into 0 .. 1
102        const float2 oldTexCoords = projPos.xy * 0.5f + 0.5f;
103        // retrieve the sample from the last frame
104        const float4 oldPixel = tex2Dlod(oldTex, float4(oldTexCoords, .0f, .0f));
105
106        const float oldEyeSpaceDepth = oldPixel.w;
107        const float3 oldViewVec = Interpol(oldTexCoords, oldbl, oldbr, oldtl, oldtr);
108
109        const float invlen = 1.0f / length(oldViewVec);
110        const float projectedEyeSpaceDepth = length(translatedPos) * invlen;
111       
112        float depthDif = (abs(eyeSpaceDepth - sampleEyeSpaceDepth) > 5.0f) ?
113                0 : abs(oldEyeSpaceDepth - projectedEyeSpaceDepth);
114
115        return depthDif;
116}
117
118
119/** This shader computes the reprojection and stores reprojected color / depth values
120        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 translatedPt = 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(translatedPt, 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(translatedPt);
175       
176        //const float depthDif = abs(oldEyeSpaceDepth - projectedEyeSpaceDepth);
177        const float depthDif = abs(1.0f - oldEyeSpaceDepth / projectedEyeSpaceDepth);
178        //const float depthDif = abs(projectedEyeSpaceDepth - oldEyeSpaceDepth ) / projectedEyeSpaceDepth;
179
180#else
181        // calculate eye space position of sample in old frame
182        const float oldDepth = oldPixel.w;
183        const float projectedDepth = projPos.z;
184        //const float projectedDepth = invW * worldPos.z;
185
186        // vector from eye pos to old sample
187        const float depthDif = abs(projectedDepth - oldDepth);
188#endif
189
190        float notValid = 0.5f;
191
192        /*
193        for (int i = 0; i < NUM_SAMPLES; ++ i)
194        {
195                float sampleDif = ComputeDifference(samples[i],
196                                          oldTex,
197                                                          oldModelViewProj,
198                                                          colors,
199                                                          noiseTex,
200                                                          scaleFactor,
201                                                          bl, br, tl, tr,
202                                                          texcoord0,
203                                                          oldEyePos,
204                                                          oldbl, oldbr, oldtl, oldtr,
205                                                          eyeSpaceDepth);
206
207                if (sampleDif >= 5e-2f) ++ notValid;
208        }
209        */
210
211        // the number of valid samples in this frame
212        //const float newNumSamples = ao.y;
213        //const float oldNumSamples = oldCol.y;
214
215        const float oldWeight = clamp(oldPixel.y, .0f, temporalCoherence);
216        float newWeight;
217
218        if ((temporalCoherence > 1e-6f)
219                && (oldTexCoords.x >= 0.0f) && (oldTexCoords.x < 1.0f)
220                && (oldTexCoords.y >= 0.0f) && (oldTexCoords.y < 1.0f)
221                && (depthDif <= MIN_DEPTH_DIFF)
222                // if visibility changed in the surrounding area we have to recompute
223                //&& (oldNumSamples > 0.8f * newNumSamples)
224                && (notValid < 1.0f)
225                )
226        {
227                // increase the weight for convergence
228                newWeight = oldWeight + 1.0f;
229                illum_col.x = (ao.x + oldPixel.x * oldWeight) / newWeight;
230                //if (notValid > 1.0f) newWeight = 2.0f;
231        }
232        else
233        {       
234                illum_col.x = ao.x;
235                newWeight = .0f;
236        }
237
238        illum_col.y = newWeight;
239
240#if USE_EYESPACE_DEPTH
241        illum_col.w = eyeSpaceDepth;
242#else
243        illum_col.w = projectedDepth;
244#endif
245
246        illum_col.z = invW;
247        //illum_col.x = length(diffVec*50.0f);
248
249        return illum_col;
250}
251
252
253/** The ssao shader returning the an intensity value between 0 and 1
254*/
255float2 ssao(fragment IN,
256                        uniform sampler2D colors,
257                        uniform sampler2D noiseTex,
258                        uniform float2 samples[NUM_SAMPLES],
259                        uniform float3 normal,
260                        uniform float3 centerPosition,
261                        uniform float scaleFactor,
262                        uniform float3 bl,
263                        uniform float3 br,
264                        uniform float3 tl,
265                        uniform float3 tr,
266                        uniform float3 viewDir
267                        )
268{
269        // Check in a circular area around the current position.
270        // Shoot vectors to the positions there, and check the angle to these positions.
271        // Summing up these angles gives an estimation of the occlusion at the current position.
272
273        float total_ao = .0f;
274        float numSamples = .0f;
275
276
277        for (int i = 0; i < NUM_SAMPLES; ++ i)
278        {
279                const float2 offset = samples[i];
280
281#if 1
282                ////////////////////
283                //-- add random noise: reflect around random normal vector (rather slow!)
284
285                float2 mynoise = tex2Dlod(noiseTex, float4(IN.texCoord * 4.0f, 0, 0)).xy;
286                const float2 offsetTransformed = myreflect(offset, mynoise);
287#else
288                const float2 offsetTransformed = offset;
289#endif
290                // weight with projected coordinate to reach similar kernel size for near and far
291                const float2 texcoord = IN.texCoord.xy + offsetTransformed * scaleFactor;
292
293                //if ((texcoord.x <= 1.0f) && (texcoord.x >= 0.0f) && (texcoord.y <= 1.0f) && (texcoord.y >= 0.0f)) ++ numSamples;
294                const float3 samplePos = ReconstructSamplePos(colors, texcoord, bl, br, tl, tr);
295
296
297                ////////////////
298                //-- compute contribution of sample using the direction and angle
299
300                float3 dirSample = samplePos - centerPosition;
301                const float lengthToSample = max(length(dirSample), 1e-6f);
302
303                dirSample /= lengthToSample; // normalize
304
305                // angle between current normal and direction to sample controls AO intensity.
306                float cosAngle = max(dot(dirSample, normal), .0f);
307       
308                // the distance_scale offset is used to avoid singularity that occurs at global illumination when
309                // the distance to a sample approaches zero
310                const float aoContrib = SAMPLE_INTENSITY / (DISTANCE_SCALE + lengthToSample * lengthToSample);
311                //const float aoContrib = (1.0f > lengthToSample) ? occlusionPower(9e-2f, DISTANCE_SCALE + lengthToSample): .0f;
312
313#if 1
314                // if surface normal perpenticular to view dir, approx. half of the samples will not count
315                // => compensate for this (on the other hand, projected sampling area could be larger!)
316
317                const float viewCorrection = 1.0f + VIEW_CORRECTION_SCALE * max(dot(viewDir, normal), 0.0f);
318                total_ao += cosAngle * aoContrib * viewCorrection;
319#else
320                total_ao += cosAngle * aoContrib;
321#endif
322        }
323
324        return float2(max(0.0f, 1.0f - total_ao), numSamples);
325}
326
327/** The mrt shader for screen space ambient occlusion
328*/
329pixel main(fragment IN,
330                   uniform sampler2D colors,
331                   uniform sampler2D normals,
332                   uniform sampler2D noiseTex,
333                   uniform float2 samples[NUM_SAMPLES],
334                   uniform sampler2D oldTex,
335                   uniform float4x4 modelViewProj,
336                   uniform float4x4 oldModelViewProj,
337                   uniform float temporalCoherence,
338                   uniform float3 bl,
339                   uniform float3 br,
340                   uniform float3 tl,
341                   uniform float3 tr,
342                   uniform float3 oldEyePos,
343                   uniform float3 oldbl,
344                   uniform float3 oldbr,
345                   uniform float3 oldtl,
346                   uniform float3 oldtr,
347                   uniform sampler2D attribsTex
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 invw = 1.0f / projPos.w;
366        projPos *= invw;
367        float scaleFactor = SAMPLE_RADIUS * invw;
368       
369        float2 ao = float2(1.0f, 0);
370        // note: this should be done with the stencil buffer
371        if (eyeSpaceDepth < 1e10f)
372                ao = ssao(IN, colors, noiseTex, samples, normal,
373                          eyeSpacePos.xyz, scaleFactor, bl, br, tl, tr, normalize(viewDir));
374
375
376        //float3 id = tex2Dlod(attribsTex, float4(IN.texCoord, 0, 0)).xyz;
377        float3 diffVec = tex2Dlod(attribsTex, float4(IN.texCoord, 0, 0)).xyz;
378
379        /////////////////
380        //-- compute temporal reprojection
381
382        OUT.illum_col = temporalSmoothing(eyeSpacePos, eyeSpaceDepth, ao, IN.texCoord, oldEyePos,
383                                              oldTex, oldModelViewProj, temporalCoherence,
384                                              colors,
385                                                                          bl, br, tl, tr,
386                                                                          projPos.xyz,
387                                                                          invw,
388                                                                          noiseTex,
389                                                                          samples,
390                                                                          scaleFactor,
391                                                                          oldbl, oldbr, oldtl, oldtr,
392                                                                          diffVec);
393
394        //OUT.illum_col.xyz = id;
395        //OUT.illum_col.xyz = normal * 0.5f + 0.5f;
396        return OUT;
397}
398
399
400float Filter(float2 texCoord,
401                         uniform sampler2D ssaoTex,
402                         uniform float2 filterOffs[NUM_SSAO_FILTERSAMPLES],
403                         uniform float filterWeights[NUM_SSAO_FILTERSAMPLES],
404                         float scale)
405{
406        float average = .0f;
407        float w = .0f;
408
409        for (int i = 0; i < NUM_SSAO_FILTERSAMPLES; ++ i)
410        {       
411                average += filterWeights[i] * tex2Dlod(ssaoTex, float4(texCoord + filterOffs[i] * scale, 0, 0)).x;
412                w += filterWeights[i];
413        }
414
415        average *= 1.0f / (float)w;
416
417        return average;
418}
419
420
421pixel combine(fragment IN,
422                          uniform sampler2D colorsTex,
423                          uniform sampler2D ssaoTex,
424                          uniform float2 filterOffs[NUM_SSAO_FILTERSAMPLES],
425                          uniform float filterWeights[NUM_SSAO_FILTERSAMPLES]
426                          )
427{
428        pixel OUT;
429
430        const float4 col = tex2Dlod(colorsTex, float4(IN.texCoord, 0, 0));
431        float4 ao = tex2Dlod(ssaoTex, float4(IN.texCoord, 0, 0));
432
433        //if ((ao.y < 10.0f) && (col.w < 1e10f))
434        //      ao.x = Filter(IN.texCoord, ssaoTex, filterOffs, filterWeights, 1.0f / (1.0f + ao.y));//ao.z);
435
436        //OUT.illum_col = col * ao.x;
437        //OUT.illum_col = float4(ao.y, ao.y, ao.y, col.w);
438        //OUT.illum_col = float4(ao.x, ao.y, ao.z, col.w);
439        OUT.illum_col = float4(ao.x, ao.x, ao.x, col.w);
440        //OUT.illum_col.xyz = float3(1.0f - ao.x, 1.0f - ao.y * 1e-2f, 1);
441        //OUT.illum_col.xyz = float3(1.0f - ao.x, ao.y, 0);
442        OUT.illum_col.w = col.w;
443
444        return OUT;
445}
Note: See TracBrowser for help on using the repository browser.