Merge pull request #39726 from AndreaCatania/add_body_impr_physics

Optimized physics object spawn time
This commit is contained in:
Rémi Verschelde 2020-07-07 12:15:09 +02:00 committed by GitHub
commit bd3a468fc2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 204 additions and 71 deletions

View file

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

View file

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

View file

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

View file

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

View file

@ -237,7 +237,7 @@ void RigidBodyBullet::KinematicUtilities::copyAllOwnerShapes() {
case PhysicsServer3D::SHAPE_CYLINDER: case PhysicsServer3D::SHAPE_CYLINDER:
case PhysicsServer3D::SHAPE_CONVEX_POLYGON: case PhysicsServer3D::SHAPE_CONVEX_POLYGON:
case PhysicsServer3D::SHAPE_RAY: { 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; } break;
default: default:
WARN_PRINT("This shape is not supported for kinematic collision."); 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 set_continuous_collision_detection(is_continuous_collision_detection_enabled()); // Reset
} }
void RigidBodyBullet::reload_body() { void RigidBodyBullet::do_reload_body() {
if (space) { if (space) {
space->remove_rigid_body(this); space->remove_rigid_body(this);
if (get_main_shape()) { if (get_main_shape()) {
@ -325,13 +325,15 @@ void RigidBodyBullet::set_space(SpaceBullet *p_space) {
assert_no_constraints(); assert_no_constraints();
// Remove this object form the physics world // Remove this object form the physics world
space->unregister_collision_object(this);
space->remove_rigid_body(this); space->remove_rigid_body(this);
} }
space = p_space; space = p_space;
if (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() { void RigidBodyBullet::do_reload_shapes() {
RigidCollisionObjectBullet::reload_shapes(); RigidCollisionObjectBullet::do_reload_shapes();
const btScalar invMass = btBody->getInvMass(); const btScalar invMass = btBody->getInvMass();
const btScalar mass = invMass == 0 ? 0 : 1 / invMass; const btScalar mass = invMass == 0 ? 0 : 1 / invMass;

View file

@ -236,7 +236,7 @@ public:
_FORCE_INLINE_ btRigidBody *get_bt_rigid_body() { return btBody; } _FORCE_INLINE_ btRigidBody *get_bt_rigid_body() { return btBody; }
virtual void main_shape_changed(); virtual void main_shape_changed();
virtual void reload_body(); virtual void do_reload_body();
virtual void set_space(SpaceBullet *p_space); virtual void set_space(SpaceBullet *p_space);
virtual void dispatch_callbacks(); virtual void dispatch_callbacks();
@ -315,7 +315,7 @@ public:
virtual void set_transform__bullet(const btTransform &p_global_transform); virtual void set_transform__bullet(const btTransform &p_global_transform);
virtual const btTransform &get_transform__bullet() const; 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_enter_area(AreaBullet *p_area);
virtual void on_exit_area(AreaBullet *p_area); virtual void on_exit_area(AreaBullet *p_area);

View file

@ -46,9 +46,15 @@
@author AndreaCatania @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) { btCollisionShape *ShapeBullet::create_bt_shape(const Vector3 &p_implicit_scale, real_t p_extra_edge) {
btVector3 s; btVector3 s;
@ -56,6 +62,22 @@ btCollisionShape *ShapeBullet::create_bt_shape(const Vector3 &p_implicit_scale,
return create_bt_shape(s, p_extra_edge); 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 { btCollisionShape *ShapeBullet::prepare(btCollisionShape *p_btShape) const {
p_btShape->setUserPointer(const_cast<ShapeBullet *>(this)); p_btShape->setUserPointer(const_cast<ShapeBullet *>(this));
p_btShape->setMargin(margin); p_btShape->setMargin(margin);
@ -63,10 +85,21 @@ btCollisionShape *ShapeBullet::prepare(btCollisionShape *p_btShape) const {
} }
void ShapeBullet::notifyShapeChanged() { 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()) { for (Map<ShapeOwnerBullet *, int>::Element *E = owners.front(); E; E = E->next()) {
ShapeOwnerBullet *owner = static_cast<ShapeOwnerBullet *>(E->key()); ShapeOwnerBullet *owner = static_cast<ShapeOwnerBullet *>(E->key());
owner->shape_changed(owner->find_shape(this)); 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) { void ShapeBullet::add_owner(ShapeOwnerBullet *p_owner) {
@ -186,7 +219,7 @@ void PlaneShapeBullet::setup(const Plane &p_plane) {
notifyShapeChanged(); 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; btVector3 btPlaneNormal;
G_TO_B(plane.normal, btPlaneNormal); G_TO_B(plane.normal, btPlaneNormal);
return prepare(PlaneShapeBullet::create_shape_plane(btPlaneNormal, plane.d)); return prepare(PlaneShapeBullet::create_shape_plane(btPlaneNormal, plane.d));
@ -214,7 +247,7 @@ void SphereShapeBullet::setup(real_t p_radius) {
notifyShapeChanged(); 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)); 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(); 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))); 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(); 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)); 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(); 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)); 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(); 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()) { if (!vertices.size()) {
// This is necessary since 0 vertices // This is necessary since 0 vertices
return prepare(ShapeBullet::create_shape_empty()); return prepare(ShapeBullet::create_shape_empty());
@ -431,7 +464,7 @@ void ConcavePolygonShapeBullet::setup(Vector<Vector3> p_faces) {
notifyShapeChanged(); 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); btCollisionShape *cs = ShapeBullet::create_shape_concave(meshShape);
if (!cs) { if (!cs) {
// This is necessary since if 0 faces the creation of concave return null // 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(); 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)); btCollisionShape *cs(ShapeBullet::create_shape_height_field(heights, width, depth, min_height, max_height));
cs->setLocalScaling(p_implicit_scale); cs->setLocalScaling(p_implicit_scale);
prepare(cs); prepare(cs);
@ -588,6 +621,6 @@ void RayShapeBullet::setup(real_t p_length, bool p_slips_on_slope) {
notifyShapeChanged(); 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)); return prepare(ShapeBullet::create_shape_ray(length * p_implicit_scale[1] + p_extra_edge, slips_on_slope));
} }

View file

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

View file

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

View file

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

View file

@ -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); btCollisionShape *btShape = shape->create_bt_shape(p_xform.basis.get_scale_abs(), p_margin);
if (!btShape->isConvex()) { 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())); ERR_PRINT("The shape is not a convex shape, then is not supported: shape type: " + itos(shape->get_type()));
return 0; return 0;
} }
@ -147,7 +147,7 @@ int BulletPhysicsDirectSpaceState::intersect_shape(const RID &p_shape, const Tra
btQuery.m_closestDistanceThreshold = 0; btQuery.m_closestDistanceThreshold = 0;
space->dynamicsWorld->contactTest(&collision_object, btQuery); space->dynamicsWorld->contactTest(&collision_object, btQuery);
bulletdelete(btConvex); shape->destroy_bt_shape(btShape);
return btQuery.m_count; 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); btCollisionShape *btShape = shape->create_bt_shape(p_xform.basis.get_scale(), p_margin);
if (!btShape->isConvex()) { 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())); ERR_PRINT("The shape is not a convex shape, then is not supported: shape type: " + itos(shape->get_type()));
return false; return false;
} }
@ -206,7 +206,7 @@ bool BulletPhysicsDirectSpaceState::cast_motion(const RID &p_shape, const Transf
r_closest_unsafe = 1.0f; r_closest_unsafe = 1.0f;
} }
bulletdelete(bt_convex_shape); shape->destroy_bt_shape(btShape);
return true; // Mean success 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); btCollisionShape *btShape = shape->create_bt_shape(p_shape_xform.basis.get_scale_abs(), p_margin);
if (!btShape->isConvex()) { 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())); ERR_PRINT("The shape is not a convex shape, then is not supported: shape type: " + itos(shape->get_type()));
return false; return false;
} }
@ -242,7 +242,7 @@ bool BulletPhysicsDirectSpaceState::collide_shape(RID p_shape, const Transform &
space->dynamicsWorld->contactTest(&collision_object, btQuery); space->dynamicsWorld->contactTest(&collision_object, btQuery);
r_result_count = btQuery.m_count; r_result_count = btQuery.m_count;
bulletdelete(btConvex); shape->destroy_bt_shape(btShape);
return btQuery.m_count; 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); btCollisionShape *btShape = shape->create_bt_shape(p_shape_xform.basis.get_scale_abs(), p_margin);
if (!btShape->isConvex()) { 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())); ERR_PRINT("The shape is not a convex shape, then is not supported: shape type: " + itos(shape->get_type()));
return false; return false;
} }
@ -273,7 +273,7 @@ bool BulletPhysicsDirectSpaceState::rest_info(RID p_shape, const Transform &p_sh
btQuery.m_closestDistanceThreshold = 0; btQuery.m_closestDistanceThreshold = 0;
space->dynamicsWorld->contactTest(&collision_object, btQuery); space->dynamicsWorld->contactTest(&collision_object, btQuery);
bulletdelete(btConvex); shape->destroy_bt_shape(btShape);
if (btQuery.m_collided) { if (btQuery.m_collided) {
if (btCollisionObject::CO_RIGID_BODY == btQuery.m_rest_info_collision_object->getInternalType()) { if (btCollisionObject::CO_RIGID_BODY == btQuery.m_rest_info_collision_object->getInternalType()) {
@ -349,9 +349,11 @@ SpaceBullet::~SpaceBullet() {
} }
void SpaceBullet::flush_queries() { void SpaceBullet::flush_queries() {
const btCollisionObjectArray &colObjArray = dynamicsWorld->getCollisionObjectArray(); const int size = collision_objects.size();
for (int i = colObjArray.size() - 1; 0 <= i; --i) { CollisionObjectBullet **objects = collision_objects.ptrw();
static_cast<CollisionObjectBullet *>(colObjArray[i]->getUserPointer())->dispatch_callbacks(); 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) { 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); areas.push_back(p_area);
dynamicsWorld->addCollisionObject(p_area->get_bt_ghost(), p_area->get_collision_layer(), p_area->get_collision_mask()); 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) { void SpaceBullet::remove_area(AreaBullet *p_area) {
areas.erase(p_area); if (p_area->is_in_world) {
dynamicsWorld->removeCollisionObject(p_area->get_bt_ghost()); 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) { void SpaceBullet::reload_collision_filters(AreaBullet *p_area) {
if (p_area->is_in_world == false) {
return;
}
btGhostObject *ghost_object = p_area->get_bt_ghost(); btGhostObject *ghost_object = p_area->get_bt_ghost();
btBroadphaseProxy *ghost_proxy = ghost_object->getBroadphaseHandle(); btBroadphaseProxy *ghost_proxy = ghost_object->getBroadphaseHandle();
@ -467,24 +483,46 @@ void SpaceBullet::reload_collision_filters(AreaBullet *p_area) {
dynamicsWorld->refreshBroadphaseProxy(ghost_object); 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) { 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()) { if (p_body->is_static()) {
dynamicsWorld->addCollisionObject(p_body->get_bt_rigid_body(), p_body->get_collision_layer(), p_body->get_collision_mask()); dynamicsWorld->addCollisionObject(p_body->get_bt_rigid_body(), p_body->get_collision_layer(), p_body->get_collision_mask());
} else { } else {
dynamicsWorld->addRigidBody(p_body->get_bt_rigid_body(), p_body->get_collision_layer(), p_body->get_collision_mask()); 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->scratch_space_override_modificator();
} }
p_body->is_in_world = true;
} }
void SpaceBullet::remove_rigid_body(RigidBodyBullet *p_body) { void SpaceBullet::remove_rigid_body(RigidBodyBullet *p_body) {
if (p_body->is_static()) { if (p_body->is_in_world) {
dynamicsWorld->removeCollisionObject(p_body->get_bt_rigid_body()); if (p_body->is_static()) {
} else { dynamicsWorld->removeCollisionObject(p_body->get_bt_rigid_body());
dynamicsWorld->removeRigidBody(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) { 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(); btRigidBody *rigid_body = p_body->get_bt_rigid_body();
btBroadphaseProxy *body_proxy = rigid_body->getBroadphaseProxy(); btBroadphaseProxy *body_proxy = rigid_body->getBroadphaseProxy();

View file

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