render: simple PCF
This commit is contained in:
parent
d02258224a
commit
ff06bd55f3
|
@ -166,7 +166,7 @@ fn setup_scene_plugin(game: &mut Game) {
|
||||||
light_tran,
|
light_tran,
|
||||||
));
|
));
|
||||||
|
|
||||||
world.spawn((
|
/* world.spawn((
|
||||||
//cube_mesh.clone(),
|
//cube_mesh.clone(),
|
||||||
PointLight {
|
PointLight {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
|
@ -188,7 +188,7 @@ fn setup_scene_plugin(game: &mut Game) {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
Transform::from_xyz(-0.5, 2.0, -5.0),
|
Transform::from_xyz(-0.5, 2.0, -5.0),
|
||||||
));
|
)); */
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut camera = CameraComponent::new_3d();
|
let mut camera = CameraComponent::new_3d();
|
||||||
|
|
|
@ -142,7 +142,7 @@ impl Node for MeshPass {
|
||||||
wgpu::BindGroupLayoutEntry {
|
wgpu::BindGroupLayoutEntry {
|
||||||
binding: 1,
|
binding: 1,
|
||||||
visibility: wgpu::ShaderStages::FRAGMENT,
|
visibility: wgpu::ShaderStages::FRAGMENT,
|
||||||
ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering),
|
ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Comparison),
|
||||||
count: None,
|
count: None,
|
||||||
},
|
},
|
||||||
wgpu::BindGroupLayoutEntry {
|
wgpu::BindGroupLayoutEntry {
|
||||||
|
|
|
@ -114,6 +114,7 @@ impl ShadowMapsPass {
|
||||||
min_filter: wgpu::FilterMode::Linear,
|
min_filter: wgpu::FilterMode::Linear,
|
||||||
mipmap_filter: wgpu::FilterMode::Linear,
|
mipmap_filter: wgpu::FilterMode::Linear,
|
||||||
border_color: Some(wgpu::SamplerBorderColor::OpaqueWhite),
|
border_color: Some(wgpu::SamplerBorderColor::OpaqueWhite),
|
||||||
|
compare: Some(wgpu::CompareFunction::LessEqual),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -58,7 +58,7 @@ impl Material {
|
||||||
//diffuse: glam::Vec3::new(value.base_color.x, value.base_color.y, value.base_color.z),
|
//diffuse: glam::Vec3::new(value.base_color.x, value.base_color.y, value.base_color.z),
|
||||||
//diffuse: glam::Vec3::new(1.0, 0.5, 0.31),
|
//diffuse: glam::Vec3::new(1.0, 0.5, 0.31),
|
||||||
//specular: glam::Vec3::new(0.5, 0.5, 0.5),
|
//specular: glam::Vec3::new(0.5, 0.5, 0.5),
|
||||||
ambient: glam::Vec3::new(1.0, 1.0, 1.0),
|
ambient: glam::Vec3::new(1.0, 1.0, 1.0) * 0.5,
|
||||||
diffuse: glam::Vec3::new(1.0, 1.0, 1.0),
|
diffuse: glam::Vec3::new(1.0, 1.0, 1.0),
|
||||||
shininess: 32.0,
|
shininess: 32.0,
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,8 @@ const LIGHT_TY_SPOT = 2u;
|
||||||
|
|
||||||
const ALPHA_CUTOFF = 0.1;
|
const ALPHA_CUTOFF = 0.1;
|
||||||
|
|
||||||
|
const SHADOW_MAP_PCF_SIZE = 4.0;
|
||||||
|
|
||||||
struct VertexInput {
|
struct VertexInput {
|
||||||
@location(0) position: vec3<f32>,
|
@location(0) position: vec3<f32>,
|
||||||
@location(1) tex_coords: vec2<f32>,
|
@location(1) tex_coords: vec2<f32>,
|
||||||
|
@ -128,7 +130,7 @@ var t_light_grid: texture_storage_2d<rg32uint, read_write>; // rg32uint = vec2<u
|
||||||
@group(5) @binding(0)
|
@group(5) @binding(0)
|
||||||
var t_shadow_maps_atlas: texture_depth_2d;
|
var t_shadow_maps_atlas: texture_depth_2d;
|
||||||
@group(5) @binding(1)
|
@group(5) @binding(1)
|
||||||
var s_shadow_maps_atlas: sampler;
|
var s_shadow_maps_atlas: sampler_comparison;
|
||||||
@group(5) @binding(2)
|
@group(5) @binding(2)
|
||||||
var<uniform> u_shadow_maps_atlas_size: vec2<u32>;
|
var<uniform> u_shadow_maps_atlas_size: vec2<u32>;
|
||||||
@group(5) @binding(3)
|
@group(5) @binding(3)
|
||||||
|
@ -165,7 +167,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.atlas_frame);
|
let shadow = calc_shadow_dir_light(in.world_normal, light_dir, frag_pos_light_space, atlas_dimensions, shadow_u);
|
||||||
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(in.world_position, in.world_normal, light_dir, light, atlas_dimensions);
|
let shadow = calc_shadow_point(in.world_position, in.world_normal, light_dir, light, atlas_dimensions);
|
||||||
|
@ -240,45 +242,60 @@ fn get_side_idx(tex_coord: vec3<f32>) -> vec3<f32> {
|
||||||
return vec3<f32>(res, f32(cube_idx));
|
return vec3<f32>(res, f32(cube_idx));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn calc_shadow_dir_light(normal: vec3<f32>, light_dir: vec3<f32>, frag_pos_light_space: vec4<f32>, atlas_dimensions: vec2<i32>, atlas_region: TextureAtlasFrame) -> f32 {
|
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 {
|
||||||
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;
|
||||||
|
|
||||||
// dont cast shadows outside the light's far plane
|
|
||||||
if (proj_coords.z > 1.0) {
|
|
||||||
return 0.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remap xy to [0.0, 1.0]
|
// Remap xy to [0.0, 1.0]
|
||||||
let xy_remapped = proj_coords.xy * 0.5 + 0.5;
|
let xy_remapped = proj_coords.xy * 0.5 + 0.5;
|
||||||
|
|
||||||
// no need to get the y since the maps are square
|
// get the atlas frame in [0; 1] in the atlas texture
|
||||||
let atlas_start = f32(atlas_region.x) / f32(atlas_dimensions.x);
|
// z is width, w is height
|
||||||
let atlas_end = f32(atlas_region.x + atlas_region.width) / f32(atlas_dimensions.x);
|
var region_rect = vec4<f32>(f32(shadow_u.atlas_frame.x), f32(shadow_u.atlas_frame.y), f32(shadow_u.atlas_frame.width), f32(shadow_u.atlas_frame.height));
|
||||||
// lerp the tex coords to the shadow map for this light.
|
region_rect /= f32(atlas_dimensions.x);
|
||||||
proj_coords.x = mix(atlas_start, atlas_end, xy_remapped.x);
|
let region_coords = vec2<f32>(
|
||||||
proj_coords.y = mix(atlas_start, atlas_end, xy_remapped.y);
|
mix(region_rect.x, region_rect.x + region_rect.z, xy_remapped.x),
|
||||||
|
mix(region_rect.y, region_rect.y + region_rect.w, xy_remapped.y)
|
||||||
// simulate `ClampToBorder`, not creating shadows past the shadow map regions
|
);
|
||||||
if (proj_coords.x > atlas_end && proj_coords.y > atlas_end)
|
|
||||||
|| (proj_coords.x < atlas_start && proj_coords.y < atlas_start) {
|
|
||||||
return 0.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// must manually apply offset to the texture coords since `textureSampleLevel` requires a
|
|
||||||
// const value.
|
|
||||||
let offset_coords = proj_coords.xy + (vec2<f32>(f32(atlas_region.x), f32(atlas_region.y)) / vec2<f32>(atlas_dimensions));
|
|
||||||
let closest_depth = textureSampleLevel(t_shadow_maps_atlas, s_shadow_maps_atlas, offset_coords, 0.0);
|
|
||||||
let current_depth = proj_coords.z;
|
|
||||||
|
|
||||||
// use a bias to avoid shadow acne
|
// use a bias to avoid shadow acne
|
||||||
let bias = max(0.05 * (1.0 - dot(normal, light_dir)), 0.005);
|
let bias = max(0.05 * (1.0 - dot(normal, light_dir)), 0.005);
|
||||||
var shadow = 0.0;
|
let current_depth = proj_coords.z - bias;
|
||||||
if current_depth - bias > closest_depth {
|
|
||||||
|
var shadow = pcf_dir_light(region_coords, current_depth, shadow_u);
|
||||||
|
|
||||||
|
// dont cast shadows outside the light's far plane
|
||||||
|
if (proj_coords.z > 1.0) {
|
||||||
shadow = 1.0;
|
shadow = 1.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// dont cast shadows if the texture coords would go past the shadow maps
|
||||||
|
if (xy_remapped.x > 1.0 || xy_remapped.x < 0.0 || xy_remapped.y > 1.0 || xy_remapped.y < 0.0) {
|
||||||
|
shadow = 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return shadow;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Calculate the shadow coefficient using PCF of a directional light
|
||||||
|
fn pcf_dir_light(tex_coords: vec2<f32>, test_depth: f32, shadow_u: LightShadowMapUniform) -> f32 {
|
||||||
|
let half_filter_size = SHADOW_MAP_PCF_SIZE / 2.0;
|
||||||
|
let texel_size = 1.0 / vec2<f32>(f32(shadow_u.atlas_frame.width), f32(shadow_u.atlas_frame.height));
|
||||||
|
|
||||||
|
// Sample PCF
|
||||||
|
var shadow = 0.0;
|
||||||
|
for (var x = -half_filter_size; x <= half_filter_size; x += 1.0) {
|
||||||
|
for (var y = -half_filter_size; y <= half_filter_size; y += 1.0) {
|
||||||
|
let offset = tex_coords + vec2<f32>(x, y) * texel_size;
|
||||||
|
let pcf_depth = textureSampleCompare(t_shadow_maps_atlas, s_shadow_maps_atlas, offset, test_depth);
|
||||||
|
shadow += pcf_depth;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
shadow /= pow(SHADOW_MAP_PCF_SIZE, 2.0);
|
||||||
|
// ensure the shadow value does not go above 1.0
|
||||||
|
shadow = min(shadow, 1.0);
|
||||||
|
|
||||||
return shadow;
|
return shadow;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -289,9 +306,9 @@ fn calc_shadow_point(world_pos: vec3<f32>, world_normal: vec3<f32>, light_dir: v
|
||||||
let cube_idx = i32(temp.z);
|
let cube_idx = i32(temp.z);
|
||||||
|
|
||||||
/// if an unknown cube side was returned, something is broken
|
/// if an unknown cube side was returned, something is broken
|
||||||
if cube_idx == 0 {
|
/*if cube_idx == 0 {
|
||||||
return 0.0;
|
return 0.0;
|
||||||
}
|
}*/
|
||||||
|
|
||||||
var indices = light.light_shadow_uniform_index;
|
var indices = light.light_shadow_uniform_index;
|
||||||
let i = indices[cube_idx - 1];
|
let i = indices[cube_idx - 1];
|
||||||
|
@ -303,27 +320,20 @@ fn calc_shadow_point(world_pos: vec3<f32>, world_normal: vec3<f32>, light_dir: v
|
||||||
region_coords /= f32(atlas_dimensions.x);
|
region_coords /= f32(atlas_dimensions.x);
|
||||||
|
|
||||||
// simulate `ClampToBorder`, not creating shadows past the shadow map regions
|
// simulate `ClampToBorder`, not creating shadows past the shadow map regions
|
||||||
if (coords_2d.x >= 1.0 || coords_2d.y >= 1.0) {
|
/*if (coords_2d.x >= 1.0 || coords_2d.y >= 1.0) {
|
||||||
return 0.0;
|
return 0.0;
|
||||||
}
|
}*/
|
||||||
|
|
||||||
// get the coords inside of the region
|
// get the coords inside of the region
|
||||||
coords_2d.x = mix(region_coords.x, region_coords.x + region_coords.z, coords_2d.x);
|
coords_2d.x = mix(region_coords.x, region_coords.x + region_coords.z, coords_2d.x);
|
||||||
coords_2d.y = mix(region_coords.y, region_coords.y + region_coords.w, coords_2d.y);
|
coords_2d.y = mix(region_coords.y, region_coords.y + region_coords.w, coords_2d.y);
|
||||||
|
|
||||||
var closest_depth = textureSampleLevel(t_shadow_maps_atlas, s_shadow_maps_atlas, coords_2d, 0.0);
|
|
||||||
let current_depth = length(frag_to_light);
|
|
||||||
|
|
||||||
// convert depth from [0; 1] to the original depth value
|
|
||||||
closest_depth *= u.far_plane;
|
|
||||||
|
|
||||||
// use a bias to avoid shadow acne
|
// use a bias to avoid shadow acne
|
||||||
let bias = max(0.05 * (1.0 - dot(world_normal, light_dir)), 0.005);
|
let bias = max(0.05 * (1.0 - dot(world_normal, light_dir)), 0.005);
|
||||||
|
var current_depth = length(frag_to_light) - bias;
|
||||||
|
current_depth /= u.far_plane;
|
||||||
|
|
||||||
var shadow = 0.0;
|
var shadow = textureSampleCompare(t_shadow_maps_atlas, s_shadow_maps_atlas, coords_2d, current_depth);
|
||||||
if current_depth - bias > closest_depth {
|
|
||||||
shadow = 1.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return shadow;
|
return shadow;
|
||||||
}
|
}
|
||||||
|
@ -369,7 +379,7 @@ fn blinn_phong_dir_light(world_pos: vec3<f32>, world_norm: vec3<f32>, dir_light:
|
||||||
diffuse_color *= dir_light.diffuse;
|
diffuse_color *= dir_light.diffuse;
|
||||||
specular_color *= dir_light.specular;*/
|
specular_color *= dir_light.specular;*/
|
||||||
|
|
||||||
return (ambient_color + (1.0 - shadow) * (diffuse_color + specular_color)) * dir_light.intensity;
|
return (ambient_color + (shadow) * (diffuse_color + specular_color)) * dir_light.intensity;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn blinn_phong_point_light(world_pos: vec3<f32>, world_norm: vec3<f32>, point_light: Light, material: Material, specular_factor: vec3<f32>, shadow: f32) -> vec3<f32> {
|
fn blinn_phong_point_light(world_pos: vec3<f32>, world_norm: vec3<f32>, point_light: Light, material: Material, specular_factor: vec3<f32>, shadow: f32) -> vec3<f32> {
|
||||||
|
|
Loading…
Reference in New Issue