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

Revision 3144, 12.9 KB checked in by mattausch, 16 years ago (diff)

working on normal mapping

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