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

Revision 3121, 11.7 KB checked in by mattausch, 16 years ago (diff)

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