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

Revision 3034, 7.4 KB checked in by mattausch, 16 years ago (diff)
RevLine 
[2884]1#include "../shaderenv.h"
2
[2881]3////////////////////
4// Screen Spaced Ambient Occlusion shader
5// based on shader of Alexander Kusternig
6
7
[3006]8#define USE_EYE_SPACE_DEPTH 1
[3001]9
10
[2881]11struct fragment
12{
[2889]13        float2 texCoord: TEXCOORD0;
14        float3 view: TEXCOORD1;
[2881]15};
16
17
18struct pixel
19{
20        float4 illum_col: COLOR0;
21};
22
23
[2990]24inline float2 myreflect(float2 pt, float2 n)
[2881]25{
26        // distance to plane
27        float d = dot(n, pt);
28        // reflect around plane
29        float2 rpt = pt - d * 2.0f * n;
[2886]30
[2881]31        return rpt;
32}
33
34
[2990]35inline float3 Interpol(float2 w, float3 bl, float3 br, float3 tl, float3 tr)
[2986]36{
[2991]37        float3 x1 = lerp(bl, tl, w.y);
38        float3 x2 = lerp(br, tr, w.y);
39        float3 v = lerp(x1, x2, w.x);
[2987]40
41        return v;
42}
43
[2988]44
[2992]45// reconstruct world space position
[3017]46inline float3 ReconstructSamplePos(uniform sampler2D colors,
47                                                                   float2 texcoord,
48                                                                   float3 bl, float3 br, float3 tl, float3 tr)
[2988]49{
[3019]50        //const float eyeSpaceDepth = tex2Dlod(colors, float4(texcoord, 0, 0)).w;
51        const float eyeSpaceDepth = tex2D(colors, texcoord).w;
[3017]52        float3 viewVec = Interpol(texcoord, bl, br, tl, tr);
53        float3 samplePos = -viewVec * eyeSpaceDepth;
54
[2999]55        return samplePos;
[2988]56}
57
58
[2881]59/** The ssao shader returning the an intensity value between 0 and 1
60*/
[2904]61float2 ssao(fragment IN,
[2985]62                   uniform sampler2D colors,
[2881]63                   uniform sampler2D noiseTexture,
64                   uniform float2 samples[NUM_SAMPLES],
65                   uniform float3 currentNormal,
[3006]66                   uniform float3 centerPosition,
[2985]67                   uniform float scaleFactor,
[2986]68                   uniform float3 bl,
69                   uniform float3 br,
70                   uniform float3 tl,
[3017]71                   uniform float3 tr,
72                   uniform float3 viewDir
[2881]73                   )
74{
75        // Check in a circular area around the current position.
76        // Shoot vectors to the positions there, and check the angle to these positions.
77        // Summing up these angles gives an estimation of the occlusion at the current position.
78
79        float total_ao = 0.0;
[2904]80        float numSamples = 0;
[2881]81
[2986]82
[2881]83        for (int i = 0; i < NUM_SAMPLES; ++ i)
84        {
[2892]85                const float2 offset = samples[i];
[2881]86
[2903]87#if 1
[2881]88                ////////////////////
[2903]89                // add random noise: reflect around random normal vector (warning: slow!)
[2985]90
[3017]91                float2 mynoise = tex2D(noiseTexture, IN.texCoord).xy;
[2892]92                const float2 offsetTransformed = myreflect(offset, mynoise);
[2903]93#else
94                const float2 offsetTransformed = offset;
95#endif
[2881]96                // weight with projected coordinate to reach similar kernel size for near and far
[3019]97                const float2 texcoord = IN.texCoord.xy + offsetTransformed * scaleFactor;
[2881]98
[3019]99                //if ((texcoord.x <= 1.0f) && (texcoord.x >= 0.0f) && (texcoord.y <= 1.0f) && (texcoord.y >= 0.0f)) ++ numSamples;
[2904]100
[3017]101                const float3 samplePos = ReconstructSamplePos(colors, texcoord, bl, br, tl, tr);
[2989]102
[2881]103
[3017]104                ////////////////
105                //-- compute contribution of sample using the direction and angle
[2881]106
[3017]107                float3 dirSample = samplePos - centerPosition;
[3019]108                const float magSample = length(dirSample);
109                // normalize
110                dirSample /= magSample;
[2999]111
[2885]112                // angle between current normal and direction to sample controls AO intensity.
[3019]113                const float cosAngle = max(dot(dirSample, currentNormal), 0.0f);
[2881]114
[2979]115                // the distance_scale offset is used to avoid singularity that occurs at global illumination when
116                // the distance to a sample approaches zero
[3019]117                const float intensity = SAMPLE_INTENSITY / (DISTANCE_SCALE + magSample * magSample);
[2881]118
[3017]119#if 1
[2885]120                // if surface normal perpenticular to view dir, approx. half of the samples will not count
121                // => compensate for this (on the other hand, projected sampling area could be larger!)
[3017]122                const float viewCorrection = 1.0f + VIEW_CORRECTION_SCALE * dot(viewDir, currentNormal);
123                total_ao += cosAngle * intensity * viewCorrection;
124#else
125                total_ao += cosAngle * intensity;
[2911]126#endif
[2881]127        }
128
[2904]129        return float2(max(0.0f, 1.0f - total_ao), numSamples);
[2881]130}
131
[3017]132#pragma position_invariant main
[2881]133
134/** The mrt shader for screen space ambient occlusion
135*/
136pixel main(fragment IN,
137                   uniform sampler2D colors,
138                   uniform sampler2D normals,
[3026]139                   uniform sampler2D noise,
[2881]140                   uniform float2 samples[NUM_SAMPLES],
141                   uniform sampler2D oldTex,
142                   const uniform float4x4 oldModelViewProj,
[3004]143                   const uniform float4x4 modelViewProj,
[2985]144                   uniform float temporalCoherence,
[2986]145                   uniform float3 eyePos,
146                   uniform float3 bl,
147                   uniform float3 br,
148                   uniform float3 tl,
[2997]149                   uniform float3 tr
[2881]150                   )
151{
152        pixel OUT;
153
[3006]154        float4 norm = tex2Dlod(normals, float4(IN.texCoord, 0 ,0));
[3017]155        const float3 normal = normalize(norm.xyz);
[2975]156
[2993]157        /// reconstruct position from the eye space depth
[3001]158        float3 viewDir = IN.view;
[3006]159        const float eyeDepth = tex2Dlod(colors, float4(IN.texCoord, 0, 0)).w;
[3014]160        const float3 eyeSpacePos = -viewDir * eyeDepth;
[3034]161        const float4 worldPos = float4(eyePos + eyeSpacePos, 1.0f);
[3014]162
[3001]163
[3017]164        ////////////////
165        //-- calculcate the current projected depth for next frame
166       
[3034]167        float4 currentPos = mul(modelViewProj, worldPos);
[3017]168       
169        const float w = SAMPLE_RADIUS / currentPos.w;
170        currentPos /= currentPos.w;
171       
[3028]172        const float precisionScale = 1e-3f;
173        const float currentDepth = currentPos.z * precisionScale;
[2993]174
[3026]175        const float2 ao = ssao(IN, colors, noise, samples, normal, eyeSpacePos, w, bl, br, tl, tr, normalize(viewDir));
[3005]176
[3000]177
[3005]178        /////////////////
179        //-- compute temporally smoothing
180
181
[3017]182        // reproject new frame into old one
[3004]183       
184        // calculate projected depth
[3034]185        float4 projPos = mul(oldModelViewProj, worldPos);
[3005]186        projPos /= projPos.w;
[3034]187       
[2996]188        // the current depth projected into the old frame
[3028]189        const float projDepth = projPos.z * precisionScale;
[2881]190
[2995]191        // fit from unit cube into 0 .. 1
[3017]192        const float2 tex = projPos.xy * 0.5f + 0.5f;
[2995]193
[3006]194        // retrieve the sample from the last frame
[2881]195        float4 oldCol = tex2D(oldTex, tex);
196
[3017]197        const float oldDepth = oldCol.z;
198        //const float depthDif = 1.0f - projDepth / oldDepth;
199        const float depthDif = projDepth - oldDepth;
[3006]200
201
[3000]202        //const float oldNumSamples = oldCol.y;
[3028]203        const float oldWeight = clamp(oldCol.y, 0, temporalCoherence);
[2881]204
[2897]205        float newWeight;
[2881]206
[2993]207        // the number of valid samples in this frame
[2999]208        //const float newNumSamples = ao.y;
[2982]209
[3026]210        if ((temporalCoherence > 0) &&
[2897]211                (tex.x >= 0.0f) && (tex.x < 1.0f) &&
[2881]212                (tex.y >= 0.0f) && (tex.y < 1.0f) &&
[3009]213                (abs(depthDif) < MIN_DEPTH_DIFF)
[2991]214                // if visibility changed in the surrounding area we have to recompute
[2999]215                //&& (oldNumSamples > 0.8f * newNumSamples)
[2904]216                )
[2881]217        {
[2904]218                // increase the weight for convergence
219                newWeight = oldWeight + 1.0f;
[3017]220                OUT.illum_col.x = (ao.x + oldCol.x * oldWeight) / newWeight;
[2904]221                //if (!(oldNumSamples > ao.y - 1.5f)) newWeight = 0;
[2881]222        }
223        else
[2982]224        {       
[3017]225                OUT.illum_col.x = ao.x;
[2897]226                newWeight = 0;
[2881]227        }
228
[3017]229        OUT.illum_col.y = newWeight;
230        OUT.illum_col.z = currentDepth;
[2880]231
[2881]232        return OUT;
233}
[2880]234
[2881]235
[3017]236float Filter(float2 texCoord,
237                         uniform sampler2D ssaoTex,
238                         uniform float2 filterOffs[NUM_DOWNSAMPLES],
239                         uniform float filterWeights[NUM_DOWNSAMPLES]
240)
241{
242        float average = .0f;
243        float w = .0f;
244
245        for (int i = 0; i < NUM_DOWNSAMPLES; ++ i)
246        {
247                average += filterWeights[i] * tex2Dlod(ssaoTex, float4(texCoord + filterOffs[i], 0, 0)).x;
248                w += filterWeights[i];
249        }
250
251        average *= 1.0f / (float)w;
252
253        return average;
254}
255
256
[2880]257pixel combine(fragment IN,
258                          uniform sampler2D colors,
[3017]259                          uniform sampler2D ssaoTex,
260                          uniform float2 filterOffs[NUM_DOWNSAMPLES],
261                          uniform float filterWeights[NUM_DOWNSAMPLES]
262                          )
[2880]263{
264        pixel OUT;
265
[3006]266        float4 col = tex2Dlod(colors, float4(IN.texCoord, 0, 0));
[3017]267        float3 ao = tex2Dlod(ssaoTex, float4(IN.texCoord, 0, 0));
[2880]268
[3026]269        //if (ao.y < 2000.0f)
270        //      ao.x = Filter(IN.texCoord, ssaoTex, filterOffs, filterWeights);
[3017]271
[3016]272        OUT.illum_col = col * ao.x;
[3017]273        //OUT.illum_col.xyz = float3(ao.x,1-ao.y*1e-2f, 0);
[2975]274        OUT.illum_col.w = col.w;
[2880]275
276        return OUT;
[3000]277}
Note: See TracBrowser for help on using the repository browser.