nphysics
nphysics copied to clipboard
Can't raycast static bodies
Hi!
I miss something, or ray doesn't intersect static rigidbodies?
Sample code:
extern crate nalgebra;
extern crate ncollide;
extern crate nphysics2d;
use nphysics2d::object::RigidBody;
use nphysics2d::world::World;
use ncollide::shape::Ball;
use ncollide::world::CollisionGroups;
use ncollide::query::Ray;
use nalgebra::{Vector2, Point2, Translation2};
fn create_static_body() -> RigidBody<f32> {
RigidBody::new_static(Ball::new(100.0), 1.0, 0.3)
}
fn create_dynamic_body() -> RigidBody<f32> {
RigidBody::new_dynamic(Ball::new(100.0), 1.0, 0.3, 1.0)
}
fn main() {
// Create world
let mut physics_world = World::new();
physics_world.set_gravity(Vector2::new(0.0, 0.0));
// Create static body at left
let mut rb = create_static_body();
rb.append_translation(&Translation2::new(-1000.0, 0.0));
physics_world.add_rigid_body(rb);
// Create dynamic body at right
let mut rb = create_dynamic_body();
rb.append_translation(&Translation2::new(1000.0, 0.0));
physics_world.add_rigid_body(rb);
let all_groups = &CollisionGroups::new();
// Raycast over static body
let ray = Ray::new(Point2::new(-1000.0, 1000.0), Vector2::new(0.0, -1.0));
println!("Static: {}",
physics_world
.collision_world()
.interferences_with_ray(&ray, all_groups)
.count());
// Raycast over dynamic body
let ray = Ray::new(Point2::new(1000.0, 1000.0), Vector2::new(0.0, -1.0));
println!("Dynamic: {}",
physics_world
.collision_world()
.interferences_with_ray(&ray, all_groups)
.count());
// Raycast from left to right over static and dynamic bodies
let ray = Ray::new(Point2::new(-2000.0, 0.0), Vector2::new(1.0, 0.0));
println!("Dynamic + Static: {}",
physics_world
.collision_world()
.interferences_with_ray(&ray, all_groups)
.count());
}
Output:
Static: 0 Dynamic: 1 Dynamic + Static: 1
This looks like a bug with how collision groups are handled.
Yes, it's collision groups, because:
RigidBodyCollisionGroups::new_static();
return group with blacklist:
0b110000000000000000000000000000
And all_groups have membership:
0b111111111111111111111111111111
and
189: ncollide_pipeline/world/collision_groups.rs
self.membership & other.blacklist == 0 &&
other.membership & self.blacklist == 0 &&
is false.
So, workaround for me is exclude {STATIC_GROUP_ID, SENSOR_GROUP_ID} from membership of ray collision groups.
Thanks for digging into this. I'm not sure yet what is the best way to deal with this. The main solution I see would be to add a ray-casting function to the physical world (not the collision world because ncollide has no knowledge about the two special groups STATIC_GROUP_ID
and SENSOR_GROUP_ID
) that would adjust the memberships.
I'm very sorry for my English.
I'm not sure, but It's looks like main problem here is "blacklist" field. I think it is redundant field, any case may be covered using "membership" and "whitelist" masks.
May be better solution - keep "blacklist" field on static rigidbodies as zero, and use something like:
Static Rigidbody | Sensor Rigidbody | Dynamic Rigidbody | |
---|---|---|---|
Membership | 0b100 | 0b010 | 0b111 |
Whitelist | 0b001 | 0b001 | 0b111 |
This way fix all issues with raycast/aabb_query.
Most of physic engines use 2 masks for handling collisions, for example:
p2.js
if(shapeA.collisionGroup & shapeB.collisionMask)!=0 && (shapeB.collisionGroup & shapeA.collisionMask)!=0){
// The shapes can collide
}
Box2D
bool collide =
(filterA.maskBits & filterB.categoryBits) != 0 &&
(filterA.categoryBits & filterB.maskBits) != 0;
Bullet Physics
bool collides = (proxy0->m_collisionFilterGroup & proxy1->m_collisionFilterMask) != 0;
collides = collides && (proxy1->m_collisionFilterGroup & proxy0->m_collisionFilterMask);