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

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