Browse Source

Optimitzed area overlap checks

Andrea Catania 6 years ago
parent
commit
15305ec91f

+ 1 - 0
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);

+ 2 - 2
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);

+ 11 - 7
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];

+ 6 - 1
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<AreaBullet *> 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);
 

+ 1 - 1
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:

+ 16 - 11
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);

+ 5 - 2
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<CollisionData> 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);
 };

+ 0 - 6
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) {}

+ 4 - 3
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);
 

+ 16 - 10
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<CollisionObjectBullet *>(colObjArray[i]->getUserPointer());
-		assert(NULL != colObj);
-		colObj->on_collision_checker_start();
+		static_cast<CollisionObjectBullet *>(colObjArray[i]->getUserPointer())->on_collision_checker_start();
 	}
 
 	SpaceBullet *sb = static_cast<SpaceBullet *>(p_dynamicsWorld->getWorldUserInfo());
 	sb->check_ghost_overlaps();
 	sb->check_body_collision();
+
+	for (int i = colObjArray.size() - 1; 0 <= i; --i) {
+		static_cast<CollisionObjectBullet *>(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<AreaBullet *>(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<RigidCollisionObjectBullet *>(overlapped_bt_co->getUserPointer());
+
+			if (!area->is_transform_changed() && !otherObject->is_transform_changed())
 				continue;
 
-			otherObject = static_cast<RigidCollisionObjectBullet *>(ghostOverlaps[i]->getUserPointer());
+			if (overlapped_bt_co->getUserIndex() == CollisionObjectBullet::TYPE_AREA) {
+				if (!static_cast<AreaBullet *>(overlapped_bt_co->getUserPointer())->is_monitorable())
+					continue;
+			} else if (overlapped_bt_co->getUserIndex() != CollisionObjectBullet::TYPE_RIGID_BODY)
+				continue;
 
 			bool hasOverlap = false;