Implement Shadows #24
|
@ -139,16 +139,17 @@ fn setup_scene_plugin(game: &mut Game) {
|
|||
world.spawn((
|
||||
platform_mesh.clone(),
|
||||
WorldTransform::default(),
|
||||
Transform::from_xyz(0.0, -5.0, -5.0),
|
||||
//Transform::from_xyz(0.0, -5.0, -5.0),
|
||||
Transform::new(math::vec3(0.0, -5.0, -5.0), math::Quat::IDENTITY, math::vec3(5.0, 1.0, 5.0)),
|
||||
));
|
||||
|
||||
{
|
||||
let mut light_tran = Transform::from_xyz(-5.5, 2.5, -3.0);
|
||||
let mut light_tran = Transform::from_xyz(0.0, 2.5, 0.0);
|
||||
light_tran.scale = Vec3::new(0.5, 0.5, 0.5);
|
||||
light_tran.rotate_x(math::Angle::Degrees(-45.0));
|
||||
light_tran.rotate_y(math::Angle::Degrees(-35.0));
|
||||
world.spawn((
|
||||
cube_mesh.clone(),
|
||||
//cube_mesh.clone(),
|
||||
DirectionalLight {
|
||||
enabled: true,
|
||||
color: Vec3::new(1.0, 0.95, 0.9),
|
||||
|
|
|
@ -100,9 +100,9 @@ impl ShadowMapsPass {
|
|||
|
||||
let sampler = device.create_sampler(&wgpu::SamplerDescriptor {
|
||||
label: Some("sampler_shadow_map_atlas"),
|
||||
address_mode_u: wgpu::AddressMode::ClampToEdge,
|
||||
address_mode_v: wgpu::AddressMode::ClampToEdge,
|
||||
address_mode_w: wgpu::AddressMode::ClampToEdge,
|
||||
address_mode_u: wgpu::AddressMode::ClampToBorder,
|
||||
address_mode_v: wgpu::AddressMode::ClampToBorder,
|
||||
address_mode_w: wgpu::AddressMode::ClampToBorder,
|
||||
mag_filter: wgpu::FilterMode::Linear,
|
||||
min_filter: wgpu::FilterMode::Linear,
|
||||
mipmap_filter: wgpu::FilterMode::Linear,
|
||||
|
@ -126,15 +126,15 @@ impl ShadowMapsPass {
|
|||
|
||||
fn create_depth_map(&mut self, device: &wgpu::Device, entity: Entity, light_pos: Transform) {
|
||||
const NEAR_PLANE: f32 = 0.1;
|
||||
const FAR_PLANE: f32 = 80.0;
|
||||
const FAR_PLANE: f32 = 25.5;
|
||||
|
||||
let ortho_proj =
|
||||
glam::Mat4::orthographic_rh_gl(-20.0, 20.0, -20.0, 20.0, NEAR_PLANE, FAR_PLANE);
|
||||
glam::Mat4::orthographic_rh(-10.0, 10.0, -10.0, 10.0, NEAR_PLANE, FAR_PLANE);
|
||||
|
||||
let look_view =
|
||||
glam::Mat4::look_to_rh(light_pos.translation, light_pos.forward(), light_pos.up());
|
||||
|
||||
let light_proj = OPENGL_TO_WGPU_MATRIX * (ortho_proj * look_view);
|
||||
let light_proj = ortho_proj * look_view;
|
||||
|
||||
let light_projection_buffer =
|
||||
device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
||||
|
|
|
@ -90,7 +90,7 @@ impl BasicRenderer {
|
|||
|
||||
let (device, queue) = adapter.request_device(
|
||||
&wgpu::DeviceDescriptor {
|
||||
features: wgpu::Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES,
|
||||
features: wgpu::Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES | wgpu::Features::ADDRESS_MODE_CLAMP_TO_BORDER,
|
||||
// WebGL does not support all wgpu features.
|
||||
// Not sure if the engine will ever completely support WASM,
|
||||
// but its here just in case
|
||||
|
|
|
@ -19,6 +19,7 @@ struct VertexOutput {
|
|||
@location(0) tex_coords: vec2<f32>,
|
||||
@location(1) world_position: vec3<f32>,
|
||||
@location(2) world_normal: vec3<f32>,
|
||||
@location(3) frag_pos_light_space: vec4<f32>,
|
||||
}
|
||||
|
||||
struct TransformData {
|
||||
|
@ -70,16 +71,18 @@ fn vs_main(
|
|||
) -> VertexOutput {
|
||||
var out: VertexOutput;
|
||||
|
||||
var world_position: vec4<f32> = u_model_transform_data.transform * vec4<f32>(model.position, 1.0);
|
||||
out.world_position = world_position.xyz;
|
||||
|
||||
out.tex_coords = model.tex_coords;
|
||||
out.clip_position = u_camera.view_projection * u_model_transform_data.transform * vec4<f32>(model.position, 1.0);
|
||||
out.clip_position = u_camera.view_projection * world_position;
|
||||
|
||||
// the normal mat is actually only a mat3x3, but there's a bug in wgpu: https://github.com/gfx-rs/wgpu-rs/issues/36
|
||||
let normal_mat4 = u_model_transform_data.normal_matrix;
|
||||
let normal_mat = mat3x3(normal_mat4[0].xyz, normal_mat4[1].xyz, normal_mat4[2].xyz);
|
||||
out.world_normal = normalize(normal_mat * model.normal, );
|
||||
|
||||
var world_position: vec4<f32> = u_model_transform_data.transform * vec4<f32>(model.position, 1.0);
|
||||
out.world_position = world_position.xyz;
|
||||
out.frag_pos_light_space = u_light_space_matrix * world_position;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
@ -115,7 +118,7 @@ var<storage, read_write> u_light_indices: array<u32>;
|
|||
var t_light_grid: texture_storage_2d<rg32uint, read_write>; // vec2<u32>
|
||||
|
||||
@group(5) @binding(0)
|
||||
var t_shadow_maps_atlas: texture_2d<f32>;
|
||||
var t_shadow_maps_atlas: texture_depth_2d;
|
||||
@group(5) @binding(1)
|
||||
var s_shadow_maps_atlas: sampler;
|
||||
@group(5) @binding(2)
|
||||
|
@ -146,7 +149,27 @@ fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
|
|||
let light: Light = u_lights.data[light_index];
|
||||
|
||||
if (light.light_ty == LIGHT_TY_DIRECTIONAL) {
|
||||
light_res += blinn_phong_dir_light(in.world_position, in.world_normal, light, u_material, specular_color);
|
||||
/*let shadow = calc_shadow(in.frag_pos_light_space);
|
||||
return vec4<f32>(vec3<f32>(shadow), 1.0);*/
|
||||
|
||||
/*var proj_coords = in.frag_pos_light_space / in.frag_pos_light_space.w;
|
||||
proj_coords = proj_coords * 0.5 + 0.5;
|
||||
|
||||
let closest_depth = textureSampleLevel(t_shadow_maps_atlas, s_shadow_maps_atlas, proj_coords.xy, 0.0);
|
||||
let current_depth = proj_coords.z;
|
||||
|
||||
if current_depth > closest_depth {
|
||||
return vec4<f32>(vec3<f32>(current_depth), 1.0);
|
||||
} else {
|
||||
return vec4<f32>(vec3<f32>(closest_depth), 1.0);
|
||||
}*/
|
||||
|
||||
//return vec4<f32>(vec3<f32>(closest_depth), 1.0);
|
||||
//let shadow = select(0.0, 1.0, current_depth > closest_depth);
|
||||
let light_dir = normalize(-light.direction);
|
||||
|
||||
let shadow = calc_shadow(in.world_normal, light_dir, in.frag_pos_light_space);
|
||||
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) {
|
||||
light_res += blinn_phong_point_light(in.world_position, in.world_normal, light, u_material, specular_color);
|
||||
} else if (light.light_ty == LIGHT_TY_SPOT) {
|
||||
|
@ -158,6 +181,34 @@ fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
|
|||
return vec4<f32>(light_object_res, object_color.a);
|
||||
}
|
||||
|
||||
fn calc_shadow(normal: vec3<f32>, light_dir: vec3<f32>, frag_pos_light_space: vec4<f32>) -> f32 {
|
||||
var proj_coords = frag_pos_light_space.xyz / frag_pos_light_space.w;
|
||||
// for some reason the y component is clipped after transforming
|
||||
proj_coords.y = -proj_coords.y;
|
||||
|
||||
// Remap xy to [0.0, 1.0]
|
||||
let xy_remapped = proj_coords.xy * 0.5 + 0.5;
|
||||
proj_coords.x = xy_remapped.x;
|
||||
proj_coords.y = xy_remapped.y;
|
||||
|
||||
let closest_depth = textureSampleLevel(t_shadow_maps_atlas, s_shadow_maps_atlas, proj_coords.xy, 0.0);
|
||||
let current_depth = proj_coords.z;
|
||||
|
||||
// use a bias to avoid shadow acne
|
||||
let bias = max(0.05 * (1.0 - dot(normal, light_dir)), 0.005);
|
||||
var shadow = 0.0;
|
||||
if current_depth - bias > closest_depth {
|
||||
shadow = 1.0;
|
||||
}
|
||||
|
||||
// dont cast shadows outside the light's far plane
|
||||
if (proj_coords.z > 1.0) {
|
||||
shadow = 0.0;
|
||||
}
|
||||
|
||||
return shadow;
|
||||
}
|
||||
|
||||
fn debug_grid(in: VertexOutput) -> vec4<f32> {
|
||||
let tile_index_float: vec2<f32> = in.clip_position.xy / 16.0;
|
||||
let tile_index = vec2<u32>(floor(tile_index_float));
|
||||
|
@ -173,7 +224,7 @@ fn debug_grid(in: VertexOutput) -> vec4<f32> {
|
|||
return vec4<f32>(ratio, ratio, ratio, 1.0);
|
||||
}
|
||||
|
||||
fn blinn_phong_dir_light(world_pos: vec3<f32>, world_norm: vec3<f32>, dir_light: Light, material: Material, specular_factor: vec3<f32>) -> vec3<f32> {
|
||||
fn blinn_phong_dir_light(world_pos: vec3<f32>, world_norm: vec3<f32>, dir_light: Light, material: Material, specular_factor: vec3<f32>, shadow: f32) -> vec3<f32> {
|
||||
let light_color = dir_light.color.xyz;
|
||||
let camera_view_pos = u_camera.position;
|
||||
|
||||
|
@ -199,7 +250,7 @@ fn blinn_phong_dir_light(world_pos: vec3<f32>, world_norm: vec3<f32>, dir_light:
|
|||
diffuse_color *= dir_light.diffuse;
|
||||
specular_color *= dir_light.specular;*/
|
||||
|
||||
return (ambient_color + diffuse_color + specular_color) * dir_light.intensity;
|
||||
return (ambient_color + (1.0 - 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>) -> vec3<f32> {
|
||||
|
|
Loading…
Reference in New Issue