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

Revision 3082, 8.1 KB checked in by mattausch, 16 years ago (diff)

debug version: working on split up of ssao and reprojection

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