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

Revision 3362, 24.2 KB checked in by mattausch, 15 years ago (diff)

cleaned up algorithm

Line 
1#include "../shaderenv.h"
2#include "common.h"
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 pixel2
20{
21        float4 illum_col: COLOR0;
22        float4 col: COLOR1;
23};
24
25
26// this function is inspired from the paper of shamulgaan in order
27// to get a physical expression for the occlusion culling
28inline float occlusionPower(float radius, float dist)
29{
30        return 6.283185307179586476925286766559f * (1.0f - cos(asin(radius / dist)));
31}
32
33
34
35// reconstruct world space position
36inline float3 ReconstructSamplePos(float eyeSpaceDepth,
37                                                                   float2 texcoord,
38                                                                   float3 bl, float3 br, float3 tl, float3 tr)
39{
40        float3 viewVec = Interpol(texcoord, bl, br, tl, tr);
41        float3 samplePos = -viewVec * eyeSpaceDepth;
42
43        return samplePos;
44}
45
46
47float ComputeConvergence(uniform sampler2D tex, float2 texCoord, float2 res)
48{
49        // get the minimum convergence by exactly sampling the 4 surrounding
50        // texels in the old texture, otherwise flickering because convergence
51        // will be interpolated when upsampling and filter size does not match!
52
53        const float2 invRes = float2(1.0f / res.x, 1.0f / res.y);
54
55        // get position exactly between texel centers
56        float2 center = (floor(texCoord * res) + float2(.5f)) * texCoord;
57        //center.x = (floor(texCoord.x * res.x - .5f) + 1.0f) / res.x;
58        //center.y = (floor(texCoord.y * res.y - .5f) + 1.0f) / res.y;
59        //center.y = (floor(texCoord.y * res.y) + .5f) * yOffs;
60
61        /*texelCenterConv.x = tex2Dlod(tex, float4(center + float2( xoffs,  yoffs), 0, 0)).y;
62        texelCenterConv.y = tex2Dlod(tex, float4(center + float2( xoffs, -yoffs), 0, 0)).y;
63        texelCenterConv.z = tex2Dlod(tex, float4(center + float2(-xoffs, -yoffs), 0, 0)).y;
64        texelCenterConv.w = tex2Dlod(tex, float4(center + float2(-xoffs,  yoffs), 0, 0)).y;
65
66        const float m1 = min(texelCenterConv.x, texelCenterConv.y);
67        const float m2 = min(texelCenterConv.z, texelCenterConv.w);
68
69        const float convergence = min(m1, m2);*/
70
71        //const float convergence = tex2Dlod(tex, float4(center, 0, 0)).y;
72        const float convergence = tex2Dlod(tex, float4(texCoord, 0, 0)).y;
73
74        return convergence;
75}
76
77/** This shader computes the reprojection and stores
78        the ssao value of the old pixel as well as the
79        weight of the pixel in the new frame.
80*/
81inline float3 Reproject(float4 worldPos,
82                                                float eyeSpaceDepth,
83                                                float2 texcoord0,
84                                                float3 oldEyePos,
85                                                sampler2D oldTex,
86                                                float4x4 oldModelViewProj,
87                                                sampler2D colors,
88                                                float3 projPos,
89                                                float invW,
90                                                float3 oldbl,
91                                                float3 oldbr,
92                                                float3 oldtl,
93                                                float3 oldtr,
94                                                float3 diffVec
95                                                )
96{
97        // compute position from old frame for dynamic objects + translational portion
98        const float3 translatedPos = diffVec - oldEyePos + worldPos.xyz;
99
100
101        /////////////////
102        //-- reproject into old frame and calculate texture position of sample in old frame
103
104        // note: the old model view matrix only holds the view orientation part
105        float4 backProjPos = mul(oldModelViewProj, float4(translatedPos, 1.0f));
106        backProjPos /= backProjPos.w;
107       
108        // fit from unit cube into 0 .. 1
109        const float2 oldTexCoords = backProjPos.xy * 0.5f + 0.5f;
110        // retrieve the sample from the last frame
111        const float4 oldPixel = tex2Dlod(oldTex, float4(oldTexCoords, .0f, .0f));
112
113        // the ssao value in the old frame
114        const float ssao = oldPixel.x;
115
116        // calculate eye space position of sample in old frame
117        const float oldEyeSpaceDepth = oldPixel.w;
118
119        // vector from eye pos to old sample
120        const float3 viewVec = Interpol(oldTexCoords, oldbl, oldbr, oldtl, oldtr);
121        const float invLen = 1.0f / length(viewVec);
122        const float projectedEyeSpaceDepth = invLen * length(translatedPos);
123        //const float projectedEyeSpaceDepth = length(translatedPos);
124       
125        const float depthDif = abs(1.0f - oldEyeSpaceDepth / projectedEyeSpaceDepth);
126
127        // the weight of the accumulated samples from the previous frames
128        float w;
129        float idx;
130
131
132        //////////////
133        //-- reuse old value only if it was still valid in the old frame
134
135        if (1
136                && (oldTexCoords.x > 0) && (oldTexCoords.x < 1.0f)
137                && (oldTexCoords.y > 0) && (oldTexCoords.y < 1.0f)
138                && (depthDif <= MIN_DEPTH_DIFF)
139                )
140        {
141                // pixel valid => retrieve the convergence weight
142                /*float w1 = tex2Dlod(oldTex, float4(oldTexCoords + float2(0.5f / 1024.0f, 0), .0f, .0f)).y;
143                float w2 = tex2Dlod(oldTex, float4(oldTexCoords - float2(0.5f / 1024.0f, 0), .0f, .0f)).y;
144                float w3 = tex2Dlod(oldTex, float4(oldTexCoords + float2(0, 0.5f / 768.0f), .0f, .0f)).y;
145                float w4 = tex2Dlod(oldTex, float4(oldTexCoords - float2(0, 0.5f / 768.0f), .0f, .0f)).y;
146
147                w = min(min(w1, w2), min(w3, w4));*/
148               
149                //w = ComputeConvergence(oldTex, oldTexCoords, float2(1024.0f, 768.0f));
150                w   = oldPixel.y;
151                idx = floor(oldPixel.z);
152                //idx = oldPixel.z;
153        }
154        else
155        {       
156                w   = .0f;
157                idx = .0f;
158        }
159
160        return float3(ssao, w, idx);
161}
162
163
164/** The ssao shader returning the an intensity value between 0 and 1.
165        This version of the ssao shader uses the dotproduct between
166        pixel-to-sample direction and sample normal as weight.
167
168    The algorithm works like the following:
169        1) Check in a circular area around the current position.
170        2) Shoot vectors to the positions there, and check the angle to these positions.
171        3) Summing up these angles gives an estimation of the occlusion at the current position.
172*/
173float3 ssao2(fragment IN,
174                         sampler2D colors,
175                         sampler2D noiseTex,
176                         sampler2D samples,
177                         float3 normal,
178                         float3 centerPosition,
179                         float radius,
180                         float3 bl,
181                         float3 br,
182                         float3 tl,
183                         float3 tr,
184                         float3 viewDir,
185                         float convergence,
186                         float sampleIntensity,
187                         bool isMovingObject,
188                         sampler2D normalTex,
189                         float idx
190                         )
191{
192        float total_ao = .0f;
193        float validSamples = .0f;
194        float numSamples = .0f;
195
196        for (int i = 0; i < NUM_SAMPLES; ++ i)
197        {
198                float2 offset;
199
200                const float2 ssaoOffset =
201                        tex2Dlod(samples, float4((0.5f + i + idx) / NUM_PRECOMPUTED_SAMPLES, 0.5f, .0f, .0f)).xy;
202
203                ////////////////////
204                //-- add random noise: reflect around random normal vector
205                //-- (affects performance for some reason!)
206
207                if (!USE_OPTIMIZATION ||
208                        (convergence < SSAO_CONVERGENCE_THRESHOLD))
209                {
210                        float2 mynoise = tex2Dlod(noiseTex, float4(IN.texCoord * 4.0f, 0, 0)).xy;
211                        //offset = myreflect(samples[i], mynoise);
212                        //offset = myrotate(samples[i], mynoise.x);
213                        offset = myrotate(ssaoOffset, mynoise.x);
214                }
215                else
216                {
217                        offset = ssaoOffset;
218                }
219               
220                // weight with projected coordinate to reach similar kernel size for near and far
221                const float2 texcoord = IN.texCoord.xy + offset * radius;
222
223                const float4 sampleColor = tex2Dlod(colors, float4(texcoord, .0f, .0f));
224                const float3 samplePos = ReconstructSamplePos(sampleColor.w, texcoord, bl, br, tl, tr);
225               
226
227                ////////////////
228                //-- compute contribution of sample using the direction and angle
229
230                float3 dirSample = samplePos - centerPosition;
231
232                const float minDist = 1e-6f;
233                const float delta = 1e-3f;
234
235                const float lengthToSample = length(dirSample);
236                const float sampleWeight = 1.0f / (lengthToSample + delta);
237
238                dirSample /= max(lengthToSample, minDist); // normalize
239
240
241                // angle between current normal and direction to sample controls AO intensity.
242                const float cosAngle = dot(dirSample, normal);
243
244                // the normal of the current sample
245                const float3 sampleNormal = normalize(tex2Dlod(normalTex, float4(texcoord, 0, 0)).xyz);
246               
247                // angle between current normal and direction to sample controls AO intensity.
248                //const float cosAngle2 = dot(-dirSample, sampleNormal);
249                const float cosAngle2 = .5f + dot(sampleNormal, -normal) * .5f;
250
251                dirSample *= minDist;
252                const float aoContrib = sampleIntensity * sampleWeight;
253
254                //const float aoContrib = (1.0f > lengthToSample) ? occlusionPower(9e-2f, DISTANCE_SCALE + lengthToSample): .0f;
255                //total_ao += max(cosAngle, .0f) * max(cosAngle2, .0f) * aoContrib;
256                total_ao += max(cosAngle, .0f) * cosAngle2 * aoContrib;
257
258                ++ numSamples;
259
260                // check if the samples have been valid in the last frame
261                // only mark sample as invalid if in the last / current frame
262                // they possibly have any influence on the ao
263
264                const float changeFactor = sampleColor.y;
265                const float pixelValid = sampleColor.x;
266
267                // hack:
268                // we check if the sample could have been near enough
269                // to the current pixel or if the angle is small enough
270                // to have any influence in the current or last frame
271#if 1
272                const float tooFarAway = step(0.5f, lengthToSample - changeFactor);
273                const float partlyResetThres = 1.0f;
274
275                if (pixelValid <= partlyResetThres)
276                        validSamples = max(validSamples, pixelValid * (1.0f - tooFarAway) * step(-0.1f, cosAngle));
277                else
278                        validSamples = max(validSamples, pixelValid);
279#endif
280
281#ifdef USE_GTX
282                // we can bail out early and use a minimal #samples)
283                // if some conditions are met as long as the hardware supports it
284                if (numSamples >= MIN_SAMPLES)
285                {
286                        //break;
287                        // if the pixel belongs to a static object and all the samples stay valid in the current frame
288                        if (!isMovingObject && (validSamples < 1.0f) && (convergence > NUM_SAMPLES)) break;
289                        // if the pixel belongs to a dynamic object but the #accumulated samples for this pixel is sufficiently high
290                        // (=> there was no discontinuity recently)
291                        //else if (isMovingObject && (convergence > SSAO_CONVERGENCE_THRESHOLD)) break;
292                        else if (isMovingObject && (convergence > NUM_SAMPLES * 5)) break;
293                }
294#endif
295        }
296
297        // "normalize" ao contribution
298        total_ao /= numSamples;
299
300#if 1
301        // if surface normal perpenticular to view dir, approx. half of the samples will not count
302        // => compensate for this (on the other hand, projected sampling area could be larger!)
303        const float viewCorrection = 1.0f + VIEW_CORRECTION_SCALE * max(dot(viewDir, normal), 0.0f);
304        total_ao *= viewCorrection;
305#endif
306
307        //return float3(total_ao, validSamples, numSamples);
308        return float3(min(1.0f, total_ao), validSamples, numSamples);
309}
310
311//#define TRYOUT
312
313#ifdef TRYOUT
314
315/** The ssao shader returning the an intensity value between 0 and 1.
316        This version of the ssao shader uses the dotproduct between
317        pixel-to-sample direction and sample normal as weight.
318
319    The algorithm works like the following:
320        1) Check in a circular area around the current position.
321        2) Shoot vectors to the positions there, and check the angle to these positions.
322        3) Summing up these angles gives an estimation of the occlusion at the current position.
323*/
324float3 ssao(fragment IN,
325                        sampler2D colors,
326                        sampler2D noiseTex,
327                        sampler2D samples,
328                        float3 normal,
329                        float3 centerPosition,
330                        float radius,
331                        float3 bl,
332                        float3 br,
333                        float3 tl,
334                        float3 tr,
335                        float3 viewDir,
336                        float convergence,
337                        float sampleIntensity,
338                        bool isMovingObject,
339                        float oldIdx
340                        )
341{
342        float total_ao = .0f;
343        float validSamples = .0f;
344        float numSamples = .0f;
345
346        for (int i = 0; i < NUM_SAMPLES; ++ i)
347        {
348                float2 offset;
349
350                const float2 ssaoOffset =
351                        tex2Dlod(samples, float4((0.5f + i + oldIdx) / NUM_PRECOMPUTED_SAMPLES, 0.5f, .0f, .0f)).xy;
352
353
354                ////////////////////
355                //-- add random noise: reflect around random normal vector
356                //-- (affects performance for some reason!)
357
358                if (!USE_OPTIMIZATION ||
359                        (convergence < SSAO_CONVERGENCE_THRESHOLD))
360                {
361                        float2 mynoise = tex2Dlod(noiseTex, float4(IN.texCoord * 4.0f, 0, 0)).xy;
362                        //offset = myreflect(samples[i], mynoise);
363                        //offset = myrotate(samples[i], mynoise.x);
364                        offset = myrotate(ssaoOffset, mynoise.x);
365                }
366                else
367                {
368                        offset = ssaoOffset;
369                }
370
371
372                // weight with projected coordinate to reach similar kernel size for near and far
373                const float2 texcoord = IN.texCoord.xy + offset * radius;
374
375                const float4 sampleColor = tex2Dlod(colors, float4(texcoord, .0f, .0f));
376                const float3 samplePos = ReconstructSamplePos(sampleColor.w, texcoord, bl, br, tl, tr);
377               
378
379                ////////////////
380                //-- compute contribution of sample using the direction and angle
381
382                float3 dirSample = samplePos - centerPosition;
383
384                const float minDist = 1e-6f;
385                const float eps = 1e-3f;
386
387                const float lengthToSample = length(dirSample);
388                const float sampleWeight = 1.0f / max(lengthToSample, eps);
389
390                dirSample /= max(length(dirSample), minDist); // normalize
391
392                // angle between current normal and direction to sample controls AO intensity.
393                const float cosAngle = dot(dirSample, normal);
394
395                //const float aoContrib = sampleIntensity / sqrLen;
396                const float aoContrib = sampleIntensity * sampleWeight;
397                //const float aoContrib = (1.0f > lengthToSample) ? occlusionPower(9e-2f, DISTANCE_SCALE + lengthToSample): .0f;
398
399                total_ao += max(cosAngle, .0f) * aoContrib;
400
401                ++ numSamples;
402
403#ifdef PERFORMANCE_TEST
404                // check if the samples have been valid in the last frame
405                // only mark sample as invalid if in the last / current frame
406                // they possibly have any influence on the AO
407
408                const float changeFactor = sampleColor.y;
409                const float pixelValid = sampleColor.x;
410
411                // hack:
412                // we check if the sample could have been near enough to the current pixel
413                // or if the angle is small enough
414                // to have any influence in the current or last frame
415
416#if 1
417                const float partlyResetThres = 1.0f;
418
419                const float tooFarAway = step(.5f, lengthToSample - changeFactor);
420                if (0)//pixelValid <= partlyResetThres)
421                        validSamples = max(validSamples, pixelValid * (1.0f - tooFarAway) * step(-0.1f, cosAngle));
422                else
423                        validSamples = max(validSamples, pixelValid);
424#endif
425
426#ifdef USE_GTX
427                // we can bail out early and use a minimal #samples)
428                // if some conditions are met as long as the hardware supports it
429                if (numSamples >= MIN_SAMPLES)
430                {
431                        //break;
432                        // if the pixel belongs to a static object and all the samples stay valid in the current frame
433                        if (!isMovingObject && (validSamples < 1.0f) && (convergence > NUM_SAMPLES)) break;
434                        // if the pixel belongs to a dynamic object but the #accumulated samples for this pixel is sufficiently high
435                        // (=> there was no discontinuity recently)
436                        //else if (isMovingObject && (convergence > SSAO_CONVERGENCE_THRESHOLD)) break;
437                        else if (isMovingObject && (convergence > NUM_SAMPLES * 5)) break;
438                }
439#endif
440
441#endif // PERFORMANCE_TEST
442        }
443
444        // "normalize" ao contribution
445        total_ao /= numSamples;
446
447#if 1
448        // if surface normal perpenticular to view dir, approx. half of the samples will not count
449        // => compensate for this (on the other hand, projected sampling area could be larger!)
450        const float viewCorrection = 1.0f + VIEW_CORRECTION_SCALE * max(dot(viewDir, normal), 0.0f);
451        total_ao *= viewCorrection;
452#endif
453
454        //return float3(total_ao, validSamples, numSamples);
455        return float3(min(1.0f, total_ao), validSamples, numSamples);
456}
457
458#else
459
460float3 ssao(fragment IN,
461                        sampler2D colors,
462                        sampler2D noiseTex,
463                        sampler2D samples,
464                        float3 normal,
465                        float3 centerPosition,
466                        float radius,
467                        float3 bl,
468                        float3 br,
469                        float3 tl,
470                        float3 tr,
471                        float3 viewDir,
472                        float convergence,
473                        float sampleIntensity,
474                        bool isMovingObject,
475                        float oldIdx,
476                        sampler2D attribsTex
477                        )
478{
479        float total_ao = .0f;
480        float validSamples = .0f;
481        float numSamples = .0f;
482
483        float3 diffVec = tex2Dlod(attribsTex, float4(IN.texCoord, 0, 0)).xyz;
484
485        for (int i = 0; i < NUM_SAMPLES; ++ i)
486        {
487                float2 offset;
488
489                const float2 ssaoOffset =
490                        tex2Dlod(samples, float4((0.5f + i + oldIdx) / NUM_PRECOMPUTED_SAMPLES, .5f, .0f, .0f)).xy;
491
492
493                ////////////////////
494                //-- add random noise: reflect around random normal vector
495                //-- (affects performance for some reason!)
496
497                if (!USE_OPTIMIZATION ||
498                        (convergence < SSAO_CONVERGENCE_THRESHOLD))
499                {
500                        float2 mynoise = tex2Dlod(noiseTex, float4(IN.texCoord * 4.0f, 0, 0)).xy;
501                        //offset = myreflect(samples[i], mynoise);
502                        //offset = myrotate(samples[i], mynoise.x);
503                        offset = myrotate(ssaoOffset, mynoise.x);
504                }
505                else
506                {
507                        offset = ssaoOffset;
508                }
509
510
511                // weight with projected coordinate to reach similar kernel size for near and far
512                const float2 texcoord = IN.texCoord.xy + offset * radius;
513
514                const float4 sampleColor = tex2Dlod(colors, float4(texcoord, .0f, .0f));
515                const float3 samplePos = ReconstructSamplePos(sampleColor.w, texcoord, bl, br, tl, tr);
516               
517               
518
519                ////////////////
520                //-- compute contribution of sample using the direction and angle
521
522                float3 dirSample = samplePos - centerPosition;
523
524                const float minDist = 1e-6f;
525                const float eps = 1e-3f;
526
527                const float lengthToSample = length(dirSample);
528                const float sampleWeight = 1.0f / max(lengthToSample, eps);
529
530                dirSample /= max(length(dirSample), minDist); // normalize
531
532                // angle between current normal and direction to sample controls AO intensity.
533                const float cosAngle = dot(dirSample, normal);
534
535                //const float aoContrib = sampleIntensity / sqrLen;
536                const float aoContrib = sampleIntensity * sampleWeight;
537                //const float aoContrib = (1.0f > lengthToSample) ? occlusionPower(9e-2f, DISTANCE_SCALE + lengthToSample): .0f;
538
539                total_ao += max(cosAngle, .0f) * aoContrib;
540
541                ++ numSamples;
542
543
544//#ifdef PERFORMANCE_TEST
545#if 1
546                // check if the samples have been valid in the last frame
547                // only mark sample as invalid if in the last / current frame
548                // they possibly have any influence on the ao
549
550                if (cosAngle > 0)
551                {
552                        float pixelValid = sampleColor.x;
553
554                        if (1)//pixelValid < 0.5f)
555                        {
556                                const float3 sampleDiffVec = tex2Dlod(attribsTex, float4(texcoord, .0f, .0f)).xyz;
557                                pixelValid = max(pixelValid, length(sampleDiffVec - diffVec) < 5e-3f ? .0f : 10.0f);
558                                //pixelValid = length(sampleDiffVec - diffVec) < 1e-3f ? .0f : 10.0f;
559                        }
560
561                        // hack:
562                        // we check if the sample could have been near enough to the current pixel
563                        // or if the angle is small enough
564                        // to have any influence in the current or last frame
565
566                        const float changeFactor = sampleColor.y;
567                        const float partlyResetThres = 1.0f;
568
569                        if (0)//pixelValid <= partlyResetThres)
570                        {
571                                const float tooFarAway = step(0.5f, lengthToSample - changeFactor);
572                                validSamples = max(validSamples, pixelValid * (1.0f - tooFarAway) * step(-0.1f, cosAngle));
573                        }
574                        else
575                        {
576                                validSamples = max(validSamples, pixelValid);
577                        }
578                }
579#ifdef USE_GTX
580                // we can bail out early and use a minimal #samples)
581                // if some conditions are met as long as the hardware supports it
582                if (numSamples >= MIN_SAMPLES)
583                {
584                        //break;
585                        // if the pixel belongs to a static object and all the samples stay valid in the current frame
586                        if (!isMovingObject && (validSamples < 1.0f) && (convergence > NUM_SAMPLES)) break;
587                        // if the pixel belongs to a dynamic object but the #accumulated samples for this pixel is sufficiently high
588                        // (=> there was no discontinuity recently)
589                        //else if (isMovingObject && (convergence > SSAO_CONVERGENCE_THRESHOLD)) break;
590                        else if (isMovingObject && (convergence > NUM_SAMPLES * 5)) break;
591                }
592#endif
593
594#endif // PERFORMANCE_TEST
595        }
596
597        // "normalize" ao contribution
598        total_ao /= numSamples;
599
600#if 1
601        // if surface normal perpenticular to view dir, approx. half of the samples will not count
602        // => compensate for this (on the other hand, projected sampling area could be larger!)
603        const float viewCorrection = 1.0f + VIEW_CORRECTION_SCALE * max(dot(viewDir, normal), 0.0f);
604        total_ao *= viewCorrection;
605#endif
606
607        //return float3(total_ao, validSamples, numSamples);
608        return float3(min(1.0f, total_ao), validSamples, numSamples);
609}
610#endif
611
612
613/** The mrt shader for screen space ambient occlusion
614*/
615pixel2 main(fragment IN,
616                        uniform sampler2D colors,
617                        uniform sampler2D normals,
618                        uniform sampler2D noiseTex,
619                        uniform sampler2D samples,
620                        uniform sampler2D oldTex,
621                        uniform float4x4 modelViewProj,
622                        uniform float4x4 oldModelViewProj,
623                        uniform float temporalCoherence,
624                        uniform float3 bl,
625                        uniform float3 br,
626                        uniform float3 tl,
627                        uniform float3 tr,
628                        uniform float3 oldEyePos,
629                        uniform float3 oldbl,
630                        uniform float3 oldbr,
631                        uniform float3 oldtl,
632                        uniform float3 oldtr,
633                        uniform sampler2D attribsTex,
634                        uniform float kernelRadius,
635                        uniform float sampleIntensity
636                        )
637{
638        pixel2 OUT;
639
640        //const float3 normal = normalize(tex2Dlod(normals, float4(IN.texCoord, 0 ,0)).xyz);
641        const float3 normal = tex2Dlod(normals, float4(IN.texCoord, 0 ,0)).xyz;
642
643        // reconstruct position from the eye space depth
644        const float3 viewDir = IN.view;
645        const float eyeSpaceDepth = tex2Dlod(colors, float4(IN.texCoord, 0, 0)).w;
646        const float4 eyeSpacePos = float4(-viewDir * eyeSpaceDepth, 1.0f);
647
648
649        ////////////////
650        //-- calculcate the current projected posiion (also used for next frame)
651       
652        float4 projPos = mul(modelViewProj, eyeSpacePos);
653        const float invw = 1.0f / projPos.w;
654        projPos *= invw;
655       
656        //const float radiusMult = kernelRadius;
657        //const float radiusMult = 3e-2;
658        const float radiusMult = kernelRadius * invw;
659       
660#ifdef PERFORMANCE_TEST
661
662        float3 diffVec = tex2Dlod(attribsTex, float4(IN.texCoord, 0, 0)).xyz;
663
664        const float sqrMoveSpeed = SqrLen(diffVec);
665        const bool isMovingObject = (sqrMoveSpeed > DYNAMIC_OBJECTS_THRESHOLD);
666
667       
668        /////////////////
669        //-- compute temporal reprojection
670
671        float3 temporalVals = Reproject(eyeSpacePos, eyeSpaceDepth, IN.texCoord, oldEyePos,
672                                        oldTex, oldModelViewProj,
673                                                                        colors,
674                                                                        projPos.xyz,
675                                                                        invw,
676                                                                        oldbl, oldbr, oldtl, oldtr,
677                                                                        diffVec
678                                                                        );
679       
680        const float oldSsao = temporalVals.x;
681       
682        float oldWeight = temporalVals.y;
683        float oldIdx = temporalCoherence > 1 ? temporalVals.z : 0;
684        //float oldIdx = temporalVals.z;
685       
686#else
687
688        const float3 diffVec = float3(.0f);
689        const bool isMovingObject = false;
690        const float oldSsao = .0f;
691       
692        float oldWeight = .0f;
693        float oldIdx    = .0f;
694       
695#endif
696
697        float3 ao;
698
699        // cull background note: this should be done with the stencil buffer
700        if (eyeSpaceDepth < DEPTH_THRESHOLD)
701        {
702                if (1)
703                {
704#ifdef TRYOUT
705                        ao = ssao(IN, colors, noiseTex, samples, normal, eyeSpacePos.xyz,
706                                      radiusMult, bl, br, tl, tr, normalize(viewDir),
707                                          oldWeight, sampleIntensity, isMovingObject, oldIdx);
708#else
709
710                          ao = ssao(IN, colors, noiseTex, samples,
711                                      normal, eyeSpacePos.xyz, radiusMult, bl,
712                                          br, tl, tr, normalize(viewDir),
713                                          oldWeight, sampleIntensity, isMovingObject, oldIdx,
714                                          attribsTex);
715#endif                           
716                }
717                else
718                {
719                        /*ao = ssao2(IN, colors, noiseTex, samples, normal, eyeSpacePos.xyz, radiusMult,
720                                   bl, br, tl, tr, normalize(viewDir), oldWeight, sampleIntensity,
721                                           isMovingObject, normals, oldIdx);
722                                           */
723                }
724        }
725        else
726        {
727                 ao = float3(1.0f);
728        }
729
730
731#ifdef PERFORMANCE_TEST
732
733        ///////////
734        //-- check if we have to reset pixel because one of the sample points was invalid
735        //-- only do this if the current pixel does not belong to a moving object
736
737        // the weight equals the number of sampled shot in this pass
738        const float newWeight = ao.z;
739        // completely reset the ao in this pixel
740        const float completelyResetThres = 20.0f;
741        // don't fully reset the ao in this pixel, but give low weight to old solution
742        const float partlyResetThres = 1.0f;
743       
744        // don't check for moving objects, otherwise almost no coherence
745        if (1)//!isMovingObject)
746        {
747                if (ao.y > completelyResetThres)
748                {
749                        oldWeight = .0f;
750                        oldIdx    = .0f;
751                }
752                else if (ao.y > partlyResetThres)
753                {
754                        const float factor = 4.0f;
755                        //if (oldIdx >= factor * newWeight) oldIdx = 0;
756                        oldWeight = min(oldWeight, factor * newWeight);
757                        oldWeight = oldIdx = .0f;
758                }
759        }
760
761
762        //////////
763        //-- blend ao between old and new samples (and avoid division by zero)
764
765        OUT.illum_col.x = ao.x * newWeight + oldSsao * oldWeight;
766        OUT.illum_col.x /= (newWeight + oldWeight);
767        //OUT.illum_col.x = clamp(OUT.illum_col.x, 0, 1);
768        //OUT.illum_col.x = ao.y;
769
770        // the new weight for the next frame
771        const float combinedWeight = clamp(newWeight + oldWeight, .0f, temporalCoherence);
772
773        OUT.illum_col.y = combinedWeight;
774        OUT.illum_col.z = oldIdx + newWeight; // the new index
775        OUT.illum_col.w = eyeSpaceDepth;
776
777        // this value can be used to check if this pixel belongs to a moving object
778        OUT.col.x = SqrLen(diffVec);
779        //OUT.illum_col.z = SqrLen(diffVec);
780
781#else
782
783        OUT.illum_col.x = ao.x;
784        OUT.illum_col.w = eyeSpaceDepth;
785       
786#endif
787
788        return OUT;
789}
Note: See TracBrowser for help on using the repository browser.