diff options
Diffstat (limited to 'modules/bullet')
29 files changed, 1169 insertions, 532 deletions
diff --git a/modules/bullet/SCsub b/modules/bullet/SCsub index 0967bca3f2..d8d0b930a5 100644 --- a/modules/bullet/SCsub +++ b/modules/bullet/SCsub @@ -3,12 +3,15 @@ Import('env') Import('env_modules') -# build only version 2 -# Bullet 2.87 - env_bullet = env_modules.Clone() -bullet_src__2_x = [ +# Thirdparty source files + +if env['builtin_bullet']: + # Build only version 2 for now (as of 2.87) + thirdparty_dir = "#thirdparty/bullet/" + + bullet2_src = [ # BulletCollision "BulletCollision/BroadphaseCollision/btAxisSweep3.cpp" , "BulletCollision/BroadphaseCollision/btBroadphaseProxy.cpp" @@ -179,17 +182,10 @@ bullet_src__2_x = [ , "LinearMath/btVector3.cpp" ] -thirdparty_dir = "#thirdparty/bullet/" -thirdparty_src = thirdparty_dir + "src/" + thirdparty_sources = [thirdparty_dir + file for file in bullet2_src] -bullet_sources = [thirdparty_src + file for file in bullet_src__2_x] - -# include headers -env_bullet.Append(CPPPATH=[thirdparty_src]) - -env_bullet.add_source_files(env.modules_sources, bullet_sources) + env_bullet.add_source_files(env.modules_sources, thirdparty_sources) + env_bullet.Append(CPPPATH=[thirdparty_dir]) # Godot source files env_bullet.add_source_files(env.modules_sources, "*.cpp") - -Export('env') diff --git a/modules/bullet/SCsub_with_lib b/modules/bullet/SCsub_with_lib deleted file mode 100644 index b362a686ff..0000000000 --- a/modules/bullet/SCsub_with_lib +++ /dev/null @@ -1,33 +0,0 @@ -#!/usr/bin/env python - -Import('env') - -thirdparty_dir = "#thirdparty/bullet/" -thirdparty_lib = thirdparty_dir + "Win64/lib/" - -bullet_libs = [ - "Bullet2FileLoader", - "Bullet3Collision", - "Bullet3Common", - "Bullet3Dynamics", - "Bullet3Geometry", - "Bullet3OpenCL_clew", - "BulletCollision", - "BulletDynamics", - "BulletInverseDynamics", - "BulletSoftBody", - "LinearMath" - ] - -thirdparty_src = thirdparty_dir + "src/" -# include headers -env.Append(CPPPATH=[thirdparty_src]) - -# lib -env.Append(LIBPATH=[thirdparty_dir + "/Win64/lib/"]) - -bullet_libs = [file+'.lib' for file in bullet_libs] -# LIBS doesn't work in windows -env.Append(LINKFLAGS=bullet_libs) - -env.add_source_files(env.modules_sources, "*.cpp") diff --git a/modules/bullet/area_bullet.cpp b/modules/bullet/area_bullet.cpp index 9d46e4fe30..b004641838 100644 --- a/modules/bullet/area_bullet.cpp +++ b/modules/bullet/area_bullet.cpp @@ -68,7 +68,9 @@ AreaBullet::AreaBullet() : } AreaBullet::~AreaBullet() { - remove_all_overlapping_instantly(); + // signal are handled by godot, so just clear without notify + for (int i = overlappingObjects.size() - 1; 0 <= i; --i) + overlappingObjects[i].object->on_exit_area(this); } void AreaBullet::dispatch_callbacks() { @@ -78,7 +80,7 @@ void AreaBullet::dispatch_callbacks() { // Reverse order because I've to remove EXIT objects for (int i = overlappingObjects.size() - 1; 0 <= i; --i) { - OverlappingObjectData &otherObj = overlappingObjects[i]; + OverlappingObjectData &otherObj = overlappingObjects.write[i]; switch (otherObj.state) { case OVERLAP_STATE_ENTER: @@ -121,23 +123,21 @@ void AreaBullet::scratch() { isScratched = true; } -void AreaBullet::remove_all_overlapping_instantly() { - CollisionObjectBullet *supportObject; +void AreaBullet::clear_overlaps(bool p_notify) { for (int i = overlappingObjects.size() - 1; 0 <= i; --i) { - supportObject = overlappingObjects[i].object; - call_event(supportObject, PhysicsServer::AREA_BODY_REMOVED); - supportObject->on_exit_area(this); + if (p_notify) + call_event(overlappingObjects[i].object, PhysicsServer::AREA_BODY_REMOVED); + overlappingObjects[i].object->on_exit_area(this); } overlappingObjects.clear(); } -void AreaBullet::remove_overlapping_instantly(CollisionObjectBullet *p_object) { - CollisionObjectBullet *supportObject; +void AreaBullet::remove_overlap(CollisionObjectBullet *p_object, bool p_notify) { for (int i = overlappingObjects.size() - 1; 0 <= i; --i) { - supportObject = overlappingObjects[i].object; - if (supportObject == p_object) { - call_event(supportObject, PhysicsServer::AREA_BODY_REMOVED); - supportObject->on_exit_area(this); + if (overlappingObjects[i].object == p_object) { + if (p_notify) + call_event(overlappingObjects[i].object, PhysicsServer::AREA_BODY_REMOVED); + overlappingObjects[i].object->on_exit_area(this); overlappingObjects.remove(i); break; } @@ -199,13 +199,13 @@ void AreaBullet::add_overlap(CollisionObjectBullet *p_otherObject) { void AreaBullet::put_overlap_as_exit(int p_index) { scratch(); - overlappingObjects[p_index].state = OVERLAP_STATE_EXIT; + overlappingObjects.write[p_index].state = OVERLAP_STATE_EXIT; } void AreaBullet::put_overlap_as_inside(int p_index) { // This check is required to be sure this body was inside if (OVERLAP_STATE_DIRTY == overlappingObjects[p_index].state) { - overlappingObjects[p_index].state = OVERLAP_STATE_INSIDE; + overlappingObjects.write[p_index].state = OVERLAP_STATE_INSIDE; } } @@ -236,7 +236,7 @@ void AreaBullet::set_param(PhysicsServer::AreaParameter p_param, const Variant & set_spOv_gravityPointAttenuation(p_value); break; default: - print_line("The Bullet areas dosn't suppot this param: " + itos(p_param)); + print_line("The Bullet areas doesn't suppot this param: " + itos(p_param)); } } @@ -259,7 +259,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 dosn't suppot this param: " + itos(p_param)); + print_line("The Bullet areas doesn't suppot this param: " + itos(p_param)); return Variant(); } } diff --git a/modules/bullet/area_bullet.h b/modules/bullet/area_bullet.h index 78136d574b..b2046c684e 100644 --- a/modules/bullet/area_bullet.h +++ b/modules/bullet/area_bullet.h @@ -150,9 +150,9 @@ public: void set_on_state_change(ObjectID p_id, const StringName &p_method, const Variant &p_udata = Variant()); void scratch(); - void remove_all_overlapping_instantly(); + void clear_overlaps(bool p_notify); // Dispatch the callbacks and removes from overlapping list - void remove_overlapping_instantly(CollisionObjectBullet *p_object); + void remove_overlap(CollisionObjectBullet *p_object, bool p_notify); virtual void on_collision_filters_change(); virtual void on_collision_checker_start() {} diff --git a/modules/bullet/btRayShape.cpp b/modules/bullet/btRayShape.cpp index 4164450cd2..8707096038 100644 --- a/modules/bullet/btRayShape.cpp +++ b/modules/bullet/btRayShape.cpp @@ -54,6 +54,11 @@ void btRayShape::setLength(btScalar p_length) { reload_cache(); } +void btRayShape::setSlipsOnSlope(bool p_slipsOnSlope) { + + slipsOnSlope = p_slipsOnSlope; +} + btVector3 btRayShape::localGetSupportingVertex(const btVector3 &vec) const { return localGetSupportingVertexWithoutMargin(vec) + (m_shapeAxis * m_collisionMargin); } diff --git a/modules/bullet/btRayShape.h b/modules/bullet/btRayShape.h index 99a9412dbe..a44c30db4b 100644 --- a/modules/bullet/btRayShape.h +++ b/modules/bullet/btRayShape.h @@ -44,6 +44,7 @@ ATTRIBUTE_ALIGNED16(class) btRayShape : public btConvexInternalShape { btScalar m_length; + bool slipsOnSlope; /// The default axis is the z btVector3 m_shapeAxis; @@ -59,6 +60,9 @@ public: void setLength(btScalar p_length); btScalar getLength() const { return m_length; } + void setSlipsOnSlope(bool p_slipOnSlope); + bool getSlipsOnSlope() const { return slipsOnSlope; } + const btTransform &getSupportPoint() const { return m_cacheSupportPoint; } const btScalar &getScaledLength() const { return m_cacheScaledLength; } diff --git a/modules/bullet/bullet_physics_server.cpp b/modules/bullet/bullet_physics_server.cpp index 51de4998fa..9263a9ba6d 100644 --- a/modules/bullet/bullet_physics_server.cpp +++ b/modules/bullet/bullet_physics_server.cpp @@ -70,8 +70,8 @@ return RID(); \ } -#define AddJointToSpace(body, joint, disableCollisionsBetweenLinkedBodies) \ - body->get_space()->add_constraint(joint, disableCollisionsBetweenLinkedBodies); +#define AddJointToSpace(body, joint) \ + body->get_space()->add_constraint(joint, joint->is_disabled_collisions_between_bodies()); // <--------------- Joint creation asserts btEmptyShape *BulletPhysicsServer::emptyShape(ShapeBullet::create_shape_empty()); @@ -89,7 +89,9 @@ BulletPhysicsServer::BulletPhysicsServer() : active(true), active_spaces_count(0) {} -BulletPhysicsServer::~BulletPhysicsServer() {} +BulletPhysicsServer::~BulletPhysicsServer() { + bulletdelete(emptyShape); +} RID BulletPhysicsServer::shape_create(ShapeType p_shape) { ShapeBullet *shape = NULL; @@ -111,6 +113,10 @@ RID BulletPhysicsServer::shape_create(ShapeType p_shape) { shape = bulletnew(CapsuleShapeBullet); } break; + case SHAPE_CYLINDER: { + + shape = bulletnew(CylinderShapeBullet); + } break; case SHAPE_CONVEX_POLYGON: { shape = bulletnew(ConvexPolygonShapeBullet); @@ -163,7 +169,7 @@ real_t BulletPhysicsServer::shape_get_custom_solver_bias(RID p_shape) const { } RID BulletPhysicsServer::space_create() { - SpaceBullet *space = bulletnew(SpaceBullet(false)); + SpaceBullet *space = bulletnew(SpaceBullet); CreateThenReturnRID(space_owner, space); } @@ -561,9 +567,6 @@ void BulletPhysicsServer::body_clear_shapes(RID p_body) { void BulletPhysicsServer::body_attach_object_instance_id(RID p_body, uint32_t p_ID) { CollisionObjectBullet *body = get_collisin_object(p_body); - if (!body) { - body = soft_body_owner.get(p_body); - } ERR_FAIL_COND(!body); body->set_instance_id(p_ID); @@ -619,11 +622,11 @@ uint32_t BulletPhysicsServer::body_get_collision_mask(RID p_body) const { } void BulletPhysicsServer::body_set_user_flags(RID p_body, uint32_t p_flags) { - WARN_PRINT("This function si not currently supported by bullet and Godot"); + // This function si not currently supported } uint32_t BulletPhysicsServer::body_get_user_flags(RID p_body) const { - WARN_PRINT("This function si not currently supported by bullet and Godot"); + // This function si not currently supported return 0; } @@ -641,6 +644,20 @@ 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); @@ -704,6 +721,34 @@ Vector3 BulletPhysicsServer::body_get_applied_torque(RID p_body) const { return body->get_applied_torque(); } +void BulletPhysicsServer::body_add_central_force(RID p_body, const Vector3 &p_force) { + RigidBodyBullet *body = rigid_body_owner.get(p_body); + ERR_FAIL_COND(!body); + + body->apply_central_force(p_force); +} + +void BulletPhysicsServer::body_add_force(RID p_body, const Vector3 &p_force, const Vector3 &p_pos) { + RigidBodyBullet *body = rigid_body_owner.get(p_body); + ERR_FAIL_COND(!body); + + body->apply_force(p_force, p_pos); +} + +void BulletPhysicsServer::body_add_torque(RID p_body, const Vector3 &p_torque) { + RigidBodyBullet *body = rigid_body_owner.get(p_body); + ERR_FAIL_COND(!body); + + body->apply_torque(p_torque); +} + +void BulletPhysicsServer::body_apply_central_impulse(RID p_body, const Vector3 &p_impulse) { + RigidBodyBullet *body = rigid_body_owner.get(p_body); + ERR_FAIL_COND(!body); + + body->apply_central_impulse(p_impulse); +} + void BulletPhysicsServer::body_apply_impulse(RID p_body, const Vector3 &p_pos, const Vector3 &p_impulse) { RigidBodyBullet *body = rigid_body_owner.get(p_body); ERR_FAIL_COND(!body); @@ -783,22 +828,27 @@ int BulletPhysicsServer::body_get_max_contacts_reported(RID p_body) const { return body->get_max_collisions_detection(); } -void BulletPhysicsServer::body_set_contacts_reported_depth_threshold(RID p_body, float p_treshold) { - WARN_PRINT("Not supported by bullet and even Godot"); +void BulletPhysicsServer::body_set_contacts_reported_depth_threshold(RID p_body, float p_threshold) { + // Not supported by bullet and even Godot } float BulletPhysicsServer::body_get_contacts_reported_depth_threshold(RID p_body) const { - WARN_PRINT("Not supported by bullet and even Godot"); + // Not supported by bullet and even Godot return 0.; } void BulletPhysicsServer::body_set_omit_force_integration(RID p_body, bool p_omit) { - WARN_PRINT("Not supported by bullet"); + RigidBodyBullet *body = rigid_body_owner.get(p_body); + ERR_FAIL_COND(!body); + + body->set_omit_forces_integration(p_omit); } bool BulletPhysicsServer::body_is_omitting_force_integration(RID p_body) const { - WARN_PRINT("Not supported by bullet"); - return false; + RigidBodyBullet *body = rigid_body_owner.get(p_body); + ERR_FAIL_COND_V(!body, false); + + return body->get_omit_forces_integration(); } void BulletPhysicsServer::body_set_force_integration_callback(RID p_body, Object *p_receiver, const StringName &p_method, const Variant &p_udata) { @@ -825,12 +875,12 @@ 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, 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) { 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, r_result); + return body->get_space()->test_body_motion(body, p_from, p_motion, p_infinite_inertia, r_result); } RID BulletPhysicsServer::soft_body_create(bool p_init_sleeping) { @@ -842,6 +892,13 @@ RID BulletPhysicsServer::soft_body_create(bool p_init_sleeping) { CreateThenReturnRID(soft_body_owner, body); } +void BulletPhysicsServer::soft_body_update_visual_server(RID p_body, class SoftBodyVisualServerHandler *p_visual_server_handler) { + SoftBodyBullet *body = soft_body_owner.get(p_body); + ERR_FAIL_COND(!body); + + body->update_visual_server(p_visual_server_handler); +} + void BulletPhysicsServer::soft_body_set_space(RID p_body, RID p_space) { SoftBodyBullet *body = soft_body_owner.get(p_body); ERR_FAIL_COND(!body); @@ -868,11 +925,11 @@ RID BulletPhysicsServer::soft_body_get_space(RID p_body) const { return space->get_self(); } -void BulletPhysicsServer::soft_body_set_trimesh_body_shape(RID p_body, PoolVector<int> p_indices, PoolVector<Vector3> p_vertices, int p_triangles_num) { +void BulletPhysicsServer::soft_body_set_mesh(RID p_body, const REF &p_mesh) { SoftBodyBullet *body = soft_body_owner.get(p_body); ERR_FAIL_COND(!body); - body->set_trimesh_body_shape(p_indices, p_vertices, p_triangles_num); + body->set_soft_mesh(p_mesh); } void BulletPhysicsServer::soft_body_set_collision_layer(RID p_body, uint32_t p_layer) { @@ -950,14 +1007,16 @@ void BulletPhysicsServer::soft_body_set_transform(RID p_body, const Transform &p SoftBodyBullet *body = soft_body_owner.get(p_body); ERR_FAIL_COND(!body); - body->set_transform(p_transform); + body->set_soft_transform(p_transform); } -Transform BulletPhysicsServer::soft_body_get_transform(RID p_body) const { +Vector3 BulletPhysicsServer::soft_body_get_vertex_position(RID p_body, int vertex_index) const { const SoftBodyBullet *body = soft_body_owner.get(p_body); - ERR_FAIL_COND_V(!body, Transform()); + Vector3 pos; + ERR_FAIL_COND_V(!body, pos); - return body->get_transform(); + body->get_node_position(vertex_index, pos); + return pos; } void BulletPhysicsServer::soft_body_set_ray_pickable(RID p_body, bool p_enable) { @@ -972,6 +1031,154 @@ bool BulletPhysicsServer::soft_body_is_ray_pickable(RID p_body) const { return body->is_ray_pickable(); } +void BulletPhysicsServer::soft_body_set_simulation_precision(RID p_body, int p_simulation_precision) { + SoftBodyBullet *body = soft_body_owner.get(p_body); + ERR_FAIL_COND(!body); + body->set_simulation_precision(p_simulation_precision); +} + +int BulletPhysicsServer::soft_body_get_simulation_precision(RID p_body) { + SoftBodyBullet *body = soft_body_owner.get(p_body); + ERR_FAIL_COND_V(!body, 0.f); + return body->get_simulation_precision(); +} + +void BulletPhysicsServer::soft_body_set_total_mass(RID p_body, real_t p_total_mass) { + SoftBodyBullet *body = soft_body_owner.get(p_body); + ERR_FAIL_COND(!body); + body->set_total_mass(p_total_mass); +} + +real_t BulletPhysicsServer::soft_body_get_total_mass(RID p_body) { + SoftBodyBullet *body = soft_body_owner.get(p_body); + ERR_FAIL_COND_V(!body, 0.f); + return body->get_total_mass(); +} + +void BulletPhysicsServer::soft_body_set_linear_stiffness(RID p_body, real_t p_stiffness) { + SoftBodyBullet *body = soft_body_owner.get(p_body); + ERR_FAIL_COND(!body); + body->set_linear_stiffness(p_stiffness); +} + +real_t BulletPhysicsServer::soft_body_get_linear_stiffness(RID p_body) { + SoftBodyBullet *body = soft_body_owner.get(p_body); + ERR_FAIL_COND_V(!body, 0.f); + return body->get_linear_stiffness(); +} + +void BulletPhysicsServer::soft_body_set_areaAngular_stiffness(RID p_body, real_t p_stiffness) { + SoftBodyBullet *body = soft_body_owner.get(p_body); + ERR_FAIL_COND(!body); + body->set_areaAngular_stiffness(p_stiffness); +} + +real_t BulletPhysicsServer::soft_body_get_areaAngular_stiffness(RID p_body) { + SoftBodyBullet *body = soft_body_owner.get(p_body); + ERR_FAIL_COND_V(!body, 0.f); + return body->get_areaAngular_stiffness(); +} + +void BulletPhysicsServer::soft_body_set_volume_stiffness(RID p_body, real_t p_stiffness) { + SoftBodyBullet *body = soft_body_owner.get(p_body); + ERR_FAIL_COND(!body); + body->set_volume_stiffness(p_stiffness); +} + +real_t BulletPhysicsServer::soft_body_get_volume_stiffness(RID p_body) { + SoftBodyBullet *body = soft_body_owner.get(p_body); + ERR_FAIL_COND_V(!body, 0.f); + return body->get_volume_stiffness(); +} + +void BulletPhysicsServer::soft_body_set_pressure_coefficient(RID p_body, real_t p_pressure_coefficient) { + SoftBodyBullet *body = soft_body_owner.get(p_body); + ERR_FAIL_COND(!body); + body->set_pressure_coefficient(p_pressure_coefficient); +} + +real_t BulletPhysicsServer::soft_body_get_pressure_coefficient(RID p_body) { + SoftBodyBullet *body = soft_body_owner.get(p_body); + ERR_FAIL_COND_V(!body, 0.f); + return body->get_pressure_coefficient(); +} + +void BulletPhysicsServer::soft_body_set_pose_matching_coefficient(RID p_body, real_t p_pose_matching_coefficient) { + SoftBodyBullet *body = soft_body_owner.get(p_body); + ERR_FAIL_COND(!body); + return body->set_pose_matching_coefficient(p_pose_matching_coefficient); +} + +real_t BulletPhysicsServer::soft_body_get_pose_matching_coefficient(RID p_body) { + SoftBodyBullet *body = soft_body_owner.get(p_body); + ERR_FAIL_COND_V(!body, 0.f); + return body->get_pose_matching_coefficient(); +} + +void BulletPhysicsServer::soft_body_set_damping_coefficient(RID p_body, real_t p_damping_coefficient) { + SoftBodyBullet *body = soft_body_owner.get(p_body); + ERR_FAIL_COND(!body); + body->set_damping_coefficient(p_damping_coefficient); +} + +real_t BulletPhysicsServer::soft_body_get_damping_coefficient(RID p_body) { + SoftBodyBullet *body = soft_body_owner.get(p_body); + ERR_FAIL_COND_V(!body, 0.f); + return body->get_damping_coefficient(); +} + +void BulletPhysicsServer::soft_body_set_drag_coefficient(RID p_body, real_t p_drag_coefficient) { + SoftBodyBullet *body = soft_body_owner.get(p_body); + ERR_FAIL_COND(!body); + body->set_drag_coefficient(p_drag_coefficient); +} + +real_t BulletPhysicsServer::soft_body_get_drag_coefficient(RID p_body) { + SoftBodyBullet *body = soft_body_owner.get(p_body); + ERR_FAIL_COND_V(!body, 0.f); + return body->get_drag_coefficient(); +} + +void BulletPhysicsServer::soft_body_move_point(RID p_body, int p_point_index, const Vector3 &p_global_position) { + SoftBodyBullet *body = soft_body_owner.get(p_body); + ERR_FAIL_COND(!body); + body->set_node_position(p_point_index, p_global_position); +} + +Vector3 BulletPhysicsServer::soft_body_get_point_global_position(RID p_body, int p_point_index) { + SoftBodyBullet *body = soft_body_owner.get(p_body); + ERR_FAIL_COND_V(!body, Vector3(0., 0., 0.)); + Vector3 pos; + body->get_node_position(p_point_index, pos); + return pos; +} + +Vector3 BulletPhysicsServer::soft_body_get_point_offset(RID p_body, int p_point_index) const { + SoftBodyBullet *body = soft_body_owner.get(p_body); + ERR_FAIL_COND_V(!body, Vector3()); + Vector3 res; + body->get_node_offset(p_point_index, res); + return res; +} + +void BulletPhysicsServer::soft_body_remove_all_pinned_points(RID p_body) { + SoftBodyBullet *body = soft_body_owner.get(p_body); + ERR_FAIL_COND(!body); + body->reset_all_node_mass(); +} + +void BulletPhysicsServer::soft_body_pin_point(RID p_body, int p_point_index, bool p_pin) { + SoftBodyBullet *body = soft_body_owner.get(p_body); + ERR_FAIL_COND(!body); + body->set_node_mass(p_point_index, p_pin ? 0 : 1); +} + +bool BulletPhysicsServer::soft_body_is_point_pinned(RID p_body, int p_point_index) { + SoftBodyBullet *body = soft_body_owner.get(p_body); + ERR_FAIL_COND_V(!body, 0.f); + return body->get_node_mass(p_point_index); +} + PhysicsServer::JointType BulletPhysicsServer::joint_get_type(RID p_joint) const { JointBullet *joint = joint_owner.get(p_joint); ERR_FAIL_COND_V(!joint, JOINT_PIN); @@ -979,14 +1186,28 @@ PhysicsServer::JointType BulletPhysicsServer::joint_get_type(RID p_joint) const } void BulletPhysicsServer::joint_set_solver_priority(RID p_joint, int p_priority) { - //WARN_PRINTS("Joint priority not supported by bullet"); + // Joint priority not supported by bullet } int BulletPhysicsServer::joint_get_solver_priority(RID p_joint) const { - //WARN_PRINTS("Joint priority not supported by bullet"); + // Joint priority not supported by bullet return 0; } +void BulletPhysicsServer::joint_disable_collisions_between_bodies(RID p_joint, const bool p_disable) { + JointBullet *joint = joint_owner.get(p_joint); + ERR_FAIL_COND(!joint); + + joint->disable_collisions_between_bodies(p_disable); +} + +bool BulletPhysicsServer::joint_is_disabled_collisions_between_bodies(RID p_joint) const { + JointBullet *joint(joint_owner.get(p_joint)); + ERR_FAIL_COND_V(!joint, false); + + return joint->is_disabled_collisions_between_bodies(); +} + RID BulletPhysicsServer::joint_create_pin(RID p_body_A, const Vector3 &p_local_A, RID p_body_B, const Vector3 &p_local_B) { RigidBodyBullet *body_A = rigid_body_owner.get(p_body_A); ERR_FAIL_COND_V(!body_A, RID()); @@ -1003,7 +1224,7 @@ RID BulletPhysicsServer::joint_create_pin(RID p_body_A, const Vector3 &p_local_A ERR_FAIL_COND_V(body_A == body_B, RID()); JointBullet *joint = bulletnew(PinJointBullet(body_A, p_local_A, body_B, p_local_B)); - AddJointToSpace(body_A, joint, true); + AddJointToSpace(body_A, joint); CreateThenReturnRID(joint_owner, joint); } @@ -1071,7 +1292,7 @@ RID BulletPhysicsServer::joint_create_hinge(RID p_body_A, const Transform &p_hin ERR_FAIL_COND_V(body_A == body_B, RID()); JointBullet *joint = bulletnew(HingeJointBullet(body_A, body_B, p_hinge_A, p_hinge_B)); - AddJointToSpace(body_A, joint, true); + AddJointToSpace(body_A, joint); CreateThenReturnRID(joint_owner, joint); } @@ -1091,7 +1312,7 @@ RID BulletPhysicsServer::joint_create_hinge_simple(RID p_body_A, const Vector3 & ERR_FAIL_COND_V(body_A == body_B, RID()); JointBullet *joint = bulletnew(HingeJointBullet(body_A, body_B, p_pivot_A, p_pivot_B, p_axis_A, p_axis_B)); - AddJointToSpace(body_A, joint, true); + AddJointToSpace(body_A, joint); CreateThenReturnRID(joint_owner, joint); } @@ -1143,7 +1364,7 @@ RID BulletPhysicsServer::joint_create_slider(RID p_body_A, const Transform &p_lo ERR_FAIL_COND_V(body_A == body_B, RID()); JointBullet *joint = bulletnew(SliderJointBullet(body_A, body_B, p_local_frame_A, p_local_frame_B)); - AddJointToSpace(body_A, joint, true); + AddJointToSpace(body_A, joint); CreateThenReturnRID(joint_owner, joint); } @@ -1177,7 +1398,7 @@ RID BulletPhysicsServer::joint_create_cone_twist(RID p_body_A, const Transform & } JointBullet *joint = bulletnew(ConeTwistJointBullet(body_A, body_B, p_local_frame_A, p_local_frame_B)); - AddJointToSpace(body_A, joint, true); + AddJointToSpace(body_A, joint); CreateThenReturnRID(joint_owner, joint); } @@ -1213,7 +1434,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)); - AddJointToSpace(body_A, joint, true); + AddJointToSpace(body_A, joint); CreateThenReturnRID(joint_owner, joint); } diff --git a/modules/bullet/bullet_physics_server.h b/modules/bullet/bullet_physics_server.h index 1c94428a2a..2c5b7e51cf 100644 --- a/modules/bullet/bullet_physics_server.h +++ b/modules/bullet/bullet_physics_server.h @@ -154,7 +154,7 @@ public: /// AREA_PARAM_GRAVITY_VECTOR /// Otherwise you can set area parameters virtual void area_set_param(RID p_area, AreaParameter p_param, const Variant &p_value); - virtual Variant area_get_param(RID p_parea, AreaParameter p_param) const; + virtual Variant area_get_param(RID p_area, AreaParameter p_param) const; virtual void area_set_transform(RID p_area, const Transform &p_transform); virtual Transform area_get_transform(RID p_area) const; @@ -213,6 +213,9 @@ 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; @@ -225,6 +228,11 @@ public: virtual void body_set_applied_torque(RID p_body, const Vector3 &p_torque); virtual Vector3 body_get_applied_torque(RID p_body) const; + virtual void body_add_central_force(RID p_body, const Vector3 &p_force); + virtual void body_add_force(RID p_body, const Vector3 &p_force, const Vector3 &p_pos); + virtual void body_add_torque(RID p_body, const Vector3 &p_torque); + + virtual void body_apply_central_impulse(RID p_body, const Vector3 &p_impulse); virtual void body_apply_impulse(RID p_body, const Vector3 &p_pos, const Vector3 &p_impulse); virtual void body_apply_torque_impulse(RID p_body, const Vector3 &p_impulse); virtual void body_set_axis_velocity(RID p_body, const Vector3 &p_axis_velocity); @@ -239,7 +247,7 @@ public: virtual void body_set_max_contacts_reported(RID p_body, int p_contacts); virtual int body_get_max_contacts_reported(RID p_body) const; - virtual void body_set_contacts_reported_depth_threshold(RID p_body, float p_treshold); + virtual void body_set_contacts_reported_depth_threshold(RID p_body, float p_threshold); virtual float body_get_contacts_reported_depth_threshold(RID p_body) const; virtual void body_set_omit_force_integration(RID p_body, bool p_omit); @@ -253,16 +261,18 @@ 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, 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); /* SOFT BODY API */ virtual RID soft_body_create(bool p_init_sleeping = false); + virtual void soft_body_update_visual_server(RID p_body, class SoftBodyVisualServerHandler *p_visual_server_handler); + virtual void soft_body_set_space(RID p_body, RID p_space); virtual RID soft_body_get_space(RID p_body) const; - virtual void soft_body_set_trimesh_body_shape(RID p_body, PoolVector<int> p_indices, PoolVector<Vector3> p_vertices, int p_triangles_num); + virtual void soft_body_set_mesh(RID p_body, const REF &p_mesh); virtual void soft_body_set_collision_layer(RID p_body, uint32_t p_layer); virtual uint32_t soft_body_get_collision_layer(RID p_body) const; @@ -277,12 +287,49 @@ public: virtual void soft_body_set_state(RID p_body, BodyState p_state, const Variant &p_variant); virtual Variant soft_body_get_state(RID p_body, BodyState p_state) const; + /// Special function. This function has bad performance virtual void soft_body_set_transform(RID p_body, const Transform &p_transform); - virtual Transform soft_body_get_transform(RID p_body) const; + virtual Vector3 soft_body_get_vertex_position(RID p_body, int vertex_index) const; virtual void soft_body_set_ray_pickable(RID p_body, bool p_enable); virtual bool soft_body_is_ray_pickable(RID p_body) const; + virtual void soft_body_set_simulation_precision(RID p_body, int p_simulation_precision); + virtual int soft_body_get_simulation_precision(RID p_body); + + virtual void soft_body_set_total_mass(RID p_body, real_t p_total_mass); + virtual real_t soft_body_get_total_mass(RID p_body); + + virtual void soft_body_set_linear_stiffness(RID p_body, real_t p_stiffness); + virtual real_t soft_body_get_linear_stiffness(RID p_body); + + virtual void soft_body_set_areaAngular_stiffness(RID p_body, real_t p_stiffness); + virtual real_t soft_body_get_areaAngular_stiffness(RID p_body); + + virtual void soft_body_set_volume_stiffness(RID p_body, real_t p_stiffness); + virtual real_t soft_body_get_volume_stiffness(RID p_body); + + virtual void soft_body_set_pressure_coefficient(RID p_body, real_t p_pressure_coefficient); + virtual real_t soft_body_get_pressure_coefficient(RID p_body); + + virtual void soft_body_set_pose_matching_coefficient(RID p_body, real_t p_pose_matching_coefficient); + virtual real_t soft_body_get_pose_matching_coefficient(RID p_body); + + virtual void soft_body_set_damping_coefficient(RID p_body, real_t p_damping_coefficient); + virtual real_t soft_body_get_damping_coefficient(RID p_body); + + virtual void soft_body_set_drag_coefficient(RID p_body, real_t p_drag_coefficient); + virtual real_t soft_body_get_drag_coefficient(RID p_body); + + virtual void soft_body_move_point(RID p_body, int p_point_index, const Vector3 &p_global_position); + virtual Vector3 soft_body_get_point_global_position(RID p_body, int p_point_index); + + virtual Vector3 soft_body_get_point_offset(RID p_body, int p_point_index) const; + + virtual void soft_body_remove_all_pinned_points(RID p_body); + virtual void soft_body_pin_point(RID p_body, int p_point_index, bool p_pin); + virtual bool soft_body_is_point_pinned(RID p_body, int p_point_index); + /* JOINT API */ virtual JointType joint_get_type(RID p_joint) const; @@ -290,6 +337,9 @@ public: virtual void joint_set_solver_priority(RID p_joint, int p_priority); virtual int joint_get_solver_priority(RID p_joint) const; + virtual void joint_disable_collisions_between_bodies(RID p_joint, const bool p_disable); + virtual bool joint_is_disabled_collisions_between_bodies(RID p_joint) const; + virtual RID joint_create_pin(RID p_body_A, const Vector3 &p_local_A, RID p_body_B, const Vector3 &p_local_B); virtual void pin_joint_set_param(RID p_joint, PinJointParam p_param, float p_value); @@ -301,7 +351,7 @@ public: virtual void pin_joint_set_local_b(RID p_joint, const Vector3 &p_B); virtual Vector3 pin_joint_get_local_b(RID p_joint) const; - virtual RID joint_create_hinge(RID p_body_A, const Transform &p_frame_A, RID p_body_B, const Transform &p_frame_B); + virtual RID joint_create_hinge(RID p_body_A, const Transform &p_hinge_A, RID p_body_B, const Transform &p_hinge_B); virtual RID joint_create_hinge_simple(RID p_body_A, const Vector3 &p_pivot_A, const Vector3 &p_axis_A, RID p_body_B, const Vector3 &p_pivot_B, const Vector3 &p_axis_B); virtual void hinge_joint_set_param(RID p_joint, HingeJointParam p_param, float p_value); diff --git a/modules/bullet/collision_object_bullet.cpp b/modules/bullet/collision_object_bullet.cpp index 873c9c31b7..271cdb0223 100644 --- a/modules/bullet/collision_object_bullet.cpp +++ b/modules/bullet/collision_object_bullet.cpp @@ -49,7 +49,7 @@ CollisionObjectBullet::ShapeWrapper::~ShapeWrapper() {} void CollisionObjectBullet::ShapeWrapper::set_transform(const Transform &p_transform) { - G_TO_B(p_transform.get_basis().get_scale(), scale); + G_TO_B(p_transform.get_basis().get_scale_abs(), scale); G_TO_B(p_transform, transform); UNSCALE_BT_BASIS(transform); } @@ -68,12 +68,10 @@ CollisionObjectBullet::CollisionObjectBullet(Type p_type) : force_shape_reset(false) {} CollisionObjectBullet::~CollisionObjectBullet() { - // Remove all overlapping + // Remove all overlapping, notify is not required since godot take care of it for (int i = areasOverlapped.size() - 1; 0 <= i; --i) { - areasOverlapped[i]->remove_overlapping_instantly(this); + areasOverlapped[i]->remove_overlap(this, /*Notify*/ false); } - // not required - // areasOverlapped.clear(); destroyBulletCollisionObject(); } @@ -113,6 +111,8 @@ void CollisionObjectBullet::setupBulletCollisionObject(btCollisionObject *p_coll void CollisionObjectBullet::add_collision_exception(const CollisionObjectBullet *p_ignoreCollisionObject) { exceptions.insert(p_ignoreCollisionObject->get_self()); + if (!bt_collision_object) + return; bt_collision_object->setIgnoreCollisionCheck(p_ignoreCollisionObject->bt_collision_object, true); if (space) space->get_broadphase()->getOverlappingPairCache()->cleanProxyFromPairs(bt_collision_object->getBroadphaseHandle(), space->get_dispatcher()); @@ -160,16 +160,13 @@ int CollisionObjectBullet::get_godot_object_flags() const { void CollisionObjectBullet::set_transform(const Transform &p_global_transform) { - btTransform btTrans; - Basis decomposed_basis; + set_body_scale(p_global_transform.basis.get_scale_abs()); - Vector3 decomposed_scale = p_global_transform.get_basis().rotref_posscale_decomposition(decomposed_basis); + btTransform bt_transform; + G_TO_B(p_global_transform, bt_transform); + UNSCALE_BT_BASIS(bt_transform); - G_TO_B(p_global_transform.get_origin(), btTrans.getOrigin()); - G_TO_B(decomposed_basis, btTrans.getBasis()); - - set_body_scale(decomposed_scale); - set_transform__bullet(btTrans); + set_transform__bullet(bt_transform); } Transform CollisionObjectBullet::get_transform() const { @@ -226,7 +223,7 @@ void RigidCollisionObjectBullet::add_shape(ShapeBullet *p_shape, const Transform } void RigidCollisionObjectBullet::set_shape(int p_index, ShapeBullet *p_shape) { - ShapeWrapper &shp = shapes[p_index]; + ShapeWrapper &shp = shapes.write[p_index]; shp.shape->remove_owner(this); p_shape->add_owner(this); shp.shape = p_shape; @@ -236,8 +233,8 @@ void RigidCollisionObjectBullet::set_shape(int p_index, ShapeBullet *p_shape) { void RigidCollisionObjectBullet::set_shape_transform(int p_index, const Transform &p_transform) { ERR_FAIL_INDEX(p_index, get_shape_count()); - shapes[p_index].set_transform(p_transform); - on_shape_changed(shapes[p_index].shape); + shapes.write[p_index].set_transform(p_transform); + on_shape_changed(shapes.write[p_index].shape); } void RigidCollisionObjectBullet::remove_shape(ShapeBullet *p_shape) { @@ -290,7 +287,7 @@ void RigidCollisionObjectBullet::on_shape_changed(const ShapeBullet *const p_sha const int size = shapes.size(); for (int i = 0; i < size; ++i) { if (shapes[i].shape == p_shape) { - bulletdelete(shapes[i].bt_shape); + bulletdelete(shapes.write[i].bt_shape); } } on_shapes_changed(); @@ -310,32 +307,34 @@ void RigidCollisionObjectBullet::on_shapes_changed() { // Reset shape if required if (force_shape_reset) { for (i = 0; i < shapes_size; ++i) { - shpWrapper = &shapes[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[i]; + shpWrapper = &shapes.write[i]; if (shpWrapper->active) { if (!shpWrapper->bt_shape) { - shpWrapper->bt_shape = shpWrapper->shape->create_bt_shape(shpWrapper->scale); + shpWrapper->bt_shape = shpWrapper->shape->create_bt_shape(shpWrapper->scale * body_scale); } - compoundShape->addChildShape(shpWrapper->transform, shpWrapper->bt_shape); + + btTransform scaled_shape_transform(shpWrapper->transform); + scaled_shape_transform.getOrigin() *= body_scale; + compoundShape->addChildShape(scaled_shape_transform, shpWrapper->bt_shape); } else { - compoundShape->addChildShape(shpWrapper->transform, BulletPhysicsServer::get_empty_shape()); + compoundShape->addChildShape(btTransform(), BulletPhysicsServer::get_empty_shape()); } } - compoundShape->setLocalScaling(get_bt_body_scale()); compoundShape->recalculateLocalAabb(); } void RigidCollisionObjectBullet::set_shape_disabled(int p_index, bool p_disabled) { - shapes[p_index].active = !p_disabled; + shapes.write[p_index].active = !p_disabled; on_shapes_changed(); } @@ -349,7 +348,7 @@ void RigidCollisionObjectBullet::on_body_scale_changed() { } void RigidCollisionObjectBullet::internal_shape_destroy(int p_index, bool p_permanentlyFromThisBody) { - ShapeWrapper &shp = shapes[p_index]; + ShapeWrapper &shp = shapes.write[p_index]; shp.shape->remove_owner(this, p_permanentlyFromThisBody); bulletdelete(shp.bt_shape); } diff --git a/modules/bullet/config.py b/modules/bullet/config.py index 0a31c2e503..92dbcf5cb0 100644 --- a/modules/bullet/config.py +++ b/modules/bullet/config.py @@ -1,4 +1,4 @@ -def can_build(platform): +def can_build(env, platform): return True def configure(env): diff --git a/modules/bullet/constraint_bullet.cpp b/modules/bullet/constraint_bullet.cpp index b60e89b6fd..d15fb8de01 100644 --- a/modules/bullet/constraint_bullet.cpp +++ b/modules/bullet/constraint_bullet.cpp @@ -39,7 +39,8 @@ ConstraintBullet::ConstraintBullet() : space(NULL), - constraint(NULL) {} + constraint(NULL), + disabled_collisions_between_bodies(true) {} void ConstraintBullet::setup(btTypedConstraint *p_constraint) { constraint = p_constraint; @@ -53,3 +54,12 @@ void ConstraintBullet::set_space(SpaceBullet *p_space) { void ConstraintBullet::destroy_internal_constraint() { space->remove_constraint(this); } + +void ConstraintBullet::disable_collisions_between_bodies(const bool p_disabled) { + disabled_collisions_between_bodies = p_disabled; + + if (space) { + space->remove_constraint(this); + space->add_constraint(this, disabled_collisions_between_bodies); + } +} diff --git a/modules/bullet/constraint_bullet.h b/modules/bullet/constraint_bullet.h index 23be5a5063..ed3a318cbc 100644 --- a/modules/bullet/constraint_bullet.h +++ b/modules/bullet/constraint_bullet.h @@ -49,6 +49,7 @@ class ConstraintBullet : public RIDBullet { protected: SpaceBullet *space; btTypedConstraint *constraint; + bool disabled_collisions_between_bodies; public: ConstraintBullet(); @@ -57,6 +58,9 @@ public: virtual void set_space(SpaceBullet *p_space); virtual void destroy_internal_constraint(); + void disable_collisions_between_bodies(const bool p_disabled); + _FORCE_INLINE_ bool is_disabled_collisions_between_bodies() const { return disabled_collisions_between_bodies; } + public: virtual ~ConstraintBullet() { bulletdelete(constraint); diff --git a/modules/bullet/doc_classes/BulletPhysicsDirectBodyState.xml b/modules/bullet/doc_classes/BulletPhysicsDirectBodyState.xml index 941a79e8ea..a4dc61d0bc 100644 --- a/modules/bullet/doc_classes/BulletPhysicsDirectBodyState.xml +++ b/modules/bullet/doc_classes/BulletPhysicsDirectBodyState.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="BulletPhysicsDirectBodyState" inherits="PhysicsDirectBodyState" category="Core" version="3.0-beta"> +<class name="BulletPhysicsDirectBodyState" inherits="PhysicsDirectBodyState" category="Core" version="3.1"> <brief_description> </brief_description> <description> diff --git a/modules/bullet/doc_classes/BulletPhysicsServer.xml b/modules/bullet/doc_classes/BulletPhysicsServer.xml index 515f0e292e..1486936cf4 100644 --- a/modules/bullet/doc_classes/BulletPhysicsServer.xml +++ b/modules/bullet/doc_classes/BulletPhysicsServer.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="BulletPhysicsServer" inherits="PhysicsServer" category="Core" version="3.0-beta"> +<class name="BulletPhysicsServer" inherits="PhysicsServer" category="Core" version="3.1"> <brief_description> </brief_description> <description> diff --git a/modules/bullet/generic_6dof_joint_bullet.cpp b/modules/bullet/generic_6dof_joint_bullet.cpp index 151a79a69f..adfad7803f 100644 --- a/modules/bullet/generic_6dof_joint_bullet.cpp +++ b/modules/bullet/generic_6dof_joint_bullet.cpp @@ -138,6 +138,12 @@ void Generic6DOFJointBullet::set_param(Vector3::Axis p_axis, PhysicsServer::G6DO case PhysicsServer::G6DOF_JOINT_LINEAR_DAMPING: sixDOFConstraint->getTranslationalLimitMotor()->m_damping = p_value; break; + case PhysicsServer::G6DOF_JOINT_LINEAR_MOTOR_TARGET_VELOCITY: + sixDOFConstraint->getTranslationalLimitMotor()->m_targetVelocity.m_floats[p_axis] = p_value; + break; + case PhysicsServer::G6DOF_JOINT_LINEAR_MOTOR_FORCE_LIMIT: + sixDOFConstraint->getTranslationalLimitMotor()->m_maxMotorForce.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 @@ -185,6 +191,10 @@ real_t Generic6DOFJointBullet::get_param(Vector3::Axis p_axis, PhysicsServer::G6 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_ANGULAR_LOWER_LIMIT: return limits_lower[1][p_axis]; case PhysicsServer::G6DOF_JOINT_ANGULAR_UPPER_LIMIT: @@ -232,6 +242,9 @@ void Generic6DOFJointBullet::set_flag(Vector3::Axis p_axis, PhysicsServer::G6DOF case PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_MOTOR: sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_enableMotor = flags[p_axis][p_flag]; break; + case PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_LINEAR_MOTOR: + sixDOFConstraint->getTranslationalLimitMotor()->m_enableMotor[p_axis] = flags[p_axis][p_flag]; + break; default: WARN_PRINT("This flag is not supported by Bullet engine"); return; diff --git a/modules/bullet/godot_motion_state.h b/modules/bullet/godot_motion_state.h index 2ebe368536..fa58e86589 100644 --- a/modules/bullet/godot_motion_state.h +++ b/modules/bullet/godot_motion_state.h @@ -41,7 +41,7 @@ class RigidBodyBullet; -// This clas is responsible to move kinematic actor +// This class is responsible to move kinematic actor // and sincronize rendering engine with Bullet /// DOC: /// http://www.bulletphysics.org/mediawiki-1.5.8/index.php/MotionStates#What.27s_a_MotionState.3F @@ -87,7 +87,7 @@ public: public: /// Use this function to move kinematic body - /// -- or set initial transfom before body creation. + /// -- or set initial transform before body creation. void moveBody(const btTransform &newWorldTransform) { bodyKinematicWorldTransf = newWorldTransform; } diff --git a/modules/bullet/godot_ray_world_algorithm.cpp b/modules/bullet/godot_ray_world_algorithm.cpp index 709eed9e40..53d0ab7e3c 100644 --- a/modules/bullet/godot_ray_world_algorithm.cpp +++ b/modules/bullet/godot_ray_world_algorithm.cpp @@ -35,6 +35,8 @@ #include <BulletDynamics/Dynamics/btDiscreteDynamicsWorld.h> +#define RAY_STABILITY_MARGIN 0.1 + /** @author AndreaCatania */ @@ -97,10 +99,17 @@ void GodotRayWorldAlgorithm::processCollision(const btCollisionObjectWrapper *bo m_world->rayTestSingleInternal(ray_transform, to, other_co_wrapper, btResult); if (btResult.hasHit()) { - btVector3 ray_normal(to.getOrigin() - ray_transform.getOrigin()); - ray_normal.normalize(); - ray_normal *= -1; - resultOut->addContactPoint(ray_normal, btResult.m_hitPointWorld, ray_shape->getScaledLength() * (btResult.m_closestHitFraction - 1)); + + btScalar depth(ray_shape->getScaledLength() * (btResult.m_closestHitFraction - 1)); + + if (depth >= -RAY_STABILITY_MARGIN) + depth = 0; + + if (ray_shape->getSlipsOnSlope()) + resultOut->addContactPoint(btResult.m_hitNormalWorld, btResult.m_hitPointWorld, depth); + else { + resultOut->addContactPoint((ray_transform.getOrigin() - to.getOrigin()).normalize(), btResult.m_hitPointWorld, depth); + } } } diff --git a/modules/bullet/godot_ray_world_algorithm.h b/modules/bullet/godot_ray_world_algorithm.h index c716c1d88d..7383dad2bf 100644 --- a/modules/bullet/godot_ray_world_algorithm.h +++ b/modules/bullet/godot_ray_world_algorithm.h @@ -49,7 +49,7 @@ class GodotRayWorldAlgorithm : public btActivatingCollisionAlgorithm { bool m_isSwapped; public: - GodotRayWorldAlgorithm(const btDiscreteDynamicsWorld *m_world, btPersistentManifold *mf, const btCollisionAlgorithmConstructionInfo &ci, const btCollisionObjectWrapper *body0Wrap, const btCollisionObjectWrapper *body1Wrap, bool isSwapped); + GodotRayWorldAlgorithm(const btDiscreteDynamicsWorld *world, btPersistentManifold *mf, const btCollisionAlgorithmConstructionInfo &ci, const btCollisionObjectWrapper *body0Wrap, const btCollisionObjectWrapper *body1Wrap, bool isSwapped); virtual ~GodotRayWorldAlgorithm(); virtual void processCollision(const btCollisionObjectWrapper *body0Wrap, const btCollisionObjectWrapper *body1Wrap, const btDispatcherInfo &dispatchInfo, btManifoldResult *resultOut); diff --git a/modules/bullet/godot_result_callbacks.cpp b/modules/bullet/godot_result_callbacks.cpp index 8d4ca6d6a7..197550d686 100644 --- a/modules/bullet/godot_result_callbacks.cpp +++ b/modules/bullet/godot_result_callbacks.cpp @@ -63,6 +63,9 @@ bool GodotClosestRayResultCallback::needsCollision(btBroadphaseProxy *proxy0) co } bool GodotAllConvexResultCallback::needsCollision(btBroadphaseProxy *proxy0) const { + if (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); @@ -70,6 +73,7 @@ bool GodotAllConvexResultCallback::needsCollision(btBroadphaseProxy *proxy0) con if (m_exclude->has(gObj->get_self())) { return false; } + return true; } else { return false; @@ -87,7 +91,7 @@ btScalar GodotAllConvexResultCallback::addSingleResult(btCollisionWorld::LocalCo result.collider = 0 == result.collider_id ? NULL : ObjectDB::get_instance(result.collider_id); ++count; - return count < m_resultMax; + return 1; // not used by bullet } bool GodotKinClosestConvexResultCallback::needsCollision(btBroadphaseProxy *proxy0) const { @@ -98,11 +102,16 @@ bool GodotKinClosestConvexResultCallback::needsCollision(btBroadphaseProxy *prox if (gObj == m_self_object) { return false; } else { - if (m_ignore_areas && gObj->getType() == CollisionObjectBullet::TYPE_AREA) { + + // A kinematic body can't be stopped by a rigid body since the mass of kinematic body is infinite + if (m_infinite_inertia && !btObj->isStaticOrKinematicObject()) return false; - } else if (m_self_object->has_collision_exception(gObj)) { + + if (gObj->getType() == CollisionObjectBullet::TYPE_AREA) + return false; + + if (m_self_object->has_collision_exception(gObj) || gObj->has_collision_exception(m_self_object)) return false; - } } return true; } else { @@ -163,10 +172,7 @@ btScalar GodotAllContactResultCallback::addSingleResult(btManifoldPoint &cp, con result.shape = cp.m_index0; } - if (colObj) - result.collider_id = colObj->get_instance_id(); - else - result.collider_id = 0; + result.collider_id = colObj->get_instance_id(); result.collider = 0 == result.collider_id ? NULL : ObjectDB::get_instance(result.collider_id); result.rid = colObj->get_self(); ++m_count; @@ -176,6 +182,9 @@ btScalar GodotAllContactResultCallback::addSingleResult(btManifoldPoint &cp, con } bool GodotContactPairContactResultCallback::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); @@ -201,7 +210,7 @@ btScalar GodotContactPairContactResultCallback::addSingleResult(btManifoldPoint ++m_count; - return m_count < m_resultMax; + return 1; // Not used by bullet } bool GodotRestInfoContactResultCallback::needsCollision(btBroadphaseProxy *proxy0) const { @@ -238,32 +247,23 @@ btScalar GodotRestInfoContactResultCallback::addSingleResult(btManifoldPoint &cp m_rest_info_collision_object = colObj0Wrap->getCollisionObject(); } - if (colObj) - m_result->collider_id = colObj->get_instance_id(); - else - m_result->collider_id = 0; + m_result->collider_id = colObj->get_instance_id(); m_result->rid = colObj->get_self(); m_collided = true; } - return cp.getDistance(); + return 1; // Not used by bullet } void GodotDeepPenetrationContactResultCallback::addContactPoint(const btVector3 &normalOnBInWorld, const btVector3 &pointInWorldOnB, btScalar depth) { - if (depth < 0) { - // Has penetration - if (m_most_penetrated_distance > depth) { - - bool isSwapped = m_manifoldPtr->getBody0() != m_body0Wrap->getCollisionObject(); + if (m_penetration_distance > depth) { // Has penetration? - m_most_penetrated_distance = depth; - m_pointCollisionObject = (isSwapped ? m_body0Wrap : m_body1Wrap)->getCollisionObject(); - m_other_compound_shape_index = isSwapped ? m_index1 : m_index0; - m_pointNormalWorld = isSwapped ? normalOnBInWorld * -1 : normalOnBInWorld; - m_pointWorld = isSwapped ? (pointInWorldOnB + normalOnBInWorld * depth) : pointInWorldOnB; - m_penetration_distance = depth; - } + 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; } } diff --git a/modules/bullet/godot_result_callbacks.h b/modules/bullet/godot_result_callbacks.h index b18965a5b8..363051f24c 100644 --- a/modules/bullet/godot_result_callbacks.h +++ b/modules/bullet/godot_result_callbacks.h @@ -93,12 +93,12 @@ public: struct GodotKinClosestConvexResultCallback : public btCollisionWorld::ClosestConvexResultCallback { public: const RigidBodyBullet *m_self_object; - const bool m_ignore_areas; + const bool m_infinite_inertia; - GodotKinClosestConvexResultCallback(const btVector3 &convexFromWorld, const btVector3 &convexToWorld, const RigidBodyBullet *p_self_object, bool p_ignore_areas) : + GodotKinClosestConvexResultCallback(const btVector3 &convexFromWorld, const btVector3 &convexToWorld, const RigidBodyBullet *p_self_object, bool p_infinite_inertia) : btCollisionWorld::ClosestConvexResultCallback(convexFromWorld, convexToWorld), m_self_object(p_self_object), - m_ignore_areas(p_ignore_areas) {} + m_infinite_inertia(p_infinite_inertia) {} virtual bool needsCollision(btBroadphaseProxy *proxy0) const; }; @@ -185,26 +185,20 @@ struct GodotDeepPenetrationContactResultCallback : public btManifoldResult { btVector3 m_pointWorld; btScalar m_penetration_distance; int m_other_compound_shape_index; - const btCollisionObject *m_pointCollisionObject; - - btScalar m_most_penetrated_distance; GodotDeepPenetrationContactResultCallback(const btCollisionObjectWrapper *body0Wrap, const btCollisionObjectWrapper *body1Wrap) : btManifoldResult(body0Wrap, body1Wrap), - m_pointCollisionObject(NULL), m_penetration_distance(0), - m_other_compound_shape_index(0), - m_most_penetrated_distance(1e20) {} + m_other_compound_shape_index(0) {} void reset() { - m_pointCollisionObject = NULL; - m_most_penetrated_distance = 1e20; + m_penetration_distance = 0; } bool hasHit() { - return m_pointCollisionObject; + return m_penetration_distance < 0; } - virtual void addContactPoint(const btVector3 &normalOnBInWorld, const btVector3 &pointInWorld, btScalar depth); + virtual void addContactPoint(const btVector3 &normalOnBInWorld, const btVector3 &pointInWorldOnB, btScalar depth); }; #endif // GODOT_RESULT_CALLBACKS_H diff --git a/modules/bullet/register_types.cpp b/modules/bullet/register_types.cpp index b119b7720f..a76b0438b4 100644 --- a/modules/bullet/register_types.cpp +++ b/modules/bullet/register_types.cpp @@ -32,19 +32,26 @@ #include "bullet_physics_server.h" #include "class_db.h" +#include "project_settings.h" /** @author AndreaCatania */ +#ifndef _3D_DISABLED PhysicsServer *_createBulletPhysicsCallback() { return memnew(BulletPhysicsServer); } +#endif void register_bullet_types() { - +#ifndef _3D_DISABLED PhysicsServerManager::register_server("Bullet", &_createBulletPhysicsCallback); PhysicsServerManager::set_default_server("Bullet", 1); + + GLOBAL_DEF("physics/3d/active_soft_world", true); + ProjectSettings::get_singleton()->set_custom_property_info("physics/3d/active_soft_world", PropertyInfo(Variant::BOOL, "physics/3d/active_soft_world")); +#endif } void unregister_bullet_types() { diff --git a/modules/bullet/rigid_body_bullet.cpp b/modules/bullet/rigid_body_bullet.cpp index fd7f1ded09..81a62edba6 100644 --- a/modules/bullet/rigid_body_bullet.cpp +++ b/modules/bullet/rigid_body_bullet.cpp @@ -114,10 +114,22 @@ Transform BulletPhysicsDirectBodyState::get_transform() const { return body->get_transform(); } +void BulletPhysicsDirectBodyState::add_central_force(const Vector3 &p_force) { + body->apply_central_force(p_force); +} + void BulletPhysicsDirectBodyState::add_force(const Vector3 &p_force, const Vector3 &p_pos) { body->apply_force(p_force, p_pos); } +void BulletPhysicsDirectBodyState::add_torque(const Vector3 &p_torque) { + body->apply_torque(p_torque); +} + +void BulletPhysicsDirectBodyState::apply_central_impulse(const Vector3 &p_j) { + body->apply_central_impulse(p_j); +} + void BulletPhysicsDirectBodyState::apply_impulse(const Vector3 &p_pos, const Vector3 &p_j) { body->apply_impulse(p_pos, p_j); } @@ -171,7 +183,7 @@ int BulletPhysicsDirectBodyState::get_contact_collider_shape(int p_contact_idx) } Vector3 BulletPhysicsDirectBodyState::get_contact_collider_velocity_at_position(int p_contact_idx) const { - RigidBodyBullet::CollisionData &colDat = body->collisions[p_contact_idx]; + RigidBodyBullet::CollisionData &colDat = body->collisions.write[p_contact_idx]; btVector3 hitLocation; G_TO_B(colDat.hitLocalLocation, hitLocation); @@ -216,19 +228,20 @@ void RigidBodyBullet::KinematicUtilities::copyAllOwnerShapes() { continue; } - shapes[i].transform = shape_wrapper->transform; - shapes[i].transform.getOrigin() *= owner_scale; + shapes.write[i].transform = shape_wrapper->transform; + shapes.write[i].transform.getOrigin() *= owner_scale; switch (shape_wrapper->shape->get_type()) { case PhysicsServer::SHAPE_SPHERE: case PhysicsServer::SHAPE_BOX: case PhysicsServer::SHAPE_CAPSULE: + case PhysicsServer::SHAPE_CYLINDER: case PhysicsServer::SHAPE_CONVEX_POLYGON: case PhysicsServer::SHAPE_RAY: { - shapes[i].shape = static_cast<btConvexShape *>(shape_wrapper->shape->create_bt_shape(owner_scale * shape_wrapper->scale, safe_margin)); + shapes.write[i].shape = static_cast<btConvexShape *>(shape_wrapper->shape->create_bt_shape(owner_scale * shape_wrapper->scale, safe_margin)); } break; default: WARN_PRINT("This shape is not supported to be kinematic!"); - shapes[i].shape = NULL; + shapes.write[i].shape = NULL; } } } @@ -236,7 +249,7 @@ void RigidBodyBullet::KinematicUtilities::copyAllOwnerShapes() { void RigidBodyBullet::KinematicUtilities::just_delete_shapes(int new_size) { for (int i = shapes.size() - 1; 0 <= i; --i) { if (shapes[i].shape) { - bulletdelete(shapes[i].shape); + bulletdelete(shapes.write[i].shape); } } shapes.resize(new_size); @@ -251,6 +264,9 @@ RigidBodyBullet::RigidBodyBullet() : 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), @@ -275,7 +291,7 @@ RigidBodyBullet::RigidBodyBullet() : areasWhereIam.resize(maxAreasWhereIam); for (int i = areasWhereIam.size() - 1; 0 <= i; --i) { - areasWhereIam[i] = NULL; + areasWhereIam.write[i] = NULL; } btBody->setSleepingThresholds(0.2, 0.2); } @@ -330,6 +346,9 @@ 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) { + if (omit_forces_integration) + btBody->clearForces(); + BulletPhysicsDirectBodyState *bodyDirect = BulletPhysicsDirectBodyState::get_singleton(this); Variant variantBodyDirect = bodyDirect; @@ -398,7 +417,7 @@ bool RigidBodyBullet::add_collision_object(RigidBodyBullet *p_otherObject, const return false; } - CollisionData &cd = collisions[collisionsCount]; + CollisionData &cd = collisions.write[collisionsCount]; cd.hitLocalLocation = p_hitLocalLocation; cd.otherObject = p_otherObject; cd.hitWorldLocation = p_hitWorldLocation; @@ -434,6 +453,10 @@ bool RigidBodyBullet::is_active() const { return btBody->isActive(); } +void RigidBodyBullet::set_omit_forces_integration(bool p_omit) { + omit_forces_integration = p_omit; +} + void RigidBodyBullet::set_param(PhysicsServer::BodyParameter p_param, real_t p_value) { switch (p_param) { case PhysicsServer::BODY_PARAM_BOUNCE: @@ -695,7 +718,7 @@ void RigidBodyBullet::set_continuous_collision_detection(bool p_enable) { /// 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 dimentions 1 meter, try 0.2 + /// for an object of dimensions 1 meter, try 0.2 btVector3 center; btScalar radius; btBody->getCollisionShape()->getBoundingSphere(center, radius); @@ -738,6 +761,22 @@ 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) { // The kinematic use MotionState class @@ -783,15 +822,15 @@ void RigidBodyBullet::on_enter_area(AreaBullet *p_area) { if (NULL == areasWhereIam[i]) { // This area has the highest priority - areasWhereIam[i] = p_area; + areasWhereIam.write[i] = p_area; break; } else { if (areasWhereIam[i]->get_spOv_priority() > p_area->get_spOv_priority()) { // The position was found, just shift all elements for (int j = i; j < areaWhereIamCount; ++j) { - areasWhereIam[j + 1] = areasWhereIam[j]; + areasWhereIam.write[j + 1] = areasWhereIam[j]; } - areasWhereIam[i] = p_area; + areasWhereIam.write[i] = p_area; break; } } @@ -815,7 +854,7 @@ void RigidBodyBullet::on_exit_area(AreaBullet *p_area) { if (p_area == areasWhereIam[i]) { // The area was fount, just shift down all elements for (int j = i; j < areaWhereIamCount; ++j) { - areasWhereIam[j] = areasWhereIam[j + 1]; + areasWhereIam.write[j] = areasWhereIam[j + 1]; } wasTheAreaFound = true; break; @@ -828,7 +867,7 @@ void RigidBodyBullet::on_exit_area(AreaBullet *p_area) { } --areaWhereIamCount; - areasWhereIam[areaWhereIamCount] = NULL; // Even if this is not required, I clear the last element to be safe + areasWhereIam.write[areaWhereIamCount] = NULL; // Even if this is not required, I clear the last element to be safe if (PhysicsServer::AREA_SPACE_OVERRIDE_DISABLED != p_area->get_spOv_mode()) { scratch_space_override_modificator(); } @@ -837,7 +876,8 @@ void RigidBodyBullet::on_exit_area(AreaBullet *p_area) { void RigidBodyBullet::reload_space_override_modificator() { - if (!is_active()) + // Make sure that kinematic bodies have their total gravity calculated + if (!is_active() && PhysicsServer::BODY_MODE_KINEMATIC != mode) return; Vector3 newGravity(space->get_gravity_direction() * space->get_gravity_magnitude()); @@ -960,7 +1000,8 @@ void RigidBodyBullet::_internal_set_mass(real_t p_mass) { const bool isDynamic = p_mass != 0.f; if (isDynamic) { - ERR_FAIL_COND(PhysicsServer::BODY_MODE_RIGID != mode && PhysicsServer::BODY_MODE_CHARACTER != mode); + if (PhysicsServer::BODY_MODE_RIGID != mode && PhysicsServer::BODY_MODE_CHARACTER != mode) + return; m_isStatic = false; compoundShape->calculateLocalInertia(p_mass, localInertia); @@ -980,7 +1021,8 @@ void RigidBodyBullet::_internal_set_mass(real_t p_mass) { } } else { - ERR_FAIL_COND(PhysicsServer::BODY_MODE_STATIC != mode && PhysicsServer::BODY_MODE_KINEMATIC != mode); + if (PhysicsServer::BODY_MODE_STATIC != mode && PhysicsServer::BODY_MODE_KINEMATIC != mode) + return; m_isStatic = true; if (PhysicsServer::BODY_MODE_STATIC == mode) { diff --git a/modules/bullet/rigid_body_bullet.h b/modules/bullet/rigid_body_bullet.h index 66275d5613..35af3b90d8 100644 --- a/modules/bullet/rigid_body_bullet.h +++ b/modules/bullet/rigid_body_bullet.h @@ -48,11 +48,11 @@ class GodotMotionState; class BulletPhysicsDirectBodyState; /// This class could be used in multi thread with few changes but currently -/// is setted to be only in one single thread. +/// is set to be only in one single thread. /// /// In the system there is only one object at a time that manage all bodies and is /// created by BulletPhysicsServer and is held by the "singleton" variable of this class -/// Each time something require it, the body must be setted again. +/// Each time something require it, the body must be set again. class BulletPhysicsDirectBodyState : public PhysicsDirectBodyState { GDCLASS(BulletPhysicsDirectBodyState, PhysicsDirectBodyState) @@ -110,7 +110,10 @@ public: virtual void set_transform(const Transform &p_transform); virtual Transform get_transform() const; + virtual void add_central_force(const Vector3 &p_force); virtual void add_force(const Vector3 &p_force, const Vector3 &p_pos); + virtual void add_torque(const Vector3 &p_torque); + virtual void apply_central_impulse(const Vector3 &p_impulse); virtual void apply_impulse(const Vector3 &p_pos, const Vector3 &p_j); virtual void apply_torque_impulse(const Vector3 &p_j); @@ -198,6 +201,10 @@ private: real_t linearDamp; real_t angularDamp; bool can_sleep; + bool omit_forces_integration; + + PhysicsServer::CombineMode restitution_combine_mode; + PhysicsServer::CombineMode friction_combine_mode; Vector<CollisionData> collisions; // these parameters are used to avoid vector resize @@ -254,6 +261,9 @@ public: void set_activation_state(bool p_active); bool is_active() const; + void set_omit_forces_integration(bool p_omit); + _FORCE_INLINE_ bool get_omit_forces_integration() const { return omit_forces_integration; } + void set_param(PhysicsServer::BodyParameter p_param, real_t); real_t get_param(PhysicsServer::BodyParameter p_param) const; @@ -264,12 +274,12 @@ public: Variant get_state(PhysicsServer::BodyState p_state) const; void apply_impulse(const Vector3 &p_pos, const Vector3 &p_impulse); - void apply_central_impulse(const Vector3 &p_force); + void apply_central_impulse(const Vector3 &p_impulse); void apply_torque_impulse(const Vector3 &p_impulse); void apply_force(const Vector3 &p_force, const Vector3 &p_pos); void apply_central_force(const Vector3 &p_force); - void apply_torque(const Vector3 &p_force); + void apply_torque(const Vector3 &p_torque); void set_applied_force(const Vector3 &p_force); Vector3 get_applied_force() const; @@ -291,6 +301,12 @@ 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; diff --git a/modules/bullet/shape_bullet.cpp b/modules/bullet/shape_bullet.cpp index 27eac4e6ee..e4c1a5f9b5 100644 --- a/modules/bullet/shape_bullet.cpp +++ b/modules/bullet/shape_bullet.cpp @@ -113,6 +113,10 @@ btCapsuleShapeZ *ShapeBullet::create_shape_capsule(btScalar radius, btScalar hei return bulletnew(btCapsuleShapeZ(radius, height)); } +btCylinderShape *ShapeBullet::create_shape_cylinder(btScalar radius, btScalar height) { + return bulletnew(btCylinderShape(btVector3(radius, height / 2.0, radius))); +} + btConvexPointCloudShape *ShapeBullet::create_shape_convex(btAlignedObjectArray<btVector3> &p_vertices, const btVector3 &p_local_scaling) { return bulletnew(btConvexPointCloudShape(&p_vertices[0], p_vertices.size(), p_local_scaling)); } @@ -125,18 +129,19 @@ btScaledBvhTriangleMeshShape *ShapeBullet::create_shape_concave(btBvhTriangleMes } } -btHeightfieldTerrainShape *ShapeBullet::create_shape_height_field(PoolVector<real_t> &p_heights, int p_width, int p_depth, real_t p_cell_size) { +btHeightfieldTerrainShape *ShapeBullet::create_shape_height_field(PoolVector<real_t> &p_heights, int p_width, int p_depth, real_t p_min_height, real_t p_max_height) { const btScalar ignoredHeightScale(1); - const btScalar fieldHeight(500); // Meters const int YAxis = 1; // 0=X, 1=Y, 2=Z const bool flipQuadEdges = false; const void *heightsPtr = p_heights.read().ptr(); - return bulletnew(btHeightfieldTerrainShape(p_width, p_depth, heightsPtr, ignoredHeightScale, -fieldHeight, fieldHeight, YAxis, PHY_FLOAT, flipQuadEdges)); + return bulletnew(btHeightfieldTerrainShape(p_width, p_depth, heightsPtr, ignoredHeightScale, p_min_height, p_max_height, YAxis, PHY_FLOAT, flipQuadEdges)); } -btRayShape *ShapeBullet::create_shape_ray(real_t p_length) { - return bulletnew(btRayShape(p_length)); +btRayShape *ShapeBullet::create_shape_ray(real_t p_length, bool p_slips_on_slope) { + btRayShape *r(bulletnew(btRayShape(p_length))); + r->setSlipsOnSlope(p_slips_on_slope); + return r; } /* PLANE */ @@ -253,6 +258,39 @@ btCollisionShape *CapsuleShapeBullet::create_bt_shape(const btVector3 &p_implici return prepare(ShapeBullet::create_shape_capsule(radius * p_implicit_scale[0] + p_margin, height * p_implicit_scale[1] + p_margin)); } +/* Cylinder */ + +CylinderShapeBullet::CylinderShapeBullet() : + ShapeBullet() {} + +void CylinderShapeBullet::set_data(const Variant &p_data) { + Dictionary d = p_data; + ERR_FAIL_COND(!d.has("radius")); + ERR_FAIL_COND(!d.has("height")); + setup(d["height"], d["radius"]); +} + +Variant CylinderShapeBullet::get_data() const { + Dictionary d; + d["radius"] = radius; + d["height"] = height; + return d; +} + +PhysicsServer::ShapeType CylinderShapeBullet::get_type() const { + return PhysicsServer::SHAPE_CYLINDER; +} + +void CylinderShapeBullet::setup(real_t p_height, real_t p_radius) { + radius = p_radius; + height = p_height; + notifyShapeChanged(); +} + +btCollisionShape *CylinderShapeBullet::create_bt_shape(const btVector3 &p_implicit_scale, real_t p_margin) { + return prepare(ShapeBullet::create_shape_cylinder(radius * p_implicit_scale[0] + p_margin, height * p_implicit_scale[1] + p_margin)); +} + /* Convex polygon */ ConvexPolygonShapeBullet::ConvexPolygonShapeBullet() : @@ -266,7 +304,7 @@ void ConvexPolygonShapeBullet::get_vertices(Vector<Vector3> &out_vertices) { const int n_of_vertices = vertices.size(); out_vertices.resize(n_of_vertices); for (int i = n_of_vertices - 1; 0 <= i; --i) { - B_TO_G(vertices[i], out_vertices[i]); + B_TO_G(vertices[i], out_vertices.write[i]); } } @@ -282,7 +320,7 @@ PhysicsServer::ShapeType ConvexPolygonShapeBullet::get_type() const { } void ConvexPolygonShapeBullet::setup(const Vector<Vector3> &p_vertices) { - // Make a copy of verticies + // Make a copy of vertices const int n_of_vertices = p_vertices.size(); vertices.resize(n_of_vertices); for (int i = n_of_vertices - 1; 0 <= i; --i) { @@ -335,10 +373,10 @@ void ConcavePolygonShapeBullet::setup(PoolVector<Vector3> p_faces) { int src_face_count = faces.size(); if (0 < src_face_count) { - btTriangleMesh *shapeInterface = bulletnew(btTriangleMesh); - // It counts the faces and assert the array contains the correct number of vertices. ERR_FAIL_COND(src_face_count % 3); + + btTriangleMesh *shapeInterface = bulletnew(btTriangleMesh); src_face_count /= 3; PoolVector<Vector3>::Read r = p_faces.read(); const Vector3 *facesr = r.ptr(); @@ -385,19 +423,44 @@ void HeightMapShapeBullet::set_data(const Variant &p_data) { Dictionary d = p_data; ERR_FAIL_COND(!d.has("width")); ERR_FAIL_COND(!d.has("depth")); - ERR_FAIL_COND(!d.has("cell_size")); ERR_FAIL_COND(!d.has("heights")); + real_t l_min_height = 0.0; + real_t l_max_height = 0.0; + + // If specified, min and max height will be used as precomputed values + if (d.has("min_height")) + l_min_height = d["min_height"]; + if (d.has("max_height")) + l_max_height = d["max_height"]; + + ERR_FAIL_COND(l_min_height > l_max_height); + int l_width = d["width"]; int l_depth = d["depth"]; - real_t l_cell_size = d["cell_size"]; PoolVector<real_t> l_heights = d["heights"]; ERR_FAIL_COND(l_width <= 0); ERR_FAIL_COND(l_depth <= 0); - ERR_FAIL_COND(l_cell_size <= CMP_EPSILON); - ERR_FAIL_COND(l_heights.size() != (width * depth)); - setup(heights, width, depth, cell_size); + ERR_FAIL_COND(l_heights.size() != (l_width * l_depth)); + + // Compute min and max heights if not specified. + if (!d.has("min_height") && !d.has("max_height")) { + + PoolVector<real_t>::Read r = heights.read(); + int heights_size = heights.size(); + + for (int i = 0; i < heights_size; ++i) { + real_t h = r[i]; + + if (h < l_min_height) + l_min_height = h; + else if (h > l_max_height) + l_max_height = h; + } + } + + setup(l_heights, l_width, l_depth, l_min_height, l_max_height); } Variant HeightMapShapeBullet::get_data() const { @@ -408,8 +471,14 @@ PhysicsServer::ShapeType HeightMapShapeBullet::get_type() const { return PhysicsServer::SHAPE_HEIGHTMAP; } -void HeightMapShapeBullet::setup(PoolVector<real_t> &p_heights, int p_width, int p_depth, real_t p_cell_size) { +void HeightMapShapeBullet::setup(PoolVector<real_t> &p_heights, int p_width, int p_depth, real_t p_min_height, real_t p_max_height) { + // TODO cell size must be tweaked using localScaling, which is a shared property for all Bullet shapes + { // Copy + + // TODO If Godot supported 16-bit integer image format, we could share the same memory block for heightfields + // without having to copy anything, optimizing memory and loading performance (Bullet only reads and doesn't take ownership of the data). + const int heights_size = p_heights.size(); heights.resize(heights_size); PoolVector<real_t>::Read p_heights_r = p_heights.read(); @@ -418,14 +487,16 @@ void HeightMapShapeBullet::setup(PoolVector<real_t> &p_heights, int p_width, int heights_w[i] = p_heights_r[i]; } } + width = p_width; depth = p_depth; - cell_size = p_cell_size; + min_height = p_min_height; + max_height = p_max_height; notifyShapeChanged(); } btCollisionShape *HeightMapShapeBullet::create_bt_shape(const btVector3 &p_implicit_scale, real_t p_margin) { - btCollisionShape *cs(ShapeBullet::create_shape_height_field(heights, width, depth, cell_size)); + 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); @@ -435,25 +506,33 @@ btCollisionShape *HeightMapShapeBullet::create_bt_shape(const btVector3 &p_impli /* Ray shape */ RayShapeBullet::RayShapeBullet() : ShapeBullet(), - length(1) {} + length(1), + slips_on_slope(false) {} void RayShapeBullet::set_data(const Variant &p_data) { - setup(p_data); + + Dictionary d = p_data; + setup(d["length"], d["slips_on_slope"]); } Variant RayShapeBullet::get_data() const { - return length; + + Dictionary d; + d["length"] = length; + d["slips_on_slope"] = slips_on_slope; + return d; } PhysicsServer::ShapeType RayShapeBullet::get_type() const { return PhysicsServer::SHAPE_RAY; } -void RayShapeBullet::setup(real_t p_length) { +void RayShapeBullet::setup(real_t p_length, bool p_slips_on_slope) { length = p_length; + slips_on_slope = 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)); + return prepare(ShapeBullet::create_shape_ray(length * p_implicit_scale[1] + p_margin, slips_on_slope)); } diff --git a/modules/bullet/shape_bullet.h b/modules/bullet/shape_bullet.h index 4a03c0f014..16a5ac1fc6 100644 --- a/modules/bullet/shape_bullet.h +++ b/modules/bullet/shape_bullet.h @@ -82,11 +82,12 @@ public: static class btSphereShape *create_shape_sphere(btScalar radius); static class btBoxShape *create_shape_box(const btVector3 &boxHalfExtents); static class btCapsuleShapeZ *create_shape_capsule(btScalar radius, btScalar height); + static class btCylinderShape *create_shape_cylinder(btScalar radius, btScalar height); /// IMPORTANT: Remember to delete the shape interface by calling: delete my_shape->getMeshInterface(); static class btConvexPointCloudShape *create_shape_convex(btAlignedObjectArray<btVector3> &p_vertices, const btVector3 &p_local_scaling = btVector3(1, 1, 1)); static class btScaledBvhTriangleMeshShape *create_shape_concave(btBvhTriangleMeshShape *p_mesh_shape, const btVector3 &p_local_scaling = btVector3(1, 1, 1)); - static class btHeightfieldTerrainShape *create_shape_height_field(PoolVector<real_t> &p_heights, int p_width, int p_depth, real_t p_cell_size); - static class btRayShape *create_shape_ray(real_t p_length); + static class btHeightfieldTerrainShape *create_shape_height_field(PoolVector<real_t> &p_heights, int p_width, int p_depth, real_t p_min_height, real_t p_max_height); + static class btRayShape *create_shape_ray(real_t p_length, bool p_slips_on_slope); }; class PlaneShapeBullet : public ShapeBullet { @@ -99,7 +100,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_scale, real_t p_margin = 0); + virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_margin = 0); private: void setup(const Plane &p_plane); @@ -116,7 +117,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_scale, real_t p_margin = 0); + virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_margin = 0); private: void setup(real_t p_radius); @@ -133,7 +134,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_scale, real_t p_margin = 0); + virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_margin = 0); private: void setup(const Vector3 &p_half_extents); @@ -152,7 +153,26 @@ 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_scale, real_t p_margin = 0); + virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_margin = 0); + +private: + void setup(real_t p_height, real_t p_radius); +}; + +class CylinderShapeBullet : public ShapeBullet { + + real_t height; + real_t radius; + +public: + CylinderShapeBullet(); + + _FORCE_INLINE_ real_t get_height() { return height; } + _FORCE_INLINE_ real_t get_radius() { return radius; } + 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); private: void setup(real_t p_height, real_t p_radius); @@ -169,7 +189,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_scale, real_t p_margin = 0); + virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_margin = 0); private: void setup(const Vector<Vector3> &p_vertices); @@ -187,7 +207,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_scale, real_t p_margin = 0); + virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_margin = 0); private: void setup(PoolVector<Vector3> p_faces); @@ -199,32 +219,34 @@ public: PoolVector<real_t> heights; int width; int depth; - real_t cell_size; + real_t min_height; + real_t max_height; HeightMapShapeBullet(); 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_scale, real_t p_margin = 0); + virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_margin = 0); private: - void setup(PoolVector<real_t> &p_heights, int p_width, int p_depth, real_t p_cell_size); + void setup(PoolVector<real_t> &p_heights, int p_width, int p_depth, real_t p_min_height, real_t p_max_height); }; class RayShapeBullet : public ShapeBullet { public: real_t length; + bool slips_on_slope; RayShapeBullet(); 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_scale, real_t p_margin = 0); + virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_margin = 0); private: - void setup(real_t p_length); + void setup(real_t p_length, bool p_slips_on_slope); }; #endif diff --git a/modules/bullet/soft_body_bullet.cpp b/modules/bullet/soft_body_bullet.cpp index 5c20eb73f1..1686a6e87e 100644 --- a/modules/bullet/soft_body_bullet.cpp +++ b/modules/bullet/soft_body_bullet.cpp @@ -32,42 +32,24 @@ #include "bullet_types_converter.h" #include "bullet_utilities.h" -#include "scene/3d/immediate_geometry.h" +#include "scene/3d/soft_body.h" #include "space_bullet.h" -/** - @author AndreaCatania -*/ - SoftBodyBullet::SoftBodyBullet() : CollisionObjectBullet(CollisionObjectBullet::TYPE_SOFT_BODY), - mass(1), + total_mass(1), simulation_precision(5), - stiffness(0.5f), - pressure_coefficient(50), - damping_coefficient(0.005), - drag_coefficient(0.005), + 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), - soft_shape_type(SOFT_SHAPETYPE_NONE), - isScratched(false), - soft_body_shape_data(NULL) { - - test_geometry = memnew(ImmediateGeometry); - - red_mat = Ref<SpatialMaterial>(memnew(SpatialMaterial)); - red_mat->set_flag(SpatialMaterial::FLAG_UNSHADED, true); - red_mat->set_line_width(20.0); - red_mat->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true); - red_mat->set_flag(SpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); - red_mat->set_flag(SpatialMaterial::FLAG_SRGB_VERTEX_COLOR, true); - red_mat->set_albedo(Color(1, 0, 0, 1)); - test_geometry->set_material_override(red_mat); - - test_is_in_scene = false; -} + isScratched(false) {} SoftBodyBullet::~SoftBodyBullet() { - bulletdelete(soft_body_shape_data); } void SoftBodyBullet::reload_body() { @@ -80,8 +62,6 @@ void SoftBodyBullet::reload_body() { void SoftBodyBullet::set_space(SpaceBullet *p_space) { if (space) { isScratched = false; - - // Remove this object from the physics world space->remove_soft_body(this); } @@ -90,86 +70,181 @@ void SoftBodyBullet::set_space(SpaceBullet *p_space) { if (space) { space->add_soft_body(this); } - - reload_soft_body(); } -void SoftBodyBullet::dispatch_callbacks() { - if (!bt_soft_body) { +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) {} + +void SoftBodyBullet::update_visual_server(SoftBodyVisualServerHandler *p_visual_server_handler) { + if (!bt_soft_body) return; + + /// Update visual server vertices + const btSoftBody::tNodeArray &nodes(bt_soft_body->m_nodes); + const int nodes_count = nodes.size(); + + const Vector<int> *vs_indices; + const void *vertex_position; + const void *vertex_normal; + + for (int vertex_index = 0; vertex_index < nodes_count; ++vertex_index) { + vertex_position = reinterpret_cast<const void *>(&nodes[vertex_index].m_x); + vertex_normal = reinterpret_cast<const void *>(&nodes[vertex_index].m_n); + + vs_indices = &indices_table[vertex_index]; + + const int vs_indices_size(vs_indices->size()); + for (int x = 0; x < vs_indices_size; ++x) { + p_visual_server_handler->set_vertex((*vs_indices)[x], vertex_position); + p_visual_server_handler->set_normal((*vs_indices)[x], vertex_normal); + } } - if (!test_is_in_scene) { - test_is_in_scene = true; - SceneTree::get_singleton()->get_current_scene()->add_child(test_geometry); + /// Generate AABB + btVector3 aabb_min; + btVector3 aabb_max; + bt_soft_body->getAabb(aabb_min, aabb_max); + + btVector3 size(aabb_max - aabb_min); + + AABB aabb; + B_TO_G(aabb_min, aabb.position); + B_TO_G(size, aabb.size); + + p_visual_server_handler->set_aabb(aabb); +} + +void SoftBodyBullet::set_soft_mesh(const Ref<Mesh> &p_mesh) { + + if (p_mesh.is_null() || !p_mesh->surface_is_softbody_friendly(0)) + soft_mesh.unref(); + else + soft_mesh = p_mesh; + + if (soft_mesh.is_null()) { + + destroy_soft_body(); + return; } - test_geometry->clear(); - test_geometry->begin(Mesh::PRIMITIVE_LINES, NULL); - bool first = true; - Vector3 pos; - for (int i = 0; i < bt_soft_body->m_nodes.size(); ++i) { - const btSoftBody::Node &n = bt_soft_body->m_nodes[i]; - B_TO_G(n.m_x, pos); - test_geometry->add_vertex(pos); - if (!first) { - test_geometry->add_vertex(pos); - } else { - first = false; - } + Array arrays = soft_mesh->surface_get_arrays(0); + ERR_FAIL_COND(!(soft_mesh->surface_get_format(0) & VS::ARRAY_FORMAT_INDEX)); + set_trimesh_body_shape(arrays[VS::ARRAY_INDEX], arrays[VS::ARRAY_VERTEX]); +} + +void SoftBodyBullet::destroy_soft_body() { + + if (!bt_soft_body) + return; + + if (space) { + /// Remove from world before deletion + space->remove_soft_body(this); } - test_geometry->end(); + + destroyBulletCollisionObject(); + bt_soft_body = NULL; +} + +void SoftBodyBullet::set_soft_transform(const Transform &p_transform) { + reset_all_node_positions(); + move_all_nodes(p_transform); } -void SoftBodyBullet::on_collision_filters_change() { +void SoftBodyBullet::move_all_nodes(const Transform &p_transform) { + if (!bt_soft_body) + return; + btTransform bt_transf; + G_TO_B(p_transform, bt_transf); + bt_soft_body->transform(bt_transf); } -void SoftBodyBullet::on_collision_checker_start() { +void SoftBodyBullet::set_node_position(int p_node_index, const Vector3 &p_global_position) { + btVector3 bt_pos; + G_TO_B(p_global_position, bt_pos); + set_node_position(p_node_index, bt_pos); } -void SoftBodyBullet::on_enter_area(AreaBullet *p_area) { +void SoftBodyBullet::set_node_position(int p_node_index, const btVector3 &p_global_position) { + if (bt_soft_body) { + bt_soft_body->m_nodes[p_node_index].m_x = p_global_position; + } } -void SoftBodyBullet::on_exit_area(AreaBullet *p_area) { +void SoftBodyBullet::get_node_position(int p_node_index, Vector3 &r_position) const { + if (bt_soft_body) { + B_TO_G(bt_soft_body->m_nodes[p_node_index].m_x, r_position); + } } -void SoftBodyBullet::set_trimesh_body_shape(PoolVector<int> p_indices, PoolVector<Vector3> p_vertices, int p_triangles_num) { +void SoftBodyBullet::get_node_offset(int p_node_index, Vector3 &r_offset) const { + if (soft_mesh.is_null()) + return; + + Array arrays = soft_mesh->surface_get_arrays(0); + PoolVector<Vector3> vertices(arrays[VS::ARRAY_VERTEX]); - TrimeshSoftShapeData *shape_data = bulletnew(TrimeshSoftShapeData); - shape_data->m_triangles_indices = p_indices; - shape_data->m_vertices = p_vertices; - shape_data->m_triangles_num = p_triangles_num; + if (0 <= p_node_index && vertices.size() > p_node_index) { + r_offset = vertices[p_node_index]; + } +} - set_body_shape_data(shape_data, SOFT_SHAPE_TYPE_TRIMESH); - reload_soft_body(); +void SoftBodyBullet::get_node_offset(int p_node_index, btVector3 &r_offset) const { + Vector3 off; + get_node_offset(p_node_index, off); + G_TO_B(off, r_offset); } -void SoftBodyBullet::set_body_shape_data(SoftShapeData *p_soft_shape_data, SoftShapeType p_type) { - bulletdelete(soft_body_shape_data); - soft_body_shape_data = p_soft_shape_data; - soft_shape_type = p_type; +void SoftBodyBullet::set_node_mass(int node_index, btScalar p_mass) { + if (0 >= p_mass) { + pin_node(node_index); + } else { + unpin_node(node_index); + } + if (bt_soft_body) { + bt_soft_body->setMass(node_index, p_mass); + } } -void SoftBodyBullet::set_transform(const Transform &p_transform) { - transform = p_transform; +btScalar SoftBodyBullet::get_node_mass(int node_index) const { if (bt_soft_body) { - // TODO the softbody set new transform considering the current transform as center of world - // like if it's local transform, so I must fix this by setting nwe transform considering the old - btTransform bt_trans; - G_TO_B(transform, bt_trans); - //bt_soft_body->transform(bt_trans); + return bt_soft_body->getMass(node_index); + } else { + return -1 == search_node_pinned(node_index) ? 1 : 0; } } -const Transform &SoftBodyBullet::get_transform() const { - return transform; +void SoftBodyBullet::reset_all_node_mass() { + if (bt_soft_body) { + for (int i = pinned_nodes.size() - 1; 0 <= i; --i) { + bt_soft_body->setMass(pinned_nodes[i], 1); + } + } + pinned_nodes.resize(0); } -void SoftBodyBullet::get_first_node_origin(btVector3 &p_out_origin) const { - if (bt_soft_body && bt_soft_body->m_nodes.size()) { - p_out_origin = bt_soft_body->m_nodes[0].m_x; - } else { - p_out_origin.setZero(); +void SoftBodyBullet::reset_all_node_positions() { + if (soft_mesh.is_null()) + return; + + Array arrays = soft_mesh->surface_get_arrays(0); + PoolVector<Vector3> vs_vertices(arrays[VS::ARRAY_VERTEX]); + PoolVector<Vector3>::Read vs_vertices_read = vs_vertices.read(); + + for (int vertex_index = bt_soft_body->m_nodes.size() - 1; 0 <= vertex_index; --vertex_index) { + + G_TO_B(vs_vertices_read[indices_table[vertex_index][0]], bt_soft_body->m_nodes[vertex_index].m_x); + + bt_soft_body->m_nodes[vertex_index].m_q = bt_soft_body->m_nodes[vertex_index].m_x; + bt_soft_body->m_nodes[vertex_index].m_v = btVector3(0, 0, 0); + bt_soft_body->m_nodes[vertex_index].m_f = btVector3(0, 0, 0); } } @@ -181,22 +256,34 @@ void SoftBodyBullet::set_activation_state(bool p_active) { } } -void SoftBodyBullet::set_mass(real_t p_val) { +void SoftBodyBullet::set_total_mass(real_t p_val) { if (0 >= p_val) { p_val = 1; } - mass = p_val; + total_mass = p_val; if (bt_soft_body) { - bt_soft_body->setTotalMass(mass); + bt_soft_body->setTotalMass(total_mass); } } -void SoftBodyBullet::set_stiffness(real_t p_val) { - stiffness = p_val; +void SoftBodyBullet::set_linear_stiffness(real_t p_val) { + linear_stiffness = p_val; if (bt_soft_body) { - mat0->m_kAST = stiffness; - mat0->m_kLST = stiffness; - mat0->m_kVST = stiffness; + mat0->m_kLST = linear_stiffness; + } +} + +void SoftBodyBullet::set_areaAngular_stiffness(real_t p_val) { + areaAngular_stiffness = p_val; + if (bt_soft_body) { + mat0->m_kAST = areaAngular_stiffness; + } +} + +void SoftBodyBullet::set_volume_stiffness(real_t p_val) { + volume_stiffness = p_val; + if (bt_soft_body) { + mat0->m_kVST = volume_stiffness; } } @@ -204,6 +291,9 @@ void SoftBodyBullet::set_simulation_precision(int p_val) { simulation_precision = p_val; if (bt_soft_body) { bt_soft_body->m_cfg.piterations = simulation_precision; + bt_soft_body->m_cfg.viterations = simulation_precision; + bt_soft_body->m_cfg.diterations = simulation_precision; + bt_soft_body->m_cfg.citerations = simulation_precision; } } @@ -214,6 +304,13 @@ void SoftBodyBullet::set_pressure_coefficient(real_t p_val) { } } +void SoftBodyBullet::set_pose_matching_coefficient(real_t p_val) { + pose_matching_coefficient = p_val; + if (bt_soft_body) { + bt_soft_body->m_cfg.kMT = pose_matching_coefficient; + } +} + void SoftBodyBullet::set_damping_coefficient(real_t p_val) { damping_coefficient = p_val; if (bt_soft_body) { @@ -228,89 +325,156 @@ void SoftBodyBullet::set_drag_coefficient(real_t p_val) { } } -void SoftBodyBullet::reload_soft_body() { - +void SoftBodyBullet::set_trimesh_body_shape(PoolVector<int> p_indices, PoolVector<Vector3> p_vertices) { + /// Assert the current soft body is destroyed destroy_soft_body(); - create_soft_body(); - if (bt_soft_body) { + /// Parse visual server indices to physical indices. + /// Merge all overlapping vertices and create a map of physical vertices to visual server - // TODO the softbody set new transform considering the current transform as center of world - // like if it's local transform, so I must fix this by setting nwe transform considering the old - btTransform bt_trans; - G_TO_B(transform, bt_trans); - bt_soft_body->transform(bt_trans); + { + /// This is the map of visual server indices to physics indices (So it's the inverse of idices_map), Thanks to it I don't need make a heavy search in the indices_map + Vector<int> vs_indices_to_physics_table; - bt_soft_body->generateBendingConstraints(2, mat0); - mat0->m_kAST = stiffness; - mat0->m_kLST = stiffness; - mat0->m_kVST = stiffness; + { // Map vertices + indices_table.resize(0); - bt_soft_body->m_cfg.piterations = simulation_precision; - bt_soft_body->m_cfg.kDP = damping_coefficient; - bt_soft_body->m_cfg.kDG = drag_coefficient; - bt_soft_body->m_cfg.kPR = pressure_coefficient; - bt_soft_body->setTotalMass(mass); - } - if (space) { - // TODO remove this please - space->add_soft_body(this); - } -} + int index = 0; + Map<Vector3, int> unique_vertices; -void SoftBodyBullet::create_soft_body() { - if (!space || !soft_body_shape_data) { - return; - } - ERR_FAIL_COND(!space->is_using_soft_world()); - switch (soft_shape_type) { - case SOFT_SHAPE_TYPE_TRIMESH: { - TrimeshSoftShapeData *trimesh_data = static_cast<TrimeshSoftShapeData *>(soft_body_shape_data); - - Vector<int> indices; - Vector<btScalar> vertices; - - int i; - const int indices_size = trimesh_data->m_triangles_indices.size(); - const int vertices_size = trimesh_data->m_vertices.size(); - indices.resize(indices_size); - vertices.resize(vertices_size * 3); - - PoolVector<int>::Read i_r = trimesh_data->m_triangles_indices.read(); - for (i = 0; i < indices_size; ++i) { - indices[i] = i_r[i]; + const int vs_vertices_size(p_vertices.size()); + + PoolVector<Vector3>::Read p_vertices_read = p_vertices.read(); + + for (int vs_vertex_index = 0; vs_vertex_index < vs_vertices_size; ++vs_vertex_index) { + + Map<Vector3, int>::Element *e = unique_vertices.find(p_vertices_read[vs_vertex_index]); + int vertex_id; + if (e) { + // Already rxisting + vertex_id = e->value(); + } else { + // Create new one + unique_vertices[p_vertices_read[vs_vertex_index]] = vertex_id = index++; + indices_table.push_back(Vector<int>()); + } + + indices_table.write[vertex_id].push_back(vs_vertex_index); + vs_indices_to_physics_table.push_back(vertex_id); + } + } + + const int indices_map_size(indices_table.size()); + + Vector<btScalar> bt_vertices; + + { // Parse vertices to bullet + + bt_vertices.resize(indices_map_size * 3); + PoolVector<Vector3>::Read p_vertices_read = p_vertices.read(); + + for (int i = 0; i < indices_map_size; ++i) { + bt_vertices.write[3 * i + 0] = p_vertices_read[indices_table[i][0]].x; + bt_vertices.write[3 * i + 1] = p_vertices_read[indices_table[i][0]].y; + bt_vertices.write[3 * i + 2] = p_vertices_read[indices_table[i][0]].z; } - i_r = PoolVector<int>::Read(); + } + + Vector<int> bt_triangles; + const int triangles_size(p_indices.size() / 3); + + { // Parse indices + + bt_triangles.resize(triangles_size * 3); + + PoolVector<int>::Read p_indices_read = p_indices.read(); - PoolVector<Vector3>::Read f_r = trimesh_data->m_vertices.read(); - for (int j = i = 0; i < vertices_size; ++i, j += 3) { - vertices[j + 0] = f_r[i][0]; - vertices[j + 1] = f_r[i][1]; - vertices[j + 2] = f_r[i][2]; + for (int i = 0; i < triangles_size; ++i) { + bt_triangles.write[3 * i + 0] = vs_indices_to_physics_table[p_indices_read[3 * i + 2]]; + bt_triangles.write[3 * i + 1] = vs_indices_to_physics_table[p_indices_read[3 * i + 1]]; + bt_triangles.write[3 * i + 2] = vs_indices_to_physics_table[p_indices_read[3 * i + 0]]; } - f_r = PoolVector<Vector3>::Read(); + } - bt_soft_body = btSoftBodyHelpers::CreateFromTriMesh(*space->get_soft_body_world_info(), vertices.ptr(), indices.ptr(), trimesh_data->m_triangles_num); - } break; - default: - ERR_PRINT("Shape type not supported"); - return; + btSoftBodyWorldInfo fake_world_info; + bt_soft_body = btSoftBodyHelpers::CreateFromTriMesh(fake_world_info, &bt_vertices[0], &bt_triangles[0], triangles_size, false); + setup_soft_body(); } +} + +void SoftBodyBullet::setup_soft_body() { + + if (!bt_soft_body) + return; + // Soft body setup setupBulletCollisionObject(bt_soft_body); - bt_soft_body->getCollisionShape()->setMargin(0.001f); + bt_soft_body->m_worldInfo = NULL; // Remove fake world info + bt_soft_body->getCollisionShape()->setMargin(0.01); bt_soft_body->setCollisionFlags(bt_soft_body->getCollisionFlags() & (~(btCollisionObject::CF_KINEMATIC_OBJECT | btCollisionObject::CF_STATIC_OBJECT))); + + // Space setup + if (space) { + space->add_soft_body(this); + } + mat0 = bt_soft_body->appendMaterial(); + + // Assign soft body data + bt_soft_body->generateBendingConstraints(2, mat0); + + mat0->m_kLST = linear_stiffness; + mat0->m_kAST = areaAngular_stiffness; + mat0->m_kVST = volume_stiffness; + + // Clusters allow to have Soft vs Soft collision but doesn't work well right now + + //bt_soft_body->m_cfg.kSRHR_CL = 1;// Soft vs rigid hardness [0,1] (cluster only) + //bt_soft_body->m_cfg.kSKHR_CL = 1;// Soft vs kinematic hardness [0,1] (cluster only) + //bt_soft_body->m_cfg.kSSHR_CL = 1;// Soft vs soft hardness [0,1] (cluster only) + //bt_soft_body->m_cfg.kSR_SPLT_CL = 1; // Soft vs rigid impulse split [0,1] (cluster only) + //bt_soft_body->m_cfg.kSK_SPLT_CL = 1; // Soft vs kinematic impulse split [0,1] (cluster only) + //bt_soft_body->m_cfg.kSS_SPLT_CL = 1; // Soft vs Soft impulse split [0,1] (cluster only) + //bt_soft_body->m_cfg.collisions = btSoftBody::fCollision::CL_SS + btSoftBody::fCollision::CL_RS + btSoftBody::fCollision::VF_SS; + //bt_soft_body->generateClusters(64); + + bt_soft_body->m_cfg.piterations = simulation_precision; + bt_soft_body->m_cfg.viterations = simulation_precision; + bt_soft_body->m_cfg.diterations = simulation_precision; + bt_soft_body->m_cfg.citerations = simulation_precision; + bt_soft_body->m_cfg.kDP = damping_coefficient; + bt_soft_body->m_cfg.kDG = drag_coefficient; + bt_soft_body->m_cfg.kPR = pressure_coefficient; + bt_soft_body->m_cfg.kMT = pose_matching_coefficient; + bt_soft_body->setTotalMass(total_mass); + + btSoftBodyHelpers::ReoptimizeLinkOrder(bt_soft_body); + bt_soft_body->updateBounds(); + + // Set pinned nodes + for (int i = pinned_nodes.size() - 1; 0 <= i; --i) { + bt_soft_body->setMass(pinned_nodes[i], 0); + } } -void SoftBodyBullet::destroy_soft_body() { - if (space) { - /// This step is required to assert that the body is not into the world during deletion - /// This step is required since to change the body shape the body must be re-created. - /// Here is handled the case when the body is assigned into a world and the body - /// shape is changed. - space->remove_soft_body(this); +void SoftBodyBullet::pin_node(int p_node_index) { + if (-1 == search_node_pinned(p_node_index)) { + pinned_nodes.push_back(p_node_index); } - destroyBulletCollisionObject(); - bt_soft_body = NULL; +} + +void SoftBodyBullet::unpin_node(int p_node_index) { + const int id = search_node_pinned(p_node_index); + if (-1 != id) { + pinned_nodes.remove(id); + } +} + +int SoftBodyBullet::search_node_pinned(int p_node_index) const { + for (int i = pinned_nodes.size() - 1; 0 <= i; --i) { + if (p_node_index == pinned_nodes[i]) { + return i; + } + } + return -1; } diff --git a/modules/bullet/soft_body_bullet.h b/modules/bullet/soft_body_bullet.h index 9895643b84..c775193584 100644 --- a/modules/bullet/soft_body_bullet.h +++ b/modules/bullet/soft_body_bullet.h @@ -40,7 +40,10 @@ #define x11_None 0L #endif -#include <BulletSoftBody/btSoftBodyHelpers.h> +#include "BulletSoftBody/btSoftBodyHelpers.h" +#include "collision_object_bullet.h" +#include "scene/resources/mesh.h" +#include "servers/physics_server.h" #ifdef x11_None /// This is required to re add the macro None defined by x11 compiler @@ -52,39 +55,34 @@ @author AndreaCatania */ -struct SoftShapeData {}; -struct TrimeshSoftShapeData : public SoftShapeData { - PoolVector<int> m_triangles_indices; - PoolVector<Vector3> m_vertices; - int m_triangles_num; -}; - class SoftBodyBullet : public CollisionObjectBullet { -public: - enum SoftShapeType { - SOFT_SHAPETYPE_NONE = 0, - SOFT_SHAPE_TYPE_TRIMESH - }; private: btSoftBody *bt_soft_body; + Vector<Vector<int> > indices_table; btSoftBody::Material *mat0; // This is just a copy of pointer managed by btSoftBody - SoftShapeType soft_shape_type; bool isScratched; - SoftShapeData *soft_body_shape_data; + Ref<Mesh> soft_mesh; - Transform transform; int simulation_precision; - real_t mass; - real_t stiffness; // [0,1] + real_t total_mass; + real_t linear_stiffness; // [0,1] + real_t areaAngular_stiffness; // [0,1] + real_t volume_stiffness; // [0,1] real_t pressure_coefficient; // [-inf,+inf] + real_t pose_matching_coefficient; // [0,1] real_t damping_coefficient; // [0,1] real_t drag_coefficient; // [0,1] + Vector<int> pinned_nodes; - class ImmediateGeometry *test_geometry; // TODO remove this please - Ref<SpatialMaterial> red_mat; // TODO remove this please - bool test_is_in_scene; // TODO remove this please + // Other property to add + //btScalar kVC; // Volume conversation coefficient [0,+inf] + //btScalar kDF; // Dynamic friction coefficient [0,1] + //btScalar kMT; // Pose matching coefficient [0,1] + //btScalar kCHR; // Rigid contacts hardness [0,1] + //btScalar kKHR; // Kinetic contacts hardness [0,1] + //btScalar kSHR; // Soft contacts hardness [0,1] public: SoftBodyBullet(); @@ -101,39 +99,64 @@ public: _FORCE_INLINE_ btSoftBody *get_bt_soft_body() const { return bt_soft_body; } - void set_trimesh_body_shape(PoolVector<int> p_indices, PoolVector<Vector3> p_vertices, int p_triangles_num); - void set_body_shape_data(SoftShapeData *p_soft_shape_data, SoftShapeType p_type); + void update_visual_server(class SoftBodyVisualServerHandler *p_visual_server_handler); - void set_transform(const Transform &p_transform); - /// This function doesn't return the exact COM transform. - /// It returns the origin only of first node (vertice) of current soft body - /// --- - /// The soft body doesn't have a fixed center of mass, but is a group of nodes (vertices) - /// that each has its own position in the world. - /// For this reason return the correct COM is not so simple and must be calculate - /// Check this to improve this function http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=8803 - const Transform &get_transform() const; - void get_first_node_origin(btVector3 &p_out_origin) const; + void set_soft_mesh(const Ref<Mesh> &p_mesh); + void destroy_soft_body(); + + // Special function. This function has bad performance + void set_soft_transform(const Transform &p_transform); + + void move_all_nodes(const Transform &p_transform); + void set_node_position(int node_index, const Vector3 &p_global_position); + void set_node_position(int node_index, const btVector3 &p_global_position); + void get_node_position(int node_index, Vector3 &r_position) const; + // Heavy function, Please cache this info + void get_node_offset(int node_index, Vector3 &r_offset) const; + // Heavy function, Please cache this info + void get_node_offset(int node_index, btVector3 &r_offset) const; + + void set_node_mass(int node_index, btScalar p_mass); + btScalar get_node_mass(int node_index) const; + void reset_all_node_mass(); + void reset_all_node_positions(); void set_activation_state(bool p_active); - void set_mass(real_t p_val); - _FORCE_INLINE_ real_t get_mass() const { return mass; } - void set_stiffness(real_t p_val); - _FORCE_INLINE_ real_t get_stiffness() const { return stiffness; } + void set_total_mass(real_t p_val); + _FORCE_INLINE_ real_t get_total_mass() const { return total_mass; } + + void set_linear_stiffness(real_t p_val); + _FORCE_INLINE_ real_t get_linear_stiffness() const { return linear_stiffness; } + + void set_areaAngular_stiffness(real_t p_val); + _FORCE_INLINE_ real_t get_areaAngular_stiffness() const { return areaAngular_stiffness; } + + void set_volume_stiffness(real_t p_val); + _FORCE_INLINE_ real_t get_volume_stiffness() const { return volume_stiffness; } + void set_simulation_precision(int p_val); _FORCE_INLINE_ int get_simulation_precision() const { return simulation_precision; } + void set_pressure_coefficient(real_t p_val); _FORCE_INLINE_ real_t get_pressure_coefficient() const { return pressure_coefficient; } + + void set_pose_matching_coefficient(real_t p_val); + _FORCE_INLINE_ real_t get_pose_matching_coefficient() const { return pose_matching_coefficient; } + void set_damping_coefficient(real_t p_val); _FORCE_INLINE_ real_t get_damping_coefficient() const { return damping_coefficient; } + void set_drag_coefficient(real_t p_val); _FORCE_INLINE_ real_t get_drag_coefficient() const { return drag_coefficient; } private: - void reload_soft_body(); - void create_soft_body(); - void destroy_soft_body(); + void set_trimesh_body_shape(PoolVector<int> p_indices, PoolVector<Vector3> p_vertices); + void setup_soft_body(); + + void pin_node(int p_node_index); + void unpin_node(int p_node_index); + int search_node_pinned(int p_node_index) const; }; #endif // SOFT_BODY_BULLET_H diff --git a/modules/bullet/space_bullet.cpp b/modules/bullet/space_bullet.cpp index dec8e66c71..8454bea4eb 100644 --- a/modules/bullet/space_bullet.cpp +++ b/modules/bullet/space_bullet.cpp @@ -36,6 +36,7 @@ #include "constraint_bullet.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" @@ -116,13 +117,13 @@ 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 *p_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) { if (p_result_max <= 0) return 0; 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); + btCollisionShape *btShape = shape->create_bt_shape(p_xform.basis.get_scale_abs(), 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())); @@ -138,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, p_results, p_result_max, &p_exclude); + GodotAllContactResultCallback btQuery(&collision_object, r_results, p_result_max, &p_exclude); btQuery.m_collisionFilterGroup = 0; btQuery.m_collisionFilterMask = p_collision_mask; btQuery.m_closestDistanceThreshold = 0; @@ -202,7 +203,7 @@ bool BulletPhysicsDirectSpaceState::collide_shape(RID p_shape, const Transform & ShapeBullet *shape = space->get_physics_server()->get_shape_owner()->get(p_shape); - btCollisionShape *btShape = shape->create_bt_shape(p_shape_xform.basis.get_scale(), p_margin); + btCollisionShape *btShape = shape->create_bt_shape(p_shape_xform.basis.get_scale_abs(), 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())); @@ -234,7 +235,7 @@ bool BulletPhysicsDirectSpaceState::rest_info(RID p_shape, const Transform &p_sh ShapeBullet *shape = space->get_physics_server()->get_shape_owner()->get(p_shape); - btCollisionShape *btShape = shape->create_bt_shape(p_shape_xform.basis.get_scale(), p_margin); + btCollisionShape *btShape = shape->create_bt_shape(p_shape_xform.basis.get_scale_abs(), 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())); @@ -325,7 +326,7 @@ Vector3 BulletPhysicsDirectSpaceState::get_closest_point_to_object_volume(RID p_ } } -SpaceBullet::SpaceBullet(bool p_create_soft_world) : +SpaceBullet::SpaceBullet() : broadphase(NULL), dispatcher(NULL), solver(NULL), @@ -338,7 +339,7 @@ SpaceBullet::SpaceBullet(bool p_create_soft_world) : gravityMagnitude(10), contactDebugCount(0) { - create_empty_world(p_create_soft_world); + create_empty_world(GLOBAL_DEF("physics/3d/active_soft_world", true)); direct_access = memnew(BulletPhysicsDirectSpaceState(this)); } @@ -355,6 +356,7 @@ void SpaceBullet::flush_queries() { } void SpaceBullet::step(real_t p_delta_time) { + delta_time = p_delta_time; dynamicsWorld->stepSimulation(p_delta_time, 0, 0); } @@ -483,6 +485,7 @@ void SpaceBullet::reload_collision_filters(RigidBodyBullet *p_body) { void SpaceBullet::add_soft_body(SoftBodyBullet *p_body) { if (is_using_soft_world()) { if (p_body->get_bt_soft_body()) { + p_body->get_bt_soft_body()->m_worldInfo = get_soft_body_world_info(); static_cast<btSoftRigidDynamicsWorld *>(dynamicsWorld)->addSoftBody(p_body->get_bt_soft_body(), p_body->get_collision_layer(), p_body->get_collision_mask()); } } else { @@ -494,6 +497,7 @@ void SpaceBullet::remove_soft_body(SoftBodyBullet *p_body) { if (is_using_soft_world()) { if (p_body->get_bt_soft_body()) { static_cast<btSoftRigidDynamicsWorld *>(dynamicsWorld)->removeSoftBody(p_body->get_bt_soft_body()); + p_body->get_bt_soft_body()->m_worldInfo = NULL; } } } @@ -549,7 +553,43 @@ BulletPhysicsDirectSpaceState *SpaceBullet::get_direct_state() { } btScalar calculateGodotCombinedRestitution(const btCollisionObject *body0, const btCollisionObject *body1) { - return MAX(body0->getRestitution(), body1->getRestitution()); + + 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; + } +} + +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; + } } void SpaceBullet::create_empty_world(bool p_create_soft_world) { @@ -585,6 +625,7 @@ void SpaceBullet::create_empty_world(bool p_create_soft_world) { ghostPairCallback = bulletnew(btGhostPairCallback); godotFilterCallback = bulletnew(GodotFilterCallback); gCalculateCombinedRestitutionCallback = &calculateGodotCombinedRestitution; + gCalculateCombinedFrictionCallback = &calculateGodotCombinedFriction; dynamicsWorld->setWorldUserInfo(this); @@ -628,7 +669,7 @@ void SpaceBullet::destroy_world() { void SpaceBullet::check_ghost_overlaps() { - /// Algorith support variables + /// Algorithm support variables btConvexShape *other_body_shape; btConvexShape *area_shape; btGjkPairDetector::ClosestPointInput gjk_input; @@ -645,7 +686,7 @@ void SpaceBullet::check_ghost_overlaps() { /// 1. Reset all states for (i = area->overlappingObjects.size() - 1; 0 <= i; --i) { - AreaBullet::OverlappingObjectData &otherObj = area->overlappingObjects[i]; + AreaBullet::OverlappingObjectData &otherObj = area->overlappingObjects.write[i]; // This check prevent the overwrite of ENTER state // if this function is called more times before dispatchCallbacks if (otherObj.state != AreaBullet::OVERLAP_STATE_ENTER) { @@ -660,7 +701,10 @@ void SpaceBullet::check_ghost_overlaps() { // For each overlapping for (i = ghostOverlaps.size() - 1; 0 <= i; --i) { - if (!(ghostOverlaps[i]->getUserIndex() == CollisionObjectBullet::TYPE_RIGID_BODY || ghostOverlaps[i]->getUserIndex() == CollisionObjectBullet::TYPE_AREA)) + 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) continue; otherObject = static_cast<RigidCollisionObjectBullet *>(ghostOverlaps[i]->getUserPointer()); @@ -791,7 +835,7 @@ void SpaceBullet::update_gravity() { /// I'm leaving this here just for future tests. /// Debug motion and normal vector drawing #define debug_test_motion 0 -#define PERFORM_INITIAL_UNSTACK 0 + #define RECOVERING_MOVEMENT_SCALE 0.4 #define RECOVERING_MOVEMENT_CYCLES 4 @@ -805,8 +849,7 @@ static Ref<SpatialMaterial> red_mat; static Ref<SpatialMaterial> blue_mat; #endif -#define IGNORE_AREAS_TRUE true -bool SpaceBullet::test_body_motion(RigidBodyBullet *p_body, const Transform &p_from, const Vector3 &p_motion, 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) { #if debug_test_motion /// Yes I know this is not good, but I've used it as fast debugging hack. @@ -840,33 +883,20 @@ bool SpaceBullet::test_body_motion(RigidBodyBullet *p_body, const Transform &p_f } #endif - ///// Release all generated manifolds - //{ - // if(p_body->get_kinematic_utilities()){ - // for(int i= p_body->get_kinematic_utilities()->m_generatedManifold.size()-1; 0<=i; --i){ - // dispatcher->releaseManifold( p_body->get_kinematic_utilities()->m_generatedManifold[i] ); - // } - // p_body->get_kinematic_utilities()->m_generatedManifold.clear(); - // } - //} - - btTransform body_safe_position; - G_TO_B(p_from, body_safe_position); - UNSCALE_BT_BASIS(body_safe_position); - -#if PERFORM_INITIAL_UNSTACK - btVector3 recover_initial_position(0, 0, 0); + btTransform body_transform; + G_TO_B(p_from, body_transform); + UNSCALE_BT_BASIS(body_transform); + + btVector3 initial_recover_motion(0, 0, 0); { /// Phase one - multi shapes depenetration using margin for (int t(RECOVERING_MOVEMENT_CYCLES); 0 < t; --t) { - if (!recover_from_penetration(p_body, body_safe_position, RECOVERING_MOVEMENT_SCALE, recover_initial_position)) { + if (!recover_from_penetration(p_body, body_transform, RECOVERING_MOVEMENT_SCALE, p_infinite_inertia, initial_recover_motion)) { break; } } - // Add recover movement in order to make it safe - body_safe_position.getOrigin() += recover_initial_position; + body_transform.getOrigin() += initial_recover_motion; } -#endif btVector3 motion; G_TO_B(p_motion, motion); @@ -896,16 +926,16 @@ bool SpaceBullet::test_body_motion(RigidBodyBullet *p_body, const Transform &p_f } btConvexShape *convex_shape_test(static_cast<btConvexShape *>(p_body->get_bt_shape(shIndex))); - btTransform shape_world_from = body_safe_position * p_body->get_kinematic_utilities()->shapes[shIndex].transform; + btTransform shape_world_from = body_transform * p_body->get_kinematic_utilities()->shapes[shIndex].transform; btTransform shape_world_to(shape_world_from); shape_world_to.getOrigin() += motion; - GodotKinClosestConvexResultCallback btResult(shape_world_from.getOrigin(), shape_world_to.getOrigin(), p_body, IGNORE_AREAS_TRUE); + GodotKinClosestConvexResultCallback btResult(shape_world_from.getOrigin(), shape_world_to.getOrigin(), p_body, p_infinite_inertia); btResult.m_collisionFilterGroup = p_body->get_collision_layer(); btResult.m_collisionFilterMask = p_body->get_collision_mask(); - dynamicsWorld->convexSweepTest(convex_shape_test, shape_world_from, shape_world_to, btResult, 0.002); + dynamicsWorld->convexSweepTest(convex_shape_test, shape_world_from, shape_world_to, btResult, dynamicsWorld->getDispatchInfo().m_allowedCcdPenetration); if (btResult.hasHit()) { /// Since for each sweep test I fix the motion of new shapes in base the recover result, @@ -914,72 +944,49 @@ bool SpaceBullet::test_body_motion(RigidBodyBullet *p_body, const Transform &p_f } } - body_safe_position.getOrigin() += motion; + body_transform.getOrigin() += motion; } bool has_penetration = false; - { /// Phase three - Recover + contact test with margin + { /// Phase three - contact test with margin - btVector3 delta_recover_movement(0, 0, 0); + btVector3 __rec(0, 0, 0); RecoverResult r_recover_result; - bool l_has_penetration; - real_t l_penetration_distance = 1e20; - for (int t(RECOVERING_MOVEMENT_CYCLES); 0 < t; --t) { - l_has_penetration = recover_from_penetration(p_body, body_safe_position, RECOVERING_MOVEMENT_SCALE, delta_recover_movement, &r_recover_result); + has_penetration = recover_from_penetration(p_body, body_transform, 0, p_infinite_inertia, __rec, &r_recover_result); - if (r_result) { -#if PERFORM_INITIAL_UNSTACK - B_TO_G(motion + delta_recover_movement + recover_initial_position, r_result->motion); -#else - B_TO_G(motion + delta_recover_movement, r_result->motion); -#endif - if (l_has_penetration) { - has_penetration = true; - if (l_penetration_distance <= r_recover_result.penetration_distance) { - continue; - } + // Parse results + if (r_result) { + B_TO_G(motion + initial_recover_motion, r_result->motion); - l_penetration_distance = r_recover_result.penetration_distance; - - const btRigidBody *btRigid = static_cast<const btRigidBody *>(r_recover_result.other_collision_object); - CollisionObjectBullet *collisionObject = static_cast<CollisionObjectBullet *>(btRigid->getUserPointer()); - - B_TO_G(motion, r_result->remainder); // is the remaining movements - r_result->remainder = p_motion - r_result->remainder; - B_TO_G(r_recover_result.pointWorld, r_result->collision_point); - B_TO_G(r_recover_result.normal, r_result->collision_normal); - B_TO_G(btRigid->getVelocityInLocalPoint(r_recover_result.pointWorld - btRigid->getWorldTransform().getOrigin()), r_result->collider_velocity); // It calculates velocity at point and assign it using special function Bullet_to_Godot - r_result->collider = collisionObject->get_self(); - r_result->collider_id = collisionObject->get_instance_id(); - r_result->collider_shape = r_recover_result.other_compound_shape_index; - r_result->collision_local_shape = r_recover_result.local_shape_most_recovered; - - //{ /// Add manifold point to manage collisions - // btPersistentManifold* manifold = dynamicsWorld->getDispatcher()->getNewManifold(p_body->getBtBody(), btRigid); - // btManifoldPoint manifoldPoint(result_callabck.m_pointWorld, result_callabck.m_pointWorld, result_callabck.m_pointNormalWorld, result_callabck.m_penetration_distance); - // manifoldPoint.m_index0 = r_result->collision_local_shape; - // manifoldPoint.m_index1 = r_result->collider_shape; - // manifold->addManifoldPoint(manifoldPoint); - // p_body->get_kinematic_utilities()->m_generatedManifold.push_back(manifold); - //} + if (has_penetration) { + + const btRigidBody *btRigid = static_cast<const btRigidBody *>(r_recover_result.other_collision_object); + CollisionObjectBullet *collisionObject = static_cast<CollisionObjectBullet *>(btRigid->getUserPointer()); + + B_TO_G(motion, r_result->remainder); // is the remaining movements + r_result->remainder = p_motion - r_result->remainder; + + B_TO_G(r_recover_result.pointWorld, r_result->collision_point); + B_TO_G(r_recover_result.normal, r_result->collision_normal); + B_TO_G(btRigid->getVelocityInLocalPoint(r_recover_result.pointWorld - btRigid->getWorldTransform().getOrigin()), r_result->collider_velocity); // It calculates velocity at point and assign it using special function Bullet_to_Godot + r_result->collider = collisionObject->get_self(); + r_result->collider_id = collisionObject->get_instance_id(); + r_result->collider_shape = r_recover_result.other_compound_shape_index; + r_result->collision_local_shape = r_recover_result.local_shape_most_recovered; #if debug_test_motion - Vector3 sup_line2; - B_TO_G(motion, sup_line2); - normalLine->clear(); - normalLine->begin(Mesh::PRIMITIVE_LINES, NULL); - normalLine->add_vertex(r_result->collision_point); - normalLine->add_vertex(r_result->collision_point + r_result->collision_normal * 10); - normalLine->end(); + Vector3 sup_line2; + B_TO_G(motion, sup_line2); + normalLine->clear(); + normalLine->begin(Mesh::PRIMITIVE_LINES, NULL); + normalLine->add_vertex(r_result->collision_point); + normalLine->add_vertex(r_result->collision_point + r_result->collision_normal * 10); + normalLine->end(); #endif - } else { - r_result->remainder = Vector3(); - } } else { - if (!l_has_penetration) - break; + r_result->remainder = Vector3(); } } } @@ -1017,11 +1024,11 @@ public: } void reset() { - result_collision_objects.empty(); + result_collision_objects.clear(); } }; -bool SpaceBullet::recover_from_penetration(RigidBodyBullet *p_body, const btTransform &p_body_position, btScalar p_recover_movement_scale, btVector3 &r_delta_recover_movement, RecoverResult *r_recover_result) { +bool SpaceBullet::recover_from_penetration(RigidBodyBullet *p_body, const btTransform &p_body_position, btScalar p_recover_movement_scale, bool p_infinite_inertia, btVector3 &r_delta_recover_movement, RecoverResult *r_recover_result) { RecoverPenetrationBroadPhaseCallback recover_broad_result(p_body->get_bt_collision_object(), p_body->get_collision_layer(), p_body->get_collision_mask()); @@ -1052,7 +1059,10 @@ bool SpaceBullet::recover_from_penetration(RigidBodyBullet *p_body, const btTran 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_body->get_bt_collision_object()->checkCollideWith(otherObject) || !otherObject->checkCollideWith(p_body->get_bt_collision_object())) + 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()) { @@ -1131,7 +1141,7 @@ bool SpaceBullet::RFP_convex_world_test(const btConvexShape *p_shapeA, const btC btCollisionObjectWrapper obA(NULL, p_shapeA, p_objectA, tA, -1, p_shapeId_A); btCollisionObjectWrapper obB(NULL, p_shapeB, p_objectB, p_transformB, -1, p_shapeId_B); - btCollisionAlgorithm *algorithm = dispatcher->findAlgorithm(&obA, &obB, NULL, BT_CLOSEST_POINT_ALGORITHMS); + btCollisionAlgorithm *algorithm = dispatcher->findAlgorithm(&obA, &obB, NULL, BT_CONTACT_POINT_ALGORITHMS); if (algorithm) { GodotDeepPenetrationContactResultCallback contactPointResult(&obA, &obB); //discrete collision detection query diff --git a/modules/bullet/space_bullet.h b/modules/bullet/space_bullet.h index 0aeb407dcc..6b86fc2f03 100644 --- a/modules/bullet/space_bullet.h +++ b/modules/bullet/space_bullet.h @@ -84,7 +84,7 @@ public: }; class SpaceBullet : public RIDBullet { -private: + friend class AreaBullet; friend void onBulletTickCallback(btDynamicsWorld *world, btScalar timeStep); friend class BulletPhysicsDirectSpaceState; @@ -109,12 +109,14 @@ private: Vector<Vector3> contactDebug; int contactDebugCount; + real_t delta_time; public: - SpaceBullet(bool p_create_soft_world); + SpaceBullet(); virtual ~SpaceBullet(); void flush_queries(); + real_t get_delta_time() { return delta_time; } void step(real_t p_delta_time); _FORCE_INLINE_ btBroadphaseInterface *get_broadphase() { return broadphase; } @@ -162,7 +164,7 @@ public: contactDebugCount = 0; } _FORCE_INLINE_ void add_debug_contact(const Vector3 &p_contact) { - if (contactDebugCount < contactDebug.size()) contactDebug[contactDebugCount++] = p_contact; + if (contactDebugCount < contactDebug.size()) contactDebug.write[contactDebugCount++] = p_contact; } _FORCE_INLINE_ Vector<Vector3> get_debug_contacts() { return contactDebug; } _FORCE_INLINE_ int get_debug_contact_count() { return contactDebugCount; } @@ -172,7 +174,7 @@ public: void update_gravity(); - bool test_body_motion(RigidBodyBullet *p_body, const Transform &p_from, const Vector3 &p_motion, 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); private: void create_empty_world(bool p_create_soft_world); @@ -199,12 +201,12 @@ private: local_shape_most_recovered(0) {} }; - bool recover_from_penetration(RigidBodyBullet *p_body, const btTransform &p_from, btScalar p_recover_movement_scale, btVector3 &r_delta_recover_movement, RecoverResult *r_recover_result = NULL); + bool recover_from_penetration(RigidBodyBullet *p_body, const btTransform &p_body_position, btScalar p_recover_movement_scale, bool p_infinite_inertia, btVector3 &r_delta_recover_movement, RecoverResult *r_recover_result = NULL); /// This is an API that recover a kinematic object from penetration /// This allow only Convex Convex test and it always use GJK algorithm, With this API we don't benefit of Bullet special accelerated functions - bool RFP_convex_convex_test(const btConvexShape *p_shapeA, const btConvexShape *p_shapeB, btCollisionObject *p_objectB, int p_shapeId_B, const btTransform &p_transformA, const btTransform &p_transformB, btScalar p_movement_scale, btVector3 &r_delta_recover_movement, RecoverResult *r_recover_result = NULL); + bool RFP_convex_convex_test(const btConvexShape *p_shapeA, const btConvexShape *p_shapeB, btCollisionObject *p_objectB, 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); /// 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_movement_scale, btVector3 &r_delta_recover_movement, RecoverResult *r_recover_result = NULL); + 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); }; #endif |