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

Revision 3101, 11.6 KB checked in by mattausch, 16 years ago (diff)

depth queries not working

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