Skip to content

Commit

Permalink
Shadow mapping
Browse files Browse the repository at this point in the history
Improve shadow demo by introducing a render source radio button to
switch between showing the canonical render result or the shadowmap.
  • Loading branch information
Fahien committed Dec 20, 2021
1 parent 08d6a36 commit 4e72328
Show file tree
Hide file tree
Showing 7 changed files with 88 additions and 30 deletions.
19 changes: 16 additions & 3 deletions res/shader/pbr/shadow.texture.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,26 @@ float calculate_shadow(vec4 pos_light_space, float NoL) {
vec3 pos = pos_light_space.xyz / pos_light_space.w;
// Now transform range to [0, 1] for shadow map
pos = pos * 0.5 + 0.5;
if (pos.z > 1.0) {
return 1.0;
}

float closest_depth = texture(shadow_sampler, pos.xy).r;
float current_depth = pos.z;

float bias = max(0.0005 * (1.0 - NoL), 0.0005);
float bias = max(0.05 * (1.0 - NoL), 0.005);
// Greater depth means it is further away
float shadow = current_depth - bias > closest_depth ? 0.5 : 1.0;
float shadow = current_depth - bias > closest_depth ? 1.0 : 0.5;

vec2 texel_size = vec2(1.0 / 512.0);
for(int x = -1; x <= 1; ++x) {
for(int y = -1; y <= 1; ++y) {
float pcfDepth = texture(shadow_sampler, pos.xy + vec2(float(x), float(y)) * texel_size).r;
shadow += current_depth - bias > pcfDepth ? 1.0 : 0.0;
}
}
shadow /= 18.0;

// 1.0 means no shadow
return shadow;
return 1.0 - shadow;
}
6 changes: 5 additions & 1 deletion src/demo/5-structure.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,15 @@ fn main() {
na::UnitQuaternion::from_axis_angle(&na::Vector3::y_axis(), delta.as_secs_f32() / 2.0);
model.nodes.get_mut(root).unwrap().trs.rotate(&rot);

let frame = spot.gfx.next_frame();
spot.gfx
.renderer
.render_shadow(&model, &frame.shadow_buffer);

spot.gfx
.renderer
.draw(&model, root, &na::Matrix4::identity());

let frame = spot.gfx.next_frame();
spot.gfx
.renderer
.render_geometry(&model, &frame.default_framebuffer);
Expand Down
72 changes: 58 additions & 14 deletions src/demo/8-shadow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,30 @@ use rustspot::*;

mod model;

#[derive(Clone, Copy, PartialEq, Eq)]
enum RenderSource {
// Render the default source
Default,

// Render the shadowmap
Shadowmap,
}

fn main() {
let width = 480;
let height = 320;
let mut spot = Spot::builder().width(width).height(height).build();
let mut spot = Spot::builder().build();

let (mut model, root) = create_model();

let mut render_source = RenderSource::Default;

'gameloop: loop {
// Handle SDL2 events
for event in spot.events.poll_iter() {
spot.input.handle(&event);

match event {
sdl2::event::Event::Quit { .. } => break 'gameloop,
_ => println!("{:?}", event),
_ => (),
}
}

Expand All @@ -39,21 +50,54 @@ fn main() {
.renderer
.render_shadow(&model, &frame.shadow_buffer);

spot.gfx
.renderer
.draw(&model, root, &na::Matrix4::identity());
match render_source {
RenderSource::Default => {
spot.gfx
.renderer
.draw(&model, root, &na::Matrix4::identity());

spot.gfx
.renderer
.render_geometry(&model, &frame.geometry_buffer);
spot.gfx
.renderer
.render_geometry(&model, &frame.geometry_buffer);

// Draw a simple triangle which cover the whole screen
spot.gfx
.renderer
.blit_color(&frame.geometry_buffer, &frame.default_framebuffer);
spot.gfx
.renderer
.blit_color(&frame.geometry_buffer, &frame.default_framebuffer);
}

RenderSource::Shadowmap => {
spot.gfx
.renderer
.blit_depth(&frame.shadow_buffer, &frame.default_framebuffer);
}
}

// Render GUI
let ui = spot.gfx.gui.frame();
// Draw gui here before drawing it
imgui::Window::new(imgui::im_str!("RustSpot"))
.size([300.0, 60.0], imgui::Condition::FirstUseEver)
.build(&ui, || {
ui.text("Render source");
let mut value = render_source;
if ui.radio_button(imgui::im_str!("Default"), &mut value, RenderSource::Default) {
render_source = value;
}
if ui.radio_button(
imgui::im_str!("Shadowmap"),
&mut value,
RenderSource::Shadowmap,
) {
render_source = value;
}
});
spot.gfx.renderer.render_gui(ui, &frame.default_framebuffer);

// Present to the screen
spot.gfx.present(frame);

// TODO greate a spot loop which automatically resets stuff?
spot.input.reset();
}
}

Expand Down
6 changes: 3 additions & 3 deletions src/demo/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ pub fn create_structure_scene(model: &mut Model) -> Handle<Node> {
.directional_lights
.push(DirectionalLight::color(1.0, 1.0, 1.0));
let mut light_node = Node::new();
light_node.trs.translate(2.0, 0.0, 8.0);
light_node.trs.translate(2.0, 0.0, 4.0);
light_node.trs.rotate(&na::UnitQuaternion::from_axis_angle(
&na::Vector3::x_axis(),
-std::f32::consts::FRAC_PI_4,
Expand Down Expand Up @@ -111,7 +111,7 @@ pub fn create_structure_scene(model: &mut Model) -> Handle<Node> {
.push(Texture::pixel(Color::rgba(160, 170, 180, 255)));
let material = Material::builder()
.texture(texture)
.shader(Shaders::LightShadow)
.shader(Shaders::PbrOcclusionDefaultMetallicRoughnessDefaultNormalDefaultShadowTexture)
.build();
let material = model.materials.push(material);
let primitives = vec![model.primitives.push(Primitive::cube(material))];
Expand All @@ -130,7 +130,7 @@ pub fn create_structure_scene(model: &mut Model) -> Handle<Node> {
.push(Texture::pixel(Color::rgba(255, 255, 255, 255)));
let material = Material::builder()
.texture(texture)
.shader(Shaders::LightShadow)
.shader(Shaders::PbrOcclusionDefaultMetallicRoughnessDefaultNormalDefaultShadowTexture)
.build();
let material = model.materials.push(material);
let primitives = vec![model.primitives.push(Primitive::cube(material))];
Expand Down
6 changes: 3 additions & 3 deletions src/rustspot/gfx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -161,14 +161,14 @@ pub struct Camera {
}

impl Camera {
pub fn orthographic(width: u32, height: u32) -> Camera {
pub fn orthographic(width: u32, height: u32, near: f32, far: f32) -> Camera {
let proj = na::Orthographic3::new(
-(width as f32) / 2.0,
width as f32 / 2.0,
-(height as f32) / 2.0,
(height as f32) / 2.0,
0.1,
100.0,
near,
far,
);
Camera {
proj: proj.to_homogeneous(),
Expand Down
7 changes: 2 additions & 5 deletions src/rustspot/renderer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ impl Renderer {
"res/shader/read-color-ms.frag.glsl",
);

let screen_camera = Camera::orthographic(1, 1);
let screen_camera = Camera::orthographic(1, 1, 0.1, 100.0);
let mut screen_node = Node::new();
screen_node.trs.translate(0.0, 0.0, 1.0);

Expand Down Expand Up @@ -234,10 +234,7 @@ impl Renderer {
if let Some(light_node) = model.nodes.get(self.directional_light) {
// Bind directional light as camera view
// Create orthographic camera but how big?
let camera = Camera::orthographic(
framebuffer.virtual_extent.width / 16,
framebuffer.virtual_extent.height / 16,
);
let camera = Camera::orthographic(8, 8, 1.0, 8.0);
draw_shadow_program.bind_camera(&camera, &light_node);
// Keep track for next pass
self.light_space = camera.proj * light_node.trs.get_view();
Expand Down
2 changes: 1 addition & 1 deletion src/rustspot/texture.rs
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@ impl Texture {
.extent(extent)
.samples(samples)
.format(gl::DEPTH_COMPONENT)
.component(gl::UNSIGNED_SHORT)
.component(gl::FLOAT)
.build()
.unwrap()
}
Expand Down

0 comments on commit 4e72328

Please sign in to comment.