wip: Added ShadowMesh component

feat/shadows
hheik 2023-12-07 02:21:51 +02:00
parent ca65416c73
commit b13ee649be
2 changed files with 45 additions and 15 deletions

View File

@ -5,7 +5,7 @@ use bevy::render::camera::ScalingMode;
use bevy::{input::mouse::MouseMotion, transform::TransformSystem}; use bevy::{input::mouse::MouseMotion, transform::TransformSystem};
use bevy_ecs_ldtk::prelude::*; use bevy_ecs_ldtk::prelude::*;
use super::darkness::{PointLight2D, SpotLight2D}; use super::darkness::{PointLight2D, ShadowMesh, SpotLight2D};
pub struct GameCameraPlugin; pub struct GameCameraPlugin;
@ -95,6 +95,7 @@ fn camera_setup(mut commands: Commands) {
ComputedVisibility::default(), ComputedVisibility::default(),
CameraRoomRestraint, CameraRoomRestraint,
PointLight2D { radius: 30.0 }, PointLight2D { radius: 30.0 },
ShadowMesh::default(),
)); ));
} }

View File

@ -28,6 +28,7 @@ impl Plugin for DarknessPlugin {
fn build(&self, app: &mut App) { fn build(&self, app: &mut App) {
app.register_type::<PointLight2D>() app.register_type::<PointLight2D>()
.register_type::<SpotLight2D>() .register_type::<SpotLight2D>()
.register_type::<ShadowMesh>()
.register_type::<VisibilityBlocker>() .register_type::<VisibilityBlocker>()
.register_asset_reflect::<DarknessMaterial>() .register_asset_reflect::<DarknessMaterial>()
.add_plugins(Material2dPlugin::<DarknessMaterial>::default()) .add_plugins(Material2dPlugin::<DarknessMaterial>::default())
@ -86,6 +87,18 @@ pub(crate) struct GpuSpotLight2D {
#[reflect(Component)] #[reflect(Component)]
pub struct VisibilityBlocker; pub struct VisibilityBlocker;
#[derive(Reflect, Default, Debug, Clone, Copy)]
pub struct ShadowVertex {
pub point: Vec2,
pub angle: f32,
}
#[derive(Component, Reflect, Default, Debug, Clone)]
#[reflect(Component)]
pub struct ShadowMesh {
pub vertices: Vec<ShadowVertex>,
}
fn add_to_level( fn add_to_level(
mut commands: Commands, mut commands: Commands,
mut level_events: EventReader<LevelEvent>, mut level_events: EventReader<LevelEvent>,
@ -150,9 +163,9 @@ fn add_to_level(
DarknessMeshBundle { DarknessMeshBundle {
transform: Transform::from_xyz(0.0, 0.0, 100.0), transform: Transform::from_xyz(0.0, 0.0, 100.0),
mesh: Mesh2dHandle(meshes.add(plane)), mesh: Mesh2dHandle(meshes.add(plane)),
material: materials.add(DarknessMaterial::new( material: materials.add(DarknessMaterial {
Color::rgba(0.0, 0.0, 0.0, 0.75), color: Color::rgba(0.0, 0.0, 0.0, 0.75),
Some(images.add(Image::new( shadowmap_texture: Some(images.add(Image::new(
Extent3d { Extent3d {
width: width as u32, width: width as u32,
height: height as u32, height: height as u32,
@ -162,7 +175,8 @@ fn add_to_level(
vec![0; width * height * 4], vec![0; width * height * 4],
bevy::render::render_resource::TextureFormat::R32Float, bevy::render::render_resource::TextureFormat::R32Float,
))), ))),
)), ..default()
}),
..default() ..default()
}, },
)); ));
@ -175,6 +189,7 @@ fn add_to_level(
} }
fn prepare_lights( fn prepare_lights(
mut shadow_mesh_query: Query<&mut ShadowMesh>,
mut materials: ResMut<Assets<DarknessMaterial>>, mut materials: ResMut<Assets<DarknessMaterial>>,
mut images: ResMut<Assets<Image>>, mut images: ResMut<Assets<Image>>,
mut debug_draw: ResMut<DebugLines>, mut debug_draw: ResMut<DebugLines>,
@ -184,11 +199,11 @@ fn prepare_lights(
transform_query: Query<&GlobalTransform>, transform_query: Query<&GlobalTransform>,
collider_query: Query<&Collider>, collider_query: Query<&Collider>,
material_query: Query<&Handle<DarknessMaterial>>, material_query: Query<&Handle<DarknessMaterial>>,
point_light_query: Query<(&GlobalTransform, &PointLight2D)>, point_light_query: Query<(&GlobalTransform, &PointLight2D, Entity)>,
spot_light_query: Query<(&GlobalTransform, &SpotLight2D)>, spot_light_query: Query<(&GlobalTransform, &SpotLight2D, Entity)>,
) { ) {
let point_lights: Vec<(_, _)> = point_light_query.iter().collect(); let point_lights: Vec<(_, _, _)> = point_light_query.iter().collect();
let spot_lights: Vec<(_, _)> = spot_light_query.iter().collect(); let spot_lights: Vec<(_, _, _)> = spot_light_query.iter().collect();
for handle in &material_query { for handle in &material_query {
let material = match materials.get_mut(handle) { let material = match materials.get_mut(handle) {
Some(material) => material, Some(material) => material,
@ -207,7 +222,7 @@ fn prepare_lights(
point_lights point_lights
.iter() .iter()
.enumerate() .enumerate()
.for_each(|(i, (transform, light))| { .for_each(|(i, (transform, light, entity))| {
let rect = light.aabb(); let rect = light.aabb();
let polygon = get_light_geometry( let polygon = get_light_geometry(
&rapier_context, &rapier_context,
@ -220,10 +235,23 @@ fn prepare_lights(
), ),
); );
if let Ok(mut shadow_mesh) = shadow_mesh_query.get_mut(*entity) {
shadow_mesh.vertices = polygon
.iter()
.map(|point| ShadowVertex {
point: *point,
angle: f32::atan2(
point.y - transform.translation().y,
point.x - transform.translation().x,
),
})
.collect()
}
if debug_mode.enabled { if debug_mode.enabled {
for (i, arr) in polygon.iter().as_slice().windows(2).enumerate() { for i in 0..polygon.len() {
let p1 = arr[0]; let p1 = polygon[i];
let p2 = arr[1]; let p2 = polygon[(i + 1) % polygon.len()];
let t1 = i as f32 / polygon.len() as f32; let t1 = i as f32 / polygon.len() as f32;
let t2 = (i + 1) as f32 / polygon.len() as f32; let t2 = (i + 1) as f32 / polygon.len() as f32;
let color1 = Color::rgba(1.0 - t1, t1, 0.0, 1.0); let color1 = Color::rgba(1.0 - t1, t1, 0.0, 1.0);
@ -242,6 +270,7 @@ 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 { for x in 0..SHADOWMAP_RESOLUTION {
let offset = (i * SHADOWMAP_RESOLUTION + x) * 4; let offset = (i * SHADOWMAP_RESOLUTION + x) * 4;
let distance = light.radius; let distance = light.radius;
@ -257,7 +286,7 @@ fn prepare_lights(
spot_lights spot_lights
.iter() .iter()
.enumerate() .enumerate()
.for_each(|(i, (transform, light))| { .for_each(|(i, (transform, light, entity))| {
material.spot_lights[i] = GpuSpotLight2D { material.spot_lights[i] = GpuSpotLight2D {
position: transform.translation().truncate(), position: transform.translation().truncate(),
radius: light.radius, radius: light.radius,
@ -267,6 +296,7 @@ fn prepare_lights(
padding2: 0, padding2: 0,
padding3: 0, padding3: 0,
}; };
// TODO: Remove when shadowmapping is done
for x in 0..SHADOWMAP_RESOLUTION { for x in 0..SHADOWMAP_RESOLUTION {
let offset = ((i + MAX_POINT_LIGHTS) * SHADOWMAP_RESOLUTION + x) * 4; let offset = ((i + MAX_POINT_LIGHTS) * SHADOWMAP_RESOLUTION + x) * 4;
let distance = x as f32 / SHADOWMAP_RESOLUTION as f32 * light.radius; let distance = x as f32 / SHADOWMAP_RESOLUTION as f32 * light.radius;
@ -347,7 +377,6 @@ fn get_light_geometry(
.for_each(|ray| polygon.push(aabb.center() + *ray)); .for_each(|ray| polygon.push(aabb.center() + *ray));
} }
polygon.push(*polygon.first().unwrap());
polygon polygon
} }