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

Revision 3144, 12.9 KB checked in by mattausch, 16 years ago (diff)

working on normal mapping

Line 
1#include "../shaderenv.h"
2
3
4////////////////////
5// Screen Spaced Ambient Occlusion shader
6// based on shader of Alexander Kusternig
7
8
9#define USE_EYESPACE_DEPTH 1
10
11
12struct fragment
13{
14        float2 texCoord: TEXCOORD0;
15        float3 view: TEXCOORD1;
16};
17
18
19struct pixel
20{
21        float4 illum_col: COLOR0;
22};
23
24
25inline float occlusionPower(float radius, float dist)
26{
27        return 6.283185307179586476925286766559f * (1.0f - cos(asin(radius / dist)));
28}
29
30
31inline float2 myreflect(float2 pt, float2 n)
32{
33        // distance to plane
34        float d = dot(n, pt);
35        // reflect around plane
36        float2 rpt = pt - d * 2.0f * n;
37
38        return rpt;
39}
40
41
42inline float3 Interpol(float2 w, float3 bl, float3 br, float3 tl, float3 tr)
43{
44        float3 x1 = lerp(bl, tl, w.y);
45        float3 x2 = lerp(br, tr, w.y);
46        float3 v = lerp(x1, x2, w.x);
47
48        return v;
49}
50
51
52// reconstruct world space position
53inline float3 ReconstructSamplePos(uniform sampler2D tex,
54                                                                   float2 texcoord,
55                                                                   float3 bl, float3 br, float3 tl, float3 tr)
56{
57        const float eyeSpaceDepth = tex2Dlod(tex, float4(texcoord, 0, 0)).w;
58       
59        float3 viewVec = Interpol(texcoord, bl, br, tl, tr);
60        float3 samplePos = -viewVec * eyeSpaceDepth;
61
62        return samplePos;
63}
64
65
66inline float ComputeDifference(float2 offset,
67                                                           sampler2D oldTex,
68                                                           float4x4 oldModelViewProj,
69                                                           sampler2D colors,
70                                                           sampler2D noiseTex,
71                                                           float scaleFactor,
72                                                           float3 bl,
73                                                           float3 br,
74                                                           float3 tl,
75                                                           float3 tr,
76                                                           float2 texcoord0,
77                                                           float3 oldEyePos,
78                                                           float3 oldbl,
79                                                           float3 oldbr,
80                                                           float3 oldtl,
81                                                           float3 oldtr,
82                                                           float eyeSpaceDepth
83                                                           )
84{
85        const float2 mynoise = tex2Dlod(noiseTex, float4(texcoord0, 0, 0)).xy;
86
87        const float2 offsetTransformed = myreflect(offset, mynoise);
88        float2 texCoord = texcoord0 + offsetTransformed * scaleFactor;
89       
90        const float sampleEyeSpaceDepth = tex2Dlod(colors, float4(texCoord, 0, 0)).w;
91       
92        const float3 viewVec = Interpol(texCoord, bl, br, tl, tr);
93        const float3 samplePos = -viewVec * sampleEyeSpaceDepth;
94        const float3 translatedPos = samplePos - oldEyePos;
95
96        // reproject into old frame and calculate projected depth
97        float4 projPos = mul(oldModelViewProj, float4(translatedPos, 1.0f));
98        projPos /= projPos.w;
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        // the eye linear depth from the previous frame
104        const float oldEyeSpaceDepth = oldPixel.w;
105       
106        // projected linear depth
107        const float3 oldViewVec = Interpol(oldTexCoords, oldbl, oldbr, oldtl, oldtr);
108        const float invlen = 1.0f / length(oldViewVec);
109        const float projectedEyeSpaceDepth = invlen * length(translatedPos);
110
111        float depthDif = (abs(eyeSpaceDepth - sampleEyeSpaceDepth) > 1.0f) ?
112                0 : abs(1.0f - oldEyeSpaceDepth / projectedEyeSpaceDepth);
113
114        return depthDif;
115}
116
117
118/** This shader computes the reprojection and stores
119        reprojected color / depth values as well as a boolean that
120*/
121inline float2 temporalSmoothing(float4 worldPos,
122                                                                float eyeSpaceDepth,
123                                                                float2 texcoord0,
124                                                                float3 oldEyePos,
125                                                                sampler2D oldTex,
126                                                                float4x4 oldModelViewProj,
127                                                                float temporalCoherence,
128                                                                sampler2D colors,
129                                                                float3 bl,
130                                                                float3 br,
131                                                                float3 tl,
132                                                                float3 tr,
133                                                                float3 projPos,
134                                                                float invW,
135                                                                sampler2D noiseTex,
136                                                                float2 samples[NUM_SAMPLES],
137                                                                float scaleFactor,
138                                                                float3 oldbl,
139                                                                float3 oldbr,
140                                                                float3 oldtl,
141                                                                float3 oldtr,
142                                                                float3 diffVec
143                                                                )
144{
145        // compute position from old frame for dynamic objects + translational portion
146        const float3 translatedPos = diffVec - oldEyePos + worldPos.xyz;
147
148
149        /////////////////
150        //-- reproject into old frame and calculate texture position of sample in old frame
151
152        // note: the old model view matrix only holds the view orientation part
153        float4 backProjPos = mul(oldModelViewProj, float4(translatedPos, 1.0f));
154        backProjPos /= backProjPos.w;
155       
156        // fit from unit cube into 0 .. 1
157        const float2 oldTexCoords = backProjPos.xy * 0.5f + 0.5f;
158        // retrieve the sample from the last frame
159        const float4 oldPixel = tex2Dlod(oldTex, float4(oldTexCoords, .0f, .0f));
160
161#if USE_EYESPACE_DEPTH
162
163        // calculate eye space position of sample in old frame
164        const float oldEyeSpaceDepth = oldPixel.w;
165
166        // vector from eye pos to old sample
167        const float3 viewVec = Interpol(oldTexCoords, oldbl, oldbr, oldtl, oldtr);
168        const float invLen = 1.0f / length(viewVec);
169        const float projectedEyeSpaceDepth = invLen * length(translatedPos);
170        //const float projectedEyeSpaceDepth = 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        // the depth projected into the old frame
179        const float projectedDepth = projPos.z;
180        // calculate depth difference
181        const float depthDif = abs(projectedDepth - oldDepth);
182
183#endif
184
185        float notValid = 0.5f;
186        float overallDepth = 0;
187
188#if 1
189        const float squaredLen = diffVec.x * diffVec.x + diffVec.y * diffVec.y + diffVec.z * diffVec.z;
190
191        if (squaredLen < 1e-8f) // object not dynamic
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                        //overallDepth += sampleDif;
208                        if (sampleDif >= MIN_DEPTH_DIFF) ++ notValid;
209                }
210        }
211#endif
212
213        const float oldWeight = clamp(oldPixel.y, .0f, temporalCoherence);
214        //const float oldWeight = oldPixel.y;
215
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                if (notValid > 1.0f) newWeight = 4.0f;
230                //if (notValid > 1.0f) newWeight = max(15.0f - notValid * 2.0f, 1.0f);
231        }
232        else
233        {       
234                newWeight = 1.0f;
235        }
236
237        //if (oldPixel.y >= 2000)
238        //      newWeight = min(temporalCoherence + 1, max(oldPixel.y - 70, 50));
239        //if (newWeight >= 2000) newWeight = 1000;
240        //newWeight -= step(512.0f, newWeight) * 256.0f;
241
242        return float2(oldPixel.x, newWeight);
243}
244
245
246/** The ssao shader returning the an intensity value between 0 and 1
247*/
248float2 ssao(fragment IN,
249                        sampler2D colors,
250                        sampler2D noiseTex,
251                        float2 samples[NUM_SAMPLES],
252                        float3 normal,
253                        float3 centerPosition,
254                        float scaleFactor,
255                        float3 bl,
256                        float3 br,
257                        float3 tl,
258                        float3 tr,
259                        float3 viewDir
260                        , float2 noiseOffs
261                        , sampler2D noiseTex1D
262                        )
263{
264        // Check in a circular area around the current position.
265        // Shoot vectors to the positions there, and check the angle to these positions.
266        // Summing up these angles gives an estimation of the occlusion at the current position.
267
268        float total_ao = .0f;
269        float numSamples = .0f;
270
271
272        //float2 jitter = tex2Dlod(noiseTex1D, float4(IN.texCoord.x * 4.0f + noiseOffs.x, 0.5f, 0, 0)).xy;
273        //float2 jitter = tex2Dlod(noiseTex1D, float4(noiseOffs.x, 0.5f, 0, 0)).xy;
274
275        for (int i = 0; i < NUM_SAMPLES; ++ i)
276        {
277                const float2 offset = samples[i];
278
279#if 1
280                ////////////////////
281                //-- add random noise: reflect around random normal vector (rather slow!)
282
283                //float2 mynoise = tex2Dlod(noiseTex, float4(IN.texCoord * 4.0f + noiseOffs, 0, 0)).xy;
284                float2 mynoise = tex2Dlod(noiseTex, float4(IN.texCoord, .0f, .0f)).xy;
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 + jitter;
292                const float2 texcoord = IN.texCoord.xy + offsetTransformed * scaleFactor;
293
294                //if ((texcoord.x <= 1.0f) && (texcoord.x >= 0.0f) && (texcoord.y <= 1.0f) && (texcoord.y >= 0.0f)) ++ numSamples;
295                const float3 samplePos = ReconstructSamplePos(colors, texcoord, bl, br, tl, tr);
296
297
298                ////////////////
299                //-- compute contribution of sample using the direction and angle
300
301                float3 dirSample = samplePos - centerPosition;
302                const float lengthToSample = max(length(dirSample), 1e-6f);
303
304                dirSample /= lengthToSample; // normalize
305
306                // angle between current normal and direction to sample controls AO intensity.
307                float cosAngle = max(dot(dirSample, normal), .0f);
308       
309                // the distance_scale offset is used to avoid singularity that occurs at global illumination when
310                // the distance to a sample approaches zero
311                const float aoContrib = SAMPLE_INTENSITY / (DISTANCE_SCALE + lengthToSample * lengthToSample);
312                //const float aoContrib = (1.0f > lengthToSample) ? occlusionPower(9e-2f, DISTANCE_SCALE + lengthToSample): .0f;
313
314#if 1
315                // if surface normal perpenticular to view dir, approx. half of the samples will not count
316                // => compensate for this (on the other hand, projected sampling area could be larger!)
317
318                const float viewCorrection = 1.0f + VIEW_CORRECTION_SCALE * max(dot(viewDir, normal), 0.0f);
319                total_ao += cosAngle * aoContrib * viewCorrection;
320#else
321                total_ao += cosAngle * aoContrib;
322#endif
323        }
324
325        return float2(max(0.0f, 1.0f - total_ao), numSamples);
326}
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                   uniform sampler2D noiseTex1D
351                   )
352{
353        pixel OUT;
354
355        const float3 normal = normalize(tex2Dlod(normals, float4(IN.texCoord, 0 ,0)).xyz);
356
357        // reconstruct position from the eye space depth
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        /*const float xoffs = 2.0f / 1024.0f;
363        const float yoffs = 2.0f / 768.0f;
364
365        //float3 id = tex2Dlod(attribsTex, float4(IN.texCoord, 0, 0)).xyz;
366        float3 x1 = tex2Dlod(attribsTex, float4(IN.texCoord, 0, 0)).xyz;
367        float3 x2 = tex2Dlod(attribsTex, float4(IN.texCoord + float2(xoffs, 0), 0, 0)).xyz;
368        float3 x3 = tex2Dlod(attribsTex, float4(IN.texCoord + float2(0, yoffs), 0, 0)).xyz;
369        float3 x4 = tex2Dlod(attribsTex, float4(IN.texCoord + float2(-xoffs, 0), 0, 0)).xyz;
370        float3 x5 = tex2Dlod(attribsTex, float4(IN.texCoord + float2(0, -yoffs), 0, 0)).xyz;
371
372        float3 diffVec = (x1+x2+x3+x4+x5) * .25f;
373*/
374        float3 diffVec = tex2Dlod(attribsTex, float4(IN.texCoord, 0, 0)).xyz;
375       
376
377        ////////////////
378        //-- calculcate the current projected posiion (also used for next frame)
379       
380        float4 projPos = mul(modelViewProj, eyeSpacePos);
381        const float invw = 1.0f / projPos.w;
382        projPos *= invw;
383        float scaleFactor = SAMPLE_RADIUS * invw;
384
385       
386        /////////////////
387        //-- compute temporal reprojection
388
389        float2 temporalVals = temporalSmoothing(eyeSpacePos, eyeSpaceDepth, IN.texCoord, oldEyePos,
390                                                oldTex, oldModelViewProj, temporalCoherence,
391                                                                                        colors,
392                                                                                        bl, br, tl, tr,
393                                                                                        projPos.xyz,
394                                                                                        invw,
395                                                                                        noiseTex,
396                                                                                        samples,
397                                                                                        scaleFactor,
398                                                                                        oldbl, oldbr, oldtl, oldtr,
399                                                                                        diffVec
400                                                                                        );
401
402        const float oldSsao = temporalVals.x;
403        //const float newWeight = clamp(temporalVals.y, 1.0f, temporalCoherence);
404        const float newWeight = temporalVals.y;
405
406        //float2 noiseOffs = float2((temporalVals.y - 1)/ 139.0f, .0f);
407        float2 noiseOffs = float2(.0f);
408
409        float2 ao;
410
411        // note: this should be done with the stencil buffer
412        if (eyeSpaceDepth < 1e10f)
413        {
414                ao = ssao(IN, colors, noiseTex, samples, normal,
415                          eyeSpacePos.xyz, scaleFactor, bl, br, tl, tr, normalize(viewDir), noiseOffs, noiseTex1D);
416        }
417        else
418        {
419                 ao = float2(1.0f, 0);
420        }
421
422        OUT.illum_col.x = (ao.x + oldSsao * (newWeight - 1.0f)) / newWeight;
423        OUT.illum_col.y = newWeight;
424        OUT.illum_col.z = invw;
425        OUT.illum_col.w = eyeSpaceDepth;
426
427        return OUT;
428}
Note: See TracBrowser for help on using the repository browser.