Skip to content

Commit

Permalink
implemented hbao
Browse files Browse the repository at this point in the history
fix blur (still is non bilateral)
  • Loading branch information
facundo-villa committed Jun 18, 2024
1 parent 6989984 commit e59cc81
Show file tree
Hide file tree
Showing 7 changed files with 40 additions and 41 deletions.
10 changes: 6 additions & 4 deletions assets/engine/shaders/blur.comp
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,8 @@ vec4 blur(in sampler2D sourceTexture, vec2 blurDirection, vec2 uv)
{
vec4 result = vec4(0.0);
for (int i = 0; i < SAMPLE_COUNT; ++i) {
vec2 offset = blurDirection * OFFSETS[i] / textureSize(sourceTexture, 0);
float weight = WEIGHTS[i];
result += texture(sourceTexture, uv + offset) * weight;
vec2 offset = blurDirection * OFFSETS[i] / vec2(textureSize(sourceTexture, 0));
result += texture(sourceTexture, uv + offset) * WEIGHTS[i];
}
return result;
}
Expand All @@ -95,7 +94,10 @@ layout(local_size_x=128) in;
void main() {
if (gl_GlobalInvocationID.x >= imageSize(result).x || gl_GlobalInvocationID.y >= imageSize(result).y) { return; }

float value = blur(source, DIRECTION, vec2(gl_GlobalInvocationID.xy) / vec2(imageSize(result).xy)).r;
uvec2 texel = uvec2(gl_GlobalInvocationID.xy);
vec2 uv = (vec2(texel) + vec2(0.5)) / vec2(imageSize(result).xy);

float value = blur(source, DIRECTION, uv).r;

imageStore(result, ivec2(gl_GlobalInvocationID.xy), vec4(vec3(value), 1.0));
}
2 changes: 1 addition & 1 deletion ghi/src/graphics_hardware_interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -532,7 +532,7 @@ pub trait GraphicsHardwareInterface where Self: Sized {
// Return a mutable slice to the buffer data.
fn get_mut_buffer_slice<'a>(&'a self, buffer_handle: BaseBufferHandle) -> &'a mut [u8];

fn get_texture_slice_mut(&self, texture_handle: ImageHandle) -> &'static mut [u8];
fn get_texture_slice_mut(&mut self, texture_handle: ImageHandle) -> &'static mut [u8];

/// Creates an image.
fn create_image(&mut self, name: Option<&str>, extent: Extent, format: Formats, resource_uses: Uses, device_accesses: DeviceAccesses, use_case: UseCases) -> ImageHandle;
Expand Down
10 changes: 9 additions & 1 deletion ghi/src/vulkan/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ pub struct VulkanGHI {
settings: graphics_hardware_interface::Features,

states: HashMap<Handle, TransitionState>,

pending_images: Vec<graphics_hardware_interface::ImageHandle>,
}

enum Descriptor {
Expand Down Expand Up @@ -624,8 +626,11 @@ impl graphics_hardware_interface::GraphicsHardwareInterface for VulkanGHI {

fn create_command_buffer_recording(&mut self, command_buffer_handle: graphics_hardware_interface::CommandBufferHandle, frmae_index: Option<u32>) -> impl graphics_hardware_interface::CommandBufferRecording + '_ {
use graphics_hardware_interface::CommandBufferRecording;
let pending_images = self.pending_images.clone();
self.pending_images.clear();
let mut recording = VulkanCommandBufferRecording::new(self, command_buffer_handle, frmae_index);
recording.begin();
recording.transfer_textures(&pending_images);
recording
}

Expand Down Expand Up @@ -751,7 +756,8 @@ impl graphics_hardware_interface::GraphicsHardwareInterface for VulkanGHI {
graphics_hardware_interface::BufferSplitter::new(slice, offset)
}

fn get_texture_slice_mut(&self, texture_handle: graphics_hardware_interface::ImageHandle) -> &'static mut [u8] {
fn get_texture_slice_mut(&mut self, texture_handle: graphics_hardware_interface::ImageHandle) -> &'static mut [u8] {
self.pending_images.push(texture_handle);
let texture = &self.images[texture_handle.0 as usize];
assert!(texture.pointer != std::ptr::null());
unsafe {
Expand Down Expand Up @@ -2335,6 +2341,8 @@ impl VulkanGHI {
settings,

states: HashMap::with_capacity(4096),

pending_images: Vec::with_capacity(128),
})
}

