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

Revision 3103, 10.6 KB checked in by mattausch, 16 years ago (diff)

still some error with ssao on edges
bilateral filter slow

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