collider point collection

feat/shadows
hheik 2023-09-03 19:39:14 +03:00
parent 69c176ed88
commit c1894235ba
2 changed files with 72 additions and 19 deletions

View File

@ -2,8 +2,6 @@ use crate::{debug, game_setup};
use bevy::prelude::*;
use bevy_ecs_ldtk::{LdtkWorldBundle, LevelSelection};
use self::darkness::SpotLight2D;
pub mod camera;
pub mod darkness;
pub mod ldtk;
@ -26,15 +24,4 @@ fn setup(mut commands: Commands, assets: Res<AssetServer>) {
ldtk_handle: assets.load("levels/world.ldtk"),
..default()
});
commands.spawn((
Name::new("Spot light"),
SpatialBundle::from_transform(Transform::from_xyz(32.0, 31.0, 0.0).with_rotation(
Quat::from_euler(EulerRot::YXZ, 0.0, 0.0, f32::to_radians(-90.0)),
)),
SpotLight2D {
radius: 100.0,
angle: 1.0,
},
));
}

View File

@ -8,8 +8,11 @@ use bevy::{
sprite::{Material2dPlugin, Mesh2dHandle},
};
use bevy_ecs_ldtk::{LdtkLevel, LevelEvent};
use bevy_prototype_debug_lines::DebugLines;
use bevy_rapier2d::prelude::{Collider, QueryFilter, RapierContext};
use crate::debug::DebugMode;
mod material;
pub use material::*;
@ -174,6 +177,8 @@ fn add_to_level(
fn prepare_lights(
mut materials: ResMut<Assets<DarknessMaterial>>,
mut images: ResMut<Assets<Image>>,
mut debug_draw: ResMut<DebugLines>,
debug_mode: Res<DebugMode>,
rapier_context: Res<RapierContext>,
visibility_blocker_query: Query<&VisibilityBlocker>,
transform_query: Query<&GlobalTransform>,
@ -204,7 +209,7 @@ fn prepare_lights(
.enumerate()
.for_each(|(i, (transform, light))| {
let rect = light.aabb();
let points = get_light_geometry(
let polygon = get_light_geometry(
&rapier_context,
&visibility_blocker_query,
&transform_query,
@ -214,14 +219,32 @@ fn prepare_lights(
rect.max + transform.translation().truncate(),
),
);
println!("{points:?}");
if debug_mode.enabled {
for (i, arr) in polygon.iter().as_slice().windows(2).enumerate() {
let p1 = arr[0];
let p2 = arr[1];
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);
let color2 = Color::rgba(1.0 - t2, t2, 0.0, 1.0);
debug_draw.line_gradient(
p1.extend(0.0),
p2.extend(0.0),
0.0,
color1,
color2,
);
}
}
material.point_lights[i] = GpuPointLight2D {
position: transform.translation().truncate(),
radius: light.radius,
};
for x in 0..SHADOWMAP_RESOLUTION {
let offset = (i * SHADOWMAP_RESOLUTION + x) * 4;
let distance = x as f32 / SHADOWMAP_RESOLUTION as f32 * light.radius;
let distance = light.radius;
let distance_bytes = bytes_of(&distance);
shadowmap.data[offset + 0] = distance_bytes[0];
shadowmap.data[offset + 1] = distance_bytes[1];
@ -295,11 +318,54 @@ fn get_light_geometry(
true
});
let center = aabb.center();
points.sort_unstable_by(|a, b| {
f32::atan2(a.y, a.x)
.partial_cmp(&f32::atan2(b.y, b.x))
f32::atan2(a.y - center.y, a.x - center.x)
.partial_cmp(&f32::atan2(b.y - center.y, b.x - center.x))
.unwrap()
});
points
// Build visibility polygon
let mut polygon: Vec<_> = vec![];
for point in points.drain(..) {
// We shoot 2 rays offset by this angle from the point.
const ANGLE_OFFSET: f32 = 0.0001;
offset_cast(
aabb.center(),
(point - aabb.center()).normalize_or_zero(),
aabb.size().max_element(),
true,
filter,
ANGLE_OFFSET,
&rapier_context,
)
.iter()
.for_each(|ray| polygon.push(aabb.center() + *ray));
}
polygon.push(*polygon.first().unwrap());
polygon
}
fn offset_cast(
ray_origin: Vec2,
ray_dir: Vec2,
max_toi: f32,
solid: bool,
filter: QueryFilter,
angle_offset: f32,
rapier_context: &Res<RapierContext>,
) -> Vec<Vec2> {
let dir1 = Vec2::new((-angle_offset).cos(), (-angle_offset).sin()).rotate(ray_dir);
let dir2 = Vec2::new(angle_offset.cos(), angle_offset.sin()).rotate(ray_dir);
let ray1 = rapier_context.cast_ray(ray_origin, dir1, max_toi, solid, filter);
let ray2 = rapier_context.cast_ray(ray_origin, dir2, max_toi, solid, filter);
let toi1 = ray1.map_or(max_toi, |(_, toi)| toi);
let toi2 = ray2.map_or(max_toi, |(_, toi)| toi);
if (toi1 - toi2).abs() > toi1 * 0.1 {
vec![dir1 * toi1, dir2 * toi2]
} else {
vec![(dir1 * toi1 + dir2 * toi2) / 2.0]
}
}