Expand Down
4 changes: 3 additions & 1 deletion src/rendering/common_shader_generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -229,11 +229,13 @@ impl CommonShaderGenerator {
return view_space.xyz;", &[], Vec::new())]);

let sin_from_tan = Node::function("sin_from_tan", vec![Node::parameter("x", "f32")], "f32", vec![Node::glsl("return x * inversesqrt(x*x + 1.0)", &[], Vec::new())]);
let tangent = Node::function("tangent", vec![Node::parameter("p", "vec3f"), Node::parameter("s", "vec3f")], "f32", vec![Node::glsl("return -(p.z - s.z) * inversesqrt(dot(s.xy - p.xy, s.xy - p.xy))", &[], Vec::new())]);
let tangent = Node::function("tangent", vec![Node::parameter("p", "vec3f"), Node::parameter("s", "vec3f")], "f32", vec![Node::glsl("return (p.z - s.z) * inversesqrt(dot(s.xy - p.xy, s.xy - p.xy))", &[], Vec::new())]);

let make_normal_from_neighbouring_depth_samples = Node::function("make_normal_from_neighbouring_depth_samples", vec![Node::parameter("p", "vec3"), Node::parameter("pr", "vec3"), Node::parameter("pl", "vec3"), Node::parameter("pt", "vec3"), Node::parameter("pb", "vec3")], "vec3f", vec![Node::glsl("return normalize(cross(min_diff(p, pr, pl), min_diff(p, pt, pb)))", &["min_diff"], Vec::new())]);

let get_perpendicular_vector = Node::function("get_perpendicular_vector", vec![Node::parameter("v", "vec3f")], "vec3f", vec![Node::glsl("return normalize(abs(v.x) > abs(v.z) ? vec3(-v.y, v.x, 0.0) : vec3(0.0, -v.z, v.y));", &[], Vec::new())]);

// Should we add .5 to the coordinates before dividing by the extent?
let snap_uv = Node::function("snap_uv", vec![Node::parameter("uv", "vec2f"), Node::parameter("extent", "vec2u")], "vec2f", vec![Node::glsl("return round(uv * vec2(extent)) * (1.0f / vec2(extent))", &[], Vec::new())]);

// Get a cosine-weighted random vector centered around a specified normal direction.
Expand Down
41 changes: 19 additions & 22 deletions src/rendering/ssao_render_pass.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ pub struct ScreenSpaceAmbientOcclusionPass {
depth_binding: ghi::DescriptorSetBindingHandle,
result: ghi::ImageHandle,
x_blur_target: ghi::ImageHandle,
y_blur_target: ghi::ImageHandle,

// Not owned by this render pass
depth_target: ghi::ImageHandle,
Expand All @@ -46,16 +45,15 @@ impl ScreenSpaceAmbientOcclusionPass {
let depth_binding = ghi.create_descriptor_binding(descriptor_set, ghi::BindingConstructor::combined_image_sampler(&DEPTH_BINDING_TEMPLATE, depth_target, sampler, ghi::Layouts::Read));
let result_binding = ghi.create_descriptor_binding(descriptor_set, ghi::BindingConstructor::image(&RESULT_BINDING_TEMPLATE, occlusion_target, ghi::Layouts::General));

let x_blur_target = ghi.create_image(Some("X Blur"), Extent::new(1920, 1080, 1), ghi::Formats::R16(ghi::Encodings::FloatingPoint), ghi::Uses::Storage | ghi::Uses::Image, ghi::DeviceAccesses::GpuWrite | ghi::DeviceAccesses::GpuRead, ghi::UseCases::DYNAMIC);
let y_blur_target = ghi.create_image(Some("Y Blur"), Extent::new(1920, 1080, 1), ghi::Formats::R16(ghi::Encodings::FloatingPoint), ghi::Uses::Storage | ghi::Uses::Image, ghi::DeviceAccesses::GpuWrite | ghi::DeviceAccesses::GpuRead, ghi::UseCases::DYNAMIC);
let x_blur_target = ghi.create_image(Some("X Blur"), Extent::new(1920, 1080, 1), ghi::Formats::R8(ghi::Encodings::UnsignedNormalized), ghi::Uses::Storage | ghi::Uses::Image, ghi::DeviceAccesses::GpuWrite | ghi::DeviceAccesses::GpuRead, ghi::UseCases::DYNAMIC);

let blur_x_depth_binding = ghi.create_descriptor_binding(blur_x_descriptor_set, ghi::BindingConstructor::combined_image_sampler(&DEPTH_BINDING_TEMPLATE, depth_target, sampler, ghi::Layouts::Read));
let blur_x_source_binding = ghi.create_descriptor_binding(blur_x_descriptor_set, ghi::BindingConstructor::combined_image_sampler(&SOURCE_BINDING_TEMPLATE, occlusion_target, sampler, ghi::Layouts::Read));
let blur_x_result_binding = ghi.create_descriptor_binding(blur_x_descriptor_set, ghi::BindingConstructor::image(&RESULT_BINDING_TEMPLATE, x_blur_target, ghi::Layouts::General));

let blur_y_depth_binding = ghi.create_descriptor_binding(blur_y_descriptor_set, ghi::BindingConstructor::combined_image_sampler(&DEPTH_BINDING_TEMPLATE, depth_target, sampler, ghi::Layouts::Read));
let blur_y_source_binding = ghi.create_descriptor_binding(blur_y_descriptor_set, ghi::BindingConstructor::combined_image_sampler(&SOURCE_BINDING_TEMPLATE, x_blur_target, sampler, ghi::Layouts::Read));
let blur_y_result_binding = ghi.create_descriptor_binding(blur_y_descriptor_set, ghi::BindingConstructor::image(&RESULT_BINDING_TEMPLATE, y_blur_target, ghi::Layouts::General));
let blur_y_result_binding = ghi.create_descriptor_binding(blur_y_descriptor_set, ghi::BindingConstructor::image(&RESULT_BINDING_TEMPLATE, occlusion_target, ghi::Layouts::General));

let shader = ghi.create_shader(Some("HBAO Shader"), ghi::ShaderSource::GLSL(get_source()), ghi::ShaderTypes::Compute, &[
CAMERA_BINDING_TEMPLATE.into_shader_binding_descriptor(0, ghi::AccessPolicies::READ),
Expand Down Expand Up @@ -83,6 +81,7 @@ impl ScreenSpaceAmbientOcclusionPass {
let format = ghi::Formats::RGBA8(ghi::Encodings::UnsignedNormalized);

let image = ghi.create_image(blue_noise.id().into(), blue_noise.resource().extent.into(), format, Uses::Image, DeviceAccesses::GpuRead | DeviceAccesses::CpuWrite, ghi::UseCases::STATIC);
let sampler = ghi.create_sampler(ghi::FilteringModes::Closest, ghi::SamplingReductionModes::WeightedAverage, ghi::FilteringModes::Linear, ghi::SamplerAddressingModes::Repeat, None, 0f32, 0f32);

let buffer = ghi.get_texture_slice_mut(image);

Expand All @@ -102,7 +101,6 @@ impl ScreenSpaceAmbientOcclusionPass {
depth_binding,
result: occlusion_target,
x_blur_target,
y_blur_target,

depth_target,
}
Expand All @@ -111,17 +109,16 @@ impl ScreenSpaceAmbientOcclusionPass {
pub fn render(&self, command_buffer_recording: &mut impl ghi::CommandBufferRecording, extent: Extent) {
command_buffer_recording.start_region("SSAO");
command_buffer_recording.clear_images(&[(self.result, ghi::ClearValue::Color(RGBA::white())),]);
if false {
if true {
command_buffer_recording.bind_descriptor_sets(&self.pipeline_layout, &[self.descriptor_set]).bind_compute_pipeline(&self.pipeline).dispatch(ghi::DispatchExtent::new(extent, Extent::square(32)));
// command_buffer_recording.bind_descriptor_sets(&self.pipeline_layout, &[self.blur_x_descriptor_set]).bind_compute_pipeline(&self.blur_x_pipeline).dispatch(ghi::DispatchExtent::new(extent, Extent::line(128)));
// command_buffer_recording.bind_descriptor_sets(&self.pipeline_layout, &[self.blur_y_descriptor_set]).bind_compute_pipeline(&self.blur_y_pipeline).dispatch(ghi::DispatchExtent::new(extent, Extent::line(128)));
command_buffer_recording.bind_descriptor_sets(&self.pipeline_layout, &[self.blur_x_descriptor_set]).bind_compute_pipeline(&self.blur_x_pipeline).dispatch(ghi::DispatchExtent::new(extent, Extent::line(128)));
command_buffer_recording.bind_descriptor_sets(&self.pipeline_layout, &[self.blur_y_descriptor_set]).bind_compute_pipeline(&self.blur_y_pipeline).dispatch(ghi::DispatchExtent::new(extent, Extent::line(128)));
}
command_buffer_recording.end_region();
}

pub fn resize(&mut self, ghi: &mut ghi::GHI, extent: Extent) {
ghi.resize_image(self.x_blur_target, extent);
ghi.resize_image(self.y_blur_target, extent);
}
}

Expand All @@ -143,30 +140,30 @@ pub fn get_source() -> String {
vec2 render_target_extent = vec2(1920.0, 1080.0);
vec2 render_target_pixel_size = vec2(1.0f) / render_target_extent;
vec2 noise_scale = render_target_extent / 4.0f;
vec2 noise_scale = render_target_extent / 128.0f; /* Scale by noise size */
uvec2 texel = uvec2(gl_GlobalInvocationID.xy);
vec2 uv = vec2(texel) / vec2(1920, 1080);
vec2 uv = (vec2(texel) + vec2(0.5f)) / vec2(1920, 1080);
Camera camera = camera.camera;
vec3 p = get_view_space_position_from_depth(depth_map, texel, camera.inverse_projection_matrix);
vec3 p = get_view_space_position_from_depth(depth_map, uv, camera.inverse_projection_matrix);
/* Sample neighboring pixels */
vec3 pr = get_view_space_position_from_depth(depth_map, texel + uvec2( 1, 0), camera.inverse_projection_matrix);
vec3 pl = get_view_space_position_from_depth(depth_map, texel + uvec2(-1, 0), camera.inverse_projection_matrix);
vec3 pt = get_view_space_position_from_depth(depth_map, texel + uvec2( 0, 1), camera.inverse_projection_matrix);
vec3 pb = get_view_space_position_from_depth(depth_map, texel + uvec2( 0,-1), camera.inverse_projection_matrix);
vec3 pr = get_view_space_position_from_depth(depth_map, uv + (render_target_pixel_size * vec2( 1, 0)), camera.inverse_projection_matrix);
vec3 pl = get_view_space_position_from_depth(depth_map, uv + (render_target_pixel_size * vec2(-1, 0)), camera.inverse_projection_matrix);
vec3 pt = get_view_space_position_from_depth(depth_map, uv + (render_target_pixel_size * vec2( 0, 1)), camera.inverse_projection_matrix);
vec3 pb = get_view_space_position_from_depth(depth_map, uv + (render_target_pixel_size * vec2( 0,-1)), camera.inverse_projection_matrix);
/* Calculate tangent basis vectors using the minimu difference */
vec3 dPdu = min_diff(p, pr, pl);
vec3 dPdv = min_diff(p, pt, pb) * (render_target_extent.y * render_target_pixel_size.x);
vec3 dPdv = min_diff(p, pt, pb);
UVDerivatives derivatives = UVDerivatives(dPdu, dPdv);
/* Get the random samples from the noise texture */
vec3 random = texture(noise_texture, uv * noise_scale).rgb;
/* Calculate the projected size of the hemisphere */
vec2 uv_ray_radius = 0.5 * R * camera.fov / -p.z;
vec2 uv_ray_radius = 0.5 * R * camera.fov / p.z;
float pixel_ray_radius = uv_ray_radius.x * render_target_extent.x;
float ao = 1.0;
Expand Down Expand Up @@ -196,7 +193,7 @@ pub fn get_source() -> String {
}
/* Average the results and produce the final AO */
ao = 1.0 - ao / float(direction_count) * 1.9f/* AO_STRENGTH */;
ao = 1.0 - ao / float(direction_count) * 3.0f;
imageStore(out_ao, ivec2(texel), vec4(vec3(ao), 1.0));
"#;
Expand Down Expand Up @@ -246,12 +243,12 @@ pub fn get_source() -> String {
// Compute the step size (in uv space) from the number of steps
let compute_trace = besl::parser::Node::function("compute_trace", vec![besl::parser::Node::member("pixel_ray_radius", "f32"), besl::parser::Node::member("rand", "f32")], "TraceSettings", vec![Node::glsl(r#"
/* Avoid oversampling if numSteps is greater than the kernel radius in pixels */
uint32_t step_count = min(4/* SAMPLE_COUNT */, uint32_t(pixel_ray_radius));
uint32_t step_count = min(6/* SAMPLE_COUNT */, uint32_t(pixel_ray_radius));
/* Divide by Ns+1 so that the farthest samples are not fully attenuated */
float stepSizePix = pixel_ray_radius / (step_count + 1);
float max_pixel_radius = 50.f; /* Tweak this for performance and effect */
float max_pixel_radius = 75.f; /* Tweak this for performance and effect */
/* Clamp numSteps if it is greater than the max kernel footprint */
float maxNumSteps = max_pixel_radius / stepSizePix;
Expand All @@ -266,7 +263,7 @@ pub fn get_source() -> String {
return TraceSettings(step_count, stepSizePix * (vec2(1.0) / vec2(1920, 1080)));
"#, &[], Vec::new())]);

let biased_tangent = Node::function("biased_tangent", vec![Node::parameter("v", "vec3f")], "f32", vec![Node::glsl("return v.z * inversesqrt(dot(v,v)) + tan(30.0 * PI / 180.0)", &[], Vec::new())]);
let biased_tangent = Node::function("biased_tangent", vec![Node::parameter("v", "vec3f")], "f32", vec![Node::glsl("return -v.z * inversesqrt(dot(v,v)) + tan(30.0 * PI / 180.0)", &[], Vec::new())]);

let camera_binding = Node::binding("camera", Node::buffer("CameraBuffer", vec![Node::member("camera", "Camera")]), 0, CAMERA_BINDING_TEMPLATE.binding(), true, false);
let out_ao = Node::binding("out_ao", Node::image("r8"), 1, RESULT_BINDING_TEMPLATE.binding(), false, true);
Expand Down
7 changes: 2 additions & 5 deletions src/rendering/visibility_model/render_domain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -976,6 +976,7 @@ impl VisibilityWorldRenderDomain {
let view_projection_matrix = projection_matrix * view_matrix;
let fov = {
let fov_x = 2f32 * ((fov_y / 2f32).to_radians().tan() * aspect_ratio).atan();
let fov_y = fov_y.to_radians();
[fov_x, fov_y]
};

Expand Down Expand Up @@ -1024,10 +1025,6 @@ impl VisibilityWorldRenderDomain {
pub fn render_a(&mut self, command_buffer_recording: &mut impl ghi::CommandBufferRecording, extent: Extent, modulo_frame_index: u32) -> Option<()> {
let camera_handle = if let Some(camera_handle) = &self.camera { camera_handle } else { return None; };

command_buffer_recording.transfer_textures(&self.pending_texture_loads);

self.pending_texture_loads.clear();

command_buffer_recording.start_region("Visibility Render Model");

self.visibility_pass.render(command_buffer_recording, &self.visibility_info, &self.render_info.instances, self.primitive_index, self.instance_id, self.depth_target, extent);
Expand All @@ -1047,7 +1044,7 @@ impl VisibilityWorldRenderDomain {
let mut directional_lights: Vec<&LightData> = self.lights.iter().filter(|l| l.light_type == 'D' as u8).collect();
directional_lights.sort_by(|a, b| maths_rs::length(a.color).partial_cmp(&maths_rs::length(b.color)).unwrap()); // Sort by intensity

if false {
if true {
if let Some(most_significant_light) = directional_lights.get(0) {
shadow_render_pass.render(command_buffer_recording, self, &self.render_info.instances);
} else {
Expand Down
7 changes: 0 additions & 7 deletions src/rendering/visibility_shader_generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,18 +144,11 @@ vec3 pos_dy = interpolate_vec3f_with_deriv(ddy, model_space_vertex_positions[0].
vec2 uv_dx = interpolate_vec2f_with_deriv(ddx, vertex_uvs[0], vertex_uvs[1], vertex_uvs[2]);
vec2 uv_dy = interpolate_vec2f_with_deriv(ddy, vertex_uvs[0], vertex_uvs[1], vertex_uvs[2]);
// // Method 1
float f = 1.0 / (uv_dx.x * uv_dy.y - uv_dy.x * uv_dx.y);
vec3 T = normalize(f * (uv_dy.y * pos_dx - uv_dx.y * pos_dy));
vec3 B = normalize(f * (-uv_dy.x * pos_dx + uv_dx.x * pos_dy));
mat3 TBN = mat3(T, B, N);
// Method 2
// vec3 T = (uv_dy.y * pos_dx - uv_dx.y * pos_dy) / (uv_dx.x * uv_dy.y - uv_dy.x * uv_dx.y);
// T = normalize(T - N * dot(T, N));
// vec3 B = cross(N, T);
// mat3 TBN = mat3(T, B, N);
vec3 albedo = vec3(1, 0, 0);
vec3 normal = vec3(0, 0, 1);
float metalness = 0;
Expand Down

0 comments on commit e59cc81

Please sign in to comment.