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

Revision 3361, 24.2 KB checked in by mattausch, 15 years ago (diff)
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 (convergence < SSAO_CONVERGENCE_THRESHOLD)
208                {
209                        float2 mynoise = tex2Dlod(noiseTex, float4(IN.texCoord * 4.0f, 0, 0)).xy;
210                        //offset = myreflect(samples[i], mynoise);
211                        //offset = myrotate(samples[i], mynoise.x);
212                        offset = myrotate(ssaoOffset, mynoise.x);
213                }
214                else
215                {
216                        offset = ssaoOffset;
217                }
218               
219                // weight with projected coordinate to reach similar kernel size for near and far
220                const float2 texcoord = IN.texCoord.xy + offset * radius;
221
222                const float4 sampleColor = tex2Dlod(colors, float4(texcoord, .0f, .0f));
223                const float3 samplePos = ReconstructSamplePos(sampleColor.w, texcoord, bl, br, tl, tr);
224               
225
226                ////////////////
227                //-- compute contribution of sample using the direction and angle
228
229                float3 dirSample = samplePos - centerPosition;
230
231                const float minDist = 1e-6f;
232                const float delta = 1e-3f;
233
234                const float lengthToSample = length(dirSample);
235                const float sampleWeight = 1.0f / (lengthToSample + delta);
236
237                dirSample /= max(lengthToSample, minDist); // normalize
238
239
240                // angle between current normal and direction to sample controls AO intensity.
241                const float cosAngle = dot(dirSample, normal);
242
243                // the normal of the current sample
244                const float3 sampleNormal = normalize(tex2Dlod(normalTex, float4(texcoord, 0, 0)).xyz);
245               
246                // angle between current normal and direction to sample controls AO intensity.
247                //const float cosAngle2 = dot(-dirSample, sampleNormal);
248                const float cosAngle2 = .5f + dot(sampleNormal, -normal) * .5f;
249
250                dirSample *= minDist;
251                const float aoContrib = sampleIntensity * sampleWeight;
252
253                //const float aoContrib = (1.0f > lengthToSample) ? occlusionPower(9e-2f, DISTANCE_SCALE + lengthToSample): .0f;
254                //total_ao += max(cosAngle, .0f) * max(cosAngle2, .0f) * aoContrib;
255                total_ao += max(cosAngle, .0f) * cosAngle2 * aoContrib;
256
257                ++ numSamples;
258
259                // check if the samples have been valid in the last frame
260                // only mark sample as invalid if in the last / current frame
261                // they possibly have any influence on the ao
262
263                const float changeFactor = sampleColor.y;
264                const float pixelValid = sampleColor.x;
265
266                // hack:
267                // we check if the sample could have been near enough
268                // to the current pixel or if the angle is small enough
269                // to have any influence in the current or last frame
270#if 1
271                const float tooFarAway = step(0.5f, lengthToSample - changeFactor);
272                const float partlyResetThres = 1.0f;
273
274                if (pixelValid <= partlyResetThres)
275                        validSamples = max(validSamples, pixelValid * (1.0f - tooFarAway) * step(-0.1f, cosAngle));
276                else
277                        validSamples = max(validSamples, pixelValid);
278#endif
279
280#ifdef USE_GTX
281                // we can bail out early and use a minimal #samples)
282                // if some conditions are met as long as the hardware supports it
283                if (numSamples >= MIN_SAMPLES)
284                {
285                        //break;
286                        // if the pixel belongs to a static object and all the samples stay valid in the current frame
287                        if (!isMovingObject && (validSamples < 1.0f) && (convergence > NUM_SAMPLES)) break;
288                        // if the pixel belongs to a dynamic object but the #accumulated samples for this pixel is sufficiently high
289                        // (=> there was no discontinuity recently)
290                        //else if (isMovingObject && (convergence > SSAO_CONVERGENCE_THRESHOLD)) break;
291                        else if (isMovingObject && (convergence > NUM_SAMPLES * 5)) break;
292                }
293#endif
294        }
295
296        // "normalize" ao contribution
297        total_ao /= numSamples;
298
299#if 1
300        // if surface normal perpenticular to view dir, approx. half of the samples will not count
301        // => compensate for this (on the other hand, projected sampling area could be larger!)
302        const float viewCorrection = 1.0f + VIEW_CORRECTION_SCALE * max(dot(viewDir, normal), 0.0f);
303        total_ao *= viewCorrection;
304#endif
305
306        //return float3(total_ao, validSamples, numSamples);
307        return float3(min(1.0f, total_ao), validSamples, numSamples);
308}
309
310//#define TRYOUT
311
312#ifdef TRYOUT
313
314/** The ssao shader returning the an intensity value between 0 and 1.
315        This version of the ssao shader uses the dotproduct between
316        pixel-to-sample direction and sample normal as weight.
317
318    The algorithm works like the following:
319        1) Check in a circular area around the current position.
320        2) Shoot vectors to the positions there, and check the angle to these positions.
321        3) Summing up these angles gives an estimation of the occlusion at the current position.
322*/
323float3 ssao(fragment IN,
324                        sampler2D colors,
325                        sampler2D noiseTex,
326                        sampler2D samples,
327                        float3 normal,
328                        float3 centerPosition,
329                        float radius,
330                        float3 bl,
331                        float3 br,
332                        float3 tl,
333                        float3 tr,
334                        float3 viewDir,
335                        float convergence,
336                        float sampleIntensity,
337                        bool isMovingObject,
338                        float oldIdx
339                        )
340{
341        float total_ao = .0f;
342        float validSamples = .0f;
343        float numSamples = .0f;
344
345        for (int i = 0; i < NUM_SAMPLES; ++ i)
346        {
347                float2 offset;
348
349                const float2 ssaoOffset =
350                        tex2Dlod(samples, float4((0.5f + i + oldIdx) / NUM_PRECOMPUTED_SAMPLES, 0.5f, .0f, .0f)).xy;
351
352
353                ////////////////////
354                //-- add random noise: reflect around random normal vector
355                //-- (affects performance for some reason!)
356
357                if (convergence < SSAO_CONVERGENCE_THRESHOLD)
358                {
359                        float2 mynoise = tex2Dlod(noiseTex, float4(IN.texCoord * 4.0f, 0, 0)).xy;
360                        //offset = myreflect(samples[i], mynoise);
361                        //offset = myrotate(samples[i], mynoise.x);
362                        offset = myrotate(ssaoOffset, mynoise.x);
363                }
364                else
365                {
366                        offset = ssaoOffset;
367                }
368
369
370                // weight with projected coordinate to reach similar kernel size for near and far
371                const float2 texcoord = IN.texCoord.xy + offset * radius;
372
373                const float4 sampleColor = tex2Dlod(colors, float4(texcoord, .0f, .0f));
374                const float3 samplePos = ReconstructSamplePos(sampleColor.w, texcoord, bl, br, tl, tr);
375               
376
377                ////////////////
378                //-- compute contribution of sample using the direction and angle
379
380                float3 dirSample = samplePos - centerPosition;
381
382                const float minDist = 1e-6f;
383                const float eps = 1e-3f;
384
385                const float lengthToSample = length(dirSample);
386                const float sampleWeight = 1.0f / max(lengthToSample, eps);
387
388                dirSample /= max(length(dirSample), minDist); // normalize
389
390                // angle between current normal and direction to sample controls AO intensity.
391                const float cosAngle = dot(dirSample, normal);
392
393                //const float aoContrib = sampleIntensity / sqrLen;
394                const float aoContrib = sampleIntensity * sampleWeight;
395                //const float aoContrib = (1.0f > lengthToSample) ? occlusionPower(9e-2f, DISTANCE_SCALE + lengthToSample): .0f;
396
397                total_ao += max(cosAngle, .0f) * aoContrib;
398
399                ++ numSamples;
400
401#ifdef PERFORMANCE_TEST
402                // check if the samples have been valid in the last frame
403                // only mark sample as invalid if in the last / current frame
404                // they possibly have any influence on the AO
405
406                const float changeFactor = sampleColor.y;
407                const float pixelValid = sampleColor.x;
408
409                // hack:
410                // we check if the sample could have been near enough to the current pixel
411                // or if the angle is small enough
412                // to have any influence in the current or last frame
413
414#if 1
415                const float partlyResetThres = 1.0f;
416
417                const float tooFarAway = step(.5f, lengthToSample - changeFactor);
418                if (0)//pixelValid <= partlyResetThres)
419                        validSamples = max(validSamples, pixelValid * (1.0f - tooFarAway) * step(-0.1f, cosAngle));
420                else
421                        validSamples = max(validSamples, pixelValid);
422#endif
423
424#ifdef USE_GTX
425                // we can bail out early and use a minimal #samples)
426                // if some conditions are met as long as the hardware supports it
427                if (numSamples >= MIN_SAMPLES)
428                {
429                        //break;
430                        // if the pixel belongs to a static object and all the samples stay valid in the current frame
431                        if (!isMovingObject && (validSamples < 1.0f) && (convergence > NUM_SAMPLES)) break;
432                        // if the pixel belongs to a dynamic object but the #accumulated samples for this pixel is sufficiently high
433                        // (=> there was no discontinuity recently)
434                        //else if (isMovingObject && (convergence > SSAO_CONVERGENCE_THRESHOLD)) break;
435                        else if (isMovingObject && (convergence > NUM_SAMPLES * 5)) break;
436                }
437#endif
438
439#endif // PERFORMANCE_TEST
440        }
441
442        // "normalize" ao contribution
443        total_ao /= numSamples;
444
445#if 1
446        // if surface normal perpenticular to view dir, approx. half of the samples will not count
447        // => compensate for this (on the other hand, projected sampling area could be larger!)
448        const float viewCorrection = 1.0f + VIEW_CORRECTION_SCALE * max(dot(viewDir, normal), 0.0f);
449        total_ao *= viewCorrection;
450#endif
451
452        //return float3(total_ao, validSamples, numSamples);
453        return float3(min(1.0f, total_ao), validSamples, numSamples);
454}
455
456#else
457
458float3 ssao(fragment IN,
459                        sampler2D colors,
460                        sampler2D noiseTex,
461                        sampler2D samples,
462                        float3 normal,
463                        float3 centerPosition,
464                        float radius,
465                        float3 bl,
466                        float3 br,
467                        float3 tl,
468                        float3 tr,
469                        float3 viewDir,
470                        float convergence,
471                        float sampleIntensity,
472                        bool isMovingObject,
473                        float oldIdx,
474                        sampler2D attribsTex
475                        )
476{
477        float total_ao = .0f;
478        float validSamples = .0f;
479        float numSamples = .0f;
480
481        float3 diffVec = tex2Dlod(attribsTex, float4(IN.texCoord, 0, 0)).xyz;
482
483        for (int i = 0; i < NUM_SAMPLES; ++ i)
484        {
485                float2 offset;
486
487                const float2 ssaoOffset =
488                        tex2Dlod(samples, float4((0.5f + i + oldIdx) / NUM_PRECOMPUTED_SAMPLES, .5f, .0f, .0f)).xy;
489
490
491                ////////////////////
492                //-- add random noise: reflect around random normal vector
493                //-- (affects performance for some reason!)
494
495                if (convergence < SSAO_CONVERGENCE_THRESHOLD)
496                {
497                        float2 mynoise = tex2Dlod(noiseTex, float4(IN.texCoord * 4.0f, 0, 0)).xy;
498                        //offset = myreflect(samples[i], mynoise);
499                        //offset = myrotate(samples[i], mynoise.x);
500                        offset = myrotate(ssaoOffset, mynoise.x);
501                }
502                else
503                {
504                        offset = ssaoOffset;
505                }
506
507
508                // weight with projected coordinate to reach similar kernel size for near and far
509                const float2 texcoord = IN.texCoord.xy + offset * radius;
510
511                const float4 sampleColor = tex2Dlod(colors, float4(texcoord, .0f, .0f));
512                const float3 samplePos = ReconstructSamplePos(sampleColor.w, texcoord, bl, br, tl, tr);
513               
514               
515
516                ////////////////
517                //-- compute contribution of sample using the direction and angle
518
519                float3 dirSample = samplePos - centerPosition;
520
521                const float minDist = 1e-6f;
522                const float eps = 1e-3f;
523
524                const float lengthToSample = length(dirSample);
525                const float sampleWeight = 1.0f / max(lengthToSample, eps);
526
527                dirSample /= max(length(dirSample), minDist); // normalize
528
529                // angle between current normal and direction to sample controls AO intensity.
530                const float cosAngle = dot(dirSample, normal);
531
532                //const float aoContrib = sampleIntensity / sqrLen;
533                const float aoContrib = sampleIntensity * sampleWeight;
534                //const float aoContrib = (1.0f > lengthToSample) ? occlusionPower(9e-2f, DISTANCE_SCALE + lengthToSample): .0f;
535
536                total_ao += max(cosAngle, .0f) * aoContrib;
537
538                ++ numSamples;
539
540
541#ifdef PERFORMANCE_TEST
542                // check if the samples have been valid in the last frame
543                // only mark sample as invalid if in the last / current frame
544                // they possibly have any influence on the ao
545
546                //const float pixelValid = sampleColor.x;
547                //const float pixelValid = length(sampleDiffVec - diffVec) < 1e-3f ? .0f : 10.0f;
548                //float pixelValid = max(sampleColor.x, length(sampleDiffVec - diffVec) < 1e-3f ? .0f : 10.0f);
549                float pixelValid = sampleColor.x;
550
551                if (pixelValid < 1)
552                {
553                        const float3 sampleDiffVec = tex2Dlod(attribsTex, float4(texcoord, .0f, .0f)).xyz;
554                        pixelValid = length(sampleDiffVec - diffVec) < 1e-3f ? .0f : 10.0f;
555                }
556
557                // hack:
558                // we check if the sample could have been near enough to the current pixel
559                // or if the angle is small enough
560                // to have any influence in the current or last frame
561
562#if 1
563                const float changeFactor = sampleColor.y;
564                const float partlyResetThres = 1.0f;
565
566                if (0)//pixelValid <= partlyResetThres)
567                {
568                        const float tooFarAway = step(0.5f, lengthToSample - changeFactor);
569                        validSamples = max(validSamples, pixelValid * (1.0f - tooFarAway) * step(-0.1f, cosAngle));
570                }
571                else
572                {
573                        validSamples = max(validSamples, pixelValid);
574                }
575#endif
576
577#ifdef USE_GTX
578                // we can bail out early and use a minimal #samples)
579                // if some conditions are met as long as the hardware supports it
580                if (numSamples >= MIN_SAMPLES)
581                {
582                        //break;
583                        // if the pixel belongs to a static object and all the samples stay valid in the current frame
584                        if (!isMovingObject && (validSamples < 1.0f) && (convergence > NUM_SAMPLES)) break;
585                        // if the pixel belongs to a dynamic object but the #accumulated samples for this pixel is sufficiently high
586                        // (=> there was no discontinuity recently)
587                        //else if (isMovingObject && (convergence > SSAO_CONVERGENCE_THRESHOLD)) break;
588                        else if (isMovingObject && (convergence > NUM_SAMPLES * 5)) break;
589                }
590#endif
591
592#endif // PERFORMANCE_TEST
593        }
594
595        // "normalize" ao contribution
596        total_ao /= numSamples;
597
598#if 1
599        // if surface normal perpenticular to view dir, approx. half of the samples will not count
600        // => compensate for this (on the other hand, projected sampling area could be larger!)
601        const float viewCorrection = 1.0f + VIEW_CORRECTION_SCALE * max(dot(viewDir, normal), 0.0f);
602        total_ao *= viewCorrection;
603#endif
604
605        //return float3(total_ao, validSamples, numSamples);
606        return float3(min(1.0f, total_ao), validSamples, numSamples);
607}
608#endif
609
610
611/** The mrt shader for screen space ambient occlusion
612*/
613pixel2 main(fragment IN,
614                        uniform sampler2D colors,
615                        uniform sampler2D normals,
616                        uniform sampler2D noiseTex,
617                        uniform sampler2D samples,
618                        uniform sampler2D oldTex,
619                        uniform float4x4 modelViewProj,
620                        uniform float4x4 oldModelViewProj,
621                        uniform float temporalCoherence,
622                        uniform float3 bl,
623                        uniform float3 br,
624                        uniform float3 tl,
625                        uniform float3 tr,
626                        uniform float3 oldEyePos,
627                        uniform float3 oldbl,
628                        uniform float3 oldbr,
629                        uniform float3 oldtl,
630                        uniform float3 oldtr,
631                        uniform sampler2D attribsTex,
632                        uniform float kernelRadius,
633                        uniform float sampleIntensity
634                        )
635{
636        pixel2 OUT;
637
638        //const float3 normal = normalize(tex2Dlod(normals, float4(IN.texCoord, 0 ,0)).xyz);
639        const float3 normal = tex2Dlod(normals, float4(IN.texCoord, 0 ,0)).xyz;
640
641        // reconstruct position from the eye space depth
642        const float3 viewDir = IN.view;
643        const float eyeSpaceDepth = tex2Dlod(colors, float4(IN.texCoord, 0, 0)).w;
644        const float4 eyeSpacePos = float4(-viewDir * eyeSpaceDepth, 1.0f);
645
646
647        ////////////////
648        //-- calculcate the current projected posiion (also used for next frame)
649       
650        float4 projPos = mul(modelViewProj, eyeSpacePos);
651        const float invw = 1.0f / projPos.w;
652        projPos *= invw;
653       
654        //const float radiusMult = kernelRadius;
655        //const float radiusMult = 3e-2;
656        const float radiusMult = kernelRadius * invw;
657       
658#ifdef PERFORMANCE_TEST
659        float3 diffVec = tex2Dlod(attribsTex, float4(IN.texCoord, 0, 0)).xyz;
660
661        const float sqrMoveSpeed = SqrLen(diffVec);
662        const bool isMovingObject = (sqrMoveSpeed > DYNAMIC_OBJECTS_THRESHOLD);
663
664       
665        /////////////////
666        //-- compute temporal reprojection
667
668        float3 temporalVals = Reproject(eyeSpacePos, eyeSpaceDepth, IN.texCoord, oldEyePos,
669                                        oldTex, oldModelViewProj,
670                                                                        colors,
671                                                                        projPos.xyz,
672                                                                        invw,
673                                                                        oldbl, oldbr, oldtl, oldtr,
674                                                                        diffVec
675                                                                        );
676       
677        const float oldSsao = temporalVals.x;
678       
679        float oldWeight = temporalVals.y;
680        float oldIdx = temporalCoherence > 1 ? temporalVals.z : 0;
681        //float oldIdx = temporalVals.z;
682       
683#else
684
685        const float3 diffVec = float3(.0f);
686        const bool isMovingObject = false;
687        const float oldSsao = .0f;
688       
689        float oldWeight = .0f;
690        float oldIdx    = .0f;
691       
692#endif
693
694        float3 ao;
695
696        // cull background note: this should be done with the stencil buffer
697        if (eyeSpaceDepth < DEPTH_THRESHOLD)
698        {
699                if (1)
700                {
701#ifdef TRYOUT
702                        ao = ssao(IN, colors, noiseTex, samples, normal, eyeSpacePos.xyz,
703                                      radiusMult, bl, br, tl, tr, normalize(viewDir),
704                                          oldWeight, sampleIntensity, isMovingObject, oldIdx);
705#else
706
707                          ao = ssao(IN, colors, noiseTex, samples,
708                                      normal, eyeSpacePos.xyz, radiusMult, bl,
709                                          br, tl, tr, normalize(viewDir),
710                                          oldWeight, sampleIntensity, isMovingObject, oldIdx,
711                                          attribsTex);
712#endif                           
713                }
714                else
715                {
716                        /*ao = ssao2(IN, colors, noiseTex, samples, normal, eyeSpacePos.xyz, radiusMult,
717                                   bl, br, tl, tr, normalize(viewDir), oldWeight, sampleIntensity,
718                                           isMovingObject, normals, oldIdx);
719                                           */
720                }
721        }
722        else
723        {
724                 ao = float3(1.0f);
725        }
726
727
728#ifdef PERFORMANCE_TEST
729
730        ///////////
731        //-- check if we have to reset pixel because one of the sample points was invalid
732        //-- only do this if the current pixel does not belong to a moving object
733
734        // the weight equals the number of sampled shot in this pass
735        const float newWeight = ao.z;
736        // completely reset the ao in this pixel
737        const float completelyResetThres = 20.0f;
738        // don't fully reset the ao in this pixel, but give low weight to old solution
739        const float partlyResetThres = 1.0f;
740       
741        // don't check for moving objects, otherwise almost no coherence
742        if (1)//!isMovingObject)
743        {
744                if (ao.y > completelyResetThres)
745                {
746                        oldWeight = .0f;
747                        oldIdx    = .0f;
748                }
749                else if (ao.y > partlyResetThres)
750                {
751                        const float factor = 4.0f;
752                        oldWeight = min(oldWeight, factor * newWeight);
753                        //oldWeight = .0f;
754                        //oldIdx    = .0f;
755                }
756        }
757
758
759        //////////
760        //-- blend ao between old and new samples (and avoid division by zero)
761
762        OUT.illum_col.x = ao.x * newWeight + oldSsao * oldWeight;
763        OUT.illum_col.x /= (newWeight + oldWeight);
764        //OUT.illum_col.x = clamp(OUT.illum_col.x, 0, 1);
765        //OUT.illum_col.x = ao.y;
766
767        // the new weight for the next frame
768        const float combinedWeight = clamp(newWeight + oldWeight, .0f, temporalCoherence);
769
770        OUT.illum_col.y = combinedWeight;
771        OUT.illum_col.z = oldIdx + newWeight; // the new index
772        OUT.illum_col.w = eyeSpaceDepth;
773
774        // this value can be used to check if this pixel belongs to a moving object
775        OUT.col.x = SqrLen(diffVec);
776        //OUT.illum_col.z = SqrLen(diffVec);
777
778#else
779
780        OUT.illum_col.x = ao.x;
781        OUT.illum_col.w = eyeSpaceDepth;
782       
783#endif
784
785        return OUT;
786}
Note: See TracBrowser for help on using the repository browser.