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_ecs_ldtk::prelude::*;
use super::darkness::{PointLight2D, SpotLight2D};
use super::darkness::{PointLight2D, ShadowMesh, SpotLight2D};
pub struct GameCameraPlugin;
@ -95,6 +95,7 @@ fn camera_setup(mut commands: Commands) {
ComputedVisibility::default(),
CameraRoomRestraint,
PointLight2D { radius: 30.0 },
ShadowMesh::default(),
));
}

View File

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