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

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