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

Revision 3094, 11.2 KB checked in by mattausch, 16 years ago (diff)

some error with reprojection when moving

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