LumixEngine/data/pipelines/ssao.shd
Mikulas Florek f48ca91d23 fixed ssao
2022-05-05 23:23:22 +02:00

80 lines
No EOL
2.4 KiB
Text

include "pipelines/common.glsl"
compute_shader [[
layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in;
// possible future optimizations https://software.intel.com/content/www/us/en/develop/articles/adaptive-screen-space-ambient-occlusion.html
// inspired by https://github.com/tobspr/RenderPipeline/blob/master/rpplugins/ao/shader/ue4ao.kernel.glsl
layout (binding=0) uniform sampler2D u_depth_buffer;
layout (binding=1) uniform sampler2D u_normal_buffer;
layout (binding=2, rgba8) uniform image2D u_output;
layout(std140, binding = 4) uniform Drawcall {
float u_radius;
float u_intensity;
float u_width;
float u_height;
};
vec3 getViewNormal(vec2 tex_coord)
{
vec3 wnormal = texture(u_normal_buffer, tex_coord).xyz * 2 - 1;
vec4 vnormal = Global.view * vec4(wnormal, 0);
return vnormal.xyz;
}
void main()
{
if (any(greaterThan(gl_GlobalInvocationID.xy, ivec2(u_width, u_height)))) return;
vec2 uv = gl_GlobalInvocationID.xy / vec2(u_width, u_height);
vec3 view_pos = getViewPosition(u_depth_buffer, Global.inv_projection, uv);
vec3 view_normal = getViewNormal(uv);
float occlusion = 0;
float occlusion_count = 0;
float rand = rand(view_pos.xyz + Global.time * 0.1);
float random_angle = rand * 6.283285;
vec3 rot;
float depth_scale = u_radius / view_pos.z * (rand * 2 + 0.1);
rot.x = sin(random_angle);
rot.y = cos(random_angle);
rot.z = -rot.x;
rot *= depth_scale;
for (int i = 0; i < 4; ++i)
{
vec2 poisson = POISSON_DISK_4[i];
vec2 s = vec2(dot(poisson, rot.yx), dot(poisson, rot.zy));
vec3 vpos_a = getViewPosition(u_depth_buffer, Global.inv_projection, uv + s) - view_pos;
vec3 vpos_b = getViewPosition(u_depth_buffer, Global.inv_projection, uv - s) - view_pos;
vec3 sample_vec_a = normalize(vpos_a);
vec3 sample_vec_b = normalize(vpos_b);
float dist_a = length(vpos_a);
float dist_b = length(vpos_b);
float valid_a = step(dist_a, 1);
float valid_b = step(dist_b, 1);
float angle_a = saturate(dot(sample_vec_a, view_normal));
float angle_b = saturate(dot(sample_vec_b, view_normal));
if (valid_a + valid_b > 1)
{
occlusion += (angle_a + angle_b) * (0.5 - 0.25 * (dist_a + dist_b));
occlusion_count += 1.0;
}
else
{
occlusion = 0;
}
}
occlusion /= max(1.0, occlusion_count);
float value = 1 - occlusion * u_intensity;
imageStore(u_output, ivec2(gl_GlobalInvocationID.xy), vec4(vec3(value), 1));
}
]]