I'm trying out Avian 0.7.0 with Bevy 0.19.0, and working on a system that will push the camera towards the player when it would be otherwise obstructed by some terrain. My approach is to project a ray from the player (the camera's focus) back to the camera, and if it hits terrain, restrict the camera's distance based on the hit distance. However, when modeling the ground with InfinitePlane3d or Plane3d, the ray cast goes straight through the terrain at certain rotations. It seems to work fine with Cuboid.
let ground_shape = Cuboid::from_corners(
Vec3::new(-30., 0., -30.),
Vec3::new(30., -0.5, 30.),
);
// Ground, as an infinite plane/grid
commands.spawn((
Name::from("Ground"),
Ground,
CollisionLayers::new(GameLayer::Terrain, LayerMask::ALL),
RigidBody::Static,
Friction::default(),
Transform::default(),
// planar geometry - weird behavior
Collider::from(InfinitePlane3d::default()),
InfiniteGrid,
CollisionMargin(0.1),
// cubic geometry - works ok
// Collider::from(ground_shape.clone()),
// Mesh3d::from(meshes.add(ground_shape.clone())),
// MeshMaterial3d(player_material.clone()),
));
In my camera control system, I have target set to the player's GlobalTransform's translation:
if let Some(ray_hit) = spatial_query.cast_ray(
target,
-camera.forward(),
camera_settings.orbit_distance,
false,
&SpatialQueryFilter::from_mask(GameLayer::Terrain)
) {
let name = names.get(ray_hit.entity).map_or("Unknown", |n| n.as_str());
println!("Camera obstructed by {} at distance: {:?}", name, ray_hit.distance);
}
In this, I noticed that there was a 180% arc in which the camera would not be obstructed, despite being underground. So, I used Gizmos to project 16 rays at once from the player down through the ground at various angles:
for i in 0..16 {
let rads = PI * 2. * (i as Scalar / 16 as Scalar);
let Rot2 { cos, sin} = Rot2::radians(rads);
let ray_dir = Dir3::new(Vec3::new(cos, -0.2, sin)).unwrap();
gizmos.line(target, target + (ray_dir * 20.), GREEN_400);
if let Some(ray_hit) = spatial_query.cast_ray(
target,
ray_dir,
20.,
true,
&SpatialQueryFilter::from_mask(GameLayer::Terrain)
) {
// blue circle at the ray hit
let hit_pos = target + (ray_dir * ray_hit.distance);
gizmos.circle(Isometry3d::from_translation(hit_pos), 0.3, BLUE_400);
} else {
// pink circle at the end of the line, for no hit
let end_pos = target + (ray_dir * 20.);
gizmos.circle(Isometry3d::from_translation(end_pos), 0.3, PINK_400);
}
}
If I swap out the plane for a cuboid (the commented-out code in the .spawn, above), every ray hits the ground as expected:
I tried to rule out misconfigurations by adding a system to spin the ground collider around:
fn spin_ground(
mut ground: Query<&mut Transform, With<Ground>>,
time: Res<Time>,
) {
for mut ground_transform in &mut ground {
ground_transform.rotate_y(FRAC_PI_2 * time.delta_secs());
}
}
and sure enough, the 180% degree arc of non-ray-cast-hitting spins along with the ground.
I'm trying out Avian 0.7.0 with Bevy 0.19.0, and working on a system that will push the camera towards the player when it would be otherwise obstructed by some terrain. My approach is to project a ray from the player (the camera's focus) back to the camera, and if it hits terrain, restrict the camera's distance based on the hit distance. However, when modeling the ground with
InfinitePlane3dorPlane3d, the ray cast goes straight through the terrain at certain rotations. It seems to work fine with Cuboid.In my camera control system, I have
targetset to the player's GlobalTransform'stranslation:In this, I noticed that there was a 180% arc in which the camera would not be obstructed, despite being underground. So, I used
Gizmosto project 16 rays at once from the player down through the ground at various angles:If I swap out the plane for a cuboid (the commented-out code in the
.spawn, above), every ray hits the ground as expected:I tried to rule out misconfigurations by adding a system to spin the ground collider around:
and sure enough, the 180% degree arc of non-ray-cast-hitting spins along with the ground.