Browse Source

Merge pull request #39726 from AndreaCatania/add_body_impr_physics

Optimized physics object spawn time
Rémi Verschelde 5 years ago
parent
commit
bd3a468fc2

+ 4 - 2
modules/bullet/area_bullet.cpp

@@ -164,7 +164,7 @@ void AreaBullet::main_shape_changed() {
 	btGhost->setCollisionShape(get_main_shape());
 }
 
-void AreaBullet::reload_body() {
+void AreaBullet::do_reload_body() {
 	if (space) {
 		space->remove_area(this);
 		space->add_area(this);
@@ -178,13 +178,15 @@ void AreaBullet::set_space(SpaceBullet *p_space) {
 		isScratched = false;
 
 		// Remove this object form the physics world
+		space->unregister_collision_object(this);
 		space->remove_area(this);
 	}
 
 	space = p_space;
 
 	if (space) {
-		space->add_area(this);
+		space->register_collision_object(this);
+		reload_body();
 	}
 }
 

+ 1 - 1
modules/bullet/area_bullet.h

@@ -140,7 +140,7 @@ public:
 	_FORCE_INLINE_ int get_spOv_priority() { return spOv_priority; }
 
 	virtual void main_shape_changed();
-	virtual void reload_body();
+	virtual void do_reload_body();
 	virtual void set_space(SpaceBullet *p_space);
 
 	virtual void dispatch_callbacks();

+ 41 - 17
modules/bullet/collision_object_bullet.cpp

@@ -79,7 +79,7 @@ btTransform CollisionObjectBullet::ShapeWrapper::get_adjusted_transform() const
 }
 
 void CollisionObjectBullet::ShapeWrapper::claim_bt_shape(const btVector3 &body_scale) {
-	if (!bt_shape) {
+	if (bt_shape == nullptr) {
 		if (active) {
 			bt_shape = shape->create_bt_shape(scale * body_scale);
 		} else {
@@ -88,6 +88,13 @@ void CollisionObjectBullet::ShapeWrapper::claim_bt_shape(const btVector3 &body_s
 	}
 }
 
+void CollisionObjectBullet::ShapeWrapper::release_bt_shape() {
+	if (bt_shape != nullptr) {
+		shape->destroy_bt_shape(bt_shape);
+		bt_shape = nullptr;
+	}
+}
+
 CollisionObjectBullet::CollisionObjectBullet(Type p_type) :
 		RIDBullet(),
 		type(p_type) {}
@@ -158,6 +165,13 @@ bool CollisionObjectBullet::has_collision_exception(const CollisionObjectBullet
 	return !bt_collision_object->checkCollideWith(p_otherCollisionObject->bt_collision_object);
 }
 
+void CollisionObjectBullet::prepare_object_for_dispatch() {
+	if (need_body_reload) {
+		do_reload_body();
+		need_body_reload = false;
+	}
+}
+
 void CollisionObjectBullet::set_collision_enabled(bool p_enabled) {
 	collisionsEnabled = p_enabled;
 	if (collisionsEnabled) {
@@ -319,16 +333,28 @@ bool RigidCollisionObjectBullet::is_shape_disabled(int p_index) {
 	return !shapes[p_index].active;
 }
 
+void RigidCollisionObjectBullet::prepare_object_for_dispatch() {
+	if (need_shape_reload) {
+		do_reload_shapes();
+		need_shape_reload = false;
+	}
+	CollisionObjectBullet::prepare_object_for_dispatch();
+}
+
 void RigidCollisionObjectBullet::shape_changed(int p_shape_index) {
 	ShapeWrapper &shp = shapes.write[p_shape_index];
 	if (shp.bt_shape == mainShape) {
 		mainShape = nullptr;
 	}
-	bulletdelete(shp.bt_shape);
+	shp.release_bt_shape();
 	reload_shapes();
 }
 
 void RigidCollisionObjectBullet::reload_shapes() {
+	need_shape_reload = true;
+}
+
+void RigidCollisionObjectBullet::do_reload_shapes() {
 	if (mainShape && mainShape->isCompound()) {
 		// Destroy compound
 		bulletdelete(mainShape);
@@ -336,41 +362,39 @@ void RigidCollisionObjectBullet::reload_shapes() {
 
 	mainShape = nullptr;
 
-	ShapeWrapper *shpWrapper;
 	const int shape_count = shapes.size();
+	ShapeWrapper *shapes_ptr = shapes.ptrw();
 
-	// Reset shape if required
+	// Reset all shapes if required
 	if (force_shape_reset) {
 		for (int i(0); i < shape_count; ++i) {
-			shpWrapper = &shapes.write[i];
-			bulletdelete(shpWrapper->bt_shape);
+			shapes_ptr[i].release_bt_shape();
 		}
 		force_shape_reset = false;
 	}
 
 	const btVector3 body_scale(get_bt_body_scale());
 
-	// Try to optimize by not using compound
 	if (1 == shape_count) {
-		shpWrapper = &shapes.write[0];
-		btTransform transform = shpWrapper->get_adjusted_transform();
+		// Is it possible to optimize by not using compound?
+		btTransform transform = shapes_ptr[0].get_adjusted_transform();
 		if (transform.getOrigin().isZero() && transform.getBasis() == transform.getBasis().getIdentity()) {
-			shpWrapper->claim_bt_shape(body_scale);
-			mainShape = shpWrapper->bt_shape;
+			shapes_ptr[0].claim_bt_shape(body_scale);
+			mainShape = shapes_ptr[0].bt_shape;
 			main_shape_changed();
+			// Nothing more to do
 			return;
 		}
 	}
 
-	// Optimization not possible use a compound shape
+	// Optimization not possible use a compound shape.
 	btCompoundShape *compoundShape = bulletnew(btCompoundShape(enableDynamicAabbTree, shape_count));
 
 	for (int i(0); i < shape_count; ++i) {
-		shpWrapper = &shapes.write[i];
-		shpWrapper->claim_bt_shape(body_scale);
-		btTransform scaled_shape_transform(shpWrapper->get_adjusted_transform());
+		shapes_ptr[i].claim_bt_shape(body_scale);
+		btTransform scaled_shape_transform(shapes_ptr[i].get_adjusted_transform());
 		scaled_shape_transform.getOrigin() *= body_scale;
-		compoundShape->addChildShape(scaled_shape_transform, shpWrapper->bt_shape);
+		compoundShape->addChildShape(scaled_shape_transform, shapes_ptr[i].bt_shape);
 	}
 
 	compoundShape->recalculateLocalAabb();
@@ -389,5 +413,5 @@ void RigidCollisionObjectBullet::internal_shape_destroy(int p_index, bool p_perm
 	if (shp.bt_shape == mainShape) {
 		mainShape = nullptr;
 	}
-	bulletdelete(shp.bt_shape);
+	shp.release_bt_shape();
 }

+ 23 - 3
modules/bullet/collision_object_bullet.h

@@ -70,11 +70,12 @@ public:
 
 	struct ShapeWrapper {
 		ShapeBullet *shape = nullptr;
-		btCollisionShape *bt_shape = nullptr;
 		btTransform transform;
 		btVector3 scale;
 		bool active = true;
+		btCollisionShape *bt_shape = nullptr;
 
+	public:
 		ShapeWrapper() {}
 
 		ShapeWrapper(ShapeBullet *p_shape, const btTransform &p_transform, bool p_active) :
@@ -107,6 +108,7 @@ public:
 		btTransform get_adjusted_transform() const;
 
 		void claim_bt_shape(const btVector3 &body_scale);
+		void release_bt_shape();
 	};
 
 protected:
@@ -124,12 +126,17 @@ protected:
 
 	VSet<RID> exceptions;
 
+	bool need_body_reload = true;
+
 	/// This array is used to know all areas where this Object is overlapped in
 	/// 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 = false;
 
+public:
+	bool is_in_world = false;
+
 public:
 	CollisionObjectBullet(Type p_type);
 	virtual ~CollisionObjectBullet();
@@ -183,13 +190,21 @@ public:
 		return collisionLayer & p_other->collisionMask || p_other->collisionLayer & collisionMask;
 	}
 
-	virtual void reload_body() = 0;
+	bool need_reload_body() const {
+		return need_body_reload;
+	}
+
+	void reload_body() {
+		need_body_reload = true;
+	}
+	virtual void do_reload_body() = 0;
 	virtual void set_space(SpaceBullet *p_space) = 0;
 	_FORCE_INLINE_ SpaceBullet *get_space() const { return space; }
 
 	virtual void on_collision_checker_start() = 0;
 	virtual void on_collision_checker_end() = 0;
 
+	virtual void prepare_object_for_dispatch();
 	virtual void dispatch_callbacks() = 0;
 
 	void set_collision_enabled(bool p_enabled);
@@ -215,6 +230,7 @@ class RigidCollisionObjectBullet : public CollisionObjectBullet, public ShapeOwn
 protected:
 	btCollisionShape *mainShape = nullptr;
 	Vector<ShapeWrapper> shapes;
+	bool need_shape_reload = true;
 
 public:
 	RigidCollisionObjectBullet(Type p_type) :
@@ -246,8 +262,12 @@ public:
 	void set_shape_disabled(int p_index, bool p_disabled);
 	bool is_shape_disabled(int p_index);
 
+	virtual void prepare_object_for_dispatch();
+
 	virtual void shape_changed(int p_shape_index);
-	virtual void reload_shapes();
+	void reload_shapes();
+	bool need_reload_shapes() const { return need_shape_reload; }
+	virtual void do_reload_shapes();
 
 	virtual void main_shape_changed() = 0;
 	virtual void body_scale_changed();

+ 7 - 5
modules/bullet/rigid_body_bullet.cpp

@@ -237,7 +237,7 @@ void RigidBodyBullet::KinematicUtilities::copyAllOwnerShapes() {
 			case PhysicsServer3D::SHAPE_CYLINDER:
 			case PhysicsServer3D::SHAPE_CONVEX_POLYGON:
 			case PhysicsServer3D::SHAPE_RAY: {
-				shapes.write[i].shape = static_cast<btConvexShape *>(shape_wrapper->shape->create_bt_shape(owner_scale * shape_wrapper->scale, safe_margin));
+				shapes.write[i].shape = static_cast<btConvexShape *>(shape_wrapper->shape->internal_create_bt_shape(owner_scale * shape_wrapper->scale, safe_margin));
 			} break;
 			default:
 				WARN_PRINT("This shape is not supported for kinematic collision.");
@@ -307,7 +307,7 @@ void RigidBodyBullet::main_shape_changed() {
 	set_continuous_collision_detection(is_continuous_collision_detection_enabled()); // Reset
 }
 
-void RigidBodyBullet::reload_body() {
+void RigidBodyBullet::do_reload_body() {
 	if (space) {
 		space->remove_rigid_body(this);
 		if (get_main_shape()) {
@@ -325,13 +325,15 @@ void RigidBodyBullet::set_space(SpaceBullet *p_space) {
 		assert_no_constraints();
 
 		// Remove this object form the physics world
+		space->unregister_collision_object(this);
 		space->remove_rigid_body(this);
 	}
 
 	space = p_space;
 
 	if (space) {
-		space->add_rigid_body(this);
+		space->register_collision_object(this);
+		reload_body();
 	}
 }
 
@@ -803,8 +805,8 @@ const btTransform &RigidBodyBullet::get_transform__bullet() const {
 	}
 }
 
-void RigidBodyBullet::reload_shapes() {
-	RigidCollisionObjectBullet::reload_shapes();
+void RigidBodyBullet::do_reload_shapes() {
+	RigidCollisionObjectBullet::do_reload_shapes();
 
 	const btScalar invMass = btBody->getInvMass();
 	const btScalar mass = invMass == 0 ? 0 : 1 / invMass;

+ 2 - 2
modules/bullet/rigid_body_bullet.h

@@ -236,7 +236,7 @@ public:
 	_FORCE_INLINE_ btRigidBody *get_bt_rigid_body() { return btBody; }
 
 	virtual void main_shape_changed();
-	virtual void reload_body();
+	virtual void do_reload_body();
 	virtual void set_space(SpaceBullet *p_space);
 
 	virtual void dispatch_callbacks();
@@ -315,7 +315,7 @@ public:
 	virtual void set_transform__bullet(const btTransform &p_global_transform);
 	virtual const btTransform &get_transform__bullet() const;
 
-	virtual void reload_shapes();
+	virtual void do_reload_shapes();
 
 	virtual void on_enter_area(AreaBullet *p_area);
 	virtual void on_exit_area(AreaBullet *p_area);

+ 44 - 11
modules/bullet/shape_bullet.cpp

@@ -46,9 +46,15 @@
 	@author AndreaCatania
 */
 
-ShapeBullet::ShapeBullet() {}
+ShapeBullet::ShapeBullet() {
+}
 
-ShapeBullet::~ShapeBullet() {}
+ShapeBullet::~ShapeBullet() {
+	if (default_shape != nullptr) {
+		bulletdelete(default_shape);
+		default_shape = nullptr;
+	}
+}
 
 btCollisionShape *ShapeBullet::create_bt_shape(const Vector3 &p_implicit_scale, real_t p_extra_edge) {
 	btVector3 s;
@@ -56,6 +62,22 @@ btCollisionShape *ShapeBullet::create_bt_shape(const Vector3 &p_implicit_scale,
 	return create_bt_shape(s, p_extra_edge);
 }
 
+btCollisionShape *ShapeBullet::create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge) {
+	if (p_extra_edge == 0.0 && (p_implicit_scale - btVector3(1, 1, 1)).length2() <= CMP_EPSILON) {
+		return default_shape;
+	}
+
+	return internal_create_bt_shape(p_implicit_scale, p_extra_edge);
+}
+
+void ShapeBullet::destroy_bt_shape(btCollisionShape *p_shape) const {
+	if (p_shape != default_shape && p_shape != old_default_shape) {
+		if (likely(p_shape != nullptr)) {
+			bulletdelete(p_shape);
+		}
+	}
+}
+
 btCollisionShape *ShapeBullet::prepare(btCollisionShape *p_btShape) const {
 	p_btShape->setUserPointer(const_cast<ShapeBullet *>(this));
 	p_btShape->setMargin(margin);
@@ -63,10 +85,21 @@ btCollisionShape *ShapeBullet::prepare(btCollisionShape *p_btShape) const {
 }
 
 void ShapeBullet::notifyShapeChanged() {
+	// Store the old shape ptr so to not lose the reference pointer.
+	old_default_shape = default_shape;
+	// Create the new default shape with the new data.
+	default_shape = internal_create_bt_shape(btVector3(1, 1, 1));
+
 	for (Map<ShapeOwnerBullet *, int>::Element *E = owners.front(); E; E = E->next()) {
 		ShapeOwnerBullet *owner = static_cast<ShapeOwnerBullet *>(E->key());
 		owner->shape_changed(owner->find_shape(this));
 	}
+
+	if (old_default_shape) {
+		// At this point now one has the old default shape; just delete it.
+		bulletdelete(old_default_shape);
+		old_default_shape = nullptr;
+	}
 }
 
 void ShapeBullet::add_owner(ShapeOwnerBullet *p_owner) {
@@ -186,7 +219,7 @@ void PlaneShapeBullet::setup(const Plane &p_plane) {
 	notifyShapeChanged();
 }
 
-btCollisionShape *PlaneShapeBullet::create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge) {
+btCollisionShape *PlaneShapeBullet::internal_create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge) {
 	btVector3 btPlaneNormal;
 	G_TO_B(plane.normal, btPlaneNormal);
 	return prepare(PlaneShapeBullet::create_shape_plane(btPlaneNormal, plane.d));
@@ -214,7 +247,7 @@ void SphereShapeBullet::setup(real_t p_radius) {
 	notifyShapeChanged();
 }
 
-btCollisionShape *SphereShapeBullet::create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge) {
+btCollisionShape *SphereShapeBullet::internal_create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge) {
 	return prepare(ShapeBullet::create_shape_sphere(radius * p_implicit_scale[0] + p_extra_edge));
 }
 
@@ -241,7 +274,7 @@ void BoxShapeBullet::setup(const Vector3 &p_half_extents) {
 	notifyShapeChanged();
 }
 
-btCollisionShape *BoxShapeBullet::create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge) {
+btCollisionShape *BoxShapeBullet::internal_create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge) {
 	return prepare(ShapeBullet::create_shape_box((half_extents * p_implicit_scale) + btVector3(p_extra_edge, p_extra_edge, p_extra_edge)));
 }
 
@@ -274,7 +307,7 @@ void CapsuleShapeBullet::setup(real_t p_height, real_t p_radius) {
 	notifyShapeChanged();
 }
 
-btCollisionShape *CapsuleShapeBullet::create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge) {
+btCollisionShape *CapsuleShapeBullet::internal_create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge) {
 	return prepare(ShapeBullet::create_shape_capsule(radius * p_implicit_scale[0] + p_extra_edge, height * p_implicit_scale[1] + p_extra_edge));
 }
 
@@ -307,7 +340,7 @@ void CylinderShapeBullet::setup(real_t p_height, real_t p_radius) {
 	notifyShapeChanged();
 }
 
-btCollisionShape *CylinderShapeBullet::create_bt_shape(const btVector3 &p_implicit_scale, real_t p_margin) {
+btCollisionShape *CylinderShapeBullet::internal_create_bt_shape(const btVector3 &p_implicit_scale, real_t p_margin) {
 	return prepare(ShapeBullet::create_shape_cylinder(radius * p_implicit_scale[0] + p_margin, height * p_implicit_scale[1] + p_margin));
 }
 
@@ -349,7 +382,7 @@ void ConvexPolygonShapeBullet::setup(const Vector<Vector3> &p_vertices) {
 	notifyShapeChanged();
 }
 
-btCollisionShape *ConvexPolygonShapeBullet::create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge) {
+btCollisionShape *ConvexPolygonShapeBullet::internal_create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge) {
 	if (!vertices.size()) {
 		// This is necessary since 0 vertices
 		return prepare(ShapeBullet::create_shape_empty());
@@ -431,7 +464,7 @@ void ConcavePolygonShapeBullet::setup(Vector<Vector3> p_faces) {
 	notifyShapeChanged();
 }
 
-btCollisionShape *ConcavePolygonShapeBullet::create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge) {
+btCollisionShape *ConcavePolygonShapeBullet::internal_create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge) {
 	btCollisionShape *cs = ShapeBullet::create_shape_concave(meshShape);
 	if (!cs) {
 		// This is necessary since if 0 faces the creation of concave return null
@@ -555,7 +588,7 @@ void HeightMapShapeBullet::setup(Vector<real_t> &p_heights, int p_width, int p_d
 	notifyShapeChanged();
 }
 
-btCollisionShape *HeightMapShapeBullet::create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge) {
+btCollisionShape *HeightMapShapeBullet::internal_create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge) {
 	btCollisionShape *cs(ShapeBullet::create_shape_height_field(heights, width, depth, min_height, max_height));
 	cs->setLocalScaling(p_implicit_scale);
 	prepare(cs);
@@ -588,6 +621,6 @@ void RayShapeBullet::setup(real_t p_length, bool p_slips_on_slope) {
 	notifyShapeChanged();
 }
 
-btCollisionShape *RayShapeBullet::create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge) {
+btCollisionShape *RayShapeBullet::internal_create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge) {
 	return prepare(ShapeBullet::create_shape_ray(length * p_implicit_scale[1] + p_extra_edge, slips_on_slope));
 }

+ 18 - 10
modules/bullet/shape_bullet.h

@@ -53,6 +53,10 @@ class ShapeBullet : public RIDBullet {
 	Map<ShapeOwnerBullet *, int> owners;
 	real_t margin = 0.04;
 
+	// Contains the default shape.
+	btCollisionShape *default_shape = nullptr;
+	btCollisionShape *old_default_shape = nullptr;
+
 protected:
 	/// return self
 	btCollisionShape *prepare(btCollisionShape *p_btShape) const;
@@ -63,7 +67,11 @@ public:
 	virtual ~ShapeBullet();
 
 	btCollisionShape *create_bt_shape(const Vector3 &p_implicit_scale, real_t p_extra_edge = 0);
-	virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge = 0) = 0;
+	btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge = 0);
+
+	void destroy_bt_shape(btCollisionShape *p_shape) const;
+
+	virtual btCollisionShape *internal_create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge = 0) = 0;
 
 	void add_owner(ShapeOwnerBullet *p_owner);
 	void remove_owner(ShapeOwnerBullet *p_owner, bool p_permanentlyFromThisBody = false);
@@ -102,7 +110,7 @@ public:
 	virtual void set_data(const Variant &p_data);
 	virtual Variant get_data() const;
 	virtual PhysicsServer3D::ShapeType get_type() const;
-	virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge = 0);
+	virtual btCollisionShape *internal_create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge = 0);
 
 private:
 	void setup(const Plane &p_plane);
@@ -118,7 +126,7 @@ public:
 	virtual void set_data(const Variant &p_data);
 	virtual Variant get_data() const;
 	virtual PhysicsServer3D::ShapeType get_type() const;
-	virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge = 0);
+	virtual btCollisionShape *internal_create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge = 0);
 
 private:
 	void setup(real_t p_radius);
@@ -134,7 +142,7 @@ public:
 	virtual void set_data(const Variant &p_data);
 	virtual Variant get_data() const;
 	virtual PhysicsServer3D::ShapeType get_type() const;
-	virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge = 0);
+	virtual btCollisionShape *internal_create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge = 0);
 
 private:
 	void setup(const Vector3 &p_half_extents);
@@ -152,7 +160,7 @@ public:
 	virtual void set_data(const Variant &p_data);
 	virtual Variant get_data() const;
 	virtual PhysicsServer3D::ShapeType get_type() const;
-	virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge = 0);
+	virtual btCollisionShape *internal_create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge = 0);
 
 private:
 	void setup(real_t p_height, real_t p_radius);
@@ -170,7 +178,7 @@ public:
 	virtual void set_data(const Variant &p_data);
 	virtual Variant get_data() const;
 	virtual PhysicsServer3D::ShapeType get_type() const;
-	virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_margin = 0);
+	virtual btCollisionShape *internal_create_bt_shape(const btVector3 &p_implicit_scale, real_t p_margin = 0);
 
 private:
 	void setup(real_t p_height, real_t p_radius);
@@ -186,7 +194,7 @@ public:
 	void get_vertices(Vector<Vector3> &out_vertices);
 	virtual Variant get_data() const;
 	virtual PhysicsServer3D::ShapeType get_type() const;
-	virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge = 0);
+	virtual btCollisionShape *internal_create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge = 0);
 
 private:
 	void setup(const Vector<Vector3> &p_vertices);
@@ -204,7 +212,7 @@ public:
 	virtual void set_data(const Variant &p_data);
 	virtual Variant get_data() const;
 	virtual PhysicsServer3D::ShapeType get_type() const;
-	virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge = 0);
+	virtual btCollisionShape *internal_create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge = 0);
 
 private:
 	void setup(Vector<Vector3> p_faces);
