diff options
author | Andrea Catania <info@andreacatania.com> | 2018-08-14 19:20:48 +0200 |
---|---|---|
committer | Andrea Catania <info@andreacatania.com> | 2018-08-19 13:45:23 +0200 |
commit | 0010d9c82a89e89fc1bc83e806f59f34f3deb893 (patch) | |
tree | aade002a85aa3d8343210ddbcaa61e3049075fec /modules | |
parent | 9826456f2e78b3502f646ffa5445c76c6d31f7ea (diff) |
Added ray shape and move_and_slide with snapping on 3D.
Added stop_on_slope on 2d part
Diffstat (limited to 'modules')
-rw-r--r-- | modules/bullet/bullet_physics_server.cpp | 8 | ||||
-rw-r--r-- | modules/bullet/bullet_physics_server.h | 1 | ||||
-rw-r--r-- | modules/bullet/godot_result_callbacks.cpp | 13 | ||||
-rw-r--r-- | modules/bullet/space_bullet.cpp | 121 | ||||
-rw-r--r-- | modules/bullet/space_bullet.h | 3 |
5 files changed, 143 insertions, 3 deletions
diff --git a/modules/bullet/bullet_physics_server.cpp b/modules/bullet/bullet_physics_server.cpp index 0857635492..032654c3f7 100644 --- a/modules/bullet/bullet_physics_server.cpp +++ b/modules/bullet/bullet_physics_server.cpp @@ -869,6 +869,14 @@ bool BulletPhysicsServer::body_test_motion(RID p_body, const Transform &p_from, return body->get_space()->test_body_motion(body, p_from, p_motion, p_infinite_inertia, r_result); } +int BulletPhysicsServer::body_test_ray_separation(RID p_body, const Transform &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, SeparationResult *r_results, int p_result_max, float p_margin) { + RigidBodyBullet *body = rigid_body_owner.get(p_body); + ERR_FAIL_COND_V(!body, 0); + ERR_FAIL_COND_V(!body->get_space(), 0); + + return body->get_space()->test_ray_separation(body, p_transform, p_infinite_inertia, r_recover_motion, r_results, p_result_max, p_margin); +} + RID BulletPhysicsServer::soft_body_create(bool p_init_sleeping) { SoftBodyBullet *body = bulletnew(SoftBodyBullet); body->set_collision_layer(1); diff --git a/modules/bullet/bullet_physics_server.h b/modules/bullet/bullet_physics_server.h index 0e858ff311..2ff83bfd7d 100644 --- a/modules/bullet/bullet_physics_server.h +++ b/modules/bullet/bullet_physics_server.h @@ -259,6 +259,7 @@ public: virtual PhysicsDirectBodyState *body_get_direct_state(RID p_body); virtual bool body_test_motion(RID p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, MotionResult *r_result = NULL); + virtual int body_test_ray_separation(RID p_body, const Transform &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, SeparationResult *r_results, int p_result_max, float p_margin = 0.001); /* SOFT BODY API */ diff --git a/modules/bullet/godot_result_callbacks.cpp b/modules/bullet/godot_result_callbacks.cpp index 197550d686..d1b48cf5a9 100644 --- a/modules/bullet/godot_result_callbacks.cpp +++ b/modules/bullet/godot_result_callbacks.cpp @@ -260,10 +260,19 @@ void GodotDeepPenetrationContactResultCallback::addContactPoint(const btVector3 if (m_penetration_distance > depth) { // Has penetration? - bool isSwapped = m_manifoldPtr->getBody0() != m_body0Wrap->getCollisionObject(); + const bool isSwapped = m_manifoldPtr->getBody0() != m_body0Wrap->getCollisionObject(); m_penetration_distance = depth; m_other_compound_shape_index = isSwapped ? m_index0 : m_index1; - m_pointNormalWorld = isSwapped ? normalOnBInWorld * -1 : normalOnBInWorld; m_pointWorld = isSwapped ? (pointInWorldOnB + (normalOnBInWorld * depth)) : pointInWorldOnB; + + const btCollisionObjectWrapper *bw0 = m_body0Wrap; + if (isSwapped) + bw0 = m_body1Wrap; + + if (bw0->getCollisionShape()->getShapeType() == CUSTOM_CONVEX_SHAPE_TYPE) { + m_pointNormalWorld = bw0->m_worldTransform.getBasis().transpose() * btVector3(0, 0, 1); + } else { + m_pointNormalWorld = isSwapped ? normalOnBInWorld * -1 : normalOnBInWorld; + } } } diff --git a/modules/bullet/space_bullet.cpp b/modules/bullet/space_bullet.cpp index d1fb5b01d6..c0fea910c2 100644 --- a/modules/bullet/space_bullet.cpp +++ b/modules/bullet/space_bullet.cpp @@ -894,6 +894,12 @@ bool SpaceBullet::test_body_motion(RigidBodyBullet *p_body, const Transform &p_f // Skip no convex shape continue; } + + if (p_body->get_bt_shape(shIndex)->getShapeType() == CUSTOM_CONVEX_SHAPE_TYPE) { + // Skip rayshape in order to implement custom separation process + continue; + } + btConvexShape *convex_shape_test(static_cast<btConvexShape *>(p_body->get_bt_shape(shIndex))); btTransform shape_world_from = body_transform * p_body->get_kinematic_utilities()->shapes[shIndex].transform; @@ -964,6 +970,39 @@ bool SpaceBullet::test_body_motion(RigidBodyBullet *p_body, const Transform &p_f return has_penetration; } +int SpaceBullet::test_ray_separation(RigidBodyBullet *p_body, const Transform &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, PhysicsServer::SeparationResult *r_results, int p_result_max, float p_margin) { + + btTransform body_transform; + G_TO_B(p_transform, body_transform); + UNSCALE_BT_BASIS(body_transform); + + btVector3 recover_motion(0, 0, 0); + + int rays_found; + + for (int t(RECOVERING_MOVEMENT_CYCLES); 0 < t; --t) { + int last_ray_index = recover_from_penetration_ray(p_body, body_transform, RECOVERING_MOVEMENT_SCALE, p_infinite_inertia, p_result_max, recover_motion, r_results); + + rays_found = MAX(last_ray_index, rays_found); + if (!rays_found) { + break; + } else { + body_transform.getOrigin() += recover_motion; + } + } + + //optimize results (remove non colliding) + for (int i = 0; i < rays_found; i++) { + if (r_results[i].collision_depth >= 0) { + rays_found--; + SWAP(r_results[i], r_results[rays_found]); + } + } + + B_TO_G(recover_motion, r_recover_motion); + return rays_found; +} + struct RecoverPenetrationBroadPhaseCallback : public btBroadphaseAabbCallback { private: const btCollisionObject *self_collision_object; @@ -1020,6 +1059,11 @@ bool SpaceBullet::recover_from_penetration(RigidBodyBullet *p_body, const btTran continue; } + if (kin_shape.shape->getShapeType() == CUSTOM_CONVEX_SHAPE_TYPE) { + // Skip rayshape in order to implement custom separation process + continue; + } + body_shape_position = p_body_position * kin_shape.transform; body_shape_position_recovered = body_shape_position; body_shape_position_recovered.getOrigin() += r_delta_recover_movement; @@ -1122,7 +1166,6 @@ bool SpaceBullet::RFP_convex_world_test(const btConvexShape *p_shapeA, const btC if (contactPointResult.hasHit()) { r_delta_recover_movement += contactPointResult.m_pointNormalWorld * (contactPointResult.m_penetration_distance * -1 * p_recover_movement_scale); - if (r_recover_result) { if (contactPointResult.m_penetration_distance < r_recover_result->penetration_distance) { r_recover_result->hasPenetration = true; @@ -1138,3 +1181,79 @@ bool SpaceBullet::RFP_convex_world_test(const btConvexShape *p_shapeA, const btC } return false; } + +int SpaceBullet::recover_from_penetration_ray(RigidBodyBullet *p_body, const btTransform &p_body_position, btScalar p_recover_movement_scale, bool p_infinite_inertia, int p_result_max, btVector3 &r_delta_recover_movement, PhysicsServer::SeparationResult *r_results) { + + RecoverPenetrationBroadPhaseCallback recover_broad_result(p_body->get_bt_collision_object(), p_body->get_collision_layer(), p_body->get_collision_mask()); + + btTransform body_shape_position; + btTransform body_shape_position_recovered; + + // Broad phase support + btVector3 minAabb, maxAabb; + + int ray_index = 0; + + // For each shape + for (int kinIndex = p_body->get_kinematic_utilities()->shapes.size() - 1; 0 <= kinIndex; --kinIndex) { + + recover_broad_result.reset(); + + if (ray_index >= p_result_max) { + break; + } + + const RigidBodyBullet::KinematicShape &kin_shape(p_body->get_kinematic_utilities()->shapes[kinIndex]); + if (!kin_shape.is_active()) { + continue; + } + + if (kin_shape.shape->getShapeType() != CUSTOM_CONVEX_SHAPE_TYPE) { + continue; + } + + body_shape_position = p_body_position * kin_shape.transform; + body_shape_position_recovered = body_shape_position; + body_shape_position_recovered.getOrigin() += r_delta_recover_movement; + + kin_shape.shape->getAabb(body_shape_position_recovered, minAabb, maxAabb); + dynamicsWorld->getBroadphase()->aabbTest(minAabb, maxAabb, recover_broad_result); + + for (int i = recover_broad_result.result_collision_objects.size() - 1; 0 <= i; --i) { + btCollisionObject *otherObject = recover_broad_result.result_collision_objects[i]; + if (p_infinite_inertia && !otherObject->isStaticOrKinematicObject()) { + otherObject->activate(); // Force activation of hitten rigid, soft body + continue; + } else if (!p_body->get_bt_collision_object()->checkCollideWith(otherObject) || !otherObject->checkCollideWith(p_body->get_bt_collision_object())) + continue; + + if (otherObject->getCollisionShape()->isCompound()) { + + // Each convex shape + btCompoundShape *cs = static_cast<btCompoundShape *>(otherObject->getCollisionShape()); + for (int x = cs->getNumChildShapes() - 1; 0 <= x; --x) { + + RecoverResult r_recover_result; + if (RFP_convex_world_test(kin_shape.shape, cs->getChildShape(x), p_body->get_bt_collision_object(), otherObject, kinIndex, x, body_shape_position, otherObject->getWorldTransform() * cs->getChildTransform(x), p_recover_movement_scale, r_delta_recover_movement, &r_recover_result)) { + + const btRigidBody *btRigid = static_cast<const btRigidBody *>(otherObject); + CollisionObjectBullet *collisionObject = static_cast<CollisionObjectBullet *>(otherObject->getUserPointer()); + + r_results[ray_index].collision_depth = r_recover_result.penetration_distance; + B_TO_G(r_recover_result.pointWorld, r_results[ray_index].collision_point); + B_TO_G(r_recover_result.normal, r_results[ray_index].collision_normal); + B_TO_G(btRigid->getVelocityInLocalPoint(r_recover_result.pointWorld - btRigid->getWorldTransform().getOrigin()), r_results[ray_index].collider_velocity); + r_results[ray_index].collision_local_shape = kinIndex; + r_results[ray_index].collider_id = collisionObject->get_instance_id(); + r_results[ray_index].collider = collisionObject->get_self(); + r_results[ray_index].collider_shape = r_recover_result.other_compound_shape_index; + } + } + } + } + + ++ray_index; + } + + return ray_index; +} diff --git a/modules/bullet/space_bullet.h b/modules/bullet/space_bullet.h index 6b86fc2f03..06f1c3f250 100644 --- a/modules/bullet/space_bullet.h +++ b/modules/bullet/space_bullet.h @@ -175,6 +175,7 @@ public: void update_gravity(); bool test_body_motion(RigidBodyBullet *p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, PhysicsServer::MotionResult *r_result); + int test_ray_separation(RigidBodyBullet *p_body, const Transform &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, PhysicsServer::SeparationResult *r_results, int p_result_max, float p_margin); private: void create_empty_world(bool p_create_soft_world); @@ -208,5 +209,7 @@ private: /// This is an API that recover a kinematic object from penetration /// Using this we leave Bullet to select the best algorithm, For example GJK in case we have Convex Convex, or a Bullet accelerated algorithm bool RFP_convex_world_test(const btConvexShape *p_shapeA, const btCollisionShape *p_shapeB, btCollisionObject *p_objectA, btCollisionObject *p_objectB, int p_shapeId_A, int p_shapeId_B, const btTransform &p_transformA, const btTransform &p_transformB, btScalar p_recover_movement_scale, btVector3 &r_delta_recover_movement, RecoverResult *r_recover_result = NULL); + + int recover_from_penetration_ray(RigidBodyBullet *p_body, const btTransform &p_body_position, btScalar p_recover_movement_scale, bool p_infinite_inertia, int p_result_max, btVector3 &r_delta_recover_movement, PhysicsServer::SeparationResult *r_results); }; #endif |