Skip to content

Commit

Permalink
Basic shadow mapping working.
Browse files Browse the repository at this point in the history
  • Loading branch information
facundo-villa committed Jan 22, 2024
1 parent 1571dcb commit 0edc1e8
Show file tree
Hide file tree
Showing 7 changed files with 146 additions and 74 deletions.
16 changes: 8 additions & 8 deletions src/ghi/graphics_hardware_interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -595,17 +595,17 @@ pub enum ClearValue {
/// Stores the information of an attachment.
pub struct AttachmentInformation {
/// The image view of the attachment.
pub image: ImageHandle,
pub(crate) image: ImageHandle,
/// The format of the attachment.
pub format: Formats,
pub(crate) format: Formats,
/// The layout of the attachment.
pub layout: Layouts,
pub(crate) layout: Layouts,
/// The clear color of the attachment.
pub clear: ClearValue,
pub(crate) clear: ClearValue,
/// Whether to load the contents of the attchment when starting a render pass.
pub load: bool,
pub(crate) load: bool,
/// Whether to store the contents of the attachment when ending a render pass.
pub store: bool,
pub(crate) store: bool,
}

impl AttachmentInformation {
Expand Down Expand Up @@ -649,7 +649,7 @@ pub struct BufferCopy {
use serde::{Serialize, Deserialize};

bitflags::bitflags! {
#[derive(Clone, Copy, PartialEq, Eq)]
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
/// Bit flags for the available access policies.
pub struct AccessPolicies : u8 {
/// Will perform read access.
Expand Down Expand Up @@ -677,7 +677,7 @@ pub enum Barrier {
}

bitflags::bitflags! {
#[derive(Clone, Copy, PartialEq, Eq)]
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
/// Bit flags for the available pipeline stages.
pub struct Stages : u64 {
/// No stage.
Expand Down
4 changes: 2 additions & 2 deletions src/ghi/vulkan_ghi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3905,14 +3905,14 @@ impl graphics_hardware_interface::CommandBufferRecording for VulkanCommandBuffer
let wait_semaphores = wait_for_synchronizer_handles.iter().map(|wait_for| {
vk::SemaphoreSubmitInfo::default()
.semaphore(self.ghi.synchronizers[wait_for.0 as usize].semaphore)
.stage_mask(vk::PipelineStageFlags2::COLOR_ATTACHMENT_OUTPUT | vk::PipelineStageFlags2::RAY_TRACING_SHADER_KHR)
.stage_mask(vk::PipelineStageFlags2::COLOR_ATTACHMENT_OUTPUT/* | vk::PipelineStageFlags2::RAY_TRACING_SHADER_KHR*/)
/* .build() */
}).collect::<Vec<_>>();

let signal_semaphores = signal_synchronizer_handles.iter().map(|signal| {
vk::SemaphoreSubmitInfo::default()
.semaphore(self.ghi.synchronizers[signal.0 as usize].semaphore)
.stage_mask(vk::PipelineStageFlags2::COLOR_ATTACHMENT_OUTPUT | vk::PipelineStageFlags2::ACCELERATION_STRUCTURE_BUILD_KHR)
.stage_mask(vk::PipelineStageFlags2::COLOR_ATTACHMENT_OUTPUT/* | vk::PipelineStageFlags2::ACCELERATION_STRUCTURE_BUILD_KHR*/)
/* .build() */
}).collect::<Vec<_>>();

Expand Down
4 changes: 3 additions & 1 deletion src/rendering/renderer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,12 +103,14 @@ impl Renderer {

self.visibility_render_model.map(|vis_rp| {
let mut vis_rp = vis_rp.write_sync();
vis_rp.render(ghi.deref(), command_buffer_recording.as_mut());
vis_rp.render_a(ghi.deref(), command_buffer_recording.as_mut());

self.shadow_render_pass.map(|shadow_rp| {
let shadow_rp = shadow_rp.write_sync();
shadow_rp.render(command_buffer_recording.as_mut(), vis_rp.deref());
});

vis_rp.render_b(ghi.deref(), command_buffer_recording.as_mut());
});

self.tonemap_render_model.map(|e| {
Expand Down
112 changes: 106 additions & 6 deletions src/rendering/shadow_render_pass.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,23 @@ pub struct ShadowRenderingPass {
pipeline_layout: ghi::PipelineLayoutHandle,
descriptor_set: ghi::DescriptorSetHandle,
shadow_map: ghi::ImageHandle,

occlusion_map_build_pipeline: ghi::PipelineHandle,
}

impl ShadowRenderingPass {
pub fn new(ghi: &mut dyn ghi::GraphicsHardwareInterface, render_domain: &impl WorldRenderDomain) -> ShadowRenderingPass {
let light_matrics_binding_template = ghi::DescriptorSetBindingTemplate::new(0, ghi::DescriptorType::StorageBuffer, ghi::Stages::MESH);

let bindings = [light_matrics_binding_template.clone(),];
let light_matrics_binding_template = ghi::DescriptorSetBindingTemplate::new(0, ghi::DescriptorType::StorageBuffer, ghi::Stages::MESH | ghi::Stages::COMPUTE);
let light_depth_map = ghi::DescriptorSetBindingTemplate::new(1, ghi::DescriptorType::CombinedImageSampler, ghi::Stages::COMPUTE);
let view_depth_map = ghi::DescriptorSetBindingTemplate::new(2, ghi::DescriptorType::CombinedImageSampler, ghi::Stages::COMPUTE);
let occlusion_image = ghi::DescriptorSetBindingTemplate::new(3, ghi::DescriptorType::StorageImage, ghi::Stages::COMPUTE);

let bindings = [
light_matrics_binding_template.clone(),
light_depth_map.clone(),
view_depth_map.clone(),
occlusion_image.clone(),
];

let descriptor_set_template = ghi.create_descriptor_set_template(Some("Shadow Rendering Set Layout"), &bindings);

Expand All @@ -33,11 +43,22 @@ impl ShadowRenderingPass {

let light_matrices_buffer = ghi.create_buffer(Some("Light Matrices Buffer"), 256 * 4 * 4 * 4, ghi::Uses::Storage, ghi::DeviceAccesses::CpuWrite | ghi::DeviceAccesses::GpuRead, ghi::UseCases::DYNAMIC);

ghi.write(&[ghi::DescriptorWrite::buffer(light_matrices_binding, light_matrices_buffer,),]);
let sampler = ghi.create_sampler(ghi::FilteringModes::Linear, ghi::FilteringModes::Linear, ghi::SamplerAddressingModes::Clamp, None, 0f32, 0f32);

let shadow_map_binding = ghi.create_descriptor_binding(descriptor_set, &light_depth_map);
let view_depth_map_binding = ghi.create_descriptor_binding(descriptor_set, &view_depth_map);
let occlusion_image_binding = ghi.create_descriptor_binding(descriptor_set, &occlusion_image);

ghi.write(&[
ghi::DescriptorWrite::buffer(light_matrices_binding, light_matrices_buffer,),
ghi::DescriptorWrite::combined_image_sampler(shadow_map_binding, shadow_map, sampler, ghi::Layouts::Read),
ghi::DescriptorWrite::combined_image_sampler(view_depth_map_binding, render_domain.get_view_depth_image(), sampler, ghi::Layouts::Read),
ghi::DescriptorWrite::image(occlusion_image_binding, render_domain.get_view_occlusion_image(), ghi::Layouts::General),
]);

let x = 4f32;

let mut light_projection_matrix = maths_rs::Mat4f::create_ortho_matrix(-x, x, -x, x, 1.0f32, 1000f32);
let mut light_projection_matrix = maths_rs::Mat4f::create_ortho_matrix(-x, x, -x, x, 0.1f32, 100f32);

light_projection_matrix[5] *= -1.0f32;

Expand All @@ -64,7 +85,17 @@ impl ShadowRenderingPass {
ghi::PipelineConfigurationBlocks::RenderTargets { targets: &[ghi::AttachmentInformation::new(shadow_map, ghi::Formats::Depth32, ghi::Layouts::RenderTarget, ghi::ClearValue::Depth(0.0f32), false, true)] },
]);

ShadowRenderingPass { pipeline, pipeline_layout, descriptor_set, shadow_map }
let occlusion_map_shader = ghi.create_shader(ghi::ShaderSource::GLSL(SHADOW_TO_OCLUSSION_MAP_SOURCE), ghi::ShaderTypes::Compute, &[
ghi::ShaderBindingDescriptor::new(0, 0, ghi::AccessPolicies::READ),
ghi::ShaderBindingDescriptor::new(1, 0, ghi::AccessPolicies::READ),
ghi::ShaderBindingDescriptor::new(1, 1, ghi::AccessPolicies::READ),
ghi::ShaderBindingDescriptor::new(1, 2, ghi::AccessPolicies::READ),
ghi::ShaderBindingDescriptor::new(1, 3, ghi::AccessPolicies::WRITE),
]);

let occlusion_map_build_pipeline = ghi.create_compute_pipeline(&pipeline_layout, (&occlusion_map_shader, ghi::ShaderTypes::Compute, vec![]));

ShadowRenderingPass { pipeline, pipeline_layout, descriptor_set, shadow_map, occlusion_map_build_pipeline }
}

pub fn render(&self, command_buffer_recording: &mut dyn ghi::CommandBufferRecording, render_domain: &impl WorldRenderDomain) {
Expand All @@ -76,6 +107,10 @@ impl ShadowRenderingPass {
pipeline.dispatch_meshes(192, 1, 1);
render_pass.end_render_pass();

let occlusion_map_build_pipeline = command_buffer_recording.bind_compute_pipeline(&self.occlusion_map_build_pipeline);
occlusion_map_build_pipeline.bind_descriptor_sets(&self.pipeline_layout, &[render_domain.get_descriptor_set(), self.descriptor_set]);
occlusion_map_build_pipeline.dispatch(ghi::DispatchExtent::new(Extent::rectangle(1920, 1080), Extent::square(32)));

command_buffer_recording.end_region();
}
}
Expand Down Expand Up @@ -171,6 +206,71 @@ void main() {
}
}";


const SHADOW_TO_OCLUSSION_MAP_SOURCE: &'static str = r#"
#version 450
#pragma shader_stage(compute)
layout(row_major) uniform; layout(row_major) buffer;
#extension GL_EXT_scalar_block_layout: enable
#extension GL_EXT_buffer_reference2: enable
#extension GL_EXT_shader_explicit_arithmetic_types : enable
struct Mesh {
mat4 model;
uint material_index;
uint32_t base_vertex_index;
};
struct Camera {
mat4 view_matrix;
mat4 projection_matrix;
mat4 view_projection;
};
layout(set=0,binding=0,scalar) buffer readonly CameraBuffer {
Camera camera;
};
layout(set=1,binding=0,scalar) buffer readonly LightMatrices {
mat4 light_matrix;
};
layout(set=1, binding=1) uniform sampler2D depth_shadow_map;
layout(set=1, binding=2) uniform sampler2D depth_map;
layout(set=1, binding=3, r8) uniform image2D oclussion_map;
vec3 get_view_position(sampler2D depth_map, uvec2 coords, mat4 projection_matrix) {
float depth_value = texelFetch(depth_map, ivec2(coords), 0).r;
vec2 uv = (vec2(coords) + vec2(0.5)) / vec2(textureSize(depth_map, 0).xy);
vec4 clip_space = vec4(uv * 2.0 - 1.0, depth_value, 1.0);
vec4 view_space = inverse(projection_matrix) * clip_space;
view_space /= view_space.w;
vec4 world_space = inverse(camera.view_matrix) * view_space;
return world_space.xyz;
}
layout(local_size_x=32, local_size_y=32) in;
void main() {
if (gl_GlobalInvocationID.x >= imageSize(oclussion_map).x || gl_GlobalInvocationID.y >= imageSize(oclussion_map).y) { return; }
vec3 surface_world_position = get_view_position(depth_map, uvec2(gl_GlobalInvocationID.xy), camera.projection_matrix);
vec4 surface_light_clip_position = light_matrix * vec4(surface_world_position, 1.0);
vec3 surface_light_ndc_position = surface_light_clip_position.xyz / surface_light_clip_position.w;
vec2 shadow_uv = surface_light_ndc_position.xy * 0.5 + 0.5;
float z = surface_light_ndc_position.z;
float shadow_sample_depth = texture(depth_shadow_map, shadow_uv).r;
float occlusion_factor = z + 0.00001 < shadow_sample_depth ? 0.0 : 1.0;
imageStore(oclussion_map, ivec2(gl_GlobalInvocationID.xy), vec4(occlusion_factor, 0, 0, 0));
}
"#;

// const SHADOW_RAY_GEN_SHADER: &'static str = "
// #version 460 core
// #pragma shader_stage(raygen)
Expand Down
78 changes: 23 additions & 55 deletions src/rendering/visibility_model/render_domain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use maths_rs::{prelude::MatTranslate, Mat4f};
use crate::core::entity::EntityBuilder;
use crate::core::listener::{Listener, EntitySubscriber};
use crate::core::{Entity, EntityHandle};
use crate::{ghi, utils};
use crate::{ghi, utils, RGBA};
use crate::rendering::{mesh, directional_light, point_light};
use crate::rendering::world_render_domain::WorldRenderDomain;
use crate::resource_management::resource_manager::ResourceManager;
Expand Down Expand Up @@ -264,30 +264,9 @@ impl VisibilityWorldRenderDomain {
instance_id = ghi_instance.create_image(Some("instance_id"), Extent::rectangle(1920, 1080), ghi::Formats::U32, None, ghi::Uses::RenderTarget | ghi::Uses::Storage, ghi::DeviceAccesses::GpuWrite | ghi::DeviceAccesses::GpuRead, ghi::UseCases::DYNAMIC);

let attachments = [
ghi::AttachmentInformation {
image: primitive_index,
layout: ghi::Layouts::RenderTarget,
format: ghi::Formats::U32,
clear: ghi::ClearValue::Integer(!0u32, 0, 0, 0),
load: false,
store: true,
},
ghi::AttachmentInformation {
image: instance_id,
layout: ghi::Layouts::RenderTarget,
format: ghi::Formats::U32,
clear: ghi::ClearValue::Integer(!0u32, 0, 0, 0),
load: false,
store: true,
},
ghi::AttachmentInformation {
image: depth_target,
layout: ghi::Layouts::RenderTarget,
format: ghi::Formats::Depth32,
clear: ghi::ClearValue::Depth(0f32),
load: false,
store: true,
},
ghi::AttachmentInformation::new(primitive_index,ghi::Formats::U32,ghi::Layouts::RenderTarget,ghi::ClearValue::Integer(!0u32, 0, 0, 0),false,true,),
ghi::AttachmentInformation::new(instance_id,ghi::Formats::U32,ghi::Layouts::RenderTarget,ghi::ClearValue::Integer(!0u32, 0, 0, 0),false,true,),
ghi::AttachmentInformation::new(depth_target,ghi::Formats::Depth32,ghi::Layouts::RenderTarget,ghi::ClearValue::Depth(0f32),false,true,),
];

vertex_layout = [
Expand Down Expand Up @@ -707,7 +686,7 @@ impl VisibilityWorldRenderDomain {
}
}

pub fn render(&mut self, ghi: &dyn ghi::GraphicsHardwareInterface, command_buffer_recording: &mut dyn ghi::CommandBufferRecording) {
pub fn render_a(&mut self, ghi: &dyn ghi::GraphicsHardwareInterface, command_buffer_recording: &mut dyn ghi::CommandBufferRecording) {
let camera_handle = if let Some(camera_handle) = &self.camera { camera_handle } else { return; };

{
Expand Down Expand Up @@ -744,35 +723,14 @@ impl VisibilityWorldRenderDomain {
camera_data_reference.projection_matrix = projection_matrix;
camera_data_reference.view_projection_matrix = view_projection_matrix;

command_buffer_recording.start_region("Visibility Model");

let attachments = [
ghi::AttachmentInformation {
image: self.primitive_index,
layout: ghi::Layouts::RenderTarget,
format: ghi::Formats::U32,
clear: ghi::ClearValue::Integer(!0u32, 0, 0, 0),
load: false,
store: true,
},
ghi::AttachmentInformation {
image: self.instance_id,
layout: ghi::Layouts::RenderTarget,
format: ghi::Formats::U32,
clear: ghi::ClearValue::Integer(!0u32, 0, 0, 0),
load: false,
store: true,
},
ghi::AttachmentInformation {
image: self.depth_target,
layout: ghi::Layouts::RenderTarget,
format: ghi::Formats::Depth32,
clear: ghi::ClearValue::Depth(0f32),
load: false,
store: true,
},
ghi::AttachmentInformation::new(self.primitive_index,ghi::Formats::U32,ghi::Layouts::RenderTarget,ghi::ClearValue::Integer(!0u32, 0, 0, 0),false,true,),
ghi::AttachmentInformation::new(self.instance_id,ghi::Formats::U32,ghi::Layouts::RenderTarget,ghi::ClearValue::Integer(!0u32, 0, 0, 0),false,true,),
ghi::AttachmentInformation::new(self.depth_target,ghi::Formats::Depth32,ghi::Layouts::RenderTarget,ghi::ClearValue::Depth(0f32),false,true,),
];

command_buffer_recording.clear_images(&[(self.occlusion_map, ghi::ClearValue::Color(RGBA::white())),]);

command_buffer_recording.start_region("Visibility Render Model");

command_buffer_recording.start_region("Visibility Buffer");
Expand Down Expand Up @@ -802,8 +760,12 @@ impl VisibilityWorldRenderDomain {
compute_pipeline_command.dispatch(ghi::DispatchExtent::new(Extent::rectangle(1920, 1080), Extent::square(32)));
command_buffer_recording.end_region();

command_buffer_recording.end_region();
}

pub fn render_b(&mut self, ghi: &dyn ghi::GraphicsHardwareInterface, command_buffer_recording: &mut dyn ghi::CommandBufferRecording) {
command_buffer_recording.start_region("Material Evaluation");
command_buffer_recording.clear_images(&[(self.albedo, ghi::ClearValue::Color(crate::RGBA::black())),(self.occlusion_map, ghi::ClearValue::Color(crate::RGBA::white()))]);
command_buffer_recording.clear_images(&[(self.albedo, ghi::ClearValue::Color(crate::RGBA::black())),]);
for (_, (i, pipeline)) in self.material_evaluation_materials.iter() {
// No need for sync here, as each thread across all invocations will write to a different pixel
let compute_pipeline_command = command_buffer_recording.bind_compute_pipeline(pipeline);
Expand All @@ -816,8 +778,6 @@ impl VisibilityWorldRenderDomain {
command_buffer_recording.end_region();

// ghi.wait(self.transfer_synchronizer); // Wait for buffers to be copied over to the GPU, or else we might overwrite them on the CPU before they are copied over

command_buffer_recording.end_region();
}
}

Expand Down Expand Up @@ -1134,6 +1094,14 @@ impl WorldRenderDomain for VisibilityWorldRenderDomain {
fn get_result_image(&self) -> ghi::ImageHandle {
self.albedo
}

fn get_view_depth_image(&self) -> ghi::ImageHandle {
self.depth_target
}

fn get_view_occlusion_image(&self) -> ghi::ImageHandle {
self.occlusion_map
}
}

const VERTEX_COUNT: u32 = 64;
Expand Down
4 changes: 2 additions & 2 deletions src/rendering/visibility_shader_generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -480,8 +480,6 @@ string.push_str(&format!("
float ao_factor = texture(ao, uv).r;
albedo *= ao_factor;
for (uint i = 0; i < lighting_data.light_count; ++i) {{
vec3 light_pos = lighting_data.lights[i].position;
vec3 light_color = lighting_data.lights[i].color;
Expand Down Expand Up @@ -511,6 +509,8 @@ string.push_str(&format!("
float NdotL = max(dot(N, L), 0.0);
lo += (kD * albedo / PI + specular) * radiance * NdotL;
}}
lo *= ao_factor;
"));

string.push_str(&format!("imageStore(out_albedo, pixel_coordinates, vec4(lo, 1.0));"));
Expand Down
2 changes: 2 additions & 0 deletions src/rendering/world_render_domain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,6 @@ pub trait WorldRenderDomain {
fn get_descriptor_set_template(&self) -> ghi::DescriptorSetTemplateHandle;
fn get_descriptor_set(&self) -> ghi::DescriptorSetHandle;
fn get_result_image(&self) -> ghi::ImageHandle;
fn get_view_depth_image(&self) -> ghi::ImageHandle;
fn get_view_occlusion_image(&self) -> ghi::ImageHandle;
}

0 comments on commit 0edc1e8

Please sign in to comment.