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

Revision 3084, 9.7 KB checked in by mattausch, 16 years ago (diff)
Line 
1#include "../shaderenv.h"
2
3////////////////////
4// Screen Spaced Ambient Occlusion shader
5// based on shader of Alexander Kusternig
6
7
8#define USE_EYE_SPACE_DEPTH 1
9
10
11struct fragment
12{
13        float2 texCoord: TEXCOORD0;
14        float3 view: TEXCOORD1;
15};
16
17
18struct pixel
19{
20        float4 illum_col: COLOR0;
21};
22
23
24inline float occlusionPower(float radius, float dist)
25{
26        return 6.283185307179586476925286766559f * (1.0f - cos(asin(radius / dist)));
27}
28
29
30inline float2 myreflect(float2 pt, float2 n)
31{
32        // distance to plane
33        float d = dot(n, pt);
34        // reflect around plane
35        float2 rpt = pt - d * 2.0f * n;
36
37        return rpt;
38}
39
40
41inline float3 Interpol(float2 w, float3 bl, float3 br, float3 tl, float3 tr)
42{
43        float3 x1 = lerp(bl, tl, w.y);
44        float3 x2 = lerp(br, tr, w.y);
45        float3 v = lerp(x1, x2, w.x);
46
47        return v;
48}
49
50
51// reconstruct world space position
52inline float3 ReconstructSamplePos(uniform sampler2D colors,
53                                                                   float2 texcoord,
54                                                                   float3 bl, float3 br, float3 tl, float3 tr)
55{
56        const float eyeSpaceDepth = tex2D(colors, texcoord).w;
57        float3 viewVec = Interpol(texcoord, bl, br, tl, tr);
58        float3 samplePos = -viewVec * eyeSpaceDepth;
59
60        return samplePos;
61}
62
63
64/** This shader computes the reprojection and stores reprojected color / depth values
65        as well as a boolean that
66*/
67float4 temporalSmoothing(float4 currentProjPos,
68                                                 float4 worldPos,
69                                                 float currentDepth,
70                                                 uniform sampler2D oldTex,
71                                                 const uniform float4x4 oldModelViewProj,
72                                                 uniform float temporalCoherence,
73                                                 uniform float2 ao,
74                                                 uniform float2 samples[NUM_SAMPLES],
75                                                 uniform sampler2D colors,
76                                                 uniform sampler2D noiseTex,
77                                                 uniform float scaleFactor,
78                                                 uniform float3 bl,
79                                                 uniform float3 br,
80                                                 uniform float3 tl,
81                                                 uniform float3 tr,
82                                                 float2 texcoord0,
83                                                 float3 eyePos
84                                                 )
85{
86        float4 illum_col;
87
88        /////////////////
89        //-- compute reprojection for temporal smoothing
90
91        // reproject into old frame and calculate projected depth
92        const float3 dummyPos = ReconstructSamplePos(colors, texcoord0, bl, br, tl, tr) + eyePos;
93        float4 backProjPos = mul(oldModelViewProj, float4(dummyPos, 1.0f));
94        //float4 backProjPos = mul(oldModelViewProj, worldPos);
95       
96        backProjPos /= backProjPos.w;
97       
98        // the current depth projected into the old frame
99        const float backProjDepth = backProjPos.z * PRECISION_SCALE;
100        // fit from unit cube into 0 .. 1
101        const float2 tex = backProjPos.xy * 0.5f + 0.5f;
102        // retrieve the sample from the last frame
103        float4 oldCol = tex2D(oldTex, tex);
104
105        const float oldDepth = oldCol.z;
106        const float depthDif = backProjDepth - oldDepth;
107
108        //const float oldNumSamples = oldCol.y;
109        const float oldWeight = clamp(oldCol.y, .0f, temporalCoherence);
110        float newWeight;
111
112        bool isValid = true;
113
114        for (int i = 0; i < NUM_SAMPLES; ++ i)
115        {
116                const float2 offset = samples[i];
117
118                float2 mynoise = tex2D(noiseTex, texcoord0).xy;
119                const float2 offsetTransformed = myreflect(offset, mynoise);
120
121                const float2 texCoord = texcoord0;// + offsetTransformed * scaleFactor;
122                const float3 samplePos = ReconstructSamplePos(colors, texCoord, bl, br, tl, tr) + eyePos;
123
124                // reproject into old frame and calculate projected depth
125                float4 projPos = mul(oldModelViewProj, float4(samplePos, 1.0f));
126                projPos /= projPos.w;
127
128                // the current depth projected into the old frame
129                const float projDepth = projPos.z * PRECISION_SCALE;
130                // fit from unit cube into 0 .. 1
131                // retrieve the sample from the last frame
132                const float4 oldSample = tex2D(oldTex, projPos.xy * 0.5f + 0.5f);
133                const float dDiff = projDepth - oldSample.z;
134
135                if (abs(dDiff) > 1e-5f) isValid = false;
136        }
137
138        // the number of valid samples in this frame
139        //const float newNumSamples = ao.y;
140
141        if ((temporalCoherence > 1e-6f)
142                && (tex.x >= 0.0f) && (tex.x < 1.0f)
143                && (tex.y >= 0.0f) && (tex.y < 1.0f)
144                && (abs(depthDif) <= MIN_DEPTH_DIFF)
145                // if visibility changed in the surrounding area we have to recompute
146                //&& (oldNumSamples > 0.8f * newNumSamples)
147                && isValid
148                )
149        {
150                // increase the weight for convergence
151                newWeight = oldWeight + 1.0f;
152                illum_col.x = (ao.x + oldCol.x * oldWeight) / newWeight;
153                //if (!(oldNumSamples > ao.y - 1.5f)) newWeight = 0;
154        }
155        else
156        {       
157                illum_col.x = ao.x;
158                newWeight = .0f;
159        }
160       
161        //isValid = 0.0f;
162        //illum_col.y = isValid / 16.0f;
163        illum_col.y = newWeight;
164        illum_col.z = currentDepth;
165
166        return illum_col;
167}
168
169
170/** The ssao shader returning the an intensity value between 0 and 1
171*/
172float2 ssao(fragment IN,
173                        uniform sampler2D colors,
174                        uniform sampler2D noiseTex,
175                        uniform float2 samples[NUM_SAMPLES],
176                        uniform float3 currentNormal,
177                        uniform float3 centerPosition,
178                        uniform float scaleFactor,
179                        uniform float3 bl,
180                        uniform float3 br,
181                        uniform float3 tl,
182                        uniform float3 tr,
183                        uniform float3 viewDir
184                        )
185{
186        // Check in a circular area around the current position.
187        // Shoot vectors to the positions there, and check the angle to these positions.
188        // Summing up these angles gives an estimation of the occlusion at the current position.
189
190        float total_ao = .0f;
191        float numSamples = .0f;
192
193
194        for (int i = 0; i < NUM_SAMPLES; ++ i)
195        {
196                const float2 offset = samples[i];
197
198#if 1
199                ////////////////////
200                //-- add random noise: reflect around random normal vector (rather slow!)
201
202                float2 mynoise = tex2D(noiseTex, IN.texCoord).xy;
203                const float2 offsetTransformed = myreflect(offset, mynoise);
204#else
205                const float2 offsetTransformed = offset;
206#endif
207                // weight with projected coordinate to reach similar kernel size for near and far
208                const float2 texcoord = IN.texCoord.xy + offsetTransformed * scaleFactor;
209
210                //if ((texcoord.x <= 1.0f) && (texcoord.x >= 0.0f) && (texcoord.y <= 1.0f) && (texcoord.y >= 0.0f)) ++ numSamples;
211
212                const float3 samplePos = ReconstructSamplePos(colors, texcoord, bl, br, tl, tr);
213
214
215                ////////////////
216                //-- compute contribution of sample using the direction and angle
217
218                float3 dirSample = samplePos - centerPosition;
219                const float lengthToSample = length(dirSample);
220                // normalize
221                dirSample /= lengthToSample;
222
223                // angle between current normal and direction to sample controls AO intensity.
224                const float cosAngle = max(dot(dirSample, currentNormal), 0.0f);
225
226                // the distance_scale offset is used to avoid singularity that occurs at global illumination when
227                // the distance to a sample approaches zero
228                //const float aoContrib = (1.0f > lengthToSample) ? occlusionPower(9e-2f, DISTANCE_SCALE + lengthToSample): .0f;
229                const float aoContrib = SAMPLE_INTENSITY / (DISTANCE_SCALE + lengthToSample * lengthToSample);
230
231#if 1
232                // if surface normal perpenticular to view dir, approx. half of the samples will not count
233                // => compensate for this (on the other hand, projected sampling area could be larger!)
234                const float viewCorrection = 1.0f + VIEW_CORRECTION_SCALE * dot(viewDir, currentNormal);
235                total_ao += cosAngle * aoContrib * viewCorrection;
236#else
237                total_ao += cosAngle * intensity;
238#endif
239        }
240
241        return float2(max(0.0f, 1.0f - total_ao), numSamples);
242}
243
244//#pragma position_invariant main
245
246/** The mrt shader for screen space ambient occlusion
247*/
248pixel main(fragment IN,
249                   uniform sampler2D colors,
250                   uniform sampler2D normals,
251                   uniform sampler2D noiseTex,
252                   uniform float2 samples[NUM_SAMPLES],
253                   uniform sampler2D oldTex,
254                   const uniform float4x4 modelViewProj,
255                   const uniform float4x4 oldModelViewProj,
256                   uniform float temporalCoherence,
257                   uniform float3 eyePos,
258                   uniform float3 bl,
259                   uniform float3 br,
260                   uniform float3 tl,
261                   uniform float3 tr
262                   )
263{
264        pixel OUT;
265
266        const float3 normal =
267                normalize(tex2Dlod(normals, float4(IN.texCoord, 0 ,0)).xyz);
268
269        // reconstruct position from the eye space depth
270        const float3 viewDir = IN.view;
271        const float eyeDepth = tex2Dlod(colors, float4(IN.texCoord, 0, 0)).w;
272        const float3 eyeSpacePos = -viewDir * eyeDepth;
273        const float4 worldPos = float4(eyePos + eyeSpacePos, 1.0f);
274
275
276        ////////////////
277        //-- calculcate the current projected posiion (also used for next frame)
278       
279        float4 projPos = mul(modelViewProj, worldPos);
280       
281        float w = 1.0f / projPos.w;
282        projPos *= w;
283        w *= SAMPLE_RADIUS;
284       
285        const float currentDepth = projPos.z * PRECISION_SCALE;
286
287        const float2 ao = ssao(IN, colors, noiseTex, samples, normal, eyeSpacePos, w, bl, br, tl, tr, normalize(viewDir));
288
289
290        /////////////////
291        //-- compute temporally smoothing
292       
293        OUT.illum_col = temporalSmoothing(projPos, worldPos, currentDepth, oldTex, oldModelViewProj, temporalCoherence, ao,
294                                              samples, colors, noiseTex, w, bl, br, tl, tr, IN.texCoord, eyePos);
295
296        return OUT;
297}
298
299
300float Filter(float2 texCoord,
301                         uniform sampler2D ssaoTex,
302                         uniform float2 filterOffs[NUM_SSAO_FILTERSAMPLES],
303                         uniform float filterWeights[NUM_SSAO_FILTERSAMPLES]
304)
305{
306        float average = .0f;
307        float w = .0f;
308
309        for (int i = 0; i < NUM_SSAO_FILTERSAMPLES; ++ i)
310        {
311                average += filterWeights[i] * tex2Dlod(ssaoTex, float4(texCoord + filterOffs[i], 0, 0)).x;
312                w += filterWeights[i];
313        }
314
315        average *= 1.0f / (float)w;
316
317        return average;
318}
319
320
321pixel combine(fragment IN,
322                          uniform sampler2D colors,
323                          uniform sampler2D ssaoTex,
324                          uniform float2 filterOffs[NUM_SSAO_FILTERSAMPLES],
325                          uniform float filterWeights[NUM_SSAO_FILTERSAMPLES]
326                          )
327{
328        pixel OUT;
329
330        float4 col = tex2Dlod(colors, float4(IN.texCoord, 0, 0));
331        float3 ao = tex2Dlod(ssaoTex, float4(IN.texCoord, 0, 0));
332
333        //if (ao.y < 10.0f)
334        //      ao.x = Filter(IN.texCoord, ssaoTex, filterOffs, filterWeights);
335
336        //OUT.illum_col = col * ao.x;
337        OUT.illum_col.xyz = float3(1.0f - ao.x, 1.0f - ao.y * 1e-2f, 1);
338        //OUT.illum_col.xyz = float3(1.0f - ao.x, ao.y, 0);
339        OUT.illum_col.w = col.w;
340
341        return OUT;
342}
Note: See TracBrowser for help on using the repository browser.