@@ -223,7 +231,7 @@ public:
 	virtual void set_data(const Variant &p_data);
 	virtual Variant get_data() const;
 	virtual PhysicsServer3D::ShapeType get_type() const;
-	virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge = 0);
+	virtual btCollisionShape *internal_create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge = 0);
 
 private:
 	void setup(Vector<real_t> &p_heights, int p_width, int p_depth, real_t p_min_height, real_t p_max_height);
@@ -239,7 +247,7 @@ public:
 	virtual void set_data(const Variant &p_data);
 	virtual Variant get_data() const;
 	virtual PhysicsServer3D::ShapeType get_type() const;
-	virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge = 0);
+	virtual btCollisionShape *internal_create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge = 0);
 
 private:
 	void setup(real_t p_length, bool p_slips_on_slope);

+ 4 - 2
modules/bullet/soft_body_bullet.cpp

@@ -41,7 +41,7 @@ SoftBodyBullet::SoftBodyBullet() :
 SoftBodyBullet::~SoftBodyBullet() {
 }
 
-void SoftBodyBullet::reload_body() {
+void SoftBodyBullet::do_reload_body() {
 	if (space) {
 		space->remove_soft_body(this);
 		space->add_soft_body(this);
@@ -51,13 +51,15 @@ void SoftBodyBullet::reload_body() {
 void SoftBodyBullet::set_space(SpaceBullet *p_space) {
 	if (space) {
 		isScratched = false;
+		space->unregister_collision_object(this);
 		space->remove_soft_body(this);
 	}
 
 	space = p_space;
 
 	if (space) {
-		space->add_soft_body(this);
+		space->register_collision_object(this);
+		reload_body();
 	}
 }
 

+ 1 - 1
modules/bullet/soft_body_bullet.h

@@ -87,7 +87,7 @@ public:
 	SoftBodyBullet();
 	~SoftBodyBullet();
 
-	virtual void reload_body();
+	virtual void do_reload_body();
 	virtual void set_space(SpaceBullet *p_space);
 
 	virtual void dispatch_callbacks() {}

+ 55 - 17
modules/bullet/space_bullet.cpp

@@ -127,7 +127,7 @@ int BulletPhysicsDirectSpaceState::intersect_shape(const RID &p_shape, const Tra
 
 	btCollisionShape *btShape = shape->create_bt_shape(p_xform.basis.get_scale_abs(), p_margin);
 	if (!btShape->isConvex()) {
-		bulletdelete(btShape);
+		shape->destroy_bt_shape(btShape);
 		ERR_PRINT("The shape is not a convex shape, then is not supported: shape type: " + itos(shape->get_type()));
 		return 0;
 	}
@@ -147,7 +147,7 @@ int BulletPhysicsDirectSpaceState::intersect_shape(const RID &p_shape, const Tra
 	btQuery.m_closestDistanceThreshold = 0;
 	space->dynamicsWorld->contactTest(&collision_object, btQuery);
 
-	bulletdelete(btConvex);
+	shape->destroy_bt_shape(btShape);
 
 	return btQuery.m_count;
 }
@@ -167,7 +167,7 @@ bool BulletPhysicsDirectSpaceState::cast_motion(const RID &p_shape, const Transf
 
 	btCollisionShape *btShape = shape->create_bt_shape(p_xform.basis.get_scale(), p_margin);
 	if (!btShape->isConvex()) {
-		bulletdelete(btShape);
+		shape->destroy_bt_shape(btShape);
 		ERR_PRINT("The shape is not a convex shape, then is not supported: shape type: " + itos(shape->get_type()));
 		return false;
 	}
@@ -206,7 +206,7 @@ bool BulletPhysicsDirectSpaceState::cast_motion(const RID &p_shape, const Transf
 		r_closest_unsafe = 1.0f;
 	}
 
-	bulletdelete(bt_convex_shape);
+	shape->destroy_bt_shape(btShape);
 	return true; // Mean success
 }
 
@@ -221,7 +221,7 @@ bool BulletPhysicsDirectSpaceState::collide_shape(RID p_shape, const Transform &
 
 	btCollisionShape *btShape = shape->create_bt_shape(p_shape_xform.basis.get_scale_abs(), p_margin);
 	if (!btShape->isConvex()) {
-		bulletdelete(btShape);
+		shape->destroy_bt_shape(btShape);
 		ERR_PRINT("The shape is not a convex shape, then is not supported: shape type: " + itos(shape->get_type()));
 		return false;
 	}
@@ -242,7 +242,7 @@ bool BulletPhysicsDirectSpaceState::collide_shape(RID p_shape, const Transform &
 	space->dynamicsWorld->contactTest(&collision_object, btQuery);
 
 	r_result_count = btQuery.m_count;
-	bulletdelete(btConvex);
+	shape->destroy_bt_shape(btShape);
 
 	return btQuery.m_count;
 }
@@ -253,7 +253,7 @@ bool BulletPhysicsDirectSpaceState::rest_info(RID p_shape, const Transform &p_sh
 
 	btCollisionShape *btShape = shape->create_bt_shape(p_shape_xform.basis.get_scale_abs(), p_margin);
 	if (!btShape->isConvex()) {
-		bulletdelete(btShape);
+		shape->destroy_bt_shape(btShape);
 		ERR_PRINT("The shape is not a convex shape, then is not supported: shape type: " + itos(shape->get_type()));
 		return false;
 	}
@@ -273,7 +273,7 @@ bool BulletPhysicsDirectSpaceState::rest_info(RID p_shape, const Transform &p_sh
 	btQuery.m_closestDistanceThreshold = 0;
 	space->dynamicsWorld->contactTest(&collision_object, btQuery);
 
-	bulletdelete(btConvex);
+	shape->destroy_bt_shape(btShape);
 
 	if (btQuery.m_collided) {
 		if (btCollisionObject::CO_RIGID_BODY == btQuery.m_rest_info_collision_object->getInternalType()) {
@@ -349,9 +349,11 @@ SpaceBullet::~SpaceBullet() {
 }
 
 void SpaceBullet::flush_queries() {
-	const btCollisionObjectArray &colObjArray = dynamicsWorld->getCollisionObjectArray();
-	for (int i = colObjArray.size() - 1; 0 <= i; --i) {
-		static_cast<CollisionObjectBullet *>(colObjArray[i]->getUserPointer())->dispatch_callbacks();
+	const int size = collision_objects.size();
+	CollisionObjectBullet **objects = collision_objects.ptrw();
+	for (int i = 0; i < size; i += 1) {
+		objects[i]->prepare_object_for_dispatch();
+		objects[i]->dispatch_callbacks();
 	}
 }
 
@@ -448,16 +450,30 @@ real_t SpaceBullet::get_param(PhysicsServer3D::SpaceParameter p_param) {
 }
 
 void SpaceBullet::add_area(AreaBullet *p_area) {
+#ifdef TOOLS_ENABLED
+	// This never happen, and there is no way for the user to trigger it.
+	// If in future a bug is introduced into this bullet integration and this
+	// function is called twice, the crash will notify the developer that will
+	// fix it even before do the eventual PR.
+	CRASH_COND(p_area->is_in_world);
+#endif
 	areas.push_back(p_area);
 	dynamicsWorld->addCollisionObject(p_area->get_bt_ghost(), p_area->get_collision_layer(), p_area->get_collision_mask());
+	p_area->is_in_world = true;
 }
 
 void SpaceBullet::remove_area(AreaBullet *p_area) {
-	areas.erase(p_area);
-	dynamicsWorld->removeCollisionObject(p_area->get_bt_ghost());
+	if (p_area->is_in_world) {
+		areas.erase(p_area);
+		dynamicsWorld->removeCollisionObject(p_area->get_bt_ghost());
+		p_area->is_in_world = false;
+	}
 }
 
 void SpaceBullet::reload_collision_filters(AreaBullet *p_area) {
+	if (p_area->is_in_world == false) {
+		return;
+	}
 	btGhostObject *ghost_object = p_area->get_bt_ghost();
 
 	btBroadphaseProxy *ghost_proxy = ghost_object->getBroadphaseHandle();
@@ -467,24 +483,46 @@ void SpaceBullet::reload_collision_filters(AreaBullet *p_area) {
 	dynamicsWorld->refreshBroadphaseProxy(ghost_object);
 }
 
+void SpaceBullet::register_collision_object(CollisionObjectBullet *p_object) {
+	collision_objects.push_back(p_object);
+}
+
+void SpaceBullet::unregister_collision_object(CollisionObjectBullet *p_object) {
+	collision_objects.erase(p_object);
+}
+
 void SpaceBullet::add_rigid_body(RigidBodyBullet *p_body) {
+#ifdef TOOLS_ENABLED
+	// This never happen, and there is no way for the user to trigger it.
+	// If in future a bug is introduced into this bullet integration and this
+	// function is called twice, the crash will notify the developer that will
+	// fix it even before do the eventual PR.
+	CRASH_COND(p_body->is_in_world);
+#endif
 	if (p_body->is_static()) {
 		dynamicsWorld->addCollisionObject(p_body->get_bt_rigid_body(), p_body->get_collision_layer(), p_body->get_collision_mask());
 	} else {
 		dynamicsWorld->addRigidBody(p_body->get_bt_rigid_body(), p_body->get_collision_layer(), p_body->get_collision_mask());
 		p_body->scratch_space_override_modificator();
 	}
+	p_body->is_in_world = true;
 }
 
 void SpaceBullet::remove_rigid_body(RigidBodyBullet *p_body) {
-	if (p_body->is_static()) {
-		dynamicsWorld->removeCollisionObject(p_body->get_bt_rigid_body());
-	} else {
-		dynamicsWorld->removeRigidBody(p_body->get_bt_rigid_body());
+	if (p_body->is_in_world) {
+		if (p_body->is_static()) {
+			dynamicsWorld->removeCollisionObject(p_body->get_bt_rigid_body());
+		} else {
+			dynamicsWorld->removeRigidBody(p_body->get_bt_rigid_body());
+		}
+		p_body->is_in_world = false;
 	}
 }
 
 void SpaceBullet::reload_collision_filters(RigidBodyBullet *p_body) {
+	if (p_body->is_in_world == false) {
+		return;
+	}
 	btRigidBody *rigid_body = p_body->get_bt_rigid_body();
 
 	btBroadphaseProxy *body_proxy = rigid_body->getBroadphaseProxy();

+ 4 - 0
modules/bullet/space_bullet.h

@@ -110,6 +110,7 @@ class SpaceBullet : public RIDBullet {
 	real_t linear_damp = 0.0;
 	real_t angular_damp = 0.0;
 
+	Vector<CollisionObjectBullet *> collision_objects;
 	Vector<AreaBullet *> areas;
 
 	Vector<Vector3> contactDebug;
@@ -150,6 +151,9 @@ public:
 	void remove_area(AreaBullet *p_area);
 	void reload_collision_filters(AreaBullet *p_area);
 
+	void register_collision_object(CollisionObjectBullet *p_object);
+	void unregister_collision_object(CollisionObjectBullet *p_object);
+
 	void add_rigid_body(RigidBodyBullet *p_body);
 	void remove_rigid_body(RigidBodyBullet *p_body);
 	void reload_collision_filters(RigidBodyBullet *p_body);