Compare commits
2 Commits
fef709d5f1
...
fefcf58765
Author | SHA1 | Date |
---|---|---|
SeanOMik | fefcf58765 | |
SeanOMik | b0a6d30afc |
|
@ -124,13 +124,6 @@ fn setup_scene_plugin(game: &mut Game) {
|
||||||
cube_gltf.wait_recurse_dependencies_load();
|
cube_gltf.wait_recurse_dependencies_load();
|
||||||
let cube_mesh = &cube_gltf.data_ref().unwrap().scenes[0];
|
let cube_mesh = &cube_gltf.data_ref().unwrap().scenes[0];
|
||||||
|
|
||||||
let platform_gltf = resman
|
|
||||||
.request::<Gltf>("../assets/wood-platform.glb")
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
platform_gltf.wait_recurse_dependencies_load();
|
|
||||||
let platform_mesh = &platform_gltf.data_ref().unwrap().scenes[0];
|
|
||||||
|
|
||||||
let palm_tree_platform_gltf = resman
|
let palm_tree_platform_gltf = resman
|
||||||
.request::<Gltf>("../assets/shadows-platform-palmtree.glb")
|
.request::<Gltf>("../assets/shadows-platform-palmtree.glb")
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
@ -189,6 +182,10 @@ fn setup_scene_plugin(game: &mut Game) {
|
||||||
color: Vec3::new(1.0, 0.95, 0.9),
|
color: Vec3::new(1.0, 0.95, 0.9),
|
||||||
intensity: 0.9,
|
intensity: 0.9,
|
||||||
},
|
},
|
||||||
|
ShadowCasterSettings {
|
||||||
|
filtering_mode: ShadowFilteringMode::Pcss,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
light_tran,
|
light_tran,
|
||||||
));
|
));
|
||||||
|
|
||||||
|
|
|
@ -256,7 +256,8 @@ impl ShadowMapsPass {
|
||||||
has_shadow_settings,
|
has_shadow_settings,
|
||||||
pcf_samples_num: u.pcf_samples_num,
|
pcf_samples_num: u.pcf_samples_num,
|
||||||
pcss_blocker_search_samples: u.pcss_blocker_search_samples,
|
pcss_blocker_search_samples: u.pcss_blocker_search_samples,
|
||||||
_padding2: [0; 2],
|
constant_depth_bias: DEFAULT_CONSTANT_DEPTH_BIAS * shadow_settings.constant_depth_bias_scale,
|
||||||
|
_padding2: 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
let uniform_index = self.light_uniforms_buffer.insert(queue, &u);
|
let uniform_index = self.light_uniforms_buffer.insert(queue, &u);
|
||||||
|
@ -348,7 +349,8 @@ impl ShadowMapsPass {
|
||||||
has_shadow_settings,
|
has_shadow_settings,
|
||||||
pcf_samples_num: u.pcf_samples_num,
|
pcf_samples_num: u.pcf_samples_num,
|
||||||
pcss_blocker_search_samples: u.pcss_blocker_search_samples,
|
pcss_blocker_search_samples: u.pcss_blocker_search_samples,
|
||||||
_padding2: [0; 2],
|
constant_depth_bias: DEFAULT_CONSTANT_DEPTH_BIAS * shadow_settings.constant_depth_bias_scale,
|
||||||
|
_padding2: 0,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
indices[i] = uniform_i;
|
indices[i] = uniform_i;
|
||||||
|
@ -594,6 +596,11 @@ impl Node for ShadowMapsPass {
|
||||||
}
|
}
|
||||||
let settings = *world.get_resource::<ShadowCasterSettings>();
|
let settings = *world.get_resource::<ShadowCasterSettings>();
|
||||||
|
|
||||||
|
if settings.use_back_faces {
|
||||||
|
// TODO: shadow maps rendering with back faces
|
||||||
|
todo!("render with back faces");
|
||||||
|
}
|
||||||
|
|
||||||
self.render_meshes = world.try_get_resource_data::<RenderMeshes>();
|
self.render_meshes = world.try_get_resource_data::<RenderMeshes>();
|
||||||
self.transform_buffers = world.try_get_resource_data::<TransformBuffers>();
|
self.transform_buffers = world.try_get_resource_data::<TransformBuffers>();
|
||||||
self.mesh_buffers = world.try_get_resource_data::<RenderAssets<MeshBufferStorage>>();
|
self.mesh_buffers = world.try_get_resource_data::<RenderAssets<MeshBufferStorage>>();
|
||||||
|
@ -888,8 +895,15 @@ pub struct ShadowCasterSettings {
|
||||||
pub pcss_blocker_search_samples: u32,
|
pub pcss_blocker_search_samples: u32,
|
||||||
pub near_plane: f32,
|
pub near_plane: f32,
|
||||||
pub far_plane: f32,
|
pub far_plane: f32,
|
||||||
|
/// The scale of the constant shadow depth bias.
|
||||||
|
///
|
||||||
|
/// This scale will be multiplied by the default constant depth bias value of 0.001.
|
||||||
|
pub constant_depth_bias_scale: f32,
|
||||||
|
pub use_back_faces: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const DEFAULT_CONSTANT_DEPTH_BIAS: f32 = 0.001;
|
||||||
|
|
||||||
impl Default for ShadowCasterSettings {
|
impl Default for ShadowCasterSettings {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
@ -898,6 +912,8 @@ impl Default for ShadowCasterSettings {
|
||||||
pcss_blocker_search_samples: 25,
|
pcss_blocker_search_samples: 25,
|
||||||
near_plane: 0.1,
|
near_plane: 0.1,
|
||||||
far_plane: 45.0,
|
far_plane: 45.0,
|
||||||
|
constant_depth_bias_scale: 1.0,
|
||||||
|
use_back_faces: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -917,7 +933,8 @@ pub struct LightShadowUniform {
|
||||||
has_shadow_settings: u32,
|
has_shadow_settings: u32,
|
||||||
pcf_samples_num: u32,
|
pcf_samples_num: u32,
|
||||||
pcss_blocker_search_samples: u32,
|
pcss_blocker_search_samples: u32,
|
||||||
_padding2: [u32; 2],
|
constant_depth_bias: f32,
|
||||||
|
_padding2: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A component that stores the ID of a shadow map in the shadow map atlas for the entities.
|
/// A component that stores the ID of a shadow map in the shadow map atlas for the entities.
|
||||||
|
|
|
@ -123,6 +123,7 @@ struct LightShadowMapUniform {
|
||||||
has_shadow_settings: u32,
|
has_shadow_settings: u32,
|
||||||
pcf_samples_num: u32,
|
pcf_samples_num: u32,
|
||||||
pcss_blocker_search_samples: u32,
|
pcss_blocker_search_samples: u32,
|
||||||
|
constant_depth_bias: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ShadowSettingsUniform {
|
struct ShadowSettingsUniform {
|
||||||
|
@ -183,7 +184,7 @@ fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
|
||||||
let shadow_u: LightShadowMapUniform = u_light_shadow[light.light_shadow_uniform_index[0]];
|
let shadow_u: LightShadowMapUniform = u_light_shadow[light.light_shadow_uniform_index[0]];
|
||||||
let frag_pos_light_space = shadow_u.light_space_matrix * vec4<f32>(in.world_position, 1.0);
|
let frag_pos_light_space = shadow_u.light_space_matrix * vec4<f32>(in.world_position, 1.0);
|
||||||
|
|
||||||
let shadow = calc_shadow_dir_light(in.world_normal, light_dir, frag_pos_light_space, atlas_dimensions, shadow_u);
|
let shadow = calc_shadow_dir_light(in.world_position, in.world_normal, light_dir, light);
|
||||||
light_res += blinn_phong_dir_light(in.world_position, in.world_normal, light, u_material, specular_color, shadow);
|
light_res += blinn_phong_dir_light(in.world_position, in.world_normal, light, u_material, specular_color, shadow);
|
||||||
} else if (light.light_ty == LIGHT_TY_POINT) {
|
} else if (light.light_ty == LIGHT_TY_POINT) {
|
||||||
let shadow = calc_shadow_point_light(in.world_position, in.world_normal, light_dir, light, atlas_dimensions);
|
let shadow = calc_shadow_point_light(in.world_position, in.world_normal, light_dir, light, atlas_dimensions);
|
||||||
|
@ -265,7 +266,10 @@ fn get_shadow_settings(shadow_u: LightShadowMapUniform) -> vec2<u32> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn calc_shadow_dir_light(normal: vec3<f32>, light_dir: vec3<f32>, frag_pos_light_space: vec4<f32>, atlas_dimensions: vec2<i32>, shadow_u: LightShadowMapUniform) -> f32 {
|
fn calc_shadow_dir_light(world_pos: vec3<f32>, world_normal: vec3<f32>, light_dir: vec3<f32>, light: Light) -> f32 {
|
||||||
|
let map_data: LightShadowMapUniform = u_light_shadow[light.light_shadow_uniform_index[0]];
|
||||||
|
let frag_pos_light_space = map_data.light_space_matrix * vec4<f32>(world_pos, 1.0);
|
||||||
|
|
||||||
var proj_coords = frag_pos_light_space.xyz / frag_pos_light_space.w;
|
var proj_coords = frag_pos_light_space.xyz / frag_pos_light_space.w;
|
||||||
// for some reason the y component is flipped after transforming
|
// for some reason the y component is flipped after transforming
|
||||||
proj_coords.y = -proj_coords.y;
|
proj_coords.y = -proj_coords.y;
|
||||||
|
@ -274,32 +278,31 @@ fn calc_shadow_dir_light(normal: vec3<f32>, light_dir: vec3<f32>, frag_pos_light
|
||||||
let xy_remapped = proj_coords.xy * 0.5 + 0.5;
|
let xy_remapped = proj_coords.xy * 0.5 + 0.5;
|
||||||
|
|
||||||
// use a bias to avoid shadow acne
|
// use a bias to avoid shadow acne
|
||||||
let bias = 0.005;//max(0.05 * (1.0 - dot(normal, light_dir)), 0.005);
|
let current_depth = proj_coords.z - map_data.constant_depth_bias;
|
||||||
let current_depth = proj_coords.z - bias;
|
|
||||||
|
|
||||||
// get settings
|
// get settings
|
||||||
let settings = get_shadow_settings(shadow_u);
|
let settings = get_shadow_settings(map_data);
|
||||||
let pcf_samples_num = settings.x;
|
let pcf_samples_num = settings.x;
|
||||||
let pcss_blocker_search_samples = settings.y;
|
let pcss_blocker_search_samples = settings.y;
|
||||||
|
|
||||||
var shadow = 0.0;
|
var shadow = 0.0;
|
||||||
// hardware 2x2 PCF via camparison sampler
|
// hardware 2x2 PCF via camparison sampler
|
||||||
if pcf_samples_num == 2u {
|
if pcf_samples_num == 2u {
|
||||||
let region_coords = to_atlas_frame_coords(shadow_u, xy_remapped);
|
let region_coords = to_atlas_frame_coords(map_data, xy_remapped, false);
|
||||||
shadow = textureSampleCompareLevel(t_shadow_maps_atlas, s_shadow_maps_atlas_compare, region_coords, current_depth);
|
shadow = textureSampleCompareLevel(t_shadow_maps_atlas, s_shadow_maps_atlas_compare, region_coords, current_depth);
|
||||||
}
|
}
|
||||||
// PCSS
|
// PCSS
|
||||||
else if pcf_samples_num > 0u && pcss_blocker_search_samples > 0u {
|
else if pcf_samples_num > 0u && pcss_blocker_search_samples > 0u {
|
||||||
shadow = pcss_dir_light(xy_remapped, current_depth, shadow_u);
|
shadow = pcss_dir_light(xy_remapped, current_depth, map_data);
|
||||||
}
|
}
|
||||||
// only PCF
|
// only PCF
|
||||||
else if pcf_samples_num > 0u {
|
else if pcf_samples_num > 0u {
|
||||||
let texel_size = 1.0 / f32(shadow_u.atlas_frame.width);
|
let texel_size = 1.0 / f32(map_data.atlas_frame.width);
|
||||||
shadow = pcf_dir_light(xy_remapped, current_depth, shadow_u, texel_size);
|
shadow = pcf_dir_light(xy_remapped, current_depth, map_data, texel_size);
|
||||||
}
|
}
|
||||||
// no filtering
|
// no filtering
|
||||||
else {
|
else {
|
||||||
let region_coords = to_atlas_frame_coords(shadow_u, xy_remapped);
|
let region_coords = to_atlas_frame_coords(map_data, xy_remapped, false);
|
||||||
let closest_depth = textureSampleLevel(t_shadow_maps_atlas, s_shadow_maps_atlas, region_coords, 0.0);
|
let closest_depth = textureSampleLevel(t_shadow_maps_atlas, s_shadow_maps_atlas, region_coords, 0.0);
|
||||||
shadow = select(1.0, 0.0, current_depth > closest_depth);
|
shadow = select(1.0, 0.0, current_depth > closest_depth);
|
||||||
}
|
}
|
||||||
|
@ -323,7 +326,10 @@ fn search_width(light_near: f32, uv_light_size: f32, receiver_depth: f32) -> f32
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convert texture coords to be texture coords of an atlas frame.
|
/// Convert texture coords to be texture coords of an atlas frame.
|
||||||
fn to_atlas_frame_coords(shadow_u: LightShadowMapUniform, coords: vec2<f32>) -> vec2<f32> {
|
///
|
||||||
|
/// If `safety_offset` is true, the frame will be shrank by a tiny amount to avoid bleeding
|
||||||
|
/// into adjacent frames from fiiltering.
|
||||||
|
fn to_atlas_frame_coords(shadow_u: LightShadowMapUniform, coords: vec2<f32>, safety_offset: bool) -> vec2<f32> {
|
||||||
let atlas_dimensions = textureDimensions(t_shadow_maps_atlas);
|
let atlas_dimensions = textureDimensions(t_shadow_maps_atlas);
|
||||||
|
|
||||||
// get the rect of the frame as a vec4
|
// get the rect of the frame as a vec4
|
||||||
|
@ -332,9 +338,9 @@ fn to_atlas_frame_coords(shadow_u: LightShadowMapUniform, coords: vec2<f32>) ->
|
||||||
// put the frame rect in atlas UV space
|
// put the frame rect in atlas UV space
|
||||||
region_rect /= f32(atlas_dimensions.x);
|
region_rect /= f32(atlas_dimensions.x);
|
||||||
|
|
||||||
// calculate a relatively tiny offset to avoid getting the end of the frame and causing
|
// if safety_offset is true, calculate a relatively tiny offset to avoid getting the end of
|
||||||
// linear or nearest filtering to bleed to the adjacent frame.
|
// the frame and causing linear or nearest filtering to bleed to the adjacent frame.
|
||||||
let texel_size = (1.0 / f32(shadow_u.atlas_frame.x)) * 4.0;
|
let texel_size = select(0.0, (1.0 / f32(shadow_u.atlas_frame.x)) * 4.0, safety_offset);
|
||||||
|
|
||||||
// lerp input coords
|
// lerp input coords
|
||||||
let region_coords = vec2<f32>(
|
let region_coords = vec2<f32>(
|
||||||
|
@ -354,7 +360,7 @@ fn find_blocker_distance_dir_light(tex_coords: vec2<f32>, receiver_depth: f32, b
|
||||||
let samples = i32(u_shadow_settings.pcss_blocker_search_samples);
|
let samples = i32(u_shadow_settings.pcss_blocker_search_samples);
|
||||||
for (var i = 0; i < samples; i++) {
|
for (var i = 0; i < samples; i++) {
|
||||||
let offset_coords = tex_coords + u_pcss_poisson_disc[i] * search_width;
|
let offset_coords = tex_coords + u_pcss_poisson_disc[i] * search_width;
|
||||||
let new_coords = to_atlas_frame_coords(shadow_u, offset_coords);
|
let new_coords = to_atlas_frame_coords(shadow_u, offset_coords, false);
|
||||||
let z = textureSampleLevel(t_shadow_maps_atlas, s_shadow_maps_atlas, new_coords, 0.0);
|
let z = textureSampleLevel(t_shadow_maps_atlas, s_shadow_maps_atlas, new_coords, 0.0);
|
||||||
|
|
||||||
if z < (receiver_depth - bias) {
|
if z < (receiver_depth - bias) {
|
||||||
|
@ -390,7 +396,7 @@ fn pcf_dir_light(tex_coords: vec2<f32>, test_depth: f32, shadow_u: LightShadowMa
|
||||||
let samples_num = i32(u_shadow_settings.pcf_samples_num);
|
let samples_num = i32(u_shadow_settings.pcf_samples_num);
|
||||||
for (var i = 0; i < samples_num; i++) {
|
for (var i = 0; i < samples_num; i++) {
|
||||||
let offset = tex_coords + u_pcf_poisson_disc[i] * uv_radius;
|
let offset = tex_coords + u_pcf_poisson_disc[i] * uv_radius;
|
||||||
let new_coords = to_atlas_frame_coords(shadow_u, offset);
|
let new_coords = to_atlas_frame_coords(shadow_u, offset, false);
|
||||||
|
|
||||||
shadow += textureSampleCompare(t_shadow_maps_atlas, s_shadow_maps_atlas_compare, new_coords, test_depth);
|
shadow += textureSampleCompare(t_shadow_maps_atlas, s_shadow_maps_atlas_compare, new_coords, test_depth);
|
||||||
}
|
}
|
||||||
|
@ -421,7 +427,7 @@ fn calc_shadow_point_light(world_pos: vec3<f32>, world_normal: vec3<f32>, light_
|
||||||
|
|
||||||
var current_depth = length(frag_to_light);
|
var current_depth = length(frag_to_light);
|
||||||
current_depth /= u.far_plane;
|
current_depth /= u.far_plane;
|
||||||
current_depth -= 0.005; // TODO: find a better way to calculate bias
|
current_depth -= u.constant_depth_bias;
|
||||||
|
|
||||||
// get settings
|
// get settings
|
||||||
let settings = get_shadow_settings(u);
|
let settings = get_shadow_settings(u);
|
||||||
|
@ -431,7 +437,7 @@ fn calc_shadow_point_light(world_pos: vec3<f32>, world_normal: vec3<f32>, light_
|
||||||
var shadow = 0.0;
|
var shadow = 0.0;
|
||||||
// hardware 2x2 PCF via camparison sampler
|
// hardware 2x2 PCF via camparison sampler
|
||||||
if pcf_samples_num == 2u {
|
if pcf_samples_num == 2u {
|
||||||
let region_coords = to_atlas_frame_coords(u, coords_2d);
|
let region_coords = to_atlas_frame_coords(u, coords_2d, true);
|
||||||
shadow = textureSampleCompareLevel(t_shadow_maps_atlas, s_shadow_maps_atlas_compare, region_coords, current_depth);
|
shadow = textureSampleCompareLevel(t_shadow_maps_atlas, s_shadow_maps_atlas_compare, region_coords, current_depth);
|
||||||
}
|
}
|
||||||
// PCSS
|
// PCSS
|
||||||
|
@ -446,7 +452,7 @@ fn calc_shadow_point_light(world_pos: vec3<f32>, world_normal: vec3<f32>, light_
|
||||||
}
|
}
|
||||||
// no filtering
|
// no filtering
|
||||||
else {
|
else {
|
||||||
let region_coords = to_atlas_frame_coords(u, coords_2d);
|
let region_coords = to_atlas_frame_coords(u, coords_2d, true);
|
||||||
let closest_depth = textureSampleLevel(t_shadow_maps_atlas, s_shadow_maps_atlas, region_coords, 0.0);
|
let closest_depth = textureSampleLevel(t_shadow_maps_atlas, s_shadow_maps_atlas, region_coords, 0.0);
|
||||||
shadow = select(1.0, 0.0, current_depth > closest_depth);
|
shadow = select(1.0, 0.0, current_depth > closest_depth);
|
||||||
}
|
}
|
||||||
|
@ -467,7 +473,7 @@ fn pcf_point_light(tex_coords: vec3<f32>, test_depth: f32, shadow_us: array<Ligh
|
||||||
|
|
||||||
coords_2d += u_pcf_poisson_disc[i] * uv_radius;
|
coords_2d += u_pcf_poisson_disc[i] * uv_radius;
|
||||||
|
|
||||||
let new_coords = to_atlas_frame_coords(shadow_u, coords_2d);
|
let new_coords = to_atlas_frame_coords(shadow_u, coords_2d, true);
|
||||||
shadow += textureSampleCompare(t_shadow_maps_atlas, s_shadow_maps_atlas_compare, new_coords, test_depth);
|
shadow += textureSampleCompare(t_shadow_maps_atlas, s_shadow_maps_atlas_compare, new_coords, test_depth);
|
||||||
}
|
}
|
||||||
shadow /= f32(samples_num);
|
shadow /= f32(samples_num);
|
||||||
|
|
|
@ -19,6 +19,7 @@ struct LightShadowMapUniform {
|
||||||
has_shadow_settings: u32,
|
has_shadow_settings: u32,
|
||||||
pcf_samples_num: u32,
|
pcf_samples_num: u32,
|
||||||
pcss_blocker_search_samples: u32,
|
pcss_blocker_search_samples: u32,
|
||||||
|
constant_depth_bias: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
@group(0) @binding(0)
|
@group(0) @binding(0)
|
||||||
|
|
Loading…
Reference in New Issue