Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve SpatialQuery APIs and docs, and add more configuration #510

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion crates/avian2d/examples/dynamic_character_2d/plugin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ impl CharacterControllerBundle {
rigid_body: RigidBody::Dynamic,
collider,
ground_caster: ShapeCaster::new(caster_shape, Vector::ZERO, 0.0, Dir2::NEG_Y)
.with_max_time_of_impact(10.0),
.with_max_distance(10.0),
locked_axes: LockedAxes::ROTATION_LOCKED,
movement: MovementBundle::default(),
}
Expand Down
2 changes: 1 addition & 1 deletion crates/avian2d/examples/kinematic_character_2d/plugin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ impl CharacterControllerBundle {
rigid_body: RigidBody::Kinematic,
collider,
ground_caster: ShapeCaster::new(caster_shape, Vector::ZERO, 0.0, Dir2::NEG_Y)
.with_max_time_of_impact(10.0),
.with_max_distance(10.0),
gravity: ControllerGravity(gravity),
movement: MovementBundle::default(),
}
Expand Down
6 changes: 1 addition & 5 deletions crates/avian2d/examples/ray_caster.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,11 +74,7 @@ fn render_rays(mut rays: Query<(&mut RayCaster, &mut RayHits)>, mut gizmos: Gizm
let direction = ray.global_direction().f32();

for hit in hits.iter() {
gizmos.line_2d(
origin,
origin + direction * hit.time_of_impact as f32,
GREEN,
);
gizmos.line_2d(origin, origin + direction * hit.distance as f32, GREEN);
}
if hits.is_empty() {
gizmos.line_2d(origin, origin + direction * 1_000_000.0, ORANGE_RED);
Expand Down
15 changes: 5 additions & 10 deletions crates/avian3d/examples/cast_ray_predicate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,19 +166,14 @@ fn raycast(

let mut ray_indicator_transform = indicator_transform.single_mut();

if let Some(ray_hit_data) = query.cast_ray_predicate(
origin,
direction,
Scalar::MAX,
true,
&SpatialQueryFilter::default(),
&|entity| {
if let Some(ray_hit_data) =
query.cast_ray_predicate(origin, direction, &RayCastConfig::default(), &|entity| {
if let Ok((_, out_of_glass)) = cubes.get(entity) {
return !out_of_glass.0; // only look at cubes not out of glass
}
true // if the collider has no OutOfGlass component, then check it nevertheless
},
) {
})
{
// set color of hit object to red
if let Ok((material_handle, _)) = cubes.get(ray_hit_data.entity) {
if let Some(material) = materials.get_mut(material_handle) {
Expand All @@ -187,7 +182,7 @@ fn raycast(
}

// set length of ray indicator to look more like a laser
let contact_point = (origin + direction.adjust_precision() * ray_hit_data.time_of_impact).x;
let contact_point = (origin + direction.adjust_precision() * ray_hit_data.distance).x;
let target_scale = 1000.0 + contact_point * 2.0;
ray_indicator_transform.scale.x = target_scale as f32;
} else {
Expand Down
2 changes: 1 addition & 1 deletion crates/avian3d/examples/dynamic_character_3d/plugin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ impl CharacterControllerBundle {
Quaternion::default(),
Dir3::NEG_Y,
)
.with_max_time_of_impact(0.2),
.with_max_distance(0.2),
locked_axes: LockedAxes::ROTATION_LOCKED,
movement: MovementBundle::default(),
}
Expand Down
2 changes: 1 addition & 1 deletion crates/avian3d/examples/kinematic_character_3d/plugin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ impl CharacterControllerBundle {
Quaternion::default(),
Dir3::NEG_Y,
)
.with_max_time_of_impact(0.2),
.with_max_distance(0.2),
gravity: ControllerGravity(gravity),
movement: MovementBundle::default(),
}
Expand Down
16 changes: 8 additions & 8 deletions src/collision/collider/parry/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -606,16 +606,16 @@ impl Collider {
.contains_point(&make_isometry(translation, rotation), &point.into())
}

/// Computes the time of impact and normal between the given ray and `self`
/// Computes the distance and normal between the given ray and `self`
/// transformed by `translation` and `rotation`.
///
/// The returned tuple is in the format `(time_of_impact, normal)`.
/// The returned tuple is in the format `(distance, normal)`.
///
/// ## Arguments
///
/// - `ray_origin`: Where the ray is cast from.
/// - `ray_direction`: What direction the ray is cast in.
/// - `max_time_of_impact`: The maximum distance that the ray can travel.
/// - `max_distance`: The maximum distance the ray can travel.
/// - `solid`: If true and the ray origin is inside of a collider, the hit point will be the ray origin itself.
/// Otherwise, the collider will be treated as hollow, and the hit point will be at the collider's boundary.
pub fn cast_ray(
Expand All @@ -624,13 +624,13 @@ impl Collider {
rotation: impl Into<Rotation>,
ray_origin: Vector,
ray_direction: Vector,
max_time_of_impact: Scalar,
max_distance: Scalar,
solid: bool,
) -> Option<(Scalar, Vector)> {
let hit = self.shape_scaled().cast_ray_and_get_normal(
&make_isometry(translation, rotation),
&parry::query::Ray::new(ray_origin.into(), ray_direction.into()),
max_time_of_impact,
max_distance,
solid,
);
hit.map(|hit| (hit.time_of_impact, hit.normal.into()))
Expand All @@ -642,19 +642,19 @@ impl Collider {
///
/// - `ray_origin`: Where the ray is cast from.
/// - `ray_direction`: What direction the ray is cast in.
/// - `max_time_of_impact`: The maximum distance that the ray can travel.
/// - `max_distance`: The maximum distance the ray can travel.
pub fn intersects_ray(
&self,
translation: impl Into<Position>,
rotation: impl Into<Rotation>,
ray_origin: Vector,
ray_direction: Vector,
max_time_of_impact: Scalar,
max_distance: Scalar,
) -> bool {
self.shape_scaled().intersects_ray(
&make_isometry(translation, rotation),
&parry::query::Ray::new(ray_origin.into(), ray_direction.into()),
max_time_of_impact,
max_distance,
)
}

Expand Down
28 changes: 14 additions & 14 deletions src/debug_render/gizmos.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ pub trait PhysicsGizmoExt {
&mut self,
origin: Vector,
direction: Dir,
max_time_of_impact: Scalar,
max_distance: Scalar,
hits: &[RayHitData],
ray_color: Color,
point_color: Color,
Expand All @@ -75,7 +75,7 @@ pub trait PhysicsGizmoExt {
origin: Vector,
shape_rotation: impl Into<Rotation>,
direction: Dir,
max_time_of_impact: Scalar,
max_distance: Scalar,
hits: &[ShapeHitData],
ray_color: Color,
shape_color: Color,
Expand Down Expand Up @@ -459,29 +459,29 @@ impl<'w, 's> PhysicsGizmoExt for Gizmos<'w, 's, PhysicsGizmos> {
&mut self,
origin: Vector,
direction: Dir,
max_time_of_impact: Scalar,
max_distance: Scalar,
hits: &[RayHitData],
ray_color: Color,
point_color: Color,
normal_color: Color,
length_unit: Scalar,
) {
let max_toi = hits
let max_distance = hits
.iter()
.max_by(|a, b| a.time_of_impact.total_cmp(&b.time_of_impact))
.map_or(max_time_of_impact, |hit| hit.time_of_impact);
.max_by(|a, b| a.distance.total_cmp(&b.distance))
.map_or(max_distance, |hit| hit.distance);

// Draw ray as arrow
self.draw_arrow(
origin,
origin + direction.adjust_precision() * max_toi,
origin + direction.adjust_precision() * max_distance,
0.1 * length_unit,
ray_color,
);

// Draw all hit points and normals
for hit in hits {
let point = origin + direction.adjust_precision() * hit.time_of_impact;
let point = origin + direction.adjust_precision() * hit.distance;

// Draw hit point
#[cfg(feature = "2d")]
Expand Down Expand Up @@ -516,7 +516,7 @@ impl<'w, 's> PhysicsGizmoExt for Gizmos<'w, 's, PhysicsGizmos> {
origin: Vector,
shape_rotation: impl Into<Rotation>,
direction: Dir,
max_time_of_impact: Scalar,
max_distance: Scalar,
hits: &[ShapeHitData],
ray_color: Color,
shape_color: Color,
Expand All @@ -528,10 +528,10 @@ impl<'w, 's> PhysicsGizmoExt for Gizmos<'w, 's, PhysicsGizmos> {
#[cfg(feature = "3d")]
let shape_rotation = Rotation(shape_rotation.normalize());

let max_toi = hits
let max_distance = hits
.iter()
.max_by(|a, b| a.time_of_impact.total_cmp(&b.time_of_impact))
.map_or(max_time_of_impact, |hit| hit.time_of_impact);
.max_by(|a, b| a.distance.total_cmp(&b.distance))
.map_or(max_distance, |hit| hit.distance);

// Draw collider at origin
self.draw_collider(shape, origin, shape_rotation, shape_color);
Expand All @@ -540,7 +540,7 @@ impl<'w, 's> PhysicsGizmoExt for Gizmos<'w, 's, PhysicsGizmos> {
// TODO: We could render the swept collider outline instead
self.draw_arrow(
origin,
origin + max_toi * direction.adjust_precision(),
origin + max_distance * direction.adjust_precision(),
0.1 * length_unit,
ray_color,
);
Expand Down Expand Up @@ -569,7 +569,7 @@ impl<'w, 's> PhysicsGizmoExt for Gizmos<'w, 's, PhysicsGizmos> {
// Draw collider at hit point
self.draw_collider(
shape,
origin + hit.time_of_impact * direction.adjust_precision(),
origin + hit.distance * direction.adjust_precision(),
shape_rotation,
shape_color.with_alpha(0.3),
);
Expand Down
4 changes: 2 additions & 2 deletions src/debug_render/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -426,7 +426,7 @@ fn debug_render_raycasts(
ray.global_origin(),
ray.global_direction(),
// f32::MAX renders nothing, but this number seems to be fine :P
ray.max_time_of_impact.min(1_000_000_000_000_000_000.0),
ray.max_distance.min(1_000_000_000_000_000_000.0),
hits.as_slice(),
ray_color,
point_color,
Expand Down Expand Up @@ -459,7 +459,7 @@ fn debug_render_shapecasts(
shape_caster.global_shape_rotation(),
shape_caster.global_direction(),
// f32::MAX renders nothing, but this number seems to be fine :P
shape_caster.max_time_of_impact.min(1_000_000_000_000_000.0),
shape_caster.max_distance.min(1_000_000_000_000_000.0),
hits.as_slice(),
ray_color,
shape_color,
Expand Down
14 changes: 6 additions & 8 deletions src/spatial_query/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,8 @@
//! a variety of things like getting information about the environment for character controllers and AI,
//! and even rendering using ray tracing.
//!
//! For each hit during raycasting, the hit entity, a *time of impact* and a normal will be stored in [`RayHitData`].
//! The time of impact refers to how long the ray travelled, which is essentially the distance from the ray origin to
//! the point of intersection.
//! For each hit during raycasting, the hit entity, a distance, and a normal will be stored in [`RayHitData`].
//! The distance is the distance from the ray origin to the point of intersection, indicating how far the ray travelled.
//!
//! There are two ways to perform raycasts.
//!
Expand Down Expand Up @@ -59,7 +58,7 @@
//! println!(
//! "Hit entity {:?} at {} with normal {}",
//! hit.entity,
//! ray.origin + *ray.direction * hit.time_of_impact,
//! ray.origin + *ray.direction * hit.distance,
//! hit.normal,
//! );
//! }
Expand All @@ -76,9 +75,8 @@
//! we have an entire shape travelling along a half-line. One use case is determining how far an object can move
//! before it hits the environment.
//!
//! For each hit during shapecasting, the hit entity, the *time of impact*, two local points of intersection and two local
//! normals will be stored in [`ShapeHitData`]. The time of impact refers to how long the shape travelled before the initial
//! hit, which is essentially the distance from the shape origin to the global point of intersection.
//! For each hit during shapecasting, the hit entity, a distance, two world-space points of intersection and two world-space
//! normals will be stored in [`ShapeHitData`]. The distance refers to how long the shape travelled before the initial hit.
//!
//! There are two ways to perform shapecasts.
//!
Expand Down Expand Up @@ -107,7 +105,7 @@
//! Collider::sphere(0.5), // Shape
//! Vec3::ZERO, // Origin
//! Quat::default(), // Shape rotation
//! Dir3::X // Direction
//! Dir3::X // Direction
//! ));
//! // ...spawn colliders and other things
//! }
Expand Down
Loading