diff options
Diffstat (limited to 'modules/bullet')
34 files changed, 951 insertions, 526 deletions
diff --git a/modules/bullet/SCsub b/modules/bullet/SCsub index d8d0b930a5..11ce18449b 100644 --- a/modules/bullet/SCsub +++ b/modules/bullet/SCsub @@ -68,11 +68,13 @@ if env['builtin_bullet']: , "BulletCollision/CollisionShapes/btEmptyShape.cpp" , "BulletCollision/CollisionShapes/btHeightfieldTerrainShape.cpp" , "BulletCollision/CollisionShapes/btMinkowskiSumShape.cpp" + , "BulletCollision/CollisionShapes/btMiniSDF.cpp" , "BulletCollision/CollisionShapes/btMultimaterialTriangleMeshShape.cpp" , "BulletCollision/CollisionShapes/btMultiSphereShape.cpp" , "BulletCollision/CollisionShapes/btOptimizedBvh.cpp" , "BulletCollision/CollisionShapes/btPolyhedralConvexShape.cpp" , "BulletCollision/CollisionShapes/btScaledBvhTriangleMeshShape.cpp" + , "BulletCollision/CollisionShapes/btSdfCollisionShape.cpp" , "BulletCollision/CollisionShapes/btShapeHull.cpp" , "BulletCollision/CollisionShapes/btSphereShape.cpp" , "BulletCollision/CollisionShapes/btStaticPlaneShape.cpp" @@ -184,8 +186,12 @@ if env['builtin_bullet']: thirdparty_sources = [thirdparty_dir + file for file in bullet2_src] - env_bullet.add_source_files(env.modules_sources, thirdparty_sources) env_bullet.Append(CPPPATH=[thirdparty_dir]) + env_thirdparty = env_bullet.Clone() + env_thirdparty.disable_warnings() + env_thirdparty.add_source_files(env.modules_sources, thirdparty_sources) + + # Godot source files env_bullet.add_source_files(env.modules_sources, "*.cpp") diff --git a/modules/bullet/area_bullet.cpp b/modules/bullet/area_bullet.cpp index b004641838..a0486443c2 100644 --- a/modules/bullet/area_bullet.cpp +++ b/modules/bullet/area_bullet.cpp @@ -30,6 +30,7 @@ #include "area_bullet.h" +#include "bullet_physics_server.h" #include "bullet_types_converter.h" #include "bullet_utilities.h" #include "collision_object_bullet.h" @@ -45,7 +46,6 @@ AreaBullet::AreaBullet() : RigidCollisionObjectBullet(CollisionObjectBullet::TYPE_AREA), monitorable(true), - isScratched(false), spOv_mode(PhysicsServer::AREA_SPACE_OVERRIDE_DISABLED), spOv_gravityPoint(false), spOv_gravityPointDistanceScale(0), @@ -54,10 +54,11 @@ AreaBullet::AreaBullet() : spOv_gravityMag(10), spOv_linearDump(0.1), spOv_angularDump(1), - spOv_priority(0) { + spOv_priority(0), + isScratched(false) { btGhost = bulletnew(btGhostObject); - btGhost->setCollisionShape(compoundShape); + reload_shapes(); setupBulletCollisionObject(btGhost); /// Collision objects with a callback still have collision response with dynamic rigid bodies. /// In order to use collision objects as trigger, you have to disable the collision response. @@ -93,6 +94,9 @@ void AreaBullet::dispatch_callbacks() { otherObj.object->on_exit_area(this); overlappingObjects.remove(i); // Remove after callback break; + case OVERLAP_STATE_DIRTY: + case OVERLAP_STATE_INSIDE: + break; } } } @@ -162,6 +166,11 @@ bool AreaBullet::is_monitoring() const { return get_godot_object_flags() & GOF_IS_MONITORING_AREA; } +void AreaBullet::main_shape_changed() { + CRASH_COND(!get_main_shape()) + btGhost->setCollisionShape(get_main_shape()); +} + void AreaBullet::reload_body() { if (space) { space->remove_area(this); @@ -236,7 +245,7 @@ void AreaBullet::set_param(PhysicsServer::AreaParameter p_param, const Variant & set_spOv_gravityPointAttenuation(p_value); break; default: - print_line("The Bullet areas doesn't suppot this param: " + itos(p_param)); + WARN_PRINTS("Area doesn't support this parameter in the Bullet backend: " + itos(p_param)); } } @@ -259,7 +268,7 @@ Variant AreaBullet::get_param(PhysicsServer::AreaParameter p_param) const { case PhysicsServer::AREA_PARAM_GRAVITY_POINT_ATTENUATION: return spOv_gravityPointAttenuation; default: - print_line("The Bullet areas doesn't suppot this param: " + itos(p_param)); + WARN_PRINTS("Area doesn't support this parameter in the Bullet backend: " + itos(p_param)); return Variant(); } } diff --git a/modules/bullet/area_bullet.h b/modules/bullet/area_bullet.h index b2046c684e..1c5962cfe3 100644 --- a/modules/bullet/area_bullet.h +++ b/modules/bullet/area_bullet.h @@ -142,6 +142,7 @@ public: _FORCE_INLINE_ void set_spOv_priority(int p_priority) { spOv_priority = p_priority; } _FORCE_INLINE_ int get_spOv_priority() { return spOv_priority; } + virtual void main_shape_changed(); virtual void reload_body(); virtual void set_space(SpaceBullet *p_space); @@ -156,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/btRayShape.cpp b/modules/bullet/btRayShape.cpp index 8707096038..6cc63d79ce 100644 --- a/modules/bullet/btRayShape.cpp +++ b/modules/bullet/btRayShape.cpp @@ -30,7 +30,7 @@ #include "btRayShape.h" -#include "math/math_funcs.h" +#include "core/math/math_funcs.h" #include <LinearMath/btAabbUtil2.h> diff --git a/modules/bullet/bullet_physics_server.cpp b/modules/bullet/bullet_physics_server.cpp index 9263a9ba6d..7bc731e75e 100644 --- a/modules/bullet/bullet_physics_server.cpp +++ b/modules/bullet/bullet_physics_server.cpp @@ -31,8 +31,8 @@ #include "bullet_physics_server.h" #include "bullet_utilities.h" -#include "class_db.h" #include "cone_twist_joint_bullet.h" +#include "core/class_db.h" #include "core/error_macros.h" #include "core/ustring.h" #include "generic_6dof_joint_bullet.h" @@ -74,12 +74,6 @@ body->get_space()->add_constraint(joint, joint->is_disabled_collisions_between_bodies()); // <--------------- Joint creation asserts -btEmptyShape *BulletPhysicsServer::emptyShape(ShapeBullet::create_shape_empty()); - -btEmptyShape *BulletPhysicsServer::get_empty_shape() { - return emptyShape; -} - void BulletPhysicsServer::_bind_methods() { //ClassDB::bind_method(D_METHOD("DoTest"), &BulletPhysicsServer::DoTest); } @@ -89,9 +83,7 @@ BulletPhysicsServer::BulletPhysicsServer() : active(true), active_spaces_count(0) {} -BulletPhysicsServer::~BulletPhysicsServer() { - bulletdelete(emptyShape); -} +BulletPhysicsServer::~BulletPhysicsServer() {} RID BulletPhysicsServer::shape_create(ShapeType p_shape) { ShapeBullet *shape = NULL; @@ -163,6 +155,18 @@ Variant BulletPhysicsServer::shape_get_data(RID p_shape) const { return shape->get_data(); } +void BulletPhysicsServer::shape_set_margin(RID p_shape, real_t p_margin) { + ShapeBullet *shape = shape_owner.get(p_shape); + ERR_FAIL_COND(!shape); + shape->set_margin(p_margin); +} + +real_t BulletPhysicsServer::shape_get_margin(RID p_shape) const { + ShapeBullet *shape = shape_owner.get(p_shape); + ERR_FAIL_COND_V(!shape, 0.0); + return shape->get_margin(); +} + real_t BulletPhysicsServer::shape_get_custom_solver_bias(RID p_shape) const { //WARN_PRINT("Bias not supported by Bullet physics engine"); return 0.; @@ -326,7 +330,7 @@ Transform BulletPhysicsServer::area_get_shape_transform(RID p_area, int p_shape_ void BulletPhysicsServer::area_remove_shape(RID p_area, int p_shape_idx) { AreaBullet *area = area_owner.get(p_area); ERR_FAIL_COND(!area); - return area->remove_shape(p_shape_idx); + return area->remove_shape_full(p_shape_idx); } void BulletPhysicsServer::area_clear_shapes(RID p_area) { @@ -334,7 +338,7 @@ void BulletPhysicsServer::area_clear_shapes(RID p_area) { ERR_FAIL_COND(!area); for (int i = area->get_shape_count(); 0 < i; --i) - area->remove_shape(0); + area->remove_shape_full(0); } void BulletPhysicsServer::area_set_shape_disabled(RID p_area, int p_shape_idx, bool p_disabled) { @@ -555,7 +559,7 @@ void BulletPhysicsServer::body_remove_shape(RID p_body, int p_shape_idx) { RigidBodyBullet *body = rigid_body_owner.get(p_body); ERR_FAIL_COND(!body); - body->remove_shape(p_shape_idx); + body->remove_shape_full(p_shape_idx); } void BulletPhysicsServer::body_clear_shapes(RID p_body) { @@ -644,20 +648,6 @@ float BulletPhysicsServer::body_get_param(RID p_body, BodyParameter p_param) con return body->get_param(p_param); } -void BulletPhysicsServer::body_set_combine_mode(RID p_body, BodyParameter p_param, CombineMode p_mode) { - RigidBodyBullet *body = rigid_body_owner.get(p_body); - ERR_FAIL_COND(!body); - - body->set_combine_mode(p_param, p_mode); -} - -PhysicsServer::CombineMode BulletPhysicsServer::body_get_combine_mode(RID p_body, BodyParameter p_param) const { - RigidBodyBullet *body = rigid_body_owner.get(p_body); - ERR_FAIL_COND_V(!body, COMBINE_MODE_INHERIT); - - return body->get_combine_mode(p_param); -} - void BulletPhysicsServer::body_set_kinematic_safe_margin(RID p_body, real_t p_margin) { RigidBodyBullet *body = rigid_body_owner.get(p_body); ERR_FAIL_COND(!body); @@ -875,12 +865,20 @@ PhysicsDirectBodyState *BulletPhysicsServer::body_get_direct_state(RID p_body) { return BulletPhysicsDirectBodyState::get_singleton(body); } -bool BulletPhysicsServer::body_test_motion(RID p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, MotionResult *r_result) { +bool BulletPhysicsServer::body_test_motion(RID p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, MotionResult *r_result, bool p_exclude_raycast_shapes) { RigidBodyBullet *body = rigid_body_owner.get(p_body); ERR_FAIL_COND_V(!body, false); ERR_FAIL_COND_V(!body->get_space(), false); - return body->get_space()->test_body_motion(body, p_from, p_motion, p_infinite_inertia, r_result); + return body->get_space()->test_body_motion(body, p_from, p_motion, p_infinite_inertia, r_result, p_exclude_raycast_shapes); +} + +int BulletPhysicsServer::body_test_ray_separation(RID p_body, const Transform &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, SeparationResult *r_results, int p_result_max, float p_margin) { + RigidBodyBullet *body = rigid_body_owner.get(p_body); + ERR_FAIL_COND_V(!body, 0); + ERR_FAIL_COND_V(!body->get_space(), 0); + + return body->get_space()->test_ray_separation(body, p_transform, p_infinite_inertia, r_recover_motion, r_results, p_result_max, p_margin); } RID BulletPhysicsServer::soft_body_create(bool p_init_sleeping) { @@ -995,11 +993,13 @@ void BulletPhysicsServer::soft_body_get_collision_exceptions(RID p_body, List<RI } void BulletPhysicsServer::soft_body_set_state(RID p_body, BodyState p_state, const Variant &p_variant) { - print_line("TODO MUST BE IMPLEMENTED"); + // FIXME: Must be implemented. + WARN_PRINT("soft_body_state is not implemented yet in Bullet backend."); } Variant BulletPhysicsServer::soft_body_get_state(RID p_body, BodyState p_state) const { - print_line("TODO MUST BE IMPLEMENTED"); + // FIXME: Must be implemented. + WARN_PRINT("soft_body_state is not implemented yet in Bullet backend."); return Variant(); } @@ -1433,7 +1433,7 @@ RID BulletPhysicsServer::joint_create_generic_6dof(RID p_body_A, const Transform ERR_FAIL_COND_V(body_A == body_B, RID()); - JointBullet *joint = bulletnew(Generic6DOFJointBullet(body_A, body_B, p_local_frame_A, p_local_frame_B, true)); + JointBullet *joint = bulletnew(Generic6DOFJointBullet(body_A, body_B, p_local_frame_A, p_local_frame_B)); AddJointToSpace(body_A, joint); CreateThenReturnRID(joint_owner, joint); @@ -1471,6 +1471,22 @@ bool BulletPhysicsServer::generic_6dof_joint_get_flag(RID p_joint, Vector3::Axis return generic_6dof_joint->get_flag(p_axis, p_flag); } +void BulletPhysicsServer::generic_6dof_joint_set_precision(RID p_joint, int p_precision) { + JointBullet *joint = joint_owner.get(p_joint); + ERR_FAIL_COND(!joint); + ERR_FAIL_COND(joint->get_type() != JOINT_6DOF); + Generic6DOFJointBullet *generic_6dof_joint = static_cast<Generic6DOFJointBullet *>(joint); + generic_6dof_joint->set_precision(p_precision); +} + +int BulletPhysicsServer::generic_6dof_joint_get_precision(RID p_joint) { + JointBullet *joint = joint_owner.get(p_joint); + ERR_FAIL_COND_V(!joint, 0); + ERR_FAIL_COND_V(joint->get_type() != JOINT_6DOF, 0); + Generic6DOFJointBullet *generic_6dof_joint = static_cast<Generic6DOFJointBullet *>(joint); + return generic_6dof_joint->get_precision(); +} + void BulletPhysicsServer::free(RID p_rid) { if (shape_owner.owns(p_rid)) { @@ -1478,7 +1494,7 @@ void BulletPhysicsServer::free(RID p_rid) { // Notify the shape is configured for (Map<ShapeOwnerBullet *, int>::Element *element = shape->get_owners().front(); element; element = element->next()) { - static_cast<ShapeOwnerBullet *>(element->key())->remove_shape(shape); + static_cast<ShapeOwnerBullet *>(element->key())->remove_shape_full(shape); } shape_owner.free(p_rid); @@ -1489,7 +1505,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 +1525,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/bullet_physics_server.h b/modules/bullet/bullet_physics_server.h index 2c5b7e51cf..0cea3f5ba6 100644 --- a/modules/bullet/bullet_physics_server.h +++ b/modules/bullet/bullet_physics_server.h @@ -32,8 +32,8 @@ #define BULLET_PHYSICS_SERVER_H #include "area_bullet.h" +#include "core/rid.h" #include "joint_bullet.h" -#include "rid.h" #include "rigid_body_bullet.h" #include "servers/physics_server.h" #include "shape_bullet.h" @@ -60,13 +60,6 @@ class BulletPhysicsServer : public PhysicsServer { mutable RID_Owner<SoftBodyBullet> soft_body_owner; mutable RID_Owner<JointBullet> joint_owner; -private: - /// This is used when a collision shape is not active, so the bullet compound shapes index are always sync with godot index - static btEmptyShape *emptyShape; - -public: - static btEmptyShape *get_empty_shape(); - protected: static void _bind_methods(); @@ -99,6 +92,9 @@ public: virtual ShapeType shape_get_type(RID p_shape) const; virtual Variant shape_get_data(RID p_shape) const; + virtual void shape_set_margin(RID p_shape, real_t p_margin); + virtual real_t shape_get_margin(RID p_shape) const; + /// Not supported virtual void shape_set_custom_solver_bias(RID p_shape, real_t p_bias); /// Not supported @@ -213,9 +209,6 @@ public: virtual void body_set_param(RID p_body, BodyParameter p_param, float p_value); virtual float body_get_param(RID p_body, BodyParameter p_param) const; - virtual void body_set_combine_mode(RID p_body, BodyParameter p_param, CombineMode p_mode); - virtual CombineMode body_get_combine_mode(RID p_body, BodyParameter p_param) const; - virtual void body_set_kinematic_safe_margin(RID p_body, real_t p_margin); virtual real_t body_get_kinematic_safe_margin(RID p_body) const; @@ -261,7 +254,8 @@ public: // this function only works on physics process, errors and returns null otherwise virtual PhysicsDirectBodyState *body_get_direct_state(RID p_body); - virtual bool body_test_motion(RID p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, MotionResult *r_result = NULL); + virtual bool body_test_motion(RID p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, MotionResult *r_result = NULL, bool p_exclude_raycast_shapes = true); + virtual int body_test_ray_separation(RID p_body, const Transform &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, SeparationResult *r_results, int p_result_max, float p_margin = 0.001); /* SOFT BODY API */ @@ -381,6 +375,9 @@ public: virtual void generic_6dof_joint_set_flag(RID p_joint, Vector3::Axis p_axis, G6DOFJointAxisFlag p_flag, bool p_enable); virtual bool generic_6dof_joint_get_flag(RID p_joint, Vector3::Axis p_axis, G6DOFJointAxisFlag p_flag); + virtual void generic_6dof_joint_set_precision(RID p_joint, int precision); + virtual int generic_6dof_joint_get_precision(RID p_joint); + /* MISC */ virtual void free(RID p_rid); @@ -403,6 +400,8 @@ public: virtual void flush_queries(); virtual void finish(); + virtual bool is_flushing_queries() const { return false; } + virtual int get_process_info(ProcessInfo p_info); CollisionObjectBullet *get_collisin_object(RID p_object) const; diff --git a/modules/bullet/bullet_types_converter.cpp b/modules/bullet/bullet_types_converter.cpp index a0fe598227..f9b7126173 100644 --- a/modules/bullet/bullet_types_converter.cpp +++ b/modules/bullet/bullet_types_converter.cpp @@ -28,8 +28,6 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#pragma once - #include "bullet_types_converter.h" /** diff --git a/modules/bullet/bullet_utilities.h b/modules/bullet/bullet_utilities.h index 2841dfbe69..553c1d0384 100644 --- a/modules/bullet/bullet_utilities.h +++ b/modules/bullet/bullet_utilities.h @@ -35,13 +35,12 @@ @author AndreaCatania */ -#pragma once - #define bulletnew(cl) \ new cl #define bulletdelete(cl) \ - delete cl; \ - cl = NULL; - + { \ + delete cl; \ + cl = NULL; \ + } #endif diff --git a/modules/bullet/collision_object_bullet.cpp b/modules/bullet/collision_object_bullet.cpp index 271cdb0223..441fa7c8af 100644 --- a/modules/bullet/collision_object_bullet.cpp +++ b/modules/bullet/collision_object_bullet.cpp @@ -43,8 +43,7 @@ @author AndreaCatania */ -#define enableDynamicAabbTree true -#define initialChildCapacity 1 +#define enableDynamicAabbTree false CollisionObjectBullet::ShapeWrapper::~ShapeWrapper() {} @@ -53,19 +52,30 @@ void CollisionObjectBullet::ShapeWrapper::set_transform(const Transform &p_trans G_TO_B(p_transform, transform); UNSCALE_BT_BASIS(transform); } + void CollisionObjectBullet::ShapeWrapper::set_transform(const btTransform &p_transform) { transform = p_transform; } +void CollisionObjectBullet::ShapeWrapper::claim_bt_shape(const btVector3 &body_scale) { + if (!bt_shape) { + if (active) + bt_shape = shape->create_bt_shape(scale * body_scale); + else + bt_shape = ShapeBullet::create_shape_empty(); + } +} + CollisionObjectBullet::CollisionObjectBullet(Type p_type) : RIDBullet(), - space(NULL), type(p_type), collisionsEnabled(true), m_isStatic(false), bt_collision_object(NULL), body_scale(1., 1., 1.), - force_shape_reset(false) {} + force_shape_reset(false), + space(NULL), + isTransformChanged(false) {} CollisionObjectBullet::~CollisionObjectBullet() { // Remove all overlapping, notify is not required since godot take care of it @@ -83,7 +93,7 @@ bool equal(real_t first, real_t second) { void CollisionObjectBullet::set_body_scale(const Vector3 &p_new_scale) { if (!equal(p_new_scale[0], body_scale[0]) || !equal(p_new_scale[1], body_scale[1]) || !equal(p_new_scale[2], body_scale[2])) { body_scale = p_new_scale; - on_body_scale_changed(); + body_scale_changed(); } } @@ -93,7 +103,7 @@ btVector3 CollisionObjectBullet::get_bt_body_scale() const { return s; } -void CollisionObjectBullet::on_body_scale_changed() { +void CollisionObjectBullet::body_scale_changed() { force_shape_reset = true; } @@ -107,6 +117,7 @@ void CollisionObjectBullet::setupBulletCollisionObject(btCollisionObject *p_coll bt_collision_object->setUserIndex(type); // Force the enabling of collision and avoid problems set_collision_enabled(collisionsEnabled); + p_collisionObject->setCollisionFlags(p_collisionObject->getCollisionFlags() | btCollisionObject::CF_CUSTOM_MATERIAL_CALLBACK); } void CollisionObjectBullet::add_collision_exception(const CollisionObjectBullet *p_ignoreCollisionObject) { @@ -178,48 +189,33 @@ 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), - compoundShape(bulletnew(btCompoundShape(enableDynamicAabbTree, initialChildCapacity))) { + mainShape(NULL) { } RigidCollisionObjectBullet::~RigidCollisionObjectBullet() { - remove_all_shapes(true); - bt_collision_object->setCollisionShape(NULL); - bulletdelete(compoundShape); -} - -/* Not used -void RigidCollisionObjectBullet::_internal_replaceShape(btCollisionShape *p_old_shape, btCollisionShape *p_new_shape) { - bool at_least_one_was_changed = false; - btTransform old_transf; - // Inverse because I need remove the shapes - // Fetch all shapes to be sure to remove all shapes - for (int i = compoundShape->getNumChildShapes() - 1; 0 <= i; --i) { - if (compoundShape->getChildShape(i) == p_old_shape) { - - old_transf = compoundShape->getChildTransform(i); - compoundShape->removeChildShapeByIndex(i); - compoundShape->addChildShape(old_transf, p_new_shape); - at_least_one_was_changed = true; - } + remove_all_shapes(true, true); + if (mainShape && mainShape->isCompound()) { + bulletdelete(mainShape); } - - if (at_least_one_was_changed) { - on_shapes_changed(); - } -}*/ +} void RigidCollisionObjectBullet::add_shape(ShapeBullet *p_shape, const Transform &p_transform) { shapes.push_back(ShapeWrapper(p_shape, p_transform, true)); p_shape->add_owner(this); - on_shapes_changed(); + reload_shapes(); } void RigidCollisionObjectBullet::set_shape(int p_index, ShapeBullet *p_shape) { @@ -227,17 +223,31 @@ void RigidCollisionObjectBullet::set_shape(int p_index, ShapeBullet *p_shape) { shp.shape->remove_owner(this); p_shape->add_owner(this); shp.shape = p_shape; - on_shapes_changed(); + reload_shapes(); } -void RigidCollisionObjectBullet::set_shape_transform(int p_index, const Transform &p_transform) { - ERR_FAIL_INDEX(p_index, get_shape_count()); +int RigidCollisionObjectBullet::get_shape_count() const { + return shapes.size(); +} - shapes.write[p_index].set_transform(p_transform); - on_shape_changed(shapes.write[p_index].shape); +ShapeBullet *RigidCollisionObjectBullet::get_shape(int p_index) const { + return shapes[p_index].shape; +} + +btCollisionShape *RigidCollisionObjectBullet::get_bt_shape(int p_index) const { + return shapes[p_index].bt_shape; +} + +int RigidCollisionObjectBullet::find_shape(ShapeBullet *p_shape) const { + const int size = shapes.size(); + for (int i = 0; i < size; ++i) { + if (shapes[i].shape == p_shape) + return i; + } + return -1; } -void RigidCollisionObjectBullet::remove_shape(ShapeBullet *p_shape) { +void RigidCollisionObjectBullet::remove_shape_full(ShapeBullet *p_shape) { // Remove the shape, all the times it appears // Reverse order required for delete. for (int i = shapes.size() - 1; 0 <= i; --i) { @@ -246,35 +256,36 @@ void RigidCollisionObjectBullet::remove_shape(ShapeBullet *p_shape) { shapes.remove(i); } } - on_shapes_changed(); + reload_shapes(); } -void RigidCollisionObjectBullet::remove_shape(int p_index) { +void RigidCollisionObjectBullet::remove_shape_full(int p_index) { ERR_FAIL_INDEX(p_index, get_shape_count()); internal_shape_destroy(p_index); shapes.remove(p_index); - on_shapes_changed(); + 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(); - on_shapes_changed(); + if (!p_force_not_reload) + reload_shapes(); } -int RigidCollisionObjectBullet::get_shape_count() const { - return shapes.size(); -} +void RigidCollisionObjectBullet::set_shape_transform(int p_index, const Transform &p_transform) { + ERR_FAIL_INDEX(p_index, get_shape_count()); -ShapeBullet *RigidCollisionObjectBullet::get_shape(int p_index) const { - return shapes[p_index].shape; + shapes.write[p_index].set_transform(p_transform); + // Note, enableDynamicAabbTree is false because on transform change compound is destroyed + reload_shapes(); } -btCollisionShape *RigidCollisionObjectBullet::get_bt_shape(int p_index) const { - return shapes[p_index].bt_shape; +const btTransform &RigidCollisionObjectBullet::get_bt_shape_transform(int p_index) const { + return shapes[p_index].transform; } Transform RigidCollisionObjectBullet::get_shape_transform(int p_index) const { @@ -283,72 +294,84 @@ Transform RigidCollisionObjectBullet::get_shape_transform(int p_index) const { return trs; } -void RigidCollisionObjectBullet::on_shape_changed(const ShapeBullet *const p_shape) { - const int size = shapes.size(); - for (int i = 0; i < size; ++i) { - if (shapes[i].shape == p_shape) { - bulletdelete(shapes.write[i].bt_shape); - } +void RigidCollisionObjectBullet::set_shape_disabled(int p_index, bool p_disabled) { + shapes.write[p_index].active = !p_disabled; + shape_changed(p_index); +} + +bool RigidCollisionObjectBullet::is_shape_disabled(int p_index) { + return !shapes[p_index].active; +} + +void RigidCollisionObjectBullet::shape_changed(int p_shape_index) { + ShapeWrapper &shp = shapes.write[p_shape_index]; + if (shp.bt_shape == mainShape) { + mainShape = NULL; } - on_shapes_changed(); + bulletdelete(shp.bt_shape); + reload_shapes(); } -void RigidCollisionObjectBullet::on_shapes_changed() { - int i; +void RigidCollisionObjectBullet::reload_shapes() { - // Remove all shapes, reverse order for performance reason (Array resize) - for (i = compoundShape->getNumChildShapes() - 1; 0 <= i; --i) { - compoundShape->removeChildShapeByIndex(i); + if (mainShape && mainShape->isCompound()) { + // Destroy compound + bulletdelete(mainShape); } + mainShape = NULL; + ShapeWrapper *shpWrapper; - const int shapes_size = shapes.size(); + const int shape_count = shapes.size(); // Reset shape if required if (force_shape_reset) { - for (i = 0; i < shapes_size; ++i) { + for (int i(0); i < shape_count; ++i) { shpWrapper = &shapes.write[i]; bulletdelete(shpWrapper->bt_shape); } force_shape_reset = false; } - // Insert all shapes - btVector3 body_scale(get_bt_body_scale()); - for (i = 0; i < shapes_size; ++i) { - shpWrapper = &shapes.write[i]; - if (shpWrapper->active) { - if (!shpWrapper->bt_shape) { - shpWrapper->bt_shape = shpWrapper->shape->create_bt_shape(shpWrapper->scale * body_scale); - } - - btTransform scaled_shape_transform(shpWrapper->transform); - scaled_shape_transform.getOrigin() *= body_scale; - compoundShape->addChildShape(scaled_shape_transform, shpWrapper->bt_shape); - } else { - compoundShape->addChildShape(btTransform(), BulletPhysicsServer::get_empty_shape()); + const btVector3 body_scale(get_bt_body_scale()); + + // Try to optimize by not using compound + if (1 == shape_count) { + shpWrapper = &shapes.write[0]; + if (shpWrapper->transform.getOrigin().isZero() && shpWrapper->transform.getBasis() == shpWrapper->transform.getBasis().getIdentity()) { + shpWrapper->claim_bt_shape(body_scale); + mainShape = shpWrapper->bt_shape; + main_shape_changed(); + return; } } - compoundShape->recalculateLocalAabb(); -} + // Optimization not possible use a compound shape + btCompoundShape *compoundShape = bulletnew(btCompoundShape(enableDynamicAabbTree, shape_count)); -void RigidCollisionObjectBullet::set_shape_disabled(int p_index, bool p_disabled) { - shapes.write[p_index].active = !p_disabled; - on_shapes_changed(); -} + for (int i(0); i < shape_count; ++i) { + shpWrapper = &shapes.write[i]; + shpWrapper->claim_bt_shape(body_scale); + btTransform scaled_shape_transform(shpWrapper->transform); + scaled_shape_transform.getOrigin() *= body_scale; + compoundShape->addChildShape(scaled_shape_transform, shpWrapper->bt_shape); + } -bool RigidCollisionObjectBullet::is_shape_disabled(int p_index) { - return !shapes[p_index].active; + compoundShape->recalculateLocalAabb(); + mainShape = compoundShape; + main_shape_changed(); } -void RigidCollisionObjectBullet::on_body_scale_changed() { - CollisionObjectBullet::on_body_scale_changed(); - on_shapes_changed(); +void RigidCollisionObjectBullet::body_scale_changed() { + CollisionObjectBullet::body_scale_changed(); + reload_shapes(); } void RigidCollisionObjectBullet::internal_shape_destroy(int p_index, bool p_permanentlyFromThisBody) { ShapeWrapper &shp = shapes.write[p_index]; shp.shape->remove_owner(this, p_permanentlyFromThisBody); + if (shp.bt_shape == mainShape) { + mainShape = NULL; + } bulletdelete(shp.bt_shape); } diff --git a/modules/bullet/collision_object_bullet.h b/modules/bullet/collision_object_bullet.h index 506976eabf..4a0c805ce5 100644 --- a/modules/bullet/collision_object_bullet.h +++ b/modules/bullet/collision_object_bullet.h @@ -31,11 +31,11 @@ #ifndef COLLISION_OBJECT_BULLET_H #define COLLISION_OBJECT_BULLET_H +#include "core/math/transform.h" +#include "core/math/vector3.h" +#include "core/object.h" #include "core/vset.h" -#include "object.h" #include "shape_owner_bullet.h" -#include "transform.h" -#include "vector3.h" #include <LinearMath/btTransform.h> @@ -109,6 +109,8 @@ public: void set_transform(const Transform &p_transform); void set_transform(const btTransform &p_transform); + + void claim_bt_shape(const btVector3 &body_scale); }; protected: @@ -130,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); @@ -155,7 +158,7 @@ public: void set_body_scale(const Vector3 &p_new_scale); const Vector3 &get_body_scale() const { return body_scale; } btVector3 get_bt_body_scale() const; - virtual void on_body_scale_changed(); + virtual void body_scale_changed(); void add_collision_exception(const CollisionObjectBullet *p_ignoreCollisionObject); void remove_collision_exception(const CollisionObjectBullet *p_ignoreCollisionObject); @@ -183,8 +186,9 @@ public: virtual void reload_body() = 0; virtual void set_space(SpaceBullet *p_space) = 0; _FORCE_INLINE_ SpaceBullet *get_space() const { return space; } - /// This is an event that is called when a collision checker starts + virtual void on_collision_checker_start() = 0; + virtual void on_collision_checker_end() = 0; virtual void dispatch_callbacks() = 0; @@ -195,7 +199,6 @@ public: virtual void on_enter_area(AreaBullet *p_area) = 0; virtual void on_exit_area(AreaBullet *p_area); - /// GodotObjectFlags void set_godot_object_flags(int flags); int get_godot_object_flags() const; @@ -203,14 +206,14 @@ 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 { protected: - /// This is required to combine some shapes together. - /// Since Godot allow to have multiple shapes for each body with custom relative location, - /// each body will attach the shapes using this class even if there is only one shape. - btCompoundShape *compoundShape; + btCollisionShape *mainShape; Vector<ShapeWrapper> shapes; public: @@ -219,28 +222,34 @@ public: _FORCE_INLINE_ const Vector<ShapeWrapper> &get_shapes_wrappers() const { return shapes; } - /// This is used to set new shape or replace existing - //virtual void _internal_replaceShape(btCollisionShape *p_old_shape, btCollisionShape *p_new_shape) = 0; + _FORCE_INLINE_ btCollisionShape *get_main_shape() const { return mainShape; } + void add_shape(ShapeBullet *p_shape, const Transform &p_transform = Transform()); void set_shape(int p_index, ShapeBullet *p_shape); - void set_shape_transform(int p_index, const Transform &p_transform); - virtual void remove_shape(ShapeBullet *p_shape); - void remove_shape(int p_index); - void remove_all_shapes(bool p_permanentlyFromThisBody = false); - - virtual void on_shape_changed(const ShapeBullet *const p_shape); - virtual void on_shapes_changed(); - _FORCE_INLINE_ btCompoundShape *get_compound_shape() const { return compoundShape; } int get_shape_count() const; ShapeBullet *get_shape(int p_index) const; btCollisionShape *get_bt_shape(int p_index) const; + + int find_shape(ShapeBullet *p_shape) const; + + virtual void remove_shape_full(ShapeBullet *p_shape); + void remove_shape_full(int p_index); + 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); + + const btTransform &get_bt_shape_transform(int p_index) const; Transform get_shape_transform(int p_index) const; void set_shape_disabled(int p_index, bool p_disabled); bool is_shape_disabled(int p_index); - virtual void on_body_scale_changed(); + virtual void shape_changed(int p_shape_index); + virtual void reload_shapes(); + + virtual void main_shape_changed() = 0; + virtual void body_scale_changed(); private: void internal_shape_destroy(int p_index, bool p_permanentlyFromThisBody = false); diff --git a/modules/bullet/cone_twist_joint_bullet.cpp b/modules/bullet/cone_twist_joint_bullet.cpp index 472ad3b52c..ecacce0bee 100644 --- a/modules/bullet/cone_twist_joint_bullet.cpp +++ b/modules/bullet/cone_twist_joint_bullet.cpp @@ -64,26 +64,6 @@ ConeTwistJointBullet::ConeTwistJointBullet(RigidBodyBullet *rbA, RigidBodyBullet setup(coneConstraint); } -void ConeTwistJointBullet::set_angular_only(bool angularOnly) { - coneConstraint->setAngularOnly(angularOnly); -} - -void ConeTwistJointBullet::set_limit(real_t _swingSpan1, real_t _swingSpan2, real_t _twistSpan, real_t _softness, real_t _biasFactor, real_t _relaxationFactor) { - coneConstraint->setLimit(_swingSpan1, _swingSpan2, _twistSpan, _softness, _biasFactor, _relaxationFactor); -} - -int ConeTwistJointBullet::get_solve_twist_limit() { - return coneConstraint->getSolveTwistLimit(); -} - -int ConeTwistJointBullet::get_solve_swing_limit() { - return coneConstraint->getSolveSwingLimit(); -} - -real_t ConeTwistJointBullet::get_twist_limit_sign() { - return coneConstraint->getTwistLimitSign(); -} - void ConeTwistJointBullet::set_param(PhysicsServer::ConeTwistJointParam p_param, real_t p_value) { switch (p_param) { case PhysicsServer::CONE_TWIST_JOINT_SWING_SPAN: @@ -103,7 +83,9 @@ void ConeTwistJointBullet::set_param(PhysicsServer::ConeTwistJointParam p_param, coneConstraint->setLimit(coneConstraint->getSwingSpan1(), coneConstraint->getSwingSpan2(), coneConstraint->getTwistSpan(), coneConstraint->getLimitSoftness(), coneConstraint->getBiasFactor(), p_value); break; default: - WARN_PRINT("This parameter is not supported by Bullet engine"); + ERR_EXPLAIN("This parameter " + itos(p_param) + " is deprecated"); + WARN_DEPRECATED + break; } } @@ -120,7 +102,8 @@ real_t ConeTwistJointBullet::get_param(PhysicsServer::ConeTwistJointParam p_para case PhysicsServer::CONE_TWIST_JOINT_RELAXATION: return coneConstraint->getRelaxationFactor(); default: - WARN_PRINT("This parameter is not supported by Bullet engine"); + ERR_EXPLAIN("This parameter " + itos(p_param) + " is deprecated"); + WARN_DEPRECATED; return 0; } } diff --git a/modules/bullet/cone_twist_joint_bullet.h b/modules/bullet/cone_twist_joint_bullet.h index bd6eb49196..d6040fd6ec 100644 --- a/modules/bullet/cone_twist_joint_bullet.h +++ b/modules/bullet/cone_twist_joint_bullet.h @@ -47,14 +47,6 @@ public: virtual PhysicsServer::JointType get_type() const { return PhysicsServer::JOINT_CONE_TWIST; } - void set_angular_only(bool angularOnly); - - void set_limit(real_t _swingSpan1, real_t _swingSpan2, real_t _twistSpan, real_t _softness = 0.8f, real_t _biasFactor = 0.3f, real_t _relaxationFactor = 1.0f); - int get_solve_twist_limit(); - - int get_solve_swing_limit(); - real_t get_twist_limit_sign(); - void set_param(PhysicsServer::ConeTwistJointParam p_param, real_t p_value); real_t get_param(PhysicsServer::ConeTwistJointParam p_param) const; }; diff --git a/modules/bullet/generic_6dof_joint_bullet.cpp b/modules/bullet/generic_6dof_joint_bullet.cpp index adfad7803f..812dcd2d56 100644 --- a/modules/bullet/generic_6dof_joint_bullet.cpp +++ b/modules/bullet/generic_6dof_joint_bullet.cpp @@ -34,13 +34,13 @@ #include "bullet_utilities.h" #include "rigid_body_bullet.h" -#include <BulletDynamics/ConstraintSolver/btGeneric6DofConstraint.h> +#include <BulletDynamics/ConstraintSolver/btGeneric6DofSpring2Constraint.h> /** @author AndreaCatania */ -Generic6DOFJointBullet::Generic6DOFJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Transform &frameInA, const Transform &frameInB, bool useLinearReferenceFrameA) : +Generic6DOFJointBullet::Generic6DOFJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Transform &frameInA, const Transform &frameInB) : JointBullet() { Transform scaled_AFrame(frameInA.scaled(rbA->get_body_scale())); @@ -58,9 +58,9 @@ Generic6DOFJointBullet::Generic6DOFJointBullet(RigidBodyBullet *rbA, RigidBodyBu btTransform btFrameB; G_TO_B(scaled_BFrame, btFrameB); - sixDOFConstraint = bulletnew(btGeneric6DofConstraint(*rbA->get_bt_rigid_body(), *rbB->get_bt_rigid_body(), btFrameA, btFrameB, useLinearReferenceFrameA)); + sixDOFConstraint = bulletnew(btGeneric6DofSpring2Constraint(*rbA->get_bt_rigid_body(), *rbB->get_bt_rigid_body(), btFrameA, btFrameB)); } else { - sixDOFConstraint = bulletnew(btGeneric6DofConstraint(*rbA->get_bt_rigid_body(), btFrameA, useLinearReferenceFrameA)); + sixDOFConstraint = bulletnew(btGeneric6DofSpring2Constraint(*rbA->get_bt_rigid_body(), btFrameA)); } setup(sixDOFConstraint); @@ -123,20 +123,11 @@ void Generic6DOFJointBullet::set_param(Vector3::Axis p_axis, PhysicsServer::G6DO switch (p_param) { case PhysicsServer::G6DOF_JOINT_LINEAR_LOWER_LIMIT: limits_lower[0][p_axis] = p_value; - set_flag(p_axis, PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_LINEAR_LIMIT, flags[p_axis][p_param]); // Reload bullet parameter + set_flag(p_axis, PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_LINEAR_LIMIT, flags[p_axis][PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_LINEAR_LIMIT]); // Reload bullet parameter break; case PhysicsServer::G6DOF_JOINT_LINEAR_UPPER_LIMIT: limits_upper[0][p_axis] = p_value; - set_flag(p_axis, PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_LINEAR_LIMIT, flags[p_axis][p_param]); // Reload bullet parameter - break; - case PhysicsServer::G6DOF_JOINT_LINEAR_LIMIT_SOFTNESS: - sixDOFConstraint->getTranslationalLimitMotor()->m_limitSoftness = p_value; - break; - case PhysicsServer::G6DOF_JOINT_LINEAR_RESTITUTION: - sixDOFConstraint->getTranslationalLimitMotor()->m_restitution = p_value; - break; - case PhysicsServer::G6DOF_JOINT_LINEAR_DAMPING: - sixDOFConstraint->getTranslationalLimitMotor()->m_damping = p_value; + set_flag(p_axis, PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_LINEAR_LIMIT, flags[p_axis][PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_LINEAR_LIMIT]); // Reload bullet parameter break; case PhysicsServer::G6DOF_JOINT_LINEAR_MOTOR_TARGET_VELOCITY: sixDOFConstraint->getTranslationalLimitMotor()->m_targetVelocity.m_floats[p_axis] = p_value; @@ -144,26 +135,26 @@ void Generic6DOFJointBullet::set_param(Vector3::Axis p_axis, PhysicsServer::G6DO case PhysicsServer::G6DOF_JOINT_LINEAR_MOTOR_FORCE_LIMIT: sixDOFConstraint->getTranslationalLimitMotor()->m_maxMotorForce.m_floats[p_axis] = p_value; break; + case PhysicsServer::G6DOF_JOINT_LINEAR_SPRING_DAMPING: + sixDOFConstraint->getTranslationalLimitMotor()->m_springDamping.m_floats[p_axis] = p_value; + break; + case PhysicsServer::G6DOF_JOINT_LINEAR_SPRING_STIFFNESS: + sixDOFConstraint->getTranslationalLimitMotor()->m_springStiffness.m_floats[p_axis] = p_value; + break; + case PhysicsServer::G6DOF_JOINT_LINEAR_SPRING_EQUILIBRIUM_POINT: + sixDOFConstraint->getTranslationalLimitMotor()->m_equilibriumPoint.m_floats[p_axis] = p_value; + break; case PhysicsServer::G6DOF_JOINT_ANGULAR_LOWER_LIMIT: limits_lower[1][p_axis] = p_value; - set_flag(p_axis, PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_LIMIT, flags[p_axis][p_param]); // Reload bullet parameter + set_flag(p_axis, PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_LIMIT, flags[p_axis][PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_LIMIT]); // Reload bullet parameter break; case PhysicsServer::G6DOF_JOINT_ANGULAR_UPPER_LIMIT: limits_upper[1][p_axis] = p_value; - set_flag(p_axis, PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_LINEAR_LIMIT, flags[p_axis][p_param]); // Reload bullet parameter - break; - case PhysicsServer::G6DOF_JOINT_ANGULAR_LIMIT_SOFTNESS: - sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_limitSoftness = p_value; - break; - case PhysicsServer::G6DOF_JOINT_ANGULAR_DAMPING: - sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_damping = p_value; + set_flag(p_axis, PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_LIMIT, flags[p_axis][PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_LIMIT]); // Reload bullet parameter break; case PhysicsServer::G6DOF_JOINT_ANGULAR_RESTITUTION: sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_bounce = p_value; break; - case PhysicsServer::G6DOF_JOINT_ANGULAR_FORCE_LIMIT: - sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_maxLimitForce = p_value; - break; case PhysicsServer::G6DOF_JOINT_ANGULAR_ERP: sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_stopERP = p_value; break; @@ -171,10 +162,21 @@ void Generic6DOFJointBullet::set_param(Vector3::Axis p_axis, PhysicsServer::G6DO sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_targetVelocity = p_value; break; case PhysicsServer::G6DOF_JOINT_ANGULAR_MOTOR_FORCE_LIMIT: - sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_maxLimitForce = p_value; + sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_maxMotorForce = p_value; + break; + case PhysicsServer::G6DOF_JOINT_ANGULAR_SPRING_STIFFNESS: + sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_springStiffness = p_value; + break; + case PhysicsServer::G6DOF_JOINT_ANGULAR_SPRING_DAMPING: + sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_springDamping = p_value; + break; + case PhysicsServer::G6DOF_JOINT_ANGULAR_SPRING_EQUILIBRIUM_POINT: + sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_equilibriumPoint = p_value; break; default: - WARN_PRINT("This parameter is not supported"); + ERR_EXPLAIN("This parameter " + itos(p_param) + " is deprecated"); + WARN_DEPRECATED + break; } } @@ -185,37 +187,38 @@ real_t Generic6DOFJointBullet::get_param(Vector3::Axis p_axis, PhysicsServer::G6 return limits_lower[0][p_axis]; case PhysicsServer::G6DOF_JOINT_LINEAR_UPPER_LIMIT: return limits_upper[0][p_axis]; - case PhysicsServer::G6DOF_JOINT_LINEAR_LIMIT_SOFTNESS: - return sixDOFConstraint->getTranslationalLimitMotor()->m_limitSoftness; - case PhysicsServer::G6DOF_JOINT_LINEAR_RESTITUTION: - return sixDOFConstraint->getTranslationalLimitMotor()->m_restitution; - case PhysicsServer::G6DOF_JOINT_LINEAR_DAMPING: - return sixDOFConstraint->getTranslationalLimitMotor()->m_damping; case PhysicsServer::G6DOF_JOINT_LINEAR_MOTOR_TARGET_VELOCITY: return sixDOFConstraint->getTranslationalLimitMotor()->m_targetVelocity.m_floats[p_axis]; case PhysicsServer::G6DOF_JOINT_LINEAR_MOTOR_FORCE_LIMIT: return sixDOFConstraint->getTranslationalLimitMotor()->m_maxMotorForce.m_floats[p_axis]; + case PhysicsServer::G6DOF_JOINT_LINEAR_SPRING_DAMPING: + return sixDOFConstraint->getTranslationalLimitMotor()->m_springDamping.m_floats[p_axis]; + case PhysicsServer::G6DOF_JOINT_LINEAR_SPRING_STIFFNESS: + return sixDOFConstraint->getTranslationalLimitMotor()->m_springStiffness.m_floats[p_axis]; + case PhysicsServer::G6DOF_JOINT_LINEAR_SPRING_EQUILIBRIUM_POINT: + return sixDOFConstraint->getTranslationalLimitMotor()->m_equilibriumPoint.m_floats[p_axis]; case PhysicsServer::G6DOF_JOINT_ANGULAR_LOWER_LIMIT: return limits_lower[1][p_axis]; case PhysicsServer::G6DOF_JOINT_ANGULAR_UPPER_LIMIT: return limits_upper[1][p_axis]; - case PhysicsServer::G6DOF_JOINT_ANGULAR_LIMIT_SOFTNESS: - return sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_limitSoftness; - case PhysicsServer::G6DOF_JOINT_ANGULAR_DAMPING: - return sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_damping; case PhysicsServer::G6DOF_JOINT_ANGULAR_RESTITUTION: return sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_bounce; - case PhysicsServer::G6DOF_JOINT_ANGULAR_FORCE_LIMIT: - return sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_maxLimitForce; case PhysicsServer::G6DOF_JOINT_ANGULAR_ERP: return sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_stopERP; case PhysicsServer::G6DOF_JOINT_ANGULAR_MOTOR_TARGET_VELOCITY: return sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_targetVelocity; case PhysicsServer::G6DOF_JOINT_ANGULAR_MOTOR_FORCE_LIMIT: - return sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_maxLimitForce; + return sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_maxMotorForce; + case PhysicsServer::G6DOF_JOINT_ANGULAR_SPRING_STIFFNESS: + return sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_springStiffness; + case PhysicsServer::G6DOF_JOINT_ANGULAR_SPRING_DAMPING: + return sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_springDamping; + case PhysicsServer::G6DOF_JOINT_ANGULAR_SPRING_EQUILIBRIUM_POINT: + return sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_equilibriumPoint; default: - WARN_PRINT("This parameter is not supported"); - return 0.; + ERR_EXPLAIN("This parameter " + itos(p_param) + " is deprecated"); + WARN_DEPRECATED; + return 0; } } @@ -245,14 +248,28 @@ void Generic6DOFJointBullet::set_flag(Vector3::Axis p_axis, PhysicsServer::G6DOF case PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_LINEAR_MOTOR: sixDOFConstraint->getTranslationalLimitMotor()->m_enableMotor[p_axis] = flags[p_axis][p_flag]; break; + case PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_LINEAR_SPRING: + sixDOFConstraint->getTranslationalLimitMotor()->m_enableSpring[p_axis] = p_value; + break; + case PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_SPRING: + sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_enableSpring = p_value; + break; default: - WARN_PRINT("This flag is not supported by Bullet engine"); - return; + ERR_EXPLAIN("This flag " + itos(p_flag) + " is deprecated"); + WARN_DEPRECATED + break; } } bool Generic6DOFJointBullet::get_flag(Vector3::Axis p_axis, PhysicsServer::G6DOFJointAxisFlag p_flag) const { ERR_FAIL_INDEX_V(p_axis, 3, false); - return flags[p_axis][p_flag]; } + +void Generic6DOFJointBullet::set_precision(int p_precision) { + sixDOFConstraint->setOverrideNumSolverIterations(MAX(1, p_precision)); +} + +int Generic6DOFJointBullet::get_precision() const { + return sixDOFConstraint->getOverrideNumSolverIterations(); +} diff --git a/modules/bullet/generic_6dof_joint_bullet.h b/modules/bullet/generic_6dof_joint_bullet.h index ad06582eac..848c3a10cd 100644 --- a/modules/bullet/generic_6dof_joint_bullet.h +++ b/modules/bullet/generic_6dof_joint_bullet.h @@ -40,7 +40,7 @@ class RigidBodyBullet; class Generic6DOFJointBullet : public JointBullet { - class btGeneric6DofConstraint *sixDOFConstraint; + class btGeneric6DofSpring2Constraint *sixDOFConstraint; // First is linear second is angular Vector3 limits_lower[2]; @@ -48,7 +48,7 @@ class Generic6DOFJointBullet : public JointBullet { bool flags[3][PhysicsServer::G6DOF_JOINT_FLAG_MAX]; public: - Generic6DOFJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Transform &frameInA, const Transform &frameInB, bool useLinearReferenceFrameA); + Generic6DOFJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Transform &frameInA, const Transform &frameInB); virtual PhysicsServer::JointType get_type() const { return PhysicsServer::JOINT_6DOF; } @@ -68,6 +68,9 @@ public: void set_flag(Vector3::Axis p_axis, PhysicsServer::G6DOFJointAxisFlag p_flag, bool p_value); bool get_flag(Vector3::Axis p_axis, PhysicsServer::G6DOFJointAxisFlag p_flag) const; + + void set_precision(int p_precision); + int get_precision() const; }; #endif diff --git a/modules/bullet/godot_collision_configuration.cpp b/modules/bullet/godot_collision_configuration.cpp index f4bb9acbd7..919c3152d7 100644 --- a/modules/bullet/godot_collision_configuration.cpp +++ b/modules/bullet/godot_collision_configuration.cpp @@ -94,3 +94,59 @@ btCollisionAlgorithmCreateFunc *GodotCollisionConfiguration::getClosestPointsAlg return btDefaultCollisionConfiguration::getClosestPointsAlgorithmCreateFunc(proxyType0, proxyType1); } } + +GodotSoftCollisionConfiguration::GodotSoftCollisionConfiguration(const btDiscreteDynamicsWorld *world, const btDefaultCollisionConstructionInfo &constructionInfo) : + btSoftBodyRigidBodyCollisionConfiguration(constructionInfo) { + + void *mem = NULL; + + mem = btAlignedAlloc(sizeof(GodotRayWorldAlgorithm::CreateFunc), 16); + m_rayWorldCF = new (mem) GodotRayWorldAlgorithm::CreateFunc(world); + + mem = btAlignedAlloc(sizeof(GodotRayWorldAlgorithm::SwappedCreateFunc), 16); + m_swappedRayWorldCF = new (mem) GodotRayWorldAlgorithm::SwappedCreateFunc(world); +} + +GodotSoftCollisionConfiguration::~GodotSoftCollisionConfiguration() { + m_rayWorldCF->~btCollisionAlgorithmCreateFunc(); + btAlignedFree(m_rayWorldCF); + + m_swappedRayWorldCF->~btCollisionAlgorithmCreateFunc(); + btAlignedFree(m_swappedRayWorldCF); +} + +btCollisionAlgorithmCreateFunc *GodotSoftCollisionConfiguration::getCollisionAlgorithmCreateFunc(int proxyType0, int proxyType1) { + + if (CUSTOM_CONVEX_SHAPE_TYPE == proxyType0 && CUSTOM_CONVEX_SHAPE_TYPE == proxyType1) { + + // This collision is not supported + return m_emptyCreateFunc; + } else if (CUSTOM_CONVEX_SHAPE_TYPE == proxyType0) { + + return m_rayWorldCF; + } else if (CUSTOM_CONVEX_SHAPE_TYPE == proxyType1) { + + return m_swappedRayWorldCF; + } else { + + return btSoftBodyRigidBodyCollisionConfiguration::getCollisionAlgorithmCreateFunc(proxyType0, proxyType1); + } +} + +btCollisionAlgorithmCreateFunc *GodotSoftCollisionConfiguration::getClosestPointsAlgorithmCreateFunc(int proxyType0, int proxyType1) { + + if (CUSTOM_CONVEX_SHAPE_TYPE == proxyType0 && CUSTOM_CONVEX_SHAPE_TYPE == proxyType1) { + + // This collision is not supported + return m_emptyCreateFunc; + } else if (CUSTOM_CONVEX_SHAPE_TYPE == proxyType0) { + + return m_rayWorldCF; + } else if (CUSTOM_CONVEX_SHAPE_TYPE == proxyType1) { + + return m_swappedRayWorldCF; + } else { + + return btSoftBodyRigidBodyCollisionConfiguration::getClosestPointsAlgorithmCreateFunc(proxyType0, proxyType1); + } +} diff --git a/modules/bullet/godot_collision_configuration.h b/modules/bullet/godot_collision_configuration.h index 9b30ad0c62..11012c5f6d 100644 --- a/modules/bullet/godot_collision_configuration.h +++ b/modules/bullet/godot_collision_configuration.h @@ -32,6 +32,7 @@ #define GODOT_COLLISION_CONFIGURATION_H #include <BulletCollision/CollisionDispatch/btDefaultCollisionConfiguration.h> +#include <BulletSoftBody/btSoftBodyRigidBodyCollisionConfiguration.h> /** @author AndreaCatania @@ -50,4 +51,16 @@ public: virtual btCollisionAlgorithmCreateFunc *getCollisionAlgorithmCreateFunc(int proxyType0, int proxyType1); virtual btCollisionAlgorithmCreateFunc *getClosestPointsAlgorithmCreateFunc(int proxyType0, int proxyType1); }; + +class GodotSoftCollisionConfiguration : public btSoftBodyRigidBodyCollisionConfiguration { + btCollisionAlgorithmCreateFunc *m_rayWorldCF; + btCollisionAlgorithmCreateFunc *m_swappedRayWorldCF; + +public: + GodotSoftCollisionConfiguration(const btDiscreteDynamicsWorld *world, const btDefaultCollisionConstructionInfo &constructionInfo = btDefaultCollisionConstructionInfo()); + virtual ~GodotSoftCollisionConfiguration(); + + virtual btCollisionAlgorithmCreateFunc *getCollisionAlgorithmCreateFunc(int proxyType0, int proxyType1); + virtual btCollisionAlgorithmCreateFunc *getClosestPointsAlgorithmCreateFunc(int proxyType0, int proxyType1); +}; #endif diff --git a/modules/bullet/godot_collision_dispatcher.h b/modules/bullet/godot_collision_dispatcher.h index 2e5a6c2732..1faaa68626 100644 --- a/modules/bullet/godot_collision_dispatcher.h +++ b/modules/bullet/godot_collision_dispatcher.h @@ -31,7 +31,7 @@ #ifndef GODOT_COLLISION_DISPATCHER_H #define GODOT_COLLISION_DISPATCHER_H -#include "int_types.h" +#include "core/int_types.h" #include <btBulletDynamicsCommon.h> 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/godot_ray_world_algorithm.cpp b/modules/bullet/godot_ray_world_algorithm.cpp index 53d0ab7e3c..27ee44d1bd 100644 --- a/modules/bullet/godot_ray_world_algorithm.cpp +++ b/modules/bullet/godot_ray_world_algorithm.cpp @@ -49,9 +49,9 @@ GodotRayWorldAlgorithm::SwappedCreateFunc::SwappedCreateFunc(const btDiscreteDyn GodotRayWorldAlgorithm::GodotRayWorldAlgorithm(const btDiscreteDynamicsWorld *world, btPersistentManifold *mf, const btCollisionAlgorithmConstructionInfo &ci, const btCollisionObjectWrapper *body0Wrap, const btCollisionObjectWrapper *body1Wrap, bool isSwapped) : btActivatingCollisionAlgorithm(ci, body0Wrap, body1Wrap), + m_world(world), m_manifoldPtr(mf), m_ownManifold(false), - m_world(world), m_isSwapped(isSwapped) {} GodotRayWorldAlgorithm::~GodotRayWorldAlgorithm() { diff --git a/modules/bullet/godot_result_callbacks.cpp b/modules/bullet/godot_result_callbacks.cpp index 197550d686..0117bb375f 100644 --- a/modules/bullet/godot_result_callbacks.cpp +++ b/modules/bullet/godot_result_callbacks.cpp @@ -30,14 +30,23 @@ #include "godot_result_callbacks.h" +#include "area_bullet.h" #include "bullet_types_converter.h" #include "collision_object_bullet.h" #include "rigid_body_bullet.h" +#include <BulletCollision/CollisionDispatch/btInternalEdgeUtility.h> /** @author AndreaCatania */ +bool godotContactAddedCallback(btManifoldPoint &cp, const btCollisionObjectWrapper *colObj0Wrap, int partId0, int index0, const btCollisionObjectWrapper *colObj1Wrap, int partId1, int index1) { + if (!colObj1Wrap->getCollisionObject()->getCollisionShape()->isCompound()) { + btAdjustInternalEdgeContacts(cp, colObj1Wrap, colObj0Wrap, partId1, index1); + } + return true; +} + bool GodotFilterCallback::test_collision_filters(uint32_t body0_collision_layer, uint32_t body0_collision_mask, uint32_t body1_collision_layer, uint32_t body1_collision_mask) { return body0_collision_layer & body1_collision_mask || body1_collision_layer & body0_collision_mask; } @@ -51,11 +60,23 @@ bool GodotClosestRayResultCallback::needsCollision(btBroadphaseProxy *proxy0) co if (needs) { btCollisionObject *btObj = static_cast<btCollisionObject *>(proxy0->m_clientObject); CollisionObjectBullet *gObj = static_cast<CollisionObjectBullet *>(btObj->getUserPointer()); - if (m_pickRay && gObj->is_ray_pickable()) { - return true; - } else if (m_exclude->has(gObj->get_self())) { + + if (CollisionObjectBullet::TYPE_AREA == gObj->getType()) { + if (!collide_with_areas) + return false; + } else { + if (!collide_with_bodies) + return false; + } + + if (m_pickRay && !gObj->is_ray_pickable()) { + return false; + } + + if (m_exclude->has(gObj->get_self())) { return false; } + return true; } else { return false; @@ -81,6 +102,9 @@ bool GodotAllConvexResultCallback::needsCollision(btBroadphaseProxy *proxy0) con } btScalar GodotAllConvexResultCallback::addSingleResult(btCollisionWorld::LocalConvexResult &convexResult, bool normalInWorldSpace) { + if (count >= m_resultMax) + return 1; // not used by bullet + CollisionObjectBullet *gObj = static_cast<CollisionObjectBullet *>(convexResult.m_hitCollisionObject->getUserPointer()); PhysicsDirectSpaceState::ShapeResult &result = m_results[count]; @@ -124,6 +148,15 @@ bool GodotClosestConvexResultCallback::needsCollision(btBroadphaseProxy *proxy0) if (needs) { btCollisionObject *btObj = static_cast<btCollisionObject *>(proxy0->m_clientObject); CollisionObjectBullet *gObj = static_cast<CollisionObjectBullet *>(btObj->getUserPointer()); + + if (CollisionObjectBullet::TYPE_AREA == gObj->getType()) { + if (!collide_with_areas) + return false; + } else { + if (!collide_with_bodies) + return false; + } + if (m_exclude->has(gObj->get_self())) { return false; } @@ -134,16 +167,30 @@ bool GodotClosestConvexResultCallback::needsCollision(btBroadphaseProxy *proxy0) } btScalar GodotClosestConvexResultCallback::addSingleResult(btCollisionWorld::LocalConvexResult &convexResult, bool normalInWorldSpace) { - btScalar res = btCollisionWorld::ClosestConvexResultCallback::addSingleResult(convexResult, normalInWorldSpace); - m_shapeId = convexResult.m_localShapeInfo->m_triangleIndex; // "m_triangleIndex" Is a odd name but contains the compound shape ID - return res; + if (convexResult.m_localShapeInfo) + m_shapeId = convexResult.m_localShapeInfo->m_triangleIndex; // "m_triangleIndex" Is a odd name but contains the compound shape ID + else + m_shapeId = 0; + return btCollisionWorld::ClosestConvexResultCallback::addSingleResult(convexResult, normalInWorldSpace); } bool GodotAllContactResultCallback::needsCollision(btBroadphaseProxy *proxy0) const { + if (m_count >= m_resultMax) + return false; + const bool needs = GodotFilterCallback::test_collision_filters(m_collisionFilterGroup, m_collisionFilterMask, proxy0->m_collisionFilterGroup, proxy0->m_collisionFilterMask); if (needs) { btCollisionObject *btObj = static_cast<btCollisionObject *>(proxy0->m_clientObject); CollisionObjectBullet *gObj = static_cast<CollisionObjectBullet *>(btObj->getUserPointer()); + + if (CollisionObjectBullet::TYPE_AREA == gObj->getType()) { + if (!collide_with_areas) + return false; + } else { + if (!collide_with_bodies) + return false; + } + if (m_exclude->has(gObj->get_self())) { return false; } @@ -189,6 +236,15 @@ bool GodotContactPairContactResultCallback::needsCollision(btBroadphaseProxy *pr if (needs) { btCollisionObject *btObj = static_cast<btCollisionObject *>(proxy0->m_clientObject); CollisionObjectBullet *gObj = static_cast<CollisionObjectBullet *>(btObj->getUserPointer()); + + if (CollisionObjectBullet::TYPE_AREA == gObj->getType()) { + if (!collide_with_areas) + return false; + } else { + if (!collide_with_bodies) + return false; + } + if (m_exclude->has(gObj->get_self())) { return false; } @@ -199,6 +255,8 @@ bool GodotContactPairContactResultCallback::needsCollision(btBroadphaseProxy *pr } btScalar GodotContactPairContactResultCallback::addSingleResult(btManifoldPoint &cp, const btCollisionObjectWrapper *colObj0Wrap, int partId0, int index0, const btCollisionObjectWrapper *colObj1Wrap, int partId1, int index1) { + if (m_count >= m_resultMax) + return 1; // not used by bullet if (m_self_object == colObj0Wrap->getCollisionObject()) { B_TO_G(cp.m_localPointA, m_results[m_count * 2 + 0]); // Local contact @@ -218,6 +276,15 @@ bool GodotRestInfoContactResultCallback::needsCollision(btBroadphaseProxy *proxy if (needs) { btCollisionObject *btObj = static_cast<btCollisionObject *>(proxy0->m_clientObject); CollisionObjectBullet *gObj = static_cast<CollisionObjectBullet *>(btObj->getUserPointer()); + + if (CollisionObjectBullet::TYPE_AREA == gObj->getType()) { + if (!collide_with_areas) + return false; + } else { + if (!collide_with_bodies) + return false; + } + if (m_exclude->has(gObj->get_self())) { return false; } @@ -260,10 +327,19 @@ void GodotDeepPenetrationContactResultCallback::addContactPoint(const btVector3 if (m_penetration_distance > depth) { // Has penetration? - bool isSwapped = m_manifoldPtr->getBody0() != m_body0Wrap->getCollisionObject(); + const bool isSwapped = m_manifoldPtr->getBody0() != m_body0Wrap->getCollisionObject(); m_penetration_distance = depth; m_other_compound_shape_index = isSwapped ? m_index0 : m_index1; - m_pointNormalWorld = isSwapped ? normalOnBInWorld * -1 : normalOnBInWorld; m_pointWorld = isSwapped ? (pointInWorldOnB + (normalOnBInWorld * depth)) : pointInWorldOnB; + + const btCollisionObjectWrapper *bw0 = m_body0Wrap; + if (isSwapped) + bw0 = m_body1Wrap; + + if (bw0->getCollisionShape()->getShapeType() == CUSTOM_CONVEX_SHAPE_TYPE) { + m_pointNormalWorld = bw0->m_worldTransform.getBasis().transpose() * btVector3(0, 0, 1); + } else { + m_pointNormalWorld = isSwapped ? normalOnBInWorld * -1 : normalOnBInWorld; + } } } diff --git a/modules/bullet/godot_result_callbacks.h b/modules/bullet/godot_result_callbacks.h index 363051f24c..73e1fc9627 100644 --- a/modules/bullet/godot_result_callbacks.h +++ b/modules/bullet/godot_result_callbacks.h @@ -42,6 +42,9 @@ class RigidBodyBullet; +/// This callback is injected inside bullet server and allow me to smooth contacts against trimesh +bool godotContactAddedCallback(btManifoldPoint &cp, const btCollisionObjectWrapper *colObj0Wrap, int partId0, int index0, const btCollisionObjectWrapper *colObj1Wrap, int partId1, int index1); + /// This class is required to implement custom collision behaviour in the broadphase struct GodotFilterCallback : public btOverlapFilterCallback { static bool test_collision_filters(uint32_t body0_collision_layer, uint32_t body0_collision_mask, uint32_t body1_collision_layer, uint32_t body1_collision_mask); @@ -56,17 +59,25 @@ struct GodotClosestRayResultCallback : public btCollisionWorld::ClosestRayResult bool m_pickRay; int m_shapeId; + bool collide_with_bodies; + bool collide_with_areas; + public: - GodotClosestRayResultCallback(const btVector3 &rayFromWorld, const btVector3 &rayToWorld, const Set<RID> *p_exclude) : + GodotClosestRayResultCallback(const btVector3 &rayFromWorld, const btVector3 &rayToWorld, const Set<RID> *p_exclude, bool p_collide_with_bodies, bool p_collide_with_areas) : btCollisionWorld::ClosestRayResultCallback(rayFromWorld, rayToWorld), m_exclude(p_exclude), m_pickRay(false), - m_shapeId(0) {} + m_shapeId(0), + collide_with_bodies(p_collide_with_bodies), + collide_with_areas(p_collide_with_areas) {} virtual bool needsCollision(btBroadphaseProxy *proxy0) const; virtual btScalar addSingleResult(btCollisionWorld::LocalRayResult &rayResult, bool normalInWorldSpace) { - m_shapeId = rayResult.m_localShapeInfo->m_triangleIndex; // "m_triangleIndex" Is a odd name but contains the compound shape ID + if (rayResult.m_localShapeInfo) + m_shapeId = rayResult.m_localShapeInfo->m_triangleIndex; // "m_triangleIndex" Is a odd name but contains the compound shape ID + else + m_shapeId = 0; return btCollisionWorld::ClosestRayResultCallback::addSingleResult(rayResult, normalInWorldSpace); } }; @@ -76,13 +87,13 @@ struct GodotAllConvexResultCallback : public btCollisionWorld::ConvexResultCallb public: PhysicsDirectSpaceState::ShapeResult *m_results; int m_resultMax; - int count; const Set<RID> *m_exclude; + int count; GodotAllConvexResultCallback(PhysicsDirectSpaceState::ShapeResult *p_results, int p_resultMax, const Set<RID> *p_exclude) : m_results(p_results), - m_exclude(p_exclude), m_resultMax(p_resultMax), + m_exclude(p_exclude), count(0) {} virtual bool needsCollision(btBroadphaseProxy *proxy0) const; @@ -108,9 +119,15 @@ public: const Set<RID> *m_exclude; int m_shapeId; - GodotClosestConvexResultCallback(const btVector3 &convexFromWorld, const btVector3 &convexToWorld, const Set<RID> *p_exclude) : + bool collide_with_bodies; + bool collide_with_areas; + + GodotClosestConvexResultCallback(const btVector3 &convexFromWorld, const btVector3 &convexToWorld, const Set<RID> *p_exclude, bool p_collide_with_bodies, bool p_collide_with_areas) : btCollisionWorld::ClosestConvexResultCallback(convexFromWorld, convexToWorld), - m_exclude(p_exclude) {} + m_exclude(p_exclude), + m_shapeId(0), + collide_with_bodies(p_collide_with_bodies), + collide_with_areas(p_collide_with_areas) {} virtual bool needsCollision(btBroadphaseProxy *proxy0) const; @@ -122,15 +139,20 @@ public: const btCollisionObject *m_self_object; PhysicsDirectSpaceState::ShapeResult *m_results; int m_resultMax; - int m_count; const Set<RID> *m_exclude; + int m_count; - GodotAllContactResultCallback(btCollisionObject *p_self_object, PhysicsDirectSpaceState::ShapeResult *p_results, int p_resultMax, const Set<RID> *p_exclude) : + bool collide_with_bodies; + bool collide_with_areas; + + GodotAllContactResultCallback(btCollisionObject *p_self_object, PhysicsDirectSpaceState::ShapeResult *p_results, int p_resultMax, const Set<RID> *p_exclude, bool p_collide_with_bodies, bool p_collide_with_areas) : m_self_object(p_self_object), m_results(p_results), - m_exclude(p_exclude), m_resultMax(p_resultMax), - m_count(0) {} + m_exclude(p_exclude), + m_count(0), + collide_with_bodies(p_collide_with_bodies), + collide_with_areas(p_collide_with_areas) {} virtual bool needsCollision(btBroadphaseProxy *proxy0) const; @@ -143,15 +165,20 @@ public: const btCollisionObject *m_self_object; Vector3 *m_results; int m_resultMax; - int m_count; const Set<RID> *m_exclude; + int m_count; - GodotContactPairContactResultCallback(btCollisionObject *p_self_object, Vector3 *p_results, int p_resultMax, const Set<RID> *p_exclude) : + bool collide_with_bodies; + bool collide_with_areas; + + GodotContactPairContactResultCallback(btCollisionObject *p_self_object, Vector3 *p_results, int p_resultMax, const Set<RID> *p_exclude, bool p_collide_with_bodies, bool p_collide_with_areas) : m_self_object(p_self_object), m_results(p_results), - m_exclude(p_exclude), m_resultMax(p_resultMax), - m_count(0) {} + m_exclude(p_exclude), + m_count(0), + collide_with_bodies(p_collide_with_bodies), + collide_with_areas(p_collide_with_areas) {} virtual bool needsCollision(btBroadphaseProxy *proxy0) const; @@ -162,18 +189,22 @@ struct GodotRestInfoContactResultCallback : public btCollisionWorld::ContactResu public: const btCollisionObject *m_self_object; PhysicsDirectSpaceState::ShapeRestInfo *m_result; + const Set<RID> *m_exclude; bool m_collided; real_t m_min_distance; const btCollisionObject *m_rest_info_collision_object; btVector3 m_rest_info_bt_point; - const Set<RID> *m_exclude; + bool collide_with_bodies; + bool collide_with_areas; - GodotRestInfoContactResultCallback(btCollisionObject *p_self_object, PhysicsDirectSpaceState::ShapeRestInfo *p_result, const Set<RID> *p_exclude) : + GodotRestInfoContactResultCallback(btCollisionObject *p_self_object, PhysicsDirectSpaceState::ShapeRestInfo *p_result, const Set<RID> *p_exclude, bool p_collide_with_bodies, bool p_collide_with_areas) : m_self_object(p_self_object), m_result(p_result), m_exclude(p_exclude), m_collided(false), - m_min_distance(0) {} + m_min_distance(0), + collide_with_bodies(p_collide_with_bodies), + collide_with_areas(p_collide_with_areas) {} virtual bool needsCollision(btBroadphaseProxy *proxy0) const; diff --git a/modules/bullet/hinge_joint_bullet.cpp b/modules/bullet/hinge_joint_bullet.cpp index 97ea7ca3df..3a4459a581 100644 --- a/modules/bullet/hinge_joint_bullet.cpp +++ b/modules/bullet/hinge_joint_bullet.cpp @@ -95,11 +95,6 @@ real_t HingeJointBullet::get_hinge_angle() { void HingeJointBullet::set_param(PhysicsServer::HingeJointParam p_param, real_t p_value) { switch (p_param) { - case PhysicsServer::HINGE_JOINT_BIAS: - if (0 < p_value) { - print_line("The Bullet Hinge Joint doesn't support bias, So it's always 0"); - } - break; case PhysicsServer::HINGE_JOINT_LIMIT_UPPER: hingeConstraint->setLimit(hingeConstraint->getLowerLimit(), p_value, hingeConstraint->getLimitSoftness(), hingeConstraint->getLimitBiasFactor(), hingeConstraint->getLimitRelaxationFactor()); break; @@ -122,7 +117,9 @@ void HingeJointBullet::set_param(PhysicsServer::HingeJointParam p_param, real_t hingeConstraint->setMaxMotorImpulse(p_value); break; default: - WARN_PRINTS("The Bullet Hinge Joint doesn't support this parameter: " + itos(p_param) + ", value: " + itos(p_value)); + ERR_EXPLAIN("The HingeJoint parameter " + itos(p_param) + " is deprecated."); + WARN_DEPRECATED + break; } } @@ -146,7 +143,8 @@ real_t HingeJointBullet::get_param(PhysicsServer::HingeJointParam p_param) const case PhysicsServer::HINGE_JOINT_MOTOR_MAX_IMPULSE: return hingeConstraint->getMaxMotorImpulse(); default: - WARN_PRINTS("The Bullet Hinge Joint doesn't support this parameter: " + itos(p_param)); + ERR_EXPLAIN("The HingeJoint parameter " + itos(p_param) + " is deprecated."); + WARN_DEPRECATED; return 0; } } @@ -161,6 +159,7 @@ void HingeJointBullet::set_flag(PhysicsServer::HingeJointFlag p_flag, bool p_val case PhysicsServer::HINGE_JOINT_FLAG_ENABLE_MOTOR: hingeConstraint->enableMotor(p_value); break; + case PhysicsServer::HINGE_JOINT_FLAG_MAX: break; // Can't happen, but silences warning } } diff --git a/modules/bullet/pin_joint_bullet.cpp b/modules/bullet/pin_joint_bullet.cpp index c4e5b8cdbe..183a7e75b9 100644 --- a/modules/bullet/pin_joint_bullet.cpp +++ b/modules/bullet/pin_joint_bullet.cpp @@ -85,7 +85,8 @@ real_t PinJointBullet::get_param(PhysicsServer::PinJointParam p_param) const { case PhysicsServer::PIN_JOINT_IMPULSE_CLAMP: return p2pConstraint->m_setting.m_impulseClamp; default: - WARN_PRINTS("This get parameter is not supported"); + ERR_EXPLAIN("This parameter " + itos(p_param) + " is deprecated"); + WARN_DEPRECATED return 0; } } diff --git a/modules/bullet/register_types.cpp b/modules/bullet/register_types.cpp index a76b0438b4..31e5f6784e 100644 --- a/modules/bullet/register_types.cpp +++ b/modules/bullet/register_types.cpp @@ -31,8 +31,8 @@ #include "register_types.h" #include "bullet_physics_server.h" -#include "class_db.h" -#include "project_settings.h" +#include "core/class_db.h" +#include "core/project_settings.h" /** @author AndreaCatania diff --git a/modules/bullet/rigid_body_bullet.cpp b/modules/bullet/rigid_body_bullet.cpp index 81a62edba6..9dd04100ed 100644 --- a/modules/bullet/rigid_body_bullet.cpp +++ b/modules/bullet/rigid_body_bullet.cpp @@ -259,31 +259,31 @@ RigidBodyBullet::RigidBodyBullet() : RigidCollisionObjectBullet(CollisionObjectBullet::TYPE_RIGID_BODY), kinematic_utilities(NULL), locked_axis(0), - gravity_scale(1), mass(1), + gravity_scale(1), linearDamp(0), angularDamp(0), can_sleep(true), omit_forces_integration(false), - restitution_combine_mode(PhysicsServer::COMBINE_MODE_INHERIT), - friction_combine_mode(PhysicsServer::COMBINE_MODE_INHERIT), - force_integration_callback(NULL), - isTransformChanged(false), - previousActiveState(true), + can_integrate_forces(false), maxCollisionsDetection(0), collisionsCount(0), + prev_collision_count(0), maxAreasWhereIam(10), areaWhereIamCount(0), countGravityPointSpaces(0), - isScratchedSpaceOverrideModificator(false) { + isScratchedSpaceOverrideModificator(false), + previousActiveState(true), + force_integration_callback(NULL) { godotMotionState = bulletnew(GodotMotionState(this)); // Initial properties const btVector3 localInertia(0, 0, 0); - btRigidBody::btRigidBodyConstructionInfo cInfo(mass, godotMotionState, compoundShape, localInertia); + btRigidBody::btRigidBodyConstructionInfo cInfo(mass, godotMotionState, NULL, localInertia); btBody = bulletnew(btRigidBody(cInfo)); + reload_shapes(); setupBulletCollisionObject(btBody); set_mode(PhysicsServer::BODY_MODE_RIGID); @@ -294,6 +294,9 @@ RigidBodyBullet::RigidBodyBullet() : areasWhereIam.write[i] = NULL; } btBody->setSleepingThresholds(0.2, 0.2); + + prev_collision_traces = &collision_traces_1; + curr_collision_traces = &collision_traces_2; } RigidBodyBullet::~RigidBodyBullet() { @@ -316,17 +319,24 @@ void RigidBodyBullet::destroy_kinematic_utilities() { } } +void RigidBodyBullet::main_shape_changed() { + CRASH_COND(!get_main_shape()) + btBody->setCollisionShape(get_main_shape()); + set_continuous_collision_detection(is_continuous_collision_detection_enabled()); // Reset +} + void RigidBodyBullet::reload_body() { if (space) { space->remove_rigid_body(this); - space->add_rigid_body(this); + if (get_main_shape()) + space->add_rigid_body(this); } } 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(); @@ -343,8 +353,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->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(); @@ -393,10 +403,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; } @@ -408,7 +414,19 @@ void RigidBodyBullet::on_collision_filters_change() { } void RigidBodyBullet::on_collision_checker_start() { + + prev_collision_count = collisionsCount; collisionsCount = 0; + + // Swap array + Vector<RigidBodyBullet *> *s = prev_collision_traces; + prev_collision_traces = curr_collision_traces; + curr_collision_traces = s; +} + +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) { @@ -426,10 +444,20 @@ bool RigidBodyBullet::add_collision_object(RigidBodyBullet *p_otherObject, const cd.other_object_shape = p_other_shape_index; cd.local_shape = p_local_shape_index; + curr_collision_traces->write[collisionsCount] = p_otherObject; + ++collisionsCount; return true; } +bool RigidBodyBullet::was_colliding(RigidBodyBullet *p_other_object) { + for (int i = prev_collision_count - 1; 0 <= i; --i) { + if ((*prev_collision_traces)[i] == p_other_object) + return true; + } + return false; +} + void RigidBodyBullet::assert_no_constraints() { if (btBody->getNumConstraintRefs()) { WARN_PRINT("A body with a joints is destroyed. Please check the implementation in order to destroy the joint before the body."); @@ -513,7 +541,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) { @@ -528,20 +556,18 @@ void RigidBodyBullet::set_mode(PhysicsServer::BodyMode p_mode) { reload_axis_lock(); _internal_set_mass(0); break; - case PhysicsServer::BODY_MODE_RIGID: { + case PhysicsServer::BODY_MODE_RIGID: mode = PhysicsServer::BODY_MODE_RIGID; reload_axis_lock(); _internal_set_mass(0 == mass ? 1 : mass); scratch_space_override_modificator(); break; - } - case PhysicsServer::BODY_MODE_CHARACTER: { + case PhysicsServer::BODY_MODE_CHARACTER: mode = PhysicsServer::BODY_MODE_CHARACTER; reload_axis_lock(); _internal_set_mass(0 == mass ? 1 : mass); scratch_space_override_modificator(); break; - } } btBody->setAngularVelocity(btVector3(0, 0, 0)); @@ -713,15 +739,19 @@ void RigidBodyBullet::set_continuous_collision_detection(bool p_enable) { if (p_enable) { // This threshold enable CCD if the object moves more than // 1 meter in one simulation frame - btBody->setCcdMotionThreshold(1); + btBody->setCcdMotionThreshold(0.1); /// Calculate using the rule writte below the CCD swept sphere radius /// CCD works on an embedded sphere of radius, make sure this radius /// is embedded inside the convex objects, preferably smaller: /// for an object of dimensions 1 meter, try 0.2 - btVector3 center; btScalar radius; - btBody->getCollisionShape()->getBoundingSphere(center, radius); + if (btBody->getCollisionShape()) { + btVector3 center; + btBody->getCollisionShape()->getBoundingSphere(center, radius); + } else { + radius = 0; + } btBody->setCcdSweptSphereRadius(radius * 0.2); } else { btBody->setCcdMotionThreshold(0.); @@ -730,7 +760,7 @@ void RigidBodyBullet::set_continuous_collision_detection(bool p_enable) { } bool RigidBodyBullet::is_continuous_collision_detection_enabled() const { - return 0. != btBody->getCcdMotionThreshold(); + return 0. < btBody->getCcdMotionThreshold(); } void RigidBodyBullet::set_linear_velocity(const Vector3 &p_velocity) { @@ -761,28 +791,14 @@ Vector3 RigidBodyBullet::get_angular_velocity() const { return gVec; } -void RigidBodyBullet::set_combine_mode(const PhysicsServer::BodyParameter p_param, const PhysicsServer::CombineMode p_mode) { - if (p_param == PhysicsServer::BODY_PARAM_BOUNCE) { - restitution_combine_mode = p_mode; - } else { - friction_combine_mode = p_mode; - } -} - -PhysicsServer::CombineMode RigidBodyBullet::get_combine_mode(PhysicsServer::BodyParameter p_param) const { - if (p_param == PhysicsServer::BODY_PARAM_BOUNCE) { - return restitution_combine_mode; - } else { - return friction_combine_mode; - } -} - void RigidBodyBullet::set_transform__bullet(const btTransform &p_global_transform) { if (mode == PhysicsServer::BODY_MODE_KINEMATIC) { + if (space) + btBody->setLinearVelocity((p_global_transform.getOrigin() - btBody->getWorldTransform().getOrigin()) / space->get_delta_time()); // The kinematic use MotionState class godotMotionState->moveBody(p_global_transform); } - btBody->setWorldTransform(p_global_transform); + CollisionObjectBullet::set_transform__bullet(p_global_transform); } const btTransform &RigidBodyBullet::get_transform__bullet() const { @@ -795,15 +811,20 @@ const btTransform &RigidBodyBullet::get_transform__bullet() const { } } -void RigidBodyBullet::on_shapes_changed() { - RigidCollisionObjectBullet::on_shapes_changed(); +void RigidBodyBullet::reload_shapes() { + RigidCollisionObjectBullet::reload_shapes(); const btScalar invMass = btBody->getInvMass(); const btScalar mass = invMass == 0 ? 0 : 1 / invMass; - btVector3 inertia; - btBody->getCollisionShape()->calculateLocalInertia(mass, inertia); - btBody->setMassProps(mass, inertia); + if (mainShape) { + // inertia initialised zero here because some of bullet's collision + // shapes incorrectly do not set the vector in calculateLocalIntertia. + // Arbitrary zero is preferable to undefined behaviour. + btVector3 inertia(0, 0, 0); + mainShape->calculateLocalInertia(mass, inertia); + btBody->setMassProps(mass, inertia); + } btBody->updateInertiaTensor(); reload_kinematic_shapes(); @@ -852,7 +873,7 @@ void RigidBodyBullet::on_exit_area(AreaBullet *p_area) { bool wasTheAreaFound = false; for (int i = 0; i < areaWhereIamCount; ++i) { if (p_area == areasWhereIam[i]) { - // The area was fount, just shift down all elements + // The area was found, just shift down all elements for (int j = i; j < areaWhereIamCount; ++j) { areasWhereIam.write[j] = areasWhereIam[j + 1]; } @@ -927,10 +948,10 @@ void RigidBodyBullet::reload_space_override_modificator() { } switch (currentArea->get_spOv_mode()) { - ///case PhysicsServer::AREA_SPACE_OVERRIDE_DISABLED: - /// This area does not affect gravity/damp. These are generally areas - /// that exist only to detect collisions, and objects entering or exiting them. - /// break; + case PhysicsServer::AREA_SPACE_OVERRIDE_DISABLED: + /// This area does not affect gravity/damp. These are generally areas + /// that exist only to detect collisions, and objects entering or exiting them. + break; case PhysicsServer::AREA_SPACE_OVERRIDE_COMBINE: /// This area adds its gravity/damp values to whatever has been /// calculated so far. This way, many overlapping areas can combine @@ -989,6 +1010,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); @@ -1004,7 +1030,8 @@ void RigidBodyBullet::_internal_set_mass(real_t p_mass) { return; m_isStatic = false; - compoundShape->calculateLocalInertia(p_mass, localInertia); + if (mainShape) + mainShape->calculateLocalInertia(p_mass, localInertia); if (PhysicsServer::BODY_MODE_RIGID == mode) { diff --git a/modules/bullet/rigid_body_bullet.h b/modules/bullet/rigid_body_bullet.h index 35af3b90d8..0696073d21 100644 --- a/modules/bullet/rigid_body_bullet.h +++ b/modules/bullet/rigid_body_bullet.h @@ -202,14 +202,18 @@ private: real_t angularDamp; bool can_sleep; bool omit_forces_integration; - - PhysicsServer::CombineMode restitution_combine_mode; - PhysicsServer::CombineMode friction_combine_mode; + bool can_integrate_forces; Vector<CollisionData> collisions; + Vector<RigidBodyBullet *> collision_traces_1; + Vector<RigidBodyBullet *> collision_traces_2; + Vector<RigidBodyBullet *> *prev_collision_traces; + Vector<RigidBodyBullet *> *curr_collision_traces; + // these parameters are used to avoid vector resize int maxCollisionsDetection; int collisionsCount; + int prev_collision_count; Vector<AreaBullet *> areasWhereIam; // these parameters are used to avoid vector resize @@ -219,7 +223,6 @@ private: int countGravityPointSpaces; bool isScratchedSpaceOverrideModificator; - bool isTransformChanged; bool previousActiveState; // Last check state ForceIntegrationCallback *force_integration_callback; @@ -230,24 +233,34 @@ public: void init_kinematic_utilities(); void destroy_kinematic_utilities(); - _FORCE_INLINE_ class KinematicUtilities *get_kinematic_utilities() const { return kinematic_utilities; } + _FORCE_INLINE_ KinematicUtilities *get_kinematic_utilities() const { return kinematic_utilities; } _FORCE_INLINE_ btRigidBody *get_bt_rigid_body() { return btBody; } + virtual void main_shape_changed(); virtual void reload_body(); virtual void set_space(SpaceBullet *p_space); 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) { + + ERR_FAIL_COND(0 > p_maxCollisionsDetection); + maxCollisionsDetection = p_maxCollisionsDetection; + collisions.resize(p_maxCollisionsDetection); + collision_traces_1.resize(p_maxCollisionsDetection); + collision_traces_2.resize(p_maxCollisionsDetection); + collisionsCount = 0; + prev_collision_count = MIN(prev_collision_count, p_maxCollisionsDetection); } int get_max_collisions_detection() { return maxCollisionsDetection; @@ -255,6 +268,7 @@ public: bool can_add_collision() { return collisionsCount < maxCollisionsDetection; } bool 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); + bool was_colliding(RigidBodyBullet *p_other_object); void assert_no_constraints(); @@ -301,16 +315,10 @@ public: void set_angular_velocity(const Vector3 &p_velocity); Vector3 get_angular_velocity() const; - void set_combine_mode(const PhysicsServer::BodyParameter p_param, const PhysicsServer::CombineMode p_mode); - PhysicsServer::CombineMode get_combine_mode(PhysicsServer::BodyParameter p_param) const; - - _FORCE_INLINE_ PhysicsServer::CombineMode get_restitution_combine_mode() const { return restitution_combine_mode; } - _FORCE_INLINE_ PhysicsServer::CombineMode get_friction_combine_mode() const { return friction_combine_mode; } - virtual void set_transform__bullet(const btTransform &p_global_transform); virtual const btTransform &get_transform__bullet() const; - virtual void on_shapes_changed(); + virtual void reload_shapes(); virtual void on_enter_area(AreaBullet *p_area); virtual void on_exit_area(AreaBullet *p_area); @@ -319,6 +327,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/shape_bullet.cpp b/modules/bullet/shape_bullet.cpp index b05a3015a9..2027d8e1eb 100644 --- a/modules/bullet/shape_bullet.cpp +++ b/modules/bullet/shape_bullet.cpp @@ -34,8 +34,10 @@ #include "bullet_physics_server.h" #include "bullet_types_converter.h" #include "bullet_utilities.h" +#include "core/project_settings.h" #include "shape_owner_bullet.h" +#include <BulletCollision/CollisionDispatch/btInternalEdgeUtility.h> #include <BulletCollision/CollisionShapes/btConvexPointCloudShape.h> #include <BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h> #include <btBulletCollisionCommon.h> @@ -44,25 +46,27 @@ @author AndreaCatania */ -ShapeBullet::ShapeBullet() {} +ShapeBullet::ShapeBullet() : + margin(0.04) {} ShapeBullet::~ShapeBullet() {} -btCollisionShape *ShapeBullet::create_bt_shape(const Vector3 &p_implicit_scale, real_t p_margin) { +btCollisionShape *ShapeBullet::create_bt_shape(const Vector3 &p_implicit_scale, real_t p_extra_edge) { btVector3 s; G_TO_B(p_implicit_scale, s); - return create_bt_shape(s, p_margin); + return create_bt_shape(s, p_extra_edge); } btCollisionShape *ShapeBullet::prepare(btCollisionShape *p_btShape) const { p_btShape->setUserPointer(const_cast<ShapeBullet *>(this)); - p_btShape->setMargin(0.); + p_btShape->setMargin(margin); return p_btShape; } void ShapeBullet::notifyShapeChanged() { for (Map<ShapeOwnerBullet *, int>::Element *E = owners.front(); E; E = E->next()) { - static_cast<ShapeOwnerBullet *>(E->key())->on_shape_changed(this); + ShapeOwnerBullet *owner = static_cast<ShapeOwnerBullet *>(E->key()); + owner->shape_changed(owner->find_shape(this)); } } @@ -93,6 +97,15 @@ const Map<ShapeOwnerBullet *, int> &ShapeBullet::get_owners() const { return owners; } +void ShapeBullet::set_margin(real_t p_margin) { + margin = p_margin; + notifyShapeChanged(); +} + +real_t ShapeBullet::get_margin() const { + return margin; +} + btEmptyShape *ShapeBullet::create_shape_empty() { return bulletnew(btEmptyShape); } @@ -166,7 +179,7 @@ void PlaneShapeBullet::setup(const Plane &p_plane) { notifyShapeChanged(); } -btCollisionShape *PlaneShapeBullet::create_bt_shape(const btVector3 &p_implicit_scale, real_t p_margin) { +btCollisionShape *PlaneShapeBullet::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)); @@ -194,8 +207,8 @@ void SphereShapeBullet::setup(real_t p_radius) { notifyShapeChanged(); } -btCollisionShape *SphereShapeBullet::create_bt_shape(const btVector3 &p_implicit_scale, real_t p_margin) { - return prepare(ShapeBullet::create_shape_sphere(radius * p_implicit_scale[0] + p_margin)); +btCollisionShape *SphereShapeBullet::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)); } /* Box */ @@ -221,8 +234,8 @@ void BoxShapeBullet::setup(const Vector3 &p_half_extents) { notifyShapeChanged(); } -btCollisionShape *BoxShapeBullet::create_bt_shape(const btVector3 &p_implicit_scale, real_t p_margin) { - return prepare(ShapeBullet::create_shape_box((half_extents * p_implicit_scale) + btVector3(p_margin, p_margin, p_margin))); +btCollisionShape *BoxShapeBullet::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))); } /* Capsule */ @@ -254,8 +267,8 @@ 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_margin) { - return prepare(ShapeBullet::create_shape_capsule(radius * p_implicit_scale[0] + p_margin, height * p_implicit_scale[1] + p_margin)); +btCollisionShape *CapsuleShapeBullet::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)); } /* Cylinder */ @@ -329,11 +342,13 @@ void ConvexPolygonShapeBullet::setup(const Vector<Vector3> &p_vertices) { notifyShapeChanged(); } -btCollisionShape *ConvexPolygonShapeBullet::create_bt_shape(const btVector3 &p_implicit_scale, real_t p_margin) { +btCollisionShape *ConvexPolygonShapeBullet::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()); btCollisionShape *cs(ShapeBullet::create_shape_convex(vertices)); cs->setLocalScaling(p_implicit_scale); prepare(cs); - cs->setMargin(p_margin); return cs; } @@ -346,7 +361,8 @@ ConcavePolygonShapeBullet::ConcavePolygonShapeBullet() : ConcavePolygonShapeBullet::~ConcavePolygonShapeBullet() { if (meshShape) { delete meshShape->getMeshInterface(); - delete meshShape; + delete meshShape->getTriangleInfoMap(); + bulletdelete(meshShape); } faces = PoolVector<Vector3>(); } @@ -368,6 +384,7 @@ void ConcavePolygonShapeBullet::setup(PoolVector<Vector3> p_faces) { if (meshShape) { /// Clear previous created shape delete meshShape->getMeshInterface(); + delete meshShape->getTriangleInfoMap(); bulletdelete(meshShape); } int src_face_count = faces.size(); @@ -385,16 +402,22 @@ void ConcavePolygonShapeBullet::setup(PoolVector<Vector3> p_faces) { btVector3 supVec_1; btVector3 supVec_2; for (int i = 0; i < src_face_count; ++i) { - G_TO_B(facesr[i * 3], supVec_0); + G_TO_B(facesr[i * 3 + 0], supVec_0); G_TO_B(facesr[i * 3 + 1], supVec_1); G_TO_B(facesr[i * 3 + 2], supVec_2); - shapeInterface->addTriangle(supVec_0, supVec_1, supVec_2); + // Inverted from standard godot otherwise btGenerateInternalEdgeInfo generates wrong edge info + shapeInterface->addTriangle(supVec_2, supVec_1, supVec_0); } const bool useQuantizedAabbCompression = true; meshShape = bulletnew(btBvhTriangleMeshShape(shapeInterface, useQuantizedAabbCompression)); + + if (GLOBAL_DEF("physics/3d/smooth_trimesh_collision", false)) { + btTriangleInfoMap *triangleInfoMap = new btTriangleInfoMap(); + btGenerateInternalEdgeInfo(meshShape, triangleInfoMap); + } } else { meshShape = NULL; ERR_PRINT("The faces count are 0, the mesh shape cannot be created"); @@ -402,14 +425,14 @@ void ConcavePolygonShapeBullet::setup(PoolVector<Vector3> p_faces) { notifyShapeChanged(); } -btCollisionShape *ConcavePolygonShapeBullet::create_bt_shape(const btVector3 &p_implicit_scale, real_t p_margin) { +btCollisionShape *ConcavePolygonShapeBullet::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 cs = ShapeBullet::create_shape_empty(); cs->setLocalScaling(p_implicit_scale); prepare(cs); - cs->setMargin(p_margin); + cs->setMargin(0); return cs; } @@ -524,11 +547,10 @@ void HeightMapShapeBullet::setup(PoolVector<real_t> &p_heights, int p_width, int notifyShapeChanged(); } -btCollisionShape *HeightMapShapeBullet::create_bt_shape(const btVector3 &p_implicit_scale, real_t p_margin) { +btCollisionShape *HeightMapShapeBullet::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); - cs->setMargin(p_margin); return cs; } @@ -562,6 +584,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_margin) { - return prepare(ShapeBullet::create_shape_ray(length * p_implicit_scale[1] + p_margin, slips_on_slope)); +btCollisionShape *RayShapeBullet::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)); } diff --git a/modules/bullet/shape_bullet.h b/modules/bullet/shape_bullet.h index 16a5ac1fc6..9a1c8f5bfa 100644 --- a/modules/bullet/shape_bullet.h +++ b/modules/bullet/shape_bullet.h @@ -31,8 +31,8 @@ #ifndef SHAPE_BULLET_H #define SHAPE_BULLET_H +#include "core/math/geometry.h" #include "core/variant.h" -#include "geometry.h" #include "rid_bullet.h" #include "servers/physics_server.h" @@ -52,6 +52,7 @@ class btBvhTriangleMeshShape; class ShapeBullet : public RIDBullet { Map<ShapeOwnerBullet *, int> owners; + real_t margin; protected: /// return self @@ -62,14 +63,17 @@ public: ShapeBullet(); virtual ~ShapeBullet(); - btCollisionShape *create_bt_shape(const Vector3 &p_implicit_scale, real_t p_margin = 0); - virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_margin = 0) = 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; void add_owner(ShapeOwnerBullet *p_owner); void remove_owner(ShapeOwnerBullet *p_owner, bool p_permanentlyFromThisBody = false); bool is_owner(ShapeOwnerBullet *p_owner) const; const Map<ShapeOwnerBullet *, int> &get_owners() const; + void set_margin(real_t p_margin); + real_t get_margin() const; + /// Setup the shape virtual void set_data(const Variant &p_data) = 0; virtual Variant get_data() const = 0; @@ -100,7 +104,7 @@ public: virtual void set_data(const Variant &p_data); virtual Variant get_data() const; virtual PhysicsServer::ShapeType get_type() const; - virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_margin = 0); + virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge = 0); private: void setup(const Plane &p_plane); @@ -117,7 +121,7 @@ public: virtual void set_data(const Variant &p_data); virtual Variant get_data() const; virtual PhysicsServer::ShapeType get_type() const; - virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_margin = 0); + virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge = 0); private: void setup(real_t p_radius); @@ -134,7 +138,7 @@ public: virtual void set_data(const Variant &p_data); virtual Variant get_data() const; virtual PhysicsServer::ShapeType get_type() const; - virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_margin = 0); + virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge = 0); private: void setup(const Vector3 &p_half_extents); @@ -153,7 +157,7 @@ public: virtual void set_data(const Variant &p_data); virtual Variant get_data() const; virtual PhysicsServer::ShapeType get_type() const; - virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_margin = 0); + virtual btCollisionShape *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); @@ -189,7 +193,7 @@ public: void get_vertices(Vector<Vector3> &out_vertices); virtual Variant get_data() const; virtual PhysicsServer::ShapeType get_type() const; - virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_margin = 0); + virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge = 0); private: void setup(const Vector<Vector3> &p_vertices); @@ -207,7 +211,7 @@ public: virtual void set_data(const Variant &p_data); virtual Variant get_data() const; virtual PhysicsServer::ShapeType get_type() const; - virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_margin = 0); + virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge = 0); private: void setup(PoolVector<Vector3> p_faces); @@ -227,7 +231,7 @@ public: virtual void set_data(const Variant &p_data); virtual Variant get_data() const; virtual PhysicsServer::ShapeType get_type() const; - virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_margin = 0); + virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge = 0); private: void setup(PoolVector<real_t> &p_heights, int p_width, int p_depth, real_t p_min_height, real_t p_max_height); @@ -244,7 +248,7 @@ public: virtual void set_data(const Variant &p_data); virtual Variant get_data() const; virtual PhysicsServer::ShapeType get_type() const; - virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_margin = 0); + virtual btCollisionShape *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); diff --git a/modules/bullet/shape_owner_bullet.h b/modules/bullet/shape_owner_bullet.h index 29d42d12f2..72ddbc482c 100644 --- a/modules/bullet/shape_owner_bullet.h +++ b/modules/bullet/shape_owner_bullet.h @@ -45,11 +45,10 @@ class CollisionObjectBullet; /// E.G. BodyShape is a child of this class ShapeOwnerBullet { public: - /// This is used to set new shape or replace existing - //virtual void _internal_replaceShape(btCollisionShape *p_old_shape, btCollisionShape *p_new_shape) = 0; - virtual void on_shape_changed(const ShapeBullet *const p_shape) = 0; - virtual void on_shapes_changed() = 0; - virtual void remove_shape(class ShapeBullet *p_shape) = 0; + virtual int find_shape(ShapeBullet *p_shape) const = 0; + virtual void shape_changed(int p_shape_index) = 0; + virtual void reload_shapes() = 0; + virtual void remove_shape_full(class ShapeBullet *p_shape) = 0; virtual ~ShapeOwnerBullet() {} }; #endif diff --git a/modules/bullet/slider_joint_bullet.cpp b/modules/bullet/slider_joint_bullet.cpp index 9e1cd23989..9016ec3bf5 100644 --- a/modules/bullet/slider_joint_bullet.cpp +++ b/modules/bullet/slider_joint_bullet.cpp @@ -366,6 +366,7 @@ void SliderJointBullet::set_param(PhysicsServer::SliderJointParam p_param, real_ case PhysicsServer::SLIDER_JOINT_ANGULAR_ORTHOGONAL_SOFTNESS: setSoftnessOrthoAng(p_value); break; case PhysicsServer::SLIDER_JOINT_ANGULAR_ORTHOGONAL_RESTITUTION: setRestitutionOrthoAng(p_value); break; case PhysicsServer::SLIDER_JOINT_ANGULAR_ORTHOGONAL_DAMPING: setDampingOrthoAng(p_value); break; + case PhysicsServer::SLIDER_JOINT_MAX: break; // Can't happen, but silences warning } } diff --git a/modules/bullet/soft_body_bullet.cpp b/modules/bullet/soft_body_bullet.cpp index 9fc7230f91..94f350210f 100644 --- a/modules/bullet/soft_body_bullet.cpp +++ b/modules/bullet/soft_body_bullet.cpp @@ -37,17 +37,17 @@ SoftBodyBullet::SoftBodyBullet() : CollisionObjectBullet(CollisionObjectBullet::TYPE_SOFT_BODY), - total_mass(1), + bt_soft_body(NULL), + isScratched(false), simulation_precision(5), + total_mass(1.), linear_stiffness(0.5), areaAngular_stiffness(0.5), volume_stiffness(0.5), pressure_coefficient(0.), pose_matching_coefficient(0.), damping_coefficient(0.01), - drag_coefficient(0.), - bt_soft_body(NULL), - isScratched(false) {} + drag_coefficient(0.) {} SoftBodyBullet::~SoftBodyBullet() { } @@ -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 8454bea4eb..fed12cd5ed 100644 --- a/modules/bullet/space_bullet.cpp +++ b/modules/bullet/space_bullet.cpp @@ -34,13 +34,13 @@ #include "bullet_types_converter.h" #include "bullet_utilities.h" #include "constraint_bullet.h" +#include "core/project_settings.h" +#include "core/ustring.h" #include "godot_collision_configuration.h" #include "godot_collision_dispatcher.h" -#include "project_settings.h" #include "rigid_body_bullet.h" #include "servers/physics_server.h" #include "soft_body_bullet.h" -#include "ustring.h" #include <BulletCollision/CollisionDispatch/btCollisionObject.h> #include <BulletCollision/CollisionDispatch/btGhostObject.h> @@ -61,7 +61,7 @@ BulletPhysicsDirectSpaceState::BulletPhysicsDirectSpaceState(SpaceBullet *p_spac PhysicsDirectSpaceState(), space(p_space) {} -int BulletPhysicsDirectSpaceState::intersect_point(const Vector3 &p_point, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude, uint32_t p_collision_mask) { +int BulletPhysicsDirectSpaceState::intersect_point(const Vector3 &p_point, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) { if (p_result_max <= 0) return 0; @@ -69,13 +69,13 @@ int BulletPhysicsDirectSpaceState::intersect_point(const Vector3 &p_point, Shape btVector3 bt_point; G_TO_B(p_point, bt_point); - btSphereShape sphere_point(0.f); + btSphereShape sphere_point(0.001f); btCollisionObject collision_object_point; collision_object_point.setCollisionShape(&sphere_point); collision_object_point.setWorldTransform(btTransform(btQuaternion::getIdentity(), bt_point)); // Setup query - GodotAllContactResultCallback btResult(&collision_object_point, r_results, p_result_max, &p_exclude); + GodotAllContactResultCallback btResult(&collision_object_point, r_results, p_result_max, &p_exclude, p_collide_with_bodies, p_collide_with_areas); btResult.m_collisionFilterGroup = 0; btResult.m_collisionFilterMask = p_collision_mask; space->dynamicsWorld->contactTest(&collision_object_point, btResult); @@ -84,7 +84,7 @@ int BulletPhysicsDirectSpaceState::intersect_point(const Vector3 &p_point, Shape return btResult.m_count; } -bool BulletPhysicsDirectSpaceState::intersect_ray(const Vector3 &p_from, const Vector3 &p_to, RayResult &r_result, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_pick_ray) { +bool BulletPhysicsDirectSpaceState::intersect_ray(const Vector3 &p_from, const Vector3 &p_to, RayResult &r_result, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas, bool p_pick_ray) { btVector3 btVec_from; btVector3 btVec_to; @@ -93,7 +93,7 @@ bool BulletPhysicsDirectSpaceState::intersect_ray(const Vector3 &p_from, const V G_TO_B(p_to, btVec_to); // setup query - GodotClosestRayResultCallback btResult(btVec_from, btVec_to, &p_exclude); + GodotClosestRayResultCallback btResult(btVec_from, btVec_to, &p_exclude, p_collide_with_bodies, p_collide_with_areas); btResult.m_collisionFilterGroup = 0; btResult.m_collisionFilterMask = p_collision_mask; btResult.m_pickRay = p_pick_ray; @@ -117,7 +117,7 @@ bool BulletPhysicsDirectSpaceState::intersect_ray(const Vector3 &p_from, const V } } -int BulletPhysicsDirectSpaceState::intersect_shape(const RID &p_shape, const Transform &p_xform, float p_margin, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude, uint32_t p_collision_mask) { +int BulletPhysicsDirectSpaceState::intersect_shape(const RID &p_shape, const Transform &p_xform, float p_margin, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) { if (p_result_max <= 0) return 0; @@ -139,7 +139,7 @@ int BulletPhysicsDirectSpaceState::intersect_shape(const RID &p_shape, const Tra collision_object.setCollisionShape(btConvex); collision_object.setWorldTransform(bt_xform); - GodotAllContactResultCallback btQuery(&collision_object, r_results, p_result_max, &p_exclude); + GodotAllContactResultCallback btQuery(&collision_object, r_results, p_result_max, &p_exclude, p_collide_with_bodies, p_collide_with_areas); btQuery.m_collisionFilterGroup = 0; btQuery.m_collisionFilterMask = p_collision_mask; btQuery.m_closestDistanceThreshold = 0; @@ -150,14 +150,14 @@ int BulletPhysicsDirectSpaceState::intersect_shape(const RID &p_shape, const Tra return btQuery.m_count; } -bool BulletPhysicsDirectSpaceState::cast_motion(const RID &p_shape, const Transform &p_xform, const Vector3 &p_motion, float p_margin, float &p_closest_safe, float &p_closest_unsafe, const Set<RID> &p_exclude, uint32_t p_collision_mask, ShapeRestInfo *r_info) { +bool BulletPhysicsDirectSpaceState::cast_motion(const RID &p_shape, const Transform &p_xform, const Vector3 &p_motion, float p_margin, float &r_closest_safe, float &r_closest_unsafe, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas, ShapeRestInfo *r_info) { ShapeBullet *shape = space->get_physics_server()->get_shape_owner()->get(p_shape); btCollisionShape *btShape = shape->create_bt_shape(p_xform.basis.get_scale(), p_margin); if (!btShape->isConvex()) { bulletdelete(btShape); ERR_PRINTS("The shape is not a convex shape, then is not supported: shape type: " + itos(shape->get_type())); - return 0; + return false; } btConvexShape *bt_convex_shape = static_cast<btConvexShape *>(btShape); @@ -171,14 +171,19 @@ bool BulletPhysicsDirectSpaceState::cast_motion(const RID &p_shape, const Transf btTransform bt_xform_to(bt_xform_from); bt_xform_to.getOrigin() += bt_motion; - GodotClosestConvexResultCallback btResult(bt_xform_from.getOrigin(), bt_xform_to.getOrigin(), &p_exclude); + GodotClosestConvexResultCallback btResult(bt_xform_from.getOrigin(), bt_xform_to.getOrigin(), &p_exclude, p_collide_with_bodies, p_collide_with_areas); btResult.m_collisionFilterGroup = 0; btResult.m_collisionFilterMask = p_collision_mask; - space->dynamicsWorld->convexSweepTest(bt_convex_shape, bt_xform_from, bt_xform_to, btResult, 0.002); + space->dynamicsWorld->convexSweepTest(bt_convex_shape, bt_xform_from, bt_xform_to, btResult, space->dynamicsWorld->getDispatchInfo().m_allowedCcdPenetration); + + r_closest_unsafe = 1.0; + r_closest_safe = 1.0; if (btResult.hasHit()) { - p_closest_safe = p_closest_unsafe = btResult.m_closestHitFraction; + const btScalar l = bt_motion.length(); + r_closest_unsafe = btResult.m_closestHitFraction; + r_closest_safe = MAX(r_closest_unsafe - (1 - ((l - 0.01) / l)), 0); if (r_info) { if (btCollisionObject::CO_RIGID_BODY == btResult.m_hitCollisionObject->getInternalType()) { B_TO_G(static_cast<const btRigidBody *>(btResult.m_hitCollisionObject)->getVelocityInLocalPoint(btResult.m_hitPointWorld), r_info->linear_velocity); @@ -193,11 +198,11 @@ bool BulletPhysicsDirectSpaceState::cast_motion(const RID &p_shape, const Transf } bulletdelete(bt_convex_shape); - return btResult.hasHit(); + return true; // Mean success } /// Returns the list of contacts pairs in this order: Local contact, other body contact -bool BulletPhysicsDirectSpaceState::collide_shape(RID p_shape, const Transform &p_shape_xform, float p_margin, Vector3 *r_results, int p_result_max, int &r_result_count, const Set<RID> &p_exclude, uint32_t p_collision_mask) { +bool BulletPhysicsDirectSpaceState::collide_shape(RID p_shape, const Transform &p_shape_xform, float p_margin, Vector3 *r_results, int p_result_max, int &r_result_count, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) { if (p_result_max <= 0) return 0; @@ -219,7 +224,7 @@ bool BulletPhysicsDirectSpaceState::collide_shape(RID p_shape, const Transform & collision_object.setCollisionShape(btConvex); collision_object.setWorldTransform(bt_xform); - GodotContactPairContactResultCallback btQuery(&collision_object, r_results, p_result_max, &p_exclude); + GodotContactPairContactResultCallback btQuery(&collision_object, r_results, p_result_max, &p_exclude, p_collide_with_bodies, p_collide_with_areas); btQuery.m_collisionFilterGroup = 0; btQuery.m_collisionFilterMask = p_collision_mask; btQuery.m_closestDistanceThreshold = 0; @@ -231,7 +236,7 @@ bool BulletPhysicsDirectSpaceState::collide_shape(RID p_shape, const Transform & return btQuery.m_count; } -bool BulletPhysicsDirectSpaceState::rest_info(RID p_shape, const Transform &p_shape_xform, float p_margin, ShapeRestInfo *r_info, const Set<RID> &p_exclude, uint32_t p_collision_mask) { +bool BulletPhysicsDirectSpaceState::rest_info(RID p_shape, const Transform &p_shape_xform, float p_margin, ShapeRestInfo *r_info, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) { ShapeBullet *shape = space->get_physics_server()->get_shape_owner()->get(p_shape); @@ -251,7 +256,7 @@ bool BulletPhysicsDirectSpaceState::rest_info(RID p_shape, const Transform &p_sh collision_object.setCollisionShape(btConvex); collision_object.setWorldTransform(bt_xform); - GodotRestInfoContactResultCallback btQuery(&collision_object, r_info, &p_exclude); + GodotRestInfoContactResultCallback btQuery(&collision_object, r_info, &p_exclude, p_collide_with_bodies, p_collide_with_areas); btQuery.m_collisionFilterGroup = 0; btQuery.m_collisionFilterMask = p_collision_mask; btQuery.m_closestDistanceThreshold = 0; @@ -293,11 +298,10 @@ Vector3 BulletPhysicsDirectSpaceState::get_closest_point_to_object_volume(RID p_ bool shapes_found = false; - btCompoundShape *compound = rigid_object->get_compound_shape(); - for (int i = compound->getNumChildShapes() - 1; 0 <= i; --i) { - shape = compound->getChildShape(i); + for (int i = rigid_object->get_shape_count() - 1; 0 <= i; --i) { + shape = rigid_object->get_bt_shape(i); if (shape->isConvex()) { - child_transform = compound->getChildTransform(i); + child_transform = rigid_object->get_bt_shape_transform(i); convex_shape = static_cast<btConvexShape *>(shape); input.m_transformB = body_transform * child_transform; @@ -328,16 +332,17 @@ Vector3 BulletPhysicsDirectSpaceState::get_closest_point_to_object_volume(RID p_ SpaceBullet::SpaceBullet() : broadphase(NULL), + collisionConfiguration(NULL), dispatcher(NULL), solver(NULL), - collisionConfiguration(NULL), dynamicsWorld(NULL), soft_body_world_info(NULL), ghostPairCallback(NULL), godotFilterCallback(NULL), gravityDirection(0, -1, 0), gravityMagnitude(10), - contactDebugCount(0) { + contactDebugCount(0), + delta_time(0.) { create_empty_world(GLOBAL_DEF("physics/3d/active_soft_world", true)); direct_access = memnew(BulletPhysicsDirectSpaceState(this)); @@ -535,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() { @@ -554,49 +562,18 @@ BulletPhysicsDirectSpaceState *SpaceBullet::get_direct_state() { btScalar calculateGodotCombinedRestitution(const btCollisionObject *body0, const btCollisionObject *body1) { - const PhysicsServer::CombineMode cm = static_cast<RigidBodyBullet *>(body0->getUserPointer())->get_restitution_combine_mode(); - - switch (cm) { - case PhysicsServer::COMBINE_MODE_INHERIT: - if (static_cast<RigidBodyBullet *>(body1->getUserPointer())->get_restitution_combine_mode() != PhysicsServer::COMBINE_MODE_INHERIT) - return calculateGodotCombinedRestitution(body1, body0); - // else use MAX [This is used when the two bodies doesn't use physical material] - case PhysicsServer::COMBINE_MODE_MAX: - return MAX(body0->getRestitution(), body1->getRestitution()); - case PhysicsServer::COMBINE_MODE_MIN: - return MIN(body0->getRestitution(), body1->getRestitution()); - case PhysicsServer::COMBINE_MODE_MULTIPLY: - return body0->getRestitution() * body1->getRestitution(); - default: // Is always PhysicsServer::COMBINE_MODE_AVERAGE: - return (body0->getRestitution() + body1->getRestitution()) / 2; - } + return CLAMP(body0->getRestitution() + body1->getRestitution(), 0, 1); } btScalar calculateGodotCombinedFriction(const btCollisionObject *body0, const btCollisionObject *body1) { - const PhysicsServer::CombineMode cm = static_cast<RigidBodyBullet *>(body0->getUserPointer())->get_friction_combine_mode(); - - switch (cm) { - case PhysicsServer::COMBINE_MODE_INHERIT: - if (static_cast<RigidBodyBullet *>(body1->getUserPointer())->get_friction_combine_mode() != PhysicsServer::COMBINE_MODE_INHERIT) - return calculateGodotCombinedFriction(body1, body0); - // else use MULTIPLY [This is used when the two bodies doesn't use physical material] - case PhysicsServer::COMBINE_MODE_MULTIPLY: - return body0->getFriction() * body1->getFriction(); - case PhysicsServer::COMBINE_MODE_MAX: - return MAX(body0->getFriction(), body1->getFriction()); - case PhysicsServer::COMBINE_MODE_MIN: - return MIN(body0->getFriction(), body1->getFriction()); - default: // Is always PhysicsServer::COMBINE_MODE_AVERAGE: - return (body0->getFriction() * body1->getFriction()) / 2; - } + return ABS(MIN(body0->getFriction(), body1->getFriction())); } void SpaceBullet::create_empty_world(bool p_create_soft_world) { gjk_epa_pen_solver = bulletnew(btGjkEpaPenetrationDepthSolver); gjk_simplex_solver = bulletnew(btVoronoiSimplexSolver); - gjk_simplex_solver->setEqualVertexThreshold(0.f); void *world_mem; if (p_create_soft_world) { @@ -606,7 +583,7 @@ void SpaceBullet::create_empty_world(bool p_create_soft_world) { } if (p_create_soft_world) { - collisionConfiguration = bulletnew(btSoftBodyRigidBodyCollisionConfiguration); + collisionConfiguration = bulletnew(GodotSoftCollisionConfiguration(static_cast<btDiscreteDynamicsWorld *>(world_mem))); } else { collisionConfiguration = bulletnew(GodotCollisionConfiguration(static_cast<btDiscreteDynamicsWorld *>(world_mem))); } @@ -626,6 +603,7 @@ void SpaceBullet::create_empty_world(bool p_create_soft_world) { godotFilterCallback = bulletnew(GodotFilterCallback); gCalculateCombinedRestitutionCallback = &calculateGodotCombinedRestitution; gCalculateCombinedFrictionCallback = &calculateGodotCombinedFriction; + gContactAddedCallback = &godotContactAddedCallback; dynamicsWorld->setWorldUserInfo(this); @@ -670,11 +648,10 @@ void SpaceBullet::destroy_world() { void SpaceBullet::check_ghost_overlaps() { /// Algorithm support variables - btConvexShape *other_body_shape; + btCollisionShape *other_body_shape; 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 @@ -701,41 +678,67 @@ 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; // For each area shape - for (y = area->get_compound_shape()->getNumChildShapes() - 1; 0 <= y; --y) { - if (!area->get_compound_shape()->getChildShape(y)->isConvex()) + for (y = area->get_shape_count() - 1; 0 <= y; --y) { + if (!area->get_bt_shape(y)->isConvex()) continue; - gjk_input.m_transformA = area->get_transform__bullet() * area->get_compound_shape()->getChildTransform(y); - area_shape = static_cast<btConvexShape *>(area->get_compound_shape()->getChildShape(y)); + gjk_input.m_transformA = area->get_transform__bullet() * area->get_bt_shape_transform(y); + area_shape = static_cast<btConvexShape *>(area->get_bt_shape(y)); // For each other object shape - for (z = otherObject->get_compound_shape()->getNumChildShapes() - 1; 0 <= z; --z) { + for (z = otherObject->get_shape_count() - 1; 0 <= z; --z) { + + other_body_shape = static_cast<btCollisionShape *>(otherObject->get_bt_shape(z)); + gjk_input.m_transformB = otherObject->get_transform__bullet() * otherObject->get_bt_shape_transform(z); + + if (other_body_shape->isConvex()) { - if (!otherObject->get_compound_shape()->getChildShape(z)->isConvex()) - continue; + btPointCollector result; + btGjkPairDetector gjk_pair_detector(area_shape, static_cast<btConvexShape *>(other_body_shape), gjk_simplex_solver, gjk_epa_pen_solver); + gjk_pair_detector.getClosestPoints(gjk_input, result, 0); + + if (0 >= result.m_distance) { + hasOverlap = true; + goto collision_found; + } + + } else { - other_body_shape = static_cast<btConvexShape *>(otherObject->get_compound_shape()->getChildShape(z)); - gjk_input.m_transformB = otherObject->get_transform__bullet() * otherObject->get_compound_shape()->getChildTransform(z); + btCollisionObjectWrapper obA(NULL, area_shape, area->get_bt_ghost(), gjk_input.m_transformA, -1, y); + btCollisionObjectWrapper obB(NULL, other_body_shape, otherObject->get_bt_collision_object(), gjk_input.m_transformB, -1, z); - btPointCollector result; - btGjkPairDetector gjk_pair_detector(area_shape, other_body_shape, gjk_simplex_solver, gjk_epa_pen_solver); - gjk_pair_detector.getClosestPoints(gjk_input, result, 0); + btCollisionAlgorithm *algorithm = dispatcher->findAlgorithm(&obA, &obB, NULL, BT_CONTACT_POINT_ALGORITHMS); - if (0 >= result.m_distance) { - hasOverlap = true; - goto collision_found; + if (!algorithm) + continue; + + GodotDeepPenetrationContactResultCallback contactPointResult(&obA, &obB); + algorithm->processCollision(&obA, &obB, dynamicsWorld->getDispatchInfo(), &contactPointResult); + + algorithm->~btCollisionAlgorithm(); + dispatcher->freeCollisionAlgorithm(algorithm); + + if (contactPointResult.hasHit()) { + hasOverlap = true; + goto collision_found; + } } + } // ~For each other object shape } // ~For each area shape @@ -783,39 +786,47 @@ void SpaceBullet::check_body_collision() { } const int numContacts = contactManifold->getNumContacts(); + + /// Since I don't need report all contacts for these objects, + /// So report only the first #define REPORT_ALL_CONTACTS 0 #if REPORT_ALL_CONTACTS for (int j = 0; j < numContacts; j++) { btManifoldPoint &pt = contactManifold->getContactPoint(j); #else - // Since I don't need report all contacts for these objects, I'll report only the first if (numContacts) { btManifoldPoint &pt = contactManifold->getContactPoint(0); #endif - Vector3 collisionWorldPosition; - Vector3 collisionLocalPosition; - Vector3 normalOnB; - float appliedImpulse = pt.m_appliedImpulse; - B_TO_G(pt.m_normalWorldOnB, normalOnB); - - if (bodyA->can_add_collision()) { - B_TO_G(pt.getPositionWorldOnB(), collisionWorldPosition); - /// pt.m_localPointB Doesn't report the exact point in local space - B_TO_G(pt.getPositionWorldOnB() - contactManifold->getBody1()->getWorldTransform().getOrigin(), collisionLocalPosition); - bodyA->add_collision_object(bodyB, collisionWorldPosition, collisionLocalPosition, normalOnB, appliedImpulse, pt.m_index1, pt.m_index0); - } - if (bodyB->can_add_collision()) { - B_TO_G(pt.getPositionWorldOnA(), collisionWorldPosition); - /// pt.m_localPointA Doesn't report the exact point in local space - B_TO_G(pt.getPositionWorldOnA() - contactManifold->getBody0()->getWorldTransform().getOrigin(), collisionLocalPosition); - bodyB->add_collision_object(bodyA, collisionWorldPosition, collisionLocalPosition, normalOnB * -1, appliedImpulse * -1, pt.m_index0, pt.m_index1); - } + if ( + pt.getDistance() <= 0.0 || + bodyA->was_colliding(bodyB) || + bodyB->was_colliding(bodyA)) { + + Vector3 collisionWorldPosition; + Vector3 collisionLocalPosition; + Vector3 normalOnB; + float appliedImpulse = pt.m_appliedImpulse; + B_TO_G(pt.m_normalWorldOnB, normalOnB); + + if (bodyA->can_add_collision()) { + B_TO_G(pt.getPositionWorldOnB(), collisionWorldPosition); + /// pt.m_localPointB Doesn't report the exact point in local space + B_TO_G(pt.getPositionWorldOnB() - contactManifold->getBody1()->getWorldTransform().getOrigin(), collisionLocalPosition); + bodyA->add_collision_object(bodyB, collisionWorldPosition, collisionLocalPosition, normalOnB, appliedImpulse, pt.m_index1, pt.m_index0); + } + if (bodyB->can_add_collision()) { + B_TO_G(pt.getPositionWorldOnA(), collisionWorldPosition); + /// pt.m_localPointA Doesn't report the exact point in local space + B_TO_G(pt.getPositionWorldOnA() - contactManifold->getBody0()->getWorldTransform().getOrigin(), collisionLocalPosition); + bodyB->add_collision_object(bodyA, collisionWorldPosition, collisionLocalPosition, normalOnB * -1, appliedImpulse * -1, pt.m_index0, pt.m_index1); + } #ifdef DEBUG_ENABLED - if (is_debugging_contacts()) { - add_debug_contact(collisionWorldPosition); - } + if (is_debugging_contacts()) { + add_debug_contact(collisionWorldPosition); + } #endif + } } } } @@ -849,7 +860,7 @@ static Ref<SpatialMaterial> red_mat; static Ref<SpatialMaterial> blue_mat; #endif -bool SpaceBullet::test_body_motion(RigidBodyBullet *p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, PhysicsServer::MotionResult *r_result) { +bool SpaceBullet::test_body_motion(RigidBodyBullet *p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, PhysicsServer::MotionResult *r_result, bool p_exclude_raycast_shapes) { #if debug_test_motion /// Yes I know this is not good, but I've used it as fast debugging hack. @@ -924,6 +935,12 @@ bool SpaceBullet::test_body_motion(RigidBodyBullet *p_body, const Transform &p_f // Skip no convex shape continue; } + + if (p_exclude_raycast_shapes && p_body->get_bt_shape(shIndex)->getShapeType() == CUSTOM_CONVEX_SHAPE_TYPE) { + // Skip rayshape in order to implement custom separation process + continue; + } + btConvexShape *convex_shape_test(static_cast<btConvexShape *>(p_body->get_bt_shape(shIndex))); btTransform shape_world_from = body_transform * p_body->get_kinematic_utilities()->shapes[shIndex].transform; @@ -954,11 +971,11 @@ bool SpaceBullet::test_body_motion(RigidBodyBullet *p_body, const Transform &p_f btVector3 __rec(0, 0, 0); RecoverResult r_recover_result; - has_penetration = recover_from_penetration(p_body, body_transform, 0, p_infinite_inertia, __rec, &r_recover_result); + has_penetration = recover_from_penetration(p_body, body_transform, 1, p_infinite_inertia, __rec, &r_recover_result); // Parse results if (r_result) { - B_TO_G(motion + initial_recover_motion, r_result->motion); + B_TO_G(motion + initial_recover_motion + __rec, r_result->motion); if (has_penetration) { @@ -994,6 +1011,39 @@ bool SpaceBullet::test_body_motion(RigidBodyBullet *p_body, const Transform &p_f return has_penetration; } +int SpaceBullet::test_ray_separation(RigidBodyBullet *p_body, const Transform &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, PhysicsServer::SeparationResult *r_results, int p_result_max, float p_margin) { + + btTransform body_transform; + G_TO_B(p_transform, body_transform); + UNSCALE_BT_BASIS(body_transform); + + btVector3 recover_motion(0, 0, 0); + + int rays_found = 0; + + for (int t(RECOVERING_MOVEMENT_CYCLES); 0 < t; --t) { + int last_ray_index = recover_from_penetration_ray(p_body, body_transform, RECOVERING_MOVEMENT_SCALE, p_infinite_inertia, p_result_max, recover_motion, r_results); + + rays_found = MAX(last_ray_index, rays_found); + if (!rays_found) { + break; + } else { + body_transform.getOrigin() += recover_motion; + } + } + + //optimize results (remove non colliding) + for (int i = 0; i < rays_found; i++) { + if (r_results[i].collision_depth >= 0) { + rays_found--; + SWAP(r_results[i], r_results[rays_found]); + } + } + + B_TO_G(recover_motion, r_recover_motion); + return rays_found; +} + struct RecoverPenetrationBroadPhaseCallback : public btBroadphaseAabbCallback { private: const btCollisionObject *self_collision_object; @@ -1050,6 +1100,11 @@ bool SpaceBullet::recover_from_penetration(RigidBodyBullet *p_body, const btTran continue; } + if (kin_shape.shape->getShapeType() == CUSTOM_CONVEX_SHAPE_TYPE) { + // Skip rayshape in order to implement custom separation process + continue; + } + body_shape_position = p_body_position * kin_shape.transform; body_shape_position_recovered = body_shape_position; body_shape_position_recovered.getOrigin() += r_delta_recover_movement; @@ -1152,7 +1207,6 @@ bool SpaceBullet::RFP_convex_world_test(const btConvexShape *p_shapeA, const btC if (contactPointResult.hasHit()) { r_delta_recover_movement += contactPointResult.m_pointNormalWorld * (contactPointResult.m_penetration_distance * -1 * p_recover_movement_scale); - if (r_recover_result) { if (contactPointResult.m_penetration_distance < r_recover_result->penetration_distance) { r_recover_result->hasPenetration = true; @@ -1168,3 +1222,79 @@ bool SpaceBullet::RFP_convex_world_test(const btConvexShape *p_shapeA, const btC } return false; } + +int SpaceBullet::recover_from_penetration_ray(RigidBodyBullet *p_body, const btTransform &p_body_position, btScalar p_recover_movement_scale, bool p_infinite_inertia, int p_result_max, btVector3 &r_delta_recover_movement, PhysicsServer::SeparationResult *r_results) { + + RecoverPenetrationBroadPhaseCallback recover_broad_result(p_body->get_bt_collision_object(), p_body->get_collision_layer(), p_body->get_collision_mask()); + + btTransform body_shape_position; + btTransform body_shape_position_recovered; + + // Broad phase support + btVector3 minAabb, maxAabb; + + int ray_index = 0; + + // For each shape + for (int kinIndex = p_body->get_kinematic_utilities()->shapes.size() - 1; 0 <= kinIndex; --kinIndex) { + + recover_broad_result.reset(); + + if (ray_index >= p_result_max) { + break; + } + + const RigidBodyBullet::KinematicShape &kin_shape(p_body->get_kinematic_utilities()->shapes[kinIndex]); + if (!kin_shape.is_active()) { + continue; + } + + if (kin_shape.shape->getShapeType() != CUSTOM_CONVEX_SHAPE_TYPE) { + continue; + } + + body_shape_position = p_body_position * kin_shape.transform; + body_shape_position_recovered = body_shape_position; + body_shape_position_recovered.getOrigin() += r_delta_recover_movement; + + kin_shape.shape->getAabb(body_shape_position_recovered, minAabb, maxAabb); + dynamicsWorld->getBroadphase()->aabbTest(minAabb, maxAabb, recover_broad_result); + + for (int i = recover_broad_result.result_collision_objects.size() - 1; 0 <= i; --i) { + btCollisionObject *otherObject = recover_broad_result.result_collision_objects[i]; + if (p_infinite_inertia && !otherObject->isStaticOrKinematicObject()) { + otherObject->activate(); // Force activation of hitten rigid, soft body + continue; + } else if (!p_body->get_bt_collision_object()->checkCollideWith(otherObject) || !otherObject->checkCollideWith(p_body->get_bt_collision_object())) + continue; + + if (otherObject->getCollisionShape()->isCompound()) { + + // Each convex shape + btCompoundShape *cs = static_cast<btCompoundShape *>(otherObject->getCollisionShape()); + for (int x = cs->getNumChildShapes() - 1; 0 <= x; --x) { + + RecoverResult r_recover_result; + if (RFP_convex_world_test(kin_shape.shape, cs->getChildShape(x), p_body->get_bt_collision_object(), otherObject, kinIndex, x, body_shape_position, otherObject->getWorldTransform() * cs->getChildTransform(x), p_recover_movement_scale, r_delta_recover_movement, &r_recover_result)) { + + const btRigidBody *btRigid = static_cast<const btRigidBody *>(otherObject); + CollisionObjectBullet *collisionObject = static_cast<CollisionObjectBullet *>(otherObject->getUserPointer()); + + r_results[ray_index].collision_depth = r_recover_result.penetration_distance; + B_TO_G(r_recover_result.pointWorld, r_results[ray_index].collision_point); + B_TO_G(r_recover_result.normal, r_results[ray_index].collision_normal); + B_TO_G(btRigid->getVelocityInLocalPoint(r_recover_result.pointWorld - btRigid->getWorldTransform().getOrigin()), r_results[ray_index].collider_velocity); + r_results[ray_index].collision_local_shape = kinIndex; + r_results[ray_index].collider_id = collisionObject->get_instance_id(); + r_results[ray_index].collider = collisionObject->get_self(); + r_results[ray_index].collider_shape = r_recover_result.other_compound_shape_index; + } + } + } + } + + ++ray_index; + } + + return ray_index; +} diff --git a/modules/bullet/space_bullet.h b/modules/bullet/space_bullet.h index 6b86fc2f03..c3d55cbbb1 100644 --- a/modules/bullet/space_bullet.h +++ b/modules/bullet/space_bullet.h @@ -57,7 +57,7 @@ class btDiscreteDynamicsWorld; class btEmptyShape; class btGhostPairCallback; class btSoftRigidDynamicsWorld; -class btSoftBodyWorldInfo; +struct btSoftBodyWorldInfo; class ConstraintBullet; class CollisionObjectBullet; class RigidBodyBullet; @@ -65,6 +65,8 @@ class SpaceBullet; class SoftBodyBullet; class btGjkEpaPenetrationDepthSolver; +extern ContactAddedCallback gContactAddedCallback; + class BulletPhysicsDirectSpaceState : public PhysicsDirectSpaceState { GDCLASS(BulletPhysicsDirectSpaceState, PhysicsDirectSpaceState) private: @@ -73,13 +75,13 @@ private: public: BulletPhysicsDirectSpaceState(SpaceBullet *p_space); - virtual int intersect_point(const Vector3 &p_point, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF); - virtual bool intersect_ray(const Vector3 &p_from, const Vector3 &p_to, RayResult &r_result, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_pick_ray = false); - virtual int intersect_shape(const RID &p_shape, const Transform &p_xform, float p_margin, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF); - virtual bool cast_motion(const RID &p_shape, const Transform &p_xform, const Vector3 &p_motion, float p_margin, float &p_closest_safe, float &p_closest_unsafe, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, ShapeRestInfo *r_info = NULL); + virtual int intersect_point(const Vector3 &p_point, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false); + virtual bool intersect_ray(const Vector3 &p_from, const Vector3 &p_to, RayResult &r_result, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false, bool p_pick_ray = false); + virtual int intersect_shape(const RID &p_shape, const Transform &p_xform, float p_margin, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false); + virtual bool cast_motion(const RID &p_shape, const Transform &p_xform, const Vector3 &p_motion, float p_margin, float &r_closest_safe, float &r_closest_unsafe, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false, ShapeRestInfo *r_info = NULL); /// Returns the list of contacts pairs in this order: Local contact, other body contact - virtual bool collide_shape(RID p_shape, const Transform &p_shape_xform, float p_margin, Vector3 *r_results, int p_result_max, int &r_result_count, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF); - virtual bool rest_info(RID p_shape, const Transform &p_shape_xform, float p_margin, ShapeRestInfo *r_info, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF); + virtual bool collide_shape(RID p_shape, const Transform &p_shape_xform, float p_margin, Vector3 *r_results, int p_result_max, int &r_result_count, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false); + virtual bool rest_info(RID p_shape, const Transform &p_shape_xform, float p_margin, ShapeRestInfo *r_info, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false); virtual Vector3 get_closest_point_to_object_volume(RID p_object, const Vector3 p_point) const; }; @@ -94,9 +96,9 @@ class SpaceBullet : public RIDBullet { btCollisionDispatcher *dispatcher; btConstraintSolver *solver; btDiscreteDynamicsWorld *dynamicsWorld; + btSoftBodyWorldInfo *soft_body_world_info; btGhostPairCallback *ghostPairCallback; GodotFilterCallback *godotFilterCallback; - btSoftBodyWorldInfo *soft_body_world_info; btGjkEpaPenetrationDepthSolver *gjk_epa_pen_solver; btVoronoiSimplexSolver *gjk_simplex_solver; @@ -174,7 +176,8 @@ public: void update_gravity(); - bool test_body_motion(RigidBodyBullet *p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, PhysicsServer::MotionResult *r_result); + bool test_body_motion(RigidBodyBullet *p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, PhysicsServer::MotionResult *r_result, bool p_exclude_raycast_shapes); + int test_ray_separation(RigidBodyBullet *p_body, const Transform &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, PhysicsServer::SeparationResult *r_results, int p_result_max, float p_margin); private: void create_empty_world(bool p_create_soft_world); @@ -208,5 +211,7 @@ private: /// This is an API that recover a kinematic object from penetration /// Using this we leave Bullet to select the best algorithm, For example GJK in case we have Convex Convex, or a Bullet accelerated algorithm bool RFP_convex_world_test(const btConvexShape *p_shapeA, const btCollisionShape *p_shapeB, btCollisionObject *p_objectA, btCollisionObject *p_objectB, int p_shapeId_A, int p_shapeId_B, const btTransform &p_transformA, const btTransform &p_transformB, btScalar p_recover_movement_scale, btVector3 &r_delta_recover_movement, RecoverResult *r_recover_result = NULL); + + int recover_from_penetration_ray(RigidBodyBullet *p_body, const btTransform &p_body_position, btScalar p_recover_movement_scale, bool p_infinite_inertia, int p_result_max, btVector3 &r_delta_recover_movement, PhysicsServer::SeparationResult *r_results); }; #endif |