Improved logic for KinematicBody collision recovery depth

Allows more flexible collision detection with different safe margin values.

Kinematic body motion changes in 2D and 3D:
-Recovery only for depth > min contact depth to help with collision
detection consistency (rest info could be lost if recovery was too much)
-Adaptive min contact depth (based on margin) instead of space parameter
This commit is contained in:
PouleyKetchoupp
2021-10-05 17:00:55 -07:00
parent df69945f1f
commit 9bc1b4b90e
10 changed files with 25 additions and 35 deletions

View File

@@ -34,6 +34,8 @@
#include "core/project_settings.h"
#include "physics_server_sw.h"
#define TEST_MOTION_MIN_CONTACT_DEPTH_FACTOR 0.05
_FORCE_INLINE_ static bool _can_collide_with(CollisionObjectSW *p_object, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) {
if (!(p_object->get_collision_layer() & p_collision_mask)) {
return false;
@@ -432,6 +434,8 @@ bool PhysicsDirectSpaceStateSW::rest_info(RID p_shape, const Transform &p_shape_
ShapeSW *shape = static_cast<PhysicsServerSW *>(PhysicsServer::get_singleton())->shape_owner.get(p_shape);
ERR_FAIL_COND_V(!shape, 0);
real_t min_contact_depth = p_margin * TEST_MOTION_MIN_CONTACT_DEPTH_FACTOR;
AABB aabb = p_shape_xform.xform(shape->get_aabb());
aabb = aabb.grow(p_margin);
@@ -441,7 +445,7 @@ bool PhysicsDirectSpaceStateSW::rest_info(RID p_shape, const Transform &p_shape_
rcd.best_len = 0;
rcd.best_object = nullptr;
rcd.best_shape = 0;
rcd.min_allowed_depth = space->test_motion_min_contact_depth;
rcd.min_allowed_depth = min_contact_depth;
for (int i = 0; i < amount; i++) {
if (!_can_collide_with(space->intersection_query_results[i], p_collision_mask, p_collide_with_bodies, p_collide_with_areas)) {
@@ -753,6 +757,8 @@ bool SpaceSW::test_body_motion(BodySW *p_body, const Transform &p_from, const Ve
body_aabb = p_from.xform(p_body->get_inv_transform().xform(body_aabb));
body_aabb = body_aabb.grow(p_margin);
real_t min_contact_depth = p_margin * TEST_MOTION_MIN_CONTACT_DEPTH_FACTOR;
float motion_length = p_motion.length();
Vector3 motion_normal = p_motion / motion_length;
@@ -815,8 +821,9 @@ bool SpaceSW::test_body_motion(BodySW *p_body, const Transform &p_from, const Ve
break;
}
Vector3 recover_motion;
recovered = true;
Vector3 recover_motion;
for (int i = 0; i < cbk.amount; i++) {
Vector3 a = sr[i * 2 + 0];
Vector3 b = sr[i * 2 + 1];
@@ -827,9 +834,9 @@ bool SpaceSW::test_body_motion(BodySW *p_body, const Transform &p_from, const Ve
// Compute depth on recovered motion.
float depth = n.dot(a + recover_motion) - d;
if (depth > 0.0) {
if (depth > min_contact_depth + CMP_EPSILON) {
// Only recover if there is penetration.
recover_motion -= n * depth * 0.4;
recover_motion -= n * (depth - min_contact_depth) * 0.4;
}
}
@@ -838,8 +845,6 @@ bool SpaceSW::test_body_motion(BodySW *p_body, const Transform &p_from, const Ve
break;
}
recovered = true;
body_transform.origin += recover_motion;
body_aabb.position += recover_motion;
@@ -991,7 +996,7 @@ bool SpaceSW::test_body_motion(BodySW *p_body, const Transform &p_from, const Ve
rcd.best_shape = 0;
// Allowed depth can't be lower than motion length, in order to handle contacts at low speed.
rcd.min_allowed_depth = MIN(motion_length, test_motion_min_contact_depth);
rcd.min_allowed_depth = MIN(motion_length, min_contact_depth);
int from_shape = best_shape != -1 ? best_shape : 0;
int to_shape = best_shape != -1 ? best_shape + 1 : p_body->get_shape_count();
@@ -1233,9 +1238,6 @@ void SpaceSW::set_param(PhysicsServer::SpaceParameter p_param, real_t p_value) {
case PhysicsServer::SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS:
constraint_bias = p_value;
break;
case PhysicsServer::SPACE_PARAM_TEST_MOTION_MIN_CONTACT_DEPTH:
test_motion_min_contact_depth = p_value;
break;
}
}
@@ -1257,8 +1259,6 @@ real_t SpaceSW::get_param(PhysicsServer::SpaceParameter p_param) const {
return body_angular_velocity_damp_ratio;
case PhysicsServer::SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS:
return constraint_bias;
case PhysicsServer::SPACE_PARAM_TEST_MOTION_MIN_CONTACT_DEPTH:
return test_motion_min_contact_depth;
}
return 0;
}
@@ -1289,7 +1289,6 @@ SpaceSW::SpaceSW() {
contact_recycle_radius = 0.01;
contact_max_separation = 0.05;
contact_max_allowed_penetration = 0.01;
test_motion_min_contact_depth = 0.00001;
constraint_bias = 0.01;
body_linear_velocity_sleep_threshold = GLOBAL_DEF("physics/3d/sleep_threshold_linear", 0.1);

View File

@@ -94,7 +94,6 @@ private:
real_t contact_max_separation;
real_t contact_max_allowed_penetration;
real_t constraint_bias;
real_t test_motion_min_contact_depth;
enum {