From 28965eccb61d06a497645e0770826de161b0e4cb Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Sat, 8 May 2021 20:33:57 +0300 Subject: [PATCH] Take ambient occlusion samples only from the forward hemisphere 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 | 12 ++++++++++++ builtin_data/_ambientocclusion_combine.glsl | 2 +- builtin_data/_ambientocclusion_occlude.glsl | 16 ++++++++++++++-- source/effects/ambientocclusion.cpp | 4 ++-- 4 files changed, 29 insertions(+), 5 deletions(-) diff --git a/builtin_data/_ambientocclusion.glsl b/builtin_data/_ambientocclusion.glsl index 81aac182..4cc74e18 100644 --- a/builtin_data/_ambientocclusion.glsl +++ b/builtin_data/_ambientocclusion.glsl @@ -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); +} diff --git a/builtin_data/_ambientocclusion_combine.glsl b/builtin_data/_ambientocclusion_combine.glsl index 2e9f75fc..353ea8c3 100644 --- a/builtin_data/_ambientocclusion_combine.glsl +++ b/builtin_data/_ambientocclusion_combine.glsl @@ -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); } diff --git a/builtin_data/_ambientocclusion_occlude.glsl b/builtin_data/_ambientocclusion_occlude.glsl index 62fd153b..7ff813e8 100644 --- a/builtin_data/_ambientocclusion_occlude.glsl +++ b/builtin_data/_ambientocclusion_occlude.glsl @@ -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; diff --git a/source/effects/ambientocclusion.cpp b/source/effects/ambientocclusion.cpp index a407c2d9..430ac0ba 100644 --- a/source/effects/ambientocclusion.cpp +++ b/source/effects/ambientocclusion.cpp @@ -73,8 +73,8 @@ void AmbientOcclusion::set_n_samples(unsigned n) Vector3 sample_points[32]; for(unsigned i=0; i(i)/n; - float r = sqrt(1.0f-z*z); + float r = static_cast(i)/n; + float z = sqrt(1.0f-r*r); float d = radical_inverse(i); Geometry::Angle a = Geometry::Angle::from_turns(d); sample_points[i] = Vector3(cos(a)*r, sin(a)*r, z)*(0.1f+0.9f*d*d); -- 2.43.0