]> git.tdb.fi Git - libs/gl.git/commitdiff
Take ambient occlusion samples only from the forward hemisphere
authorMikko Rasa <tdb@tdb.fi>
Sat, 8 May 2021 17:33:57 +0000 (20:33 +0300)
committerMikko Rasa <tdb@tdb.fi>
Sun, 9 May 2021 07:53:57 +0000 (10:53 +0300)
This requires a few more samples from the depth buffer to determine the
normal, but that should not be an issue with today's GPUs.

Also generate the sample points for cosine-weighted importance sampling
to obtain physically correct occlusion values.

builtin_data/_ambientocclusion.glsl
builtin_data/_ambientocclusion_combine.glsl
builtin_data/_ambientocclusion_occlude.glsl
source/effects/ambientocclusion.cpp

index 81aac182acb4683412d429d7d33b58938bdd1722..4cc74e18c26962f5db7b10a238d38a9cf8f0ba36 100644 (file)
@@ -35,3 +35,15 @@ vec3 unproject(vec3 position)
        vec4 upp = eye_clip_matrix*vec4(position, 1.0);
        return upp.xyz/upp.w;
 }
+
+vec3 get_fragment_position(vec2 tc)
+{
+       return unproject(vec3(tc*2.0-1.0, texture(depth, tc).r));
+}
+
+vec3 get_slope(vec3 a, vec3 x, vec3 b)
+{
+       float dz1 = abs(x.z-a.z);
+       float dz2 = abs(b.z-x.z);
+       return (dz1>2.0*dz2 ? b-x : dz2>2.0*dz1 ? x-a : b-a);
+}
index 2e9f75fc30595c05066c77c3c780718c24ed8d7a..353ea8c385d1d0166cc03d096fa4bf174588bc3a 100644 (file)
@@ -26,5 +26,5 @@ void main()
                        }
                }
        vec4 src_color = texture(source, texcoord);
-       frag_color = vec4(src_color.rgb*mix(1.0, min(sum*2.0/count, 1.0), darkness), src_color.a);
+       frag_color = vec4(src_color.rgb*mix(1.0, min(sum/count, 1.0), darkness), src_color.a);
 }
index 62fd153b712589e205f73738887a7db4e05f05c9..7ff813e8d27a1c175d8716a0c20fa7e0a4aabbee 100644 (file)
@@ -5,9 +5,21 @@ import _ambientocclusion;
 layout(location=0) out float frag_out;
 void main()
 {
+       vec3 tex_scale = vec3(1.0/vec2(textureSize(depth, 0)), 0.0);
+
+       vec3 center = get_fragment_position(texcoord);
+       vec3 left = get_fragment_position(texcoord-tex_scale.xz);
+       vec3 right = get_fragment_position(texcoord+tex_scale.xz);
+       vec3 bottom = get_fragment_position(texcoord-tex_scale.zy);
+       vec3 top = get_fragment_position(texcoord+tex_scale.zy);
+
+       vec3 normal = normalize(cross(get_slope(left, center, right), get_slope(bottom, center, top)));
+       vec3 tangent = (abs(normal.x)>abs(normal.y) ? vec3(-normal.z, 0.0, normal.x) : vec3(0.0, -normal.z, normal.y));
+       vec3 binormal = cross(normal, tangent);
+
        vec4 rv = texture(rotate, gl_FragCoord.xy/4.0)*2.0-1.0;
-       mat3 transform = mat3(rv.xy, 0.0, rv.zx, 0.0, 0.0, 0.0, rv.w)*occlusion_radius;
-       vec3 center = unproject(vec3(vertex.xy, texture(depth, texcoord).r));
+       mat3 transform = mat3(tangent, binormal, normal)*mat3(rv.xy, 0.0, rv.zx, 0.0, 0.0, 0.0, 1.0)*occlusion_radius;
+
        float min_depth = project(vec3(center.xy, center.z+occlusion_radius)).z;
        float occlusion_sum = 0.0;
        float count = 0.0;
index a407c2d9918621b3aa9f057fd93597845635f1e9..430ac0ba86556747005fb046ce5a3e32aaaddb7d 100644 (file)
@@ -73,8 +73,8 @@ void AmbientOcclusion::set_n_samples(unsigned n)
        Vector3 sample_points[32];
        for(unsigned i=0; i<n; ++i)
        {
-               float z = static_cast<float>(i)/n;
-               float r = sqrt(1.0f-z*z);
+               float r = static_cast<float>(i)/n;
+               float z = sqrt(1.0f-r*r);
                float d = radical_inverse(i);
                Geometry::Angle<float> a = Geometry::Angle<float>::from_turns(d);
                sample_points[i] = Vector3(cos(a)*r, sin(a)*r, z)*(0.1f+0.9f*d*d);