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

Ensure KinematicBodies only interact with other Bodies with matching mask. #42641

Merged
merged 1 commit into from
Jul 19, 2021
Merged
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
27 changes: 8 additions & 19 deletions modules/bullet/godot_result_callbacks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,17 +47,12 @@ bool godotContactAddedCallback(btManifoldPoint &cp, const btCollisionObjectWrapp
return true;
}

bool GodotFilterCallback::test_collision_filters(uint32_t body0_collision_layer, uint32_t body0_collision_mask, uint32_t body1_collision_layer, uint32_t body1_collision_mask) {
return body0_collision_layer & body1_collision_mask || body1_collision_layer & body0_collision_mask;
}

bool GodotFilterCallback::needBroadphaseCollision(btBroadphaseProxy *proxy0, btBroadphaseProxy *proxy1) const {
return GodotFilterCallback::test_collision_filters(proxy0->m_collisionFilterGroup, proxy0->m_collisionFilterMask, proxy1->m_collisionFilterGroup, proxy1->m_collisionFilterMask);
return (proxy0->m_collisionFilterGroup & proxy1->m_collisionFilterMask) || (proxy1->m_collisionFilterGroup & proxy0->m_collisionFilterMask);
}

bool GodotClosestRayResultCallback::needsCollision(btBroadphaseProxy *proxy0) const {
const bool needs = GodotFilterCallback::test_collision_filters(m_collisionFilterGroup, m_collisionFilterMask, proxy0->m_collisionFilterGroup, proxy0->m_collisionFilterMask);
if (needs) {
if (m_collisionFilterGroup & proxy0->m_collisionFilterMask) {
btCollisionObject *btObj = static_cast<btCollisionObject *>(proxy0->m_clientObject);
CollisionObjectBullet *gObj = static_cast<CollisionObjectBullet *>(btObj->getUserPointer());

Expand Down Expand Up @@ -90,8 +85,7 @@ bool GodotAllConvexResultCallback::needsCollision(btBroadphaseProxy *proxy0) con
return false;
}

const bool needs = GodotFilterCallback::test_collision_filters(m_collisionFilterGroup, m_collisionFilterMask, proxy0->m_collisionFilterGroup, proxy0->m_collisionFilterMask);
if (needs) {
if (m_collisionFilterGroup & proxy0->m_collisionFilterMask) {
btCollisionObject *btObj = static_cast<btCollisionObject *>(proxy0->m_clientObject);
CollisionObjectBullet *gObj = static_cast<CollisionObjectBullet *>(btObj->getUserPointer());
if (m_exclude->has(gObj->get_self())) {
Expand Down Expand Up @@ -123,8 +117,7 @@ btScalar GodotAllConvexResultCallback::addSingleResult(btCollisionWorld::LocalCo
}

bool GodotKinClosestConvexResultCallback::needsCollision(btBroadphaseProxy *proxy0) const {
const bool needs = GodotFilterCallback::test_collision_filters(m_collisionFilterGroup, m_collisionFilterMask, proxy0->m_collisionFilterGroup, proxy0->m_collisionFilterMask);
if (needs) {
if (m_collisionFilterGroup & proxy0->m_collisionFilterMask) {
btCollisionObject *btObj = static_cast<btCollisionObject *>(proxy0->m_clientObject);
CollisionObjectBullet *gObj = static_cast<CollisionObjectBullet *>(btObj->getUserPointer());
if (gObj == m_self_object) {
Expand All @@ -150,8 +143,7 @@ bool GodotKinClosestConvexResultCallback::needsCollision(btBroadphaseProxy *prox
}

bool GodotClosestConvexResultCallback::needsCollision(btBroadphaseProxy *proxy0) const {
const bool needs = GodotFilterCallback::test_collision_filters(m_collisionFilterGroup, m_collisionFilterMask, proxy0->m_collisionFilterGroup, proxy0->m_collisionFilterMask);
if (needs) {
if (m_collisionFilterGroup & proxy0->m_collisionFilterMask) {
btCollisionObject *btObj = static_cast<btCollisionObject *>(proxy0->m_clientObject);
CollisionObjectBullet *gObj = static_cast<CollisionObjectBullet *>(btObj->getUserPointer());

Expand Down Expand Up @@ -188,8 +180,7 @@ bool GodotAllContactResultCallback::needsCollision(btBroadphaseProxy *proxy0) co
return false;
}

const bool needs = GodotFilterCallback::test_collision_filters(m_collisionFilterGroup, m_collisionFilterMask, proxy0->m_collisionFilterGroup, proxy0->m_collisionFilterMask);
if (needs) {
if (m_collisionFilterGroup & proxy0->m_collisionFilterMask) {
btCollisionObject *btObj = static_cast<btCollisionObject *>(proxy0->m_clientObject);
CollisionObjectBullet *gObj = static_cast<CollisionObjectBullet *>(btObj->getUserPointer());

Expand Down Expand Up @@ -244,8 +235,7 @@ bool GodotContactPairContactResultCallback::needsCollision(btBroadphaseProxy *pr
return false;
}

const bool needs = GodotFilterCallback::test_collision_filters(m_collisionFilterGroup, m_collisionFilterMask, proxy0->m_collisionFilterGroup, proxy0->m_collisionFilterMask);
if (needs) {
if (m_collisionFilterGroup & proxy0->m_collisionFilterMask) {
btCollisionObject *btObj = static_cast<btCollisionObject *>(proxy0->m_clientObject);
CollisionObjectBullet *gObj = static_cast<CollisionObjectBullet *>(btObj->getUserPointer());

Expand Down Expand Up @@ -287,8 +277,7 @@ btScalar GodotContactPairContactResultCallback::addSingleResult(btManifoldPoint
}

bool GodotRestInfoContactResultCallback::needsCollision(btBroadphaseProxy *proxy0) const {
const bool needs = GodotFilterCallback::test_collision_filters(m_collisionFilterGroup, m_collisionFilterMask, proxy0->m_collisionFilterGroup, proxy0->m_collisionFilterMask);
if (needs) {
if (m_collisionFilterGroup & proxy0->m_collisionFilterMask) {
btCollisionObject *btObj = static_cast<btCollisionObject *>(proxy0->m_clientObject);
CollisionObjectBullet *gObj = static_cast<CollisionObjectBullet *>(btObj->getUserPointer());

Expand Down
2 changes: 0 additions & 2 deletions modules/bullet/godot_result_callbacks.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,6 @@ bool godotContactAddedCallback(btManifoldPoint &cp, const btCollisionObjectWrapp

/// This class is required to implement custom collision behaviour in the broadphase
struct GodotFilterCallback : public btOverlapFilterCallback {
static bool test_collision_filters(uint32_t body0_collision_layer, uint32_t body0_collision_mask, uint32_t body1_collision_layer, uint32_t body1_collision_mask);

// return true when pairs need collision
virtual bool needBroadphaseCollision(btBroadphaseProxy *proxy0, btBroadphaseProxy *proxy1) const;
};
Expand Down
12 changes: 5 additions & 7 deletions modules/bullet/space_bullet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1093,7 +1093,6 @@ struct RecoverPenetrationBroadPhaseCallback : public btBroadphaseAabbCallback {

const btCollisionObject *self_collision_object;
uint32_t collision_layer = 0;
uint32_t collision_mask = 0;

struct CompoundLeafCallback : btDbvt::ICollide {
private:
Expand Down Expand Up @@ -1123,10 +1122,9 @@ struct RecoverPenetrationBroadPhaseCallback : public btBroadphaseAabbCallback {
Vector<BroadphaseResult> results;

public:
RecoverPenetrationBroadPhaseCallback(const btCollisionObject *p_self_collision_object, uint32_t p_collision_layer, uint32_t p_collision_mask, btVector3 p_aabb_min, btVector3 p_aabb_max) :
RecoverPenetrationBroadPhaseCallback(const btCollisionObject *p_self_collision_object, uint32_t p_collision_layer, btVector3 p_aabb_min, btVector3 p_aabb_max) :
self_collision_object(p_self_collision_object),
collision_layer(p_collision_layer),
collision_mask(p_collision_mask) {
collision_layer(p_collision_layer) {
bounds = btDbvtVolume::FromMM(p_aabb_min, p_aabb_max);
}

Expand All @@ -1135,7 +1133,7 @@ struct RecoverPenetrationBroadPhaseCallback : public btBroadphaseAabbCallback {
virtual bool process(const btBroadphaseProxy *proxy) {
btCollisionObject *co = static_cast<btCollisionObject *>(proxy->m_clientObject);
if (co->getInternalType() <= btCollisionObject::CO_RIGID_BODY) {
if (self_collision_object != proxy->m_clientObject && GodotFilterCallback::test_collision_filters(collision_layer, collision_mask, proxy->m_collisionFilterGroup, proxy->m_collisionFilterMask)) {
if (self_collision_object != proxy->m_clientObject && (collision_layer & proxy->m_collisionFilterMask)) {
if (co->getCollisionShape()->isCompound()) {
const btCompoundShape *cs = static_cast<btCompoundShape *>(co->getCollisionShape());

Expand Down Expand Up @@ -1218,7 +1216,7 @@ bool SpaceBullet::recover_from_penetration(RigidBodyBullet *p_body, const btTran
}

// Perform broadphase test
RecoverPenetrationBroadPhaseCallback recover_broad_result(p_body->get_bt_collision_object(), p_body->get_collision_layer(), p_body->get_collision_mask(), aabb_min, aabb_max);
RecoverPenetrationBroadPhaseCallback recover_broad_result(p_body->get_bt_collision_object(), p_body->get_collision_layer(), aabb_min, aabb_max);
dynamicsWorld->getBroadphase()->aabbTest(aabb_min, aabb_max, recover_broad_result);

bool penetration = false;
Expand Down Expand Up @@ -1409,7 +1407,7 @@ int SpaceBullet::recover_from_penetration_ray(RigidBodyBullet *p_body, const btT
}

// Perform broadphase test
RecoverPenetrationBroadPhaseCallback recover_broad_result(p_body->get_bt_collision_object(), p_body->get_collision_layer(), p_body->get_collision_mask(), aabb_min, aabb_max);
RecoverPenetrationBroadPhaseCallback recover_broad_result(p_body->get_bt_collision_object(), p_body->get_collision_layer(), aabb_min, aabb_max);
dynamicsWorld->getBroadphase()->aabbTest(aabb_min, aabb_max, recover_broad_result);

int ray_count = 0;
Expand Down
4 changes: 2 additions & 2 deletions servers/physics_2d/area_pair_2d_sw.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@

bool AreaPair2DSW::setup(real_t p_step) {
bool result = false;
if (area->test_collision_mask(body) && CollisionSolver2DSW::solve(body->get_shape(body_shape), body->get_transform() * body->get_shape_transform(body_shape), Vector2(), area->get_shape(area_shape), area->get_transform() * area->get_shape_transform(area_shape), Vector2(), nullptr, this)) {
if (area->interacts_with(body) && CollisionSolver2DSW::solve(body->get_shape(body_shape), body->get_transform() * body->get_shape_transform(body_shape), Vector2(), area->get_shape(area_shape), area->get_transform() * area->get_shape_transform(area_shape), Vector2(), nullptr, this)) {
result = true;
}

Expand Down Expand Up @@ -110,7 +110,7 @@ AreaPair2DSW::~AreaPair2DSW() {

bool Area2Pair2DSW::setup(real_t p_step) {
bool result = false;
if (area_a->test_collision_mask(area_b) && CollisionSolver2DSW::solve(area_a->get_shape(shape_a), area_a->get_transform() * area_a->get_shape_transform(shape_a), Vector2(), area_b->get_shape(shape_b), area_b->get_transform() * area_b->get_shape_transform(shape_b), Vector2(), nullptr, this)) {
if (area_a->interacts_with(area_b) && CollisionSolver2DSW::solve(area_a->get_shape(shape_a), area_a->get_transform() * area_a->get_shape_transform(shape_a), Vector2(), area_b->get_shape(shape_b), area_b->get_transform() * area_b->get_shape_transform(shape_b), Vector2(), nullptr, this)) {
result = true;
}

Expand Down
2 changes: 1 addition & 1 deletion servers/physics_2d/body_pair_2d_sw.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ bool BodyPair2DSW::setup(real_t p_step) {
dynamic_A = (A->get_mode() > PhysicsServer2D::BODY_MODE_KINEMATIC);
dynamic_B = (B->get_mode() > PhysicsServer2D::BODY_MODE_KINEMATIC);

if (!A->test_collision_mask(B) || A->has_exception(B->get_self()) || B->has_exception(A->get_self())) {
if (!A->interacts_with(B) || A->has_exception(B->get_self()) || B->has_exception(A->get_self())) {
collided = false;
return false;
}
Expand Down
6 changes: 5 additions & 1 deletion servers/physics_2d/collision_object_2d_sw.h
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,11 @@ class CollisionObject2DSW : public ShapeOwner2DSW {
void set_pickable(bool p_pickable) { pickable = p_pickable; }
_FORCE_INLINE_ bool is_pickable() const { return pickable; }

_FORCE_INLINE_ bool test_collision_mask(CollisionObject2DSW *p_other) const {
_FORCE_INLINE_ bool layer_in_mask(CollisionObject2DSW *p_other) const {
return collision_layer & p_other->collision_mask;
}

_FORCE_INLINE_ bool interacts_with(CollisionObject2DSW *p_other) const {
return collision_layer & p_other->collision_mask || p_other->collision_layer & collision_mask;
}

Expand Down
4 changes: 2 additions & 2 deletions servers/physics_2d/space_2d_sw.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -508,7 +508,7 @@ int Space2DSW::_cull_aabb_for_body(Body2DSW *p_body, const Rect2 &p_aabb) {
keep = false;
} else if (intersection_query_results[i]->get_type() == CollisionObject2DSW::TYPE_AREA) {
keep = false;
} else if ((static_cast<Body2DSW *>(intersection_query_results[i])->test_collision_mask(p_body)) == 0) {
} else if (!p_body->layer_in_mask(static_cast<Body2DSW *>(intersection_query_results[i]))) {
keep = false;
} else if (static_cast<Body2DSW *>(intersection_query_results[i])->has_exception(p_body->get_self()) || p_body->has_exception(intersection_query_results[i]->get_self())) {
keep = false;
Expand Down Expand Up @@ -1188,7 +1188,7 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
}

void *Space2DSW::_broadphase_pair(CollisionObject2DSW *A, int p_subindex_A, CollisionObject2DSW *B, int p_subindex_B, void *p_self) {
if (!A->test_collision_mask(B)) {
if (!A->interacts_with(B)) {
return nullptr;
}

Expand Down
4 changes: 2 additions & 2 deletions servers/physics_3d/area_pair_3d_sw.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@

bool AreaPair3DSW::setup(real_t p_step) {
bool result = false;
if (area->test_collision_mask(body) && CollisionSolver3DSW::solve_static(body->get_shape(body_shape), body->get_transform() * body->get_shape_transform(body_shape), area->get_shape(area_shape), area->get_transform() * area->get_shape_transform(area_shape), nullptr, this)) {
if (area->interacts_with(body) && CollisionSolver3DSW::solve_static(body->get_shape(body_shape), body->get_transform() * body->get_shape_transform(body_shape), area->get_shape(area_shape), area->get_transform() * area->get_shape_transform(area_shape), nullptr, this)) {
result = true;
}

Expand Down Expand Up @@ -110,7 +110,7 @@ AreaPair3DSW::~AreaPair3DSW() {

bool Area2Pair3DSW::setup(real_t p_step) {
bool result = false;
if (area_a->test_collision_mask(area_b) && CollisionSolver3DSW::solve_static(area_a->get_shape(shape_a), area_a->get_transform() * area_a->get_shape_transform(shape_a), area_b->get_shape(shape_b), area_b->get_transform() * area_b->get_shape_transform(shape_b), nullptr, this)) {
if (area_a->interacts_with(area_b) && CollisionSolver3DSW::solve_static(area_a->get_shape(shape_a), area_a->get_transform() * area_a->get_shape_transform(shape_a), area_b->get_shape(shape_b), area_b->get_transform() * area_b->get_shape_transform(shape_b), nullptr, this)) {
result = true;
}

Expand Down
4 changes: 2 additions & 2 deletions servers/physics_3d/body_pair_3d_sw.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ bool BodyPair3DSW::setup(real_t p_step) {
dynamic_A = (A->get_mode() > PhysicsServer3D::BODY_MODE_KINEMATIC);
dynamic_B = (B->get_mode() > PhysicsServer3D::BODY_MODE_KINEMATIC);

if (!A->test_collision_mask(B) || A->has_exception(B->get_self()) || B->has_exception(A->get_self())) {
if (!A->interacts_with(B) || A->has_exception(B->get_self()) || B->has_exception(A->get_self())) {
collided = false;
return false;
}
Expand Down Expand Up @@ -597,7 +597,7 @@ void BodySoftBodyPair3DSW::validate_contacts() {
bool BodySoftBodyPair3DSW::setup(real_t p_step) {
body_dynamic = (body->get_mode() > PhysicsServer3D::BODY_MODE_KINEMATIC);

if (!body->test_collision_mask(soft_body) || body->has_exception(soft_body->get_self()) || soft_body->has_exception(body->get_self())) {
if (!body->interacts_with(soft_body) || body->has_exception(soft_body->get_self()) || soft_body->has_exception(body->get_self())) {
collided = false;
return false;
}
Expand Down
6 changes: 5 additions & 1 deletion servers/physics_3d/collision_object_3d_sw.h
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,11 @@ class CollisionObject3DSW : public ShapeOwner3DSW {
}
_FORCE_INLINE_ uint32_t get_collision_mask() const { return collision_mask; }

_FORCE_INLINE_ bool test_collision_mask(CollisionObject3DSW *p_other) const {
_FORCE_INLINE_ bool layer_in_mask(CollisionObject3DSW *p_other) const {
return collision_layer & p_other->collision_mask;
}

_FORCE_INLINE_ bool interacts_with(CollisionObject3DSW *p_other) const {
return collision_layer & p_other->collision_mask || p_other->collision_layer & collision_mask;
}

Expand Down
4 changes: 2 additions & 2 deletions servers/physics_3d/space_3d_sw.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -549,7 +549,7 @@ int Space3DSW::_cull_aabb_for_body(Body3DSW *p_body, const AABB &p_aabb) {
keep = false;
} else if (intersection_query_results[i]->get_type() == CollisionObject3DSW::TYPE_SOFT_BODY) {
keep = false;
} else if ((static_cast<Body3DSW *>(intersection_query_results[i])->test_collision_mask(p_body)) == 0) {
} else if (!p_body->layer_in_mask(static_cast<Body3DSW *>(intersection_query_results[i]))) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually after doing more tests I realized this layer check is inverted, a kinematic body should collide with objects it scans in its own mask, not objects which have its own layer in their mask. I'll make a fix in another PR.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the correct way around. A KinematicBody should only interact with other Bodies that have a matching mask.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The way you implemented things, walls would define what they stop instead of moving bodies what they collide with. That would be a nightmare for users to setup.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right. Its mask is the layers it sees. So it is the other way around.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It probably makes more sense then to revert the logic (and the name) of layer_in_mask to mask_has_layer.

keep = false;
} else if (static_cast<Body3DSW *>(intersection_query_results[i])->has_exception(p_body->get_self()) || p_body->has_exception(intersection_query_results[i]->get_self())) {
keep = false;
Expand Down Expand Up @@ -1070,7 +1070,7 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform3D &p_from, co
}

void *Space3DSW::_broadphase_pair(CollisionObject3DSW *A, int p_subindex_A, CollisionObject3DSW *B, int p_subindex_B, void *p_self) {
if (!A->test_collision_mask(B)) {
if (!A->interacts_with(B)) {
return nullptr;
}

Expand Down