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

Revision 3001, 7.3 KB checked in by mattausch, 16 years ago (diff)

reverted back from trying to use less components in fbo for faster sampling

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 0
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 float4 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                   uniform float maxDepth,
152                   uniform float temporalCoherence,
153                   uniform float3 eyePos,
154                   uniform float3 bl,
155                   uniform float3 br,
156                   uniform float3 tl,
157                   uniform float3 tr
158                   )
159{
160        pixel OUT;
161
162        float4 norm = tex2D(normals, IN.texCoord.xy);
163        float3 normal = normalize(norm.xyz);
164
165        // a constant ambient term
166        const float amb = norm.w;
167        // the w coordinate from the persp. projection
168        float w = norm.w;
169
170
171        // the current world position
172        const float4 centerPosition = tex2D(positions, IN.texCoord.xy);
173
174#if USE_EYE_SPACE_DEPTH
175        /// reconstruct position from the eye space depth
176        float3 viewDir = IN.view;
177        const float eyeDepth = tex2D(colors, IN.texCoord.xy).w;
178        float4 centerPosition2;
179
180        centerPosition2.xyz = eyePos - viewDir * eyeDepth;
181        centerPosition2.w = centerPosition.w;
182
183        const float2 ao = ssao(IN, colors, noiseTexture, samples, normal, centerPosition2, w, eyePos, bl, br, tl, tr);
184#else
185
186        const float2 ao = ssao(IN, positions, noiseTexture, samples, normal, centerPosition, w, eyePos, bl, br, tl, tr);
187
188#endif
189
190        // the current depth
191        const float currentDepth = centerPosition.w;
192       
193
194        /////////////////
195        //-- compute temporally smoothing
196
197        float4 realPos = centerPosition * maxDepth;
198        realPos.w = 1.0f;
199
200
201        ///////////
202        //-- reprojection from new frame into old one
203       
204        // note: could be done using eye space depth values
205        float4 oldPos = mul(oldModelViewProj, realPos);
206
207        const float4 projPos = oldPos / oldPos.w;
208
209        // the current depth projected into the old frame
210        const float projDepth = projPos.z;
211
212        // fit from unit cube into 0 .. 1
213        float2 tex = (projPos.xy) * 0.5f + 0.5f;
214
215        // optain the sample from the last frame
216        float4 oldCol = tex2D(oldTex, tex);
217
218        const float oldDepth = oldCol.w;
219        //const float oldNumSamples = oldCol.y;
220        const float oldWeight = clamp(oldCol.z, 0, temporalCoherence);
221
222        const float depthDif = 1.0f - projDepth / oldDepth;
223
224        float newWeight;
225
226        // the number of valid samples in this frame
227        //const float newNumSamples = ao.y;
228
229
230        if (//(temporalCoherence > 0) &&
231                (tex.x >= 0.0f) && (tex.x < 1.0f) &&
232                (tex.y >= 0.0f) && (tex.y < 1.0f) &&
233                (abs(depthDif) < 1e-4f)
234                // if visibility changed in the surrounding area we have to recompute
235                //&& (oldNumSamples > 0.8f * newNumSamples)
236                )
237        {
238                // increase the weight for convergence
239                newWeight = oldWeight + 1.0f;
240                OUT.illum_col.xy = (ao.xy + oldCol.xy * oldWeight) / newWeight;
241                //if (!(oldNumSamples > ao.y - 1.5f)) newWeight = 0;
242        }
243        else
244        {       
245                OUT.illum_col.xy = ao.xy;
246                newWeight = 0;
247        }
248
249        OUT.illum_col.z = newWeight;
250        OUT.illum_col.w = currentDepth;
251
252        return OUT;
253}
254
255
256pixel combine(fragment IN,
257                          uniform sampler2D colors,
258                          uniform sampler2D ssaoTex)
259{
260        pixel OUT;
261
262        float4 col = tex2Dlod(colors, float4(IN.texCoord.xy, 0, 0));
263        float4 ao = tex2D(ssaoTex, IN.texCoord.xy);
264
265        OUT.illum_col = col * ao.x;
266        //OUT.illum_col = float4(ao.x,ao.x,ao.x, ao.w);
267        OUT.illum_col.w = col.w;
268
269        return OUT;
270}
Note: See TracBrowser for help on using the repository browser.