From 15305ec91f791cb294b38f4d66d6f14e076c6aaa Mon Sep 17 00:00:00 2001 From: Andrea Catania Date: Sun, 7 Oct 2018 07:14:38 +0200 Subject: [PATCH] Optimitzed area overlap checks --- modules/bullet/area_bullet.h | 1 + modules/bullet/bullet_physics_server.cpp | 4 ++-- modules/bullet/collision_object_bullet.cpp | 18 +++++++++------ modules/bullet/collision_object_bullet.h | 7 +++++- modules/bullet/godot_motion_state.h | 2 +- modules/bullet/rigid_body_bullet.cpp | 27 +++++++++++++--------- modules/bullet/rigid_body_bullet.h | 7 ++++-- modules/bullet/soft_body_bullet.cpp | 6 ----- modules/bullet/soft_body_bullet.h | 7 +++--- modules/bullet/space_bullet.cpp | 26 +++++++++++++-------- 10 files changed, 62 insertions(+), 43 deletions(-) diff --git a/modules/bullet/area_bullet.h b/modules/bullet/area_bullet.h index 07550023f1..1c5962cfe3 100644 --- a/modules/bullet/area_bullet.h +++ b/modules/bullet/area_bullet.h @@ -157,6 +157,7 @@ public: virtual void on_collision_filters_change(); virtual void on_collision_checker_start() {} + virtual void on_collision_checker_end() { isTransformChanged = false; } void add_overlap(CollisionObjectBullet *p_otherObject); void put_overlap_as_exit(int p_index); diff --git a/modules/bullet/bullet_physics_server.cpp b/modules/bullet/bullet_physics_server.cpp index 1c03f47a30..315afe3d72 100644 --- a/modules/bullet/bullet_physics_server.cpp +++ b/modules/bullet/bullet_physics_server.cpp @@ -1489,7 +1489,7 @@ void BulletPhysicsServer::free(RID p_rid) { body->set_space(NULL); - body->remove_all_shapes(true); + body->remove_all_shapes(true, true); rigid_body_owner.free(p_rid); bulletdelete(body); @@ -1509,7 +1509,7 @@ void BulletPhysicsServer::free(RID p_rid) { area->set_space(NULL); - area->remove_all_shapes(true); + area->remove_all_shapes(true, true); area_owner.free(p_rid); bulletdelete(area); diff --git a/modules/bullet/collision_object_bullet.cpp b/modules/bullet/collision_object_bullet.cpp index e62a22311f..a3944b4f99 100644 --- a/modules/bullet/collision_object_bullet.cpp +++ b/modules/bullet/collision_object_bullet.cpp @@ -74,7 +74,8 @@ CollisionObjectBullet::CollisionObjectBullet(Type p_type) : bt_collision_object(NULL), body_scale(1., 1., 1.), force_shape_reset(false), - space(NULL) {} + space(NULL), + isTransformChanged(false) {} CollisionObjectBullet::~CollisionObjectBullet() { // Remove all overlapping, notify is not required since godot take care of it @@ -188,19 +189,24 @@ Transform CollisionObjectBullet::get_transform() const { void CollisionObjectBullet::set_transform__bullet(const btTransform &p_global_transform) { bt_collision_object->setWorldTransform(p_global_transform); + notify_transform_changed(); } const btTransform &CollisionObjectBullet::get_transform__bullet() const { return bt_collision_object->getWorldTransform(); } +void CollisionObjectBullet::notify_transform_changed() { + isTransformChanged = true; +} + RigidCollisionObjectBullet::RigidCollisionObjectBullet(Type p_type) : CollisionObjectBullet(p_type), mainShape(NULL) { } RigidCollisionObjectBullet::~RigidCollisionObjectBullet() { - remove_all_shapes(true); + remove_all_shapes(true, true); if (mainShape && mainShape->isCompound()) { bulletdelete(mainShape); } @@ -260,13 +266,14 @@ void RigidCollisionObjectBullet::remove_shape_full(int p_index) { reload_shapes(); } -void RigidCollisionObjectBullet::remove_all_shapes(bool p_permanentlyFromThisBody) { +void RigidCollisionObjectBullet::remove_all_shapes(bool p_permanentlyFromThisBody, bool p_force_not_reload) { // Reverse order required for delete. for (int i = shapes.size() - 1; 0 <= i; --i) { internal_shape_destroy(i, p_permanentlyFromThisBody); } shapes.clear(); - reload_shapes(); + if (!p_force_not_reload) + reload_shapes(); } void RigidCollisionObjectBullet::set_shape_transform(int p_index, const Transform &p_transform) { @@ -323,9 +330,6 @@ void RigidCollisionObjectBullet::reload_shapes() { const btVector3 body_scale(get_bt_body_scale()); - if (!shape_count) - return; - // Try to optimize by not using compound if (1 == shape_count) { shpWrapper = &shapes.write[0]; diff --git a/modules/bullet/collision_object_bullet.h b/modules/bullet/collision_object_bullet.h index 230dca9498..4a0c805ce5 100644 --- a/modules/bullet/collision_object_bullet.h +++ b/modules/bullet/collision_object_bullet.h @@ -132,6 +132,7 @@ protected: /// New area is added when overlap with new area (AreaBullet::addOverlap), then is removed when it exit (CollisionObjectBullet::onExitArea) /// This array is used mainly to know which area hold the pointer of this object Vector areasOverlapped; + bool isTransformChanged; public: CollisionObjectBullet(Type p_type); @@ -187,6 +188,7 @@ public: _FORCE_INLINE_ SpaceBullet *get_space() const { return space; } virtual void on_collision_checker_start() = 0; + virtual void on_collision_checker_end() = 0; virtual void dispatch_callbacks() = 0; @@ -204,6 +206,9 @@ public: Transform get_transform() const; virtual void set_transform__bullet(const btTransform &p_global_transform); virtual const btTransform &get_transform__bullet() const; + + bool is_transform_changed() const { return isTransformChanged; } + virtual void notify_transform_changed(); }; class RigidCollisionObjectBullet : public CollisionObjectBullet, public ShapeOwnerBullet { @@ -230,7 +235,7 @@ public: virtual void remove_shape_full(ShapeBullet *p_shape); void remove_shape_full(int p_index); - void remove_all_shapes(bool p_permanentlyFromThisBody = false); + void remove_all_shapes(bool p_permanentlyFromThisBody = false, bool p_force_not_reload = false); void set_shape_transform(int p_index, const Transform &p_transform); diff --git a/modules/bullet/godot_motion_state.h b/modules/bullet/godot_motion_state.h index fa58e86589..5844ef8bf3 100644 --- a/modules/bullet/godot_motion_state.h +++ b/modules/bullet/godot_motion_state.h @@ -82,7 +82,7 @@ public: virtual void setWorldTransform(const btTransform &worldTrans) { bodyCurrentWorldTransform = worldTrans; - owner->scratch(); + owner->notify_transform_changed(); } public: diff --git a/modules/bullet/rigid_body_bullet.cpp b/modules/bullet/rigid_body_bullet.cpp index 22c3637bd5..37e7718969 100644 --- a/modules/bullet/rigid_body_bullet.cpp +++ b/modules/bullet/rigid_body_bullet.cpp @@ -265,13 +265,13 @@ RigidBodyBullet::RigidBodyBullet() : angularDamp(0), can_sleep(true), omit_forces_integration(false), + can_integrate_forces(false), maxCollisionsDetection(0), collisionsCount(0), maxAreasWhereIam(10), areaWhereIamCount(0), countGravityPointSpaces(0), isScratchedSpaceOverrideModificator(false), - isTransformChanged(false), previousActiveState(true), force_integration_callback(NULL) { @@ -332,7 +332,7 @@ void RigidBodyBullet::reload_body() { void RigidBodyBullet::set_space(SpaceBullet *p_space) { // Clear the old space if there is one if (space) { - isTransformChanged = false; + can_integrate_forces = false; // Remove all eventual constraints assert_no_constraints(); @@ -349,8 +349,8 @@ void RigidBodyBullet::set_space(SpaceBullet *p_space) { } void RigidBodyBullet::dispatch_callbacks() { - /// The check isTransformChanged is necessary in order to call integrated forces only when the first transform is sent - if ((btBody->isKinematicObject() || btBody->isActive() || previousActiveState != btBody->isActive()) && force_integration_callback && isTransformChanged) { + /// The check isFirstTransformChanged is necessary in order to call integrated forces only when the first transform is sent + if ((btBody->isKinematicObject() || btBody->isActive() || previousActiveState != btBody->isActive()) && force_integration_callback && can_integrate_forces) { if (omit_forces_integration) btBody->clearForces(); @@ -399,10 +399,6 @@ void RigidBodyBullet::set_force_integration_callback(ObjectID p_id, const String } } -void RigidBodyBullet::scratch() { - isTransformChanged = true; -} - void RigidBodyBullet::scratch_space_override_modificator() { isScratchedSpaceOverrideModificator = true; } @@ -417,6 +413,11 @@ void RigidBodyBullet::on_collision_checker_start() { collisionsCount = 0; } +void RigidBodyBullet::on_collision_checker_end() { + // Always true if active and not a static or kinematic body + isTransformChanged = btBody->isActive() && !btBody->isStaticOrKinematicObject(); +} + bool RigidBodyBullet::add_collision_object(RigidBodyBullet *p_otherObject, const Vector3 &p_hitWorldLocation, const Vector3 &p_hitLocalLocation, const Vector3 &p_hitNormal, const float &p_appliedImpulse, int p_other_shape_index, int p_local_shape_index) { if (collisionsCount >= maxCollisionsDetection) { @@ -519,7 +520,7 @@ real_t RigidBodyBullet::get_param(PhysicsServer::BodyParameter p_param) const { void RigidBodyBullet::set_mode(PhysicsServer::BodyMode p_mode) { // This is necessary to block force_integration untile next move - isTransformChanged = false; + can_integrate_forces = false; destroy_kinematic_utilities(); // The mode change is relevant to its mass switch (p_mode) { @@ -776,8 +777,7 @@ void RigidBodyBullet::set_transform__bullet(const btTransform &p_global_transfor // The kinematic use MotionState class godotMotionState->moveBody(p_global_transform); } - btBody->setWorldTransform(p_global_transform); - scratch(); + CollisionObjectBullet::set_transform__bullet(p_global_transform); } const btTransform &RigidBodyBullet::get_transform__bullet() const { @@ -986,6 +986,11 @@ void RigidBodyBullet::reload_kinematic_shapes() { kinematic_utilities->copyAllOwnerShapes(); } +void RigidBodyBullet::notify_transform_changed() { + RigidCollisionObjectBullet::notify_transform_changed(); + can_integrate_forces = true; +} + void RigidBodyBullet::_internal_set_mass(real_t p_mass) { btVector3 localInertia(0, 0, 0); diff --git a/modules/bullet/rigid_body_bullet.h b/modules/bullet/rigid_body_bullet.h index 7c7f307c3c..26e5018c87 100644 --- a/modules/bullet/rigid_body_bullet.h +++ b/modules/bullet/rigid_body_bullet.h @@ -202,6 +202,7 @@ private: real_t angularDamp; bool can_sleep; bool omit_forces_integration; + bool can_integrate_forces; Vector collisions; // these parameters are used to avoid vector resize @@ -216,7 +217,6 @@ private: int countGravityPointSpaces; bool isScratchedSpaceOverrideModificator; - bool isTransformChanged; bool previousActiveState; // Last check state ForceIntegrationCallback *force_integration_callback; @@ -237,11 +237,12 @@ public: virtual void dispatch_callbacks(); void set_force_integration_callback(ObjectID p_id, const StringName &p_method, const Variant &p_udata = Variant()); - void scratch(); void scratch_space_override_modificator(); virtual void on_collision_filters_change(); virtual void on_collision_checker_start(); + virtual void on_collision_checker_end(); + void set_max_collisions_detection(int p_maxCollisionsDetection) { maxCollisionsDetection = p_maxCollisionsDetection; collisions.resize(p_maxCollisionsDetection); @@ -311,6 +312,8 @@ public: /// Kinematic void reload_kinematic_shapes(); + virtual void notify_transform_changed(); + private: void _internal_set_mass(real_t p_mass); }; diff --git a/modules/bullet/soft_body_bullet.cpp b/modules/bullet/soft_body_bullet.cpp index f373ce5db4..94f350210f 100644 --- a/modules/bullet/soft_body_bullet.cpp +++ b/modules/bullet/soft_body_bullet.cpp @@ -72,12 +72,6 @@ void SoftBodyBullet::set_space(SpaceBullet *p_space) { } } -void SoftBodyBullet::dispatch_callbacks() {} - -void SoftBodyBullet::on_collision_filters_change() {} - -void SoftBodyBullet::on_collision_checker_start() {} - void SoftBodyBullet::on_enter_area(AreaBullet *p_area) {} void SoftBodyBullet::on_exit_area(AreaBullet *p_area) {} diff --git a/modules/bullet/soft_body_bullet.h b/modules/bullet/soft_body_bullet.h index c775193584..d04bfca046 100644 --- a/modules/bullet/soft_body_bullet.h +++ b/modules/bullet/soft_body_bullet.h @@ -91,9 +91,10 @@ public: virtual void reload_body(); virtual void set_space(SpaceBullet *p_space); - virtual void dispatch_callbacks(); - virtual void on_collision_filters_change(); - virtual void on_collision_checker_start(); + virtual void dispatch_callbacks() {} + virtual void on_collision_filters_change() {} + virtual void on_collision_checker_start() {} + virtual void on_collision_checker_end() {} virtual void on_enter_area(AreaBullet *p_area); virtual void on_exit_area(AreaBullet *p_area); diff --git a/modules/bullet/space_bullet.cpp b/modules/bullet/space_bullet.cpp index 71048888b4..ab2d1781ad 100644 --- a/modules/bullet/space_bullet.cpp +++ b/modules/bullet/space_bullet.cpp @@ -540,17 +540,20 @@ void onBulletPreTickCallback(btDynamicsWorld *p_dynamicsWorld, btScalar timeStep void onBulletTickCallback(btDynamicsWorld *p_dynamicsWorld, btScalar timeStep) { - // Notify all Collision objects the collision checker is started const btCollisionObjectArray &colObjArray = p_dynamicsWorld->getCollisionObjectArray(); + + // Notify all Collision objects the collision checker is started for (int i = colObjArray.size() - 1; 0 <= i; --i) { - CollisionObjectBullet *colObj = static_cast(colObjArray[i]->getUserPointer()); - assert(NULL != colObj); - colObj->on_collision_checker_start(); + static_cast(colObjArray[i]->getUserPointer())->on_collision_checker_start(); } SpaceBullet *sb = static_cast(p_dynamicsWorld->getWorldUserInfo()); sb->check_ghost_overlaps(); sb->check_body_collision(); + + for (int i = colObjArray.size() - 1; 0 <= i; --i) { + static_cast(colObjArray[i]->getUserPointer())->on_collision_checker_end(); + } } BulletPhysicsDirectSpaceState *SpaceBullet::get_direct_state() { @@ -649,7 +652,6 @@ void SpaceBullet::check_ghost_overlaps() { btConvexShape *area_shape; btGjkPairDetector::ClosestPointInput gjk_input; AreaBullet *area; - RigidCollisionObjectBullet *otherObject; int x(-1), i(-1), y(-1), z(-1), indexOverlap(-1); /// For each areas @@ -676,13 +678,17 @@ void SpaceBullet::check_ghost_overlaps() { // For each overlapping for (i = ghostOverlaps.size() - 1; 0 <= i; --i) { - if (ghostOverlaps[i]->getUserIndex() == CollisionObjectBullet::TYPE_AREA) { - if (!static_cast(ghostOverlaps[i]->getUserPointer())->is_monitorable()) - continue; - } else if (ghostOverlaps[i]->getUserIndex() != CollisionObjectBullet::TYPE_RIGID_BODY) + btCollisionObject *overlapped_bt_co = ghostOverlaps[i]; + RigidCollisionObjectBullet *otherObject = static_cast(overlapped_bt_co->getUserPointer()); + + if (!area->is_transform_changed() && !otherObject->is_transform_changed()) continue; - otherObject = static_cast(ghostOverlaps[i]->getUserPointer()); + if (overlapped_bt_co->getUserIndex() == CollisionObjectBullet::TYPE_AREA) { + if (!static_cast(overlapped_bt_co->getUserPointer())->is_monitorable()) + continue; + } else if (overlapped_bt_co->getUserIndex() != CollisionObjectBullet::TYPE_RIGID_BODY) + continue; bool hasOverlap = false;