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

Revision 3121, 11.7 KB checked in by mattausch, 16 years ago (diff)

reordered ssao function to redcude flikering with one kernel but not working yet

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