wip: Software shadows to corners only
parent
b13ee649be
commit
499e6ded41
|
|
@ -20,7 +20,7 @@ pub use material::*;
|
||||||
// Needs to be the same as in darkness.wgsl
|
// Needs to be the same as in darkness.wgsl
|
||||||
pub const MAX_POINT_LIGHTS: usize = 64;
|
pub const MAX_POINT_LIGHTS: usize = 64;
|
||||||
pub const MAX_SPOT_LIGHTS: usize = 64;
|
pub const MAX_SPOT_LIGHTS: usize = 64;
|
||||||
pub const SHADOWMAP_RESOLUTION: usize = 256;
|
pub const SHADOWMAP_RESOLUTION: usize = 1024;
|
||||||
|
|
||||||
pub struct DarknessPlugin;
|
pub struct DarknessPlugin;
|
||||||
|
|
||||||
|
|
@ -33,7 +33,7 @@ impl Plugin for DarknessPlugin {
|
||||||
.register_asset_reflect::<DarknessMaterial>()
|
.register_asset_reflect::<DarknessMaterial>()
|
||||||
.add_plugins(Material2dPlugin::<DarknessMaterial>::default())
|
.add_plugins(Material2dPlugin::<DarknessMaterial>::default())
|
||||||
.add_systems(Update, add_to_level)
|
.add_systems(Update, add_to_level)
|
||||||
.add_systems(Last, prepare_lights);
|
.add_systems(Last, (prepare_lights, prepare_shadows).chain());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -96,6 +96,7 @@ pub struct ShadowVertex {
|
||||||
#[derive(Component, Reflect, Default, Debug, Clone)]
|
#[derive(Component, Reflect, Default, Debug, Clone)]
|
||||||
#[reflect(Component)]
|
#[reflect(Component)]
|
||||||
pub struct ShadowMesh {
|
pub struct ShadowMesh {
|
||||||
|
pub light_index: usize,
|
||||||
pub vertices: Vec<ShadowVertex>,
|
pub vertices: Vec<ShadowVertex>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -236,6 +237,7 @@ fn prepare_lights(
|
||||||
);
|
);
|
||||||
|
|
||||||
if let Ok(mut shadow_mesh) = shadow_mesh_query.get_mut(*entity) {
|
if let Ok(mut shadow_mesh) = shadow_mesh_query.get_mut(*entity) {
|
||||||
|
shadow_mesh.light_index = i;
|
||||||
shadow_mesh.vertices = polygon
|
shadow_mesh.vertices = polygon
|
||||||
.iter()
|
.iter()
|
||||||
.map(|point| ShadowVertex {
|
.map(|point| ShadowVertex {
|
||||||
|
|
@ -270,16 +272,6 @@ fn prepare_lights(
|
||||||
position: transform.translation().truncate(),
|
position: transform.translation().truncate(),
|
||||||
radius: light.radius,
|
radius: light.radius,
|
||||||
};
|
};
|
||||||
// TODO: Remove when shadowmapping is done
|
|
||||||
for x in 0..SHADOWMAP_RESOLUTION {
|
|
||||||
let offset = (i * SHADOWMAP_RESOLUTION + x) * 4;
|
|
||||||
let distance = light.radius;
|
|
||||||
let distance_bytes = bytes_of(&distance);
|
|
||||||
shadowmap.data[offset + 0] = distance_bytes[0];
|
|
||||||
shadowmap.data[offset + 1] = distance_bytes[1];
|
|
||||||
shadowmap.data[offset + 2] = distance_bytes[2];
|
|
||||||
shadowmap.data[offset + 3] = distance_bytes[3];
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
material.spot_light_count = spot_lights.len() as i32;
|
material.spot_light_count = spot_lights.len() as i32;
|
||||||
|
|
@ -310,6 +302,78 @@ fn prepare_lights(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn prepare_shadows(
|
||||||
|
mut materials: ResMut<Assets<DarknessMaterial>>,
|
||||||
|
mut images: ResMut<Assets<Image>>,
|
||||||
|
shadow_mesh_query: Query<(&ShadowMesh, &GlobalTransform), Changed<ShadowMesh>>,
|
||||||
|
material_query: Query<&Handle<DarknessMaterial>>,
|
||||||
|
) {
|
||||||
|
// TODO: Check that the shadow mesh overlaps the darkness material
|
||||||
|
for handle in &material_query {
|
||||||
|
let material = match materials.get_mut(handle) {
|
||||||
|
Some(material) => material,
|
||||||
|
None => continue,
|
||||||
|
};
|
||||||
|
|
||||||
|
let shadowmap = match &material.shadowmap_texture {
|
||||||
|
Some(handle) => match images.get_mut(&handle) {
|
||||||
|
Some(image) => image,
|
||||||
|
None => continue,
|
||||||
|
},
|
||||||
|
None => continue,
|
||||||
|
};
|
||||||
|
|
||||||
|
for (shadow_mesh, global_transform) in &shadow_mesh_query {
|
||||||
|
let shadow_map = calculate_shadow_map(
|
||||||
|
global_transform.translation().truncate(),
|
||||||
|
&shadow_mesh.vertices,
|
||||||
|
);
|
||||||
|
for x in 0..SHADOWMAP_RESOLUTION {
|
||||||
|
let offset = (shadow_mesh.light_index * SHADOWMAP_RESOLUTION + x) * 4;
|
||||||
|
let distance_bytes = bytes_of(&shadow_map[x]);
|
||||||
|
shadowmap.data[offset + 0] = distance_bytes[0];
|
||||||
|
shadowmap.data[offset + 1] = distance_bytes[1];
|
||||||
|
shadowmap.data[offset + 2] = distance_bytes[2];
|
||||||
|
shadowmap.data[offset + 3] = distance_bytes[3];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn calculate_shadow_map(
|
||||||
|
global_position: Vec2,
|
||||||
|
vertices: &Vec<ShadowVertex>,
|
||||||
|
) -> [f32; SHADOWMAP_RESOLUTION] {
|
||||||
|
let mut shadow_map = [0.0; SHADOWMAP_RESOLUTION];
|
||||||
|
let mut next_index = 0;
|
||||||
|
for x in 0..SHADOWMAP_RESOLUTION {
|
||||||
|
let angle = (x as f32 / SHADOWMAP_RESOLUTION as f32) * 2.0 * std::f32::consts::PI
|
||||||
|
- std::f32::consts::PI;
|
||||||
|
|
||||||
|
let prev_vertex = if next_index == 0 {
|
||||||
|
vertices[vertices.len() - 1]
|
||||||
|
} else {
|
||||||
|
vertices[(next_index - 1) % vertices.len()]
|
||||||
|
};
|
||||||
|
let next_vertex = vertices[next_index % vertices.len()];
|
||||||
|
if angle >= next_vertex.angle && next_index < vertices.len() {
|
||||||
|
next_index += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut relative_angle = angle - prev_vertex.angle;
|
||||||
|
// Technically not correct, but works
|
||||||
|
if relative_angle < 0.0 {
|
||||||
|
relative_angle =
|
||||||
|
(std::f32::consts::PI - prev_vertex.angle) + (angle + std::f32::consts::PI);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Calculate between-points
|
||||||
|
let distance = (next_vertex.point - global_position).length();
|
||||||
|
shadow_map[x] = distance;
|
||||||
|
}
|
||||||
|
shadow_map
|
||||||
|
}
|
||||||
|
|
||||||
fn get_light_geometry(
|
fn get_light_geometry(
|
||||||
rapier_context: &Res<RapierContext>,
|
rapier_context: &Res<RapierContext>,
|
||||||
visibility_blocker_query: &Query<&VisibilityBlocker>,
|
visibility_blocker_query: &Query<&VisibilityBlocker>,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue