summaryrefslogtreecommitdiff
path: root/servers/physics_3d/godot_space_3d.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'servers/physics_3d/godot_space_3d.cpp')
-rw-r--r--servers/physics_3d/godot_space_3d.cpp213
1 files changed, 130 insertions, 83 deletions
diff --git a/servers/physics_3d/godot_space_3d.cpp b/servers/physics_3d/godot_space_3d.cpp
index 750bf3a16d..074232dd66 100644
--- a/servers/physics_3d/godot_space_3d.cpp
+++ b/servers/physics_3d/godot_space_3d.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -35,6 +35,7 @@
#include "core/config/project_settings.h"
+#define TEST_MOTION_MARGIN_MIN_VALUE 0.0001
#define TEST_MOTION_MIN_CONTACT_DEPTH_FACTOR 0.05
_FORCE_INLINE_ static bool _can_collide_with(GodotCollisionObject3D *p_object, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) {
@@ -57,9 +58,9 @@ _FORCE_INLINE_ static bool _can_collide_with(GodotCollisionObject3D *p_object, u
return true;
}
-int GodotPhysicsDirectSpaceState3D::intersect_point(const Vector3 &p_point, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) {
+int GodotPhysicsDirectSpaceState3D::intersect_point(const PointParameters &p_parameters, ShapeResult *r_results, int p_result_max) {
ERR_FAIL_COND_V(space->locked, false);
- int amount = space->broadphase->cull_point(p_point, space->intersection_query_results, GodotSpace3D::INTERSECTION_QUERY_MAX, space->intersection_query_subindex_results);
+ int amount = space->broadphase->cull_point(p_parameters.position, space->intersection_query_results, GodotSpace3D::INTERSECTION_QUERY_MAX, space->intersection_query_subindex_results);
int cc = 0;
//Transform3D ai = p_xform.affine_inverse();
@@ -69,13 +70,13 @@ int GodotPhysicsDirectSpaceState3D::intersect_point(const Vector3 &p_point, Shap
break;
}
- if (!_can_collide_with(space->intersection_query_results[i], p_collision_mask, p_collide_with_bodies, p_collide_with_areas)) {
+ if (!_can_collide_with(space->intersection_query_results[i], p_parameters.collision_mask, p_parameters.collide_with_bodies, p_parameters.collide_with_areas)) {
continue;
}
//area can't be picked by ray (default)
- if (p_exclude.has(space->intersection_query_results[i]->get_self())) {
+ if (p_parameters.exclude.has(space->intersection_query_results[i]->get_self())) {
continue;
}
@@ -85,7 +86,7 @@ int GodotPhysicsDirectSpaceState3D::intersect_point(const Vector3 &p_point, Shap
Transform3D inv_xform = col_obj->get_transform() * col_obj->get_shape_transform(shape_idx);
inv_xform.affine_invert();
- if (!col_obj->get_shape(shape_idx)->intersect_point(inv_xform.xform(p_point))) {
+ if (!col_obj->get_shape(shape_idx)->intersect_point(inv_xform.xform(p_parameters.position))) {
continue;
}
@@ -104,13 +105,13 @@ int GodotPhysicsDirectSpaceState3D::intersect_point(const Vector3 &p_point, Shap
return cc;
}
-bool GodotPhysicsDirectSpaceState3D::intersect_ray(const Vector3 &p_from, const Vector3 &p_to, RayResult &r_result, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas, bool p_pick_ray) {
+bool GodotPhysicsDirectSpaceState3D::intersect_ray(const RayParameters &p_parameters, RayResult &r_result) {
ERR_FAIL_COND_V(space->locked, false);
Vector3 begin, end;
Vector3 normal;
- begin = p_from;
- end = p_to;
+ begin = p_parameters.from;
+ end = p_parameters.to;
normal = (end - begin).normalized();
int amount = space->broadphase->cull_segment(begin, end, space->intersection_query_results, GodotSpace3D::INTERSECTION_QUERY_MAX, space->intersection_query_subindex_results);
@@ -124,15 +125,15 @@ bool GodotPhysicsDirectSpaceState3D::intersect_ray(const Vector3 &p_from, const
real_t min_d = 1e10;
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)) {
+ if (!_can_collide_with(space->intersection_query_results[i], p_parameters.collision_mask, p_parameters.collide_with_bodies, p_parameters.collide_with_areas)) {
continue;
}
- if (p_pick_ray && !(space->intersection_query_results[i]->is_ray_pickable())) {
+ if (p_parameters.pick_ray && !(space->intersection_query_results[i]->is_ray_pickable())) {
continue;
}
- if (p_exclude.has(space->intersection_query_results[i]->get_self())) {
+ if (p_parameters.exclude.has(space->intersection_query_results[i]->get_self())) {
continue;
}
@@ -148,7 +149,23 @@ bool GodotPhysicsDirectSpaceState3D::intersect_ray(const Vector3 &p_from, const
Vector3 shape_point, shape_normal;
- if (shape->intersect_segment(local_from, local_to, shape_point, shape_normal)) {
+ if (shape->intersect_point(local_from)) {
+ if (p_parameters.hit_from_inside) {
+ // Hit shape at starting point.
+ min_d = 0;
+ res_point = begin;
+ res_normal = Vector3();
+ res_shape = shape_idx;
+ res_obj = col_obj;
+ collided = true;
+ break;
+ } else {
+ // Ignore shape when starting inside.
+ continue;
+ }
+ }
+
+ if (shape->intersect_segment(local_from, local_to, shape_point, shape_normal, p_parameters.hit_back_faces)) {
Transform3D xform = col_obj->get_transform() * col_obj->get_shape_transform(shape_idx);
shape_point = xform.xform(shape_point);
@@ -183,15 +200,15 @@ bool GodotPhysicsDirectSpaceState3D::intersect_ray(const Vector3 &p_from, const
return true;
}
-int GodotPhysicsDirectSpaceState3D::intersect_shape(const RID &p_shape, const Transform3D &p_xform, real_t p_margin, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) {
+int GodotPhysicsDirectSpaceState3D::intersect_shape(const ShapeParameters &p_parameters, ShapeResult *r_results, int p_result_max) {
if (p_result_max <= 0) {
return 0;
}
- GodotShape3D *shape = GodotPhysicsServer3D::godot_singleton->shape_owner.get_or_null(p_shape);
+ GodotShape3D *shape = GodotPhysicsServer3D::godot_singleton->shape_owner.get_or_null(p_parameters.shape_rid);
ERR_FAIL_COND_V(!shape, 0);
- AABB aabb = p_xform.xform(shape->get_aabb());
+ AABB aabb = p_parameters.transform.xform(shape->get_aabb());
int amount = space->broadphase->cull_aabb(aabb, space->intersection_query_results, GodotSpace3D::INTERSECTION_QUERY_MAX, space->intersection_query_subindex_results);
@@ -204,20 +221,20 @@ int GodotPhysicsDirectSpaceState3D::intersect_shape(const RID &p_shape, const Tr
break;
}
- if (!_can_collide_with(space->intersection_query_results[i], p_collision_mask, p_collide_with_bodies, p_collide_with_areas)) {
+ if (!_can_collide_with(space->intersection_query_results[i], p_parameters.collision_mask, p_parameters.collide_with_bodies, p_parameters.collide_with_areas)) {
continue;
}
//area can't be picked by ray (default)
- if (p_exclude.has(space->intersection_query_results[i]->get_self())) {
+ if (p_parameters.exclude.has(space->intersection_query_results[i]->get_self())) {
continue;
}
const GodotCollisionObject3D *col_obj = space->intersection_query_results[i];
int shape_idx = space->intersection_query_subindex_results[i];
- if (!GodotCollisionSolver3D::solve_static(shape, p_xform, col_obj->get_shape(shape_idx), col_obj->get_transform() * col_obj->get_shape_transform(shape_idx), nullptr, nullptr, nullptr, p_margin, 0)) {
+ if (!GodotCollisionSolver3D::solve_static(shape, p_parameters.transform, col_obj->get_shape(shape_idx), col_obj->get_transform() * col_obj->get_shape_transform(shape_idx), nullptr, nullptr, nullptr, p_parameters.margin, 0)) {
continue;
}
@@ -238,36 +255,36 @@ int GodotPhysicsDirectSpaceState3D::intersect_shape(const RID &p_shape, const Tr
return cc;
}
-bool GodotPhysicsDirectSpaceState3D::cast_motion(const RID &p_shape, const Transform3D &p_xform, const Vector3 &p_motion, real_t p_margin, real_t &p_closest_safe, real_t &p_closest_unsafe, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas, ShapeRestInfo *r_info) {
- GodotShape3D *shape = GodotPhysicsServer3D::godot_singleton->shape_owner.get_or_null(p_shape);
+bool GodotPhysicsDirectSpaceState3D::cast_motion(const ShapeParameters &p_parameters, real_t &p_closest_safe, real_t &p_closest_unsafe, ShapeRestInfo *r_info) {
+ GodotShape3D *shape = GodotPhysicsServer3D::godot_singleton->shape_owner.get_or_null(p_parameters.shape_rid);
ERR_FAIL_COND_V(!shape, false);
- AABB aabb = p_xform.xform(shape->get_aabb());
- aabb = aabb.merge(AABB(aabb.position + p_motion, aabb.size)); //motion
- aabb = aabb.grow(p_margin);
+ AABB aabb = p_parameters.transform.xform(shape->get_aabb());
+ aabb = aabb.merge(AABB(aabb.position + p_parameters.motion, aabb.size)); //motion
+ aabb = aabb.grow(p_parameters.margin);
int amount = space->broadphase->cull_aabb(aabb, space->intersection_query_results, GodotSpace3D::INTERSECTION_QUERY_MAX, space->intersection_query_subindex_results);
real_t best_safe = 1;
real_t best_unsafe = 1;
- Transform3D xform_inv = p_xform.affine_inverse();
+ Transform3D xform_inv = p_parameters.transform.affine_inverse();
GodotMotionShape3D mshape;
mshape.shape = shape;
- mshape.motion = xform_inv.basis.xform(p_motion);
+ mshape.motion = xform_inv.basis.xform(p_parameters.motion);
bool best_first = true;
- Vector3 motion_normal = p_motion.normalized();
+ Vector3 motion_normal = p_parameters.motion.normalized();
Vector3 closest_A, closest_B;
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)) {
+ if (!_can_collide_with(space->intersection_query_results[i], p_parameters.collision_mask, p_parameters.collide_with_bodies, p_parameters.collide_with_areas)) {
continue;
}
- if (p_exclude.has(space->intersection_query_results[i]->get_self())) {
+ if (p_parameters.exclude.has(space->intersection_query_results[i]->get_self())) {
continue; //ignore excluded
}
@@ -279,14 +296,14 @@ bool GodotPhysicsDirectSpaceState3D::cast_motion(const RID &p_shape, const Trans
Transform3D col_obj_xform = col_obj->get_transform() * col_obj->get_shape_transform(shape_idx);
//test initial overlap, does it collide if going all the way?
- if (GodotCollisionSolver3D::solve_distance(&mshape, p_xform, col_obj->get_shape(shape_idx), col_obj_xform, point_A, point_B, aabb, &sep_axis)) {
+ if (GodotCollisionSolver3D::solve_distance(&mshape, p_parameters.transform, col_obj->get_shape(shape_idx), col_obj_xform, point_A, point_B, aabb, &sep_axis)) {
continue;
}
//test initial overlap, ignore objects it's inside of.
sep_axis = motion_normal;
- if (!GodotCollisionSolver3D::solve_distance(shape, p_xform, col_obj->get_shape(shape_idx), col_obj_xform, point_A, point_B, aabb, &sep_axis)) {
+ if (!GodotCollisionSolver3D::solve_distance(shape, p_parameters.transform, col_obj->get_shape(shape_idx), col_obj_xform, point_A, point_B, aabb, &sep_axis)) {
continue;
}
@@ -297,11 +314,11 @@ bool GodotPhysicsDirectSpaceState3D::cast_motion(const RID &p_shape, const Trans
for (int j = 0; j < 8; j++) { //steps should be customizable..
real_t fraction = low + (hi - low) * fraction_coeff;
- mshape.motion = xform_inv.basis.xform(p_motion * fraction);
+ mshape.motion = xform_inv.basis.xform(p_parameters.motion * fraction);
Vector3 lA, lB;
Vector3 sep = motion_normal; //important optimization for this to work fast enough
- bool collided = !GodotCollisionSolver3D::solve_distance(&mshape, p_xform, col_obj->get_shape(shape_idx), col_obj_xform, lA, lB, aabb, &sep);
+ bool collided = !GodotCollisionSolver3D::solve_distance(&mshape, p_parameters.transform, col_obj->get_shape(shape_idx), col_obj_xform, lA, lB, aabb, &sep);
if (collided) {
hi = fraction;
@@ -357,16 +374,16 @@ bool GodotPhysicsDirectSpaceState3D::cast_motion(const RID &p_shape, const Trans
return true;
}
-bool GodotPhysicsDirectSpaceState3D::collide_shape(RID p_shape, const Transform3D &p_shape_xform, real_t p_margin, Vector3 *r_results, int p_result_max, int &r_result_count, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) {
+bool GodotPhysicsDirectSpaceState3D::collide_shape(const ShapeParameters &p_parameters, Vector3 *r_results, int p_result_max, int &r_result_count) {
if (p_result_max <= 0) {
return false;
}
- GodotShape3D *shape = GodotPhysicsServer3D::godot_singleton->shape_owner.get_or_null(p_shape);
+ GodotShape3D *shape = GodotPhysicsServer3D::godot_singleton->shape_owner.get_or_null(p_parameters.shape_rid);
ERR_FAIL_COND_V(!shape, 0);
- AABB aabb = p_shape_xform.xform(shape->get_aabb());
- aabb = aabb.grow(p_margin);
+ AABB aabb = p_parameters.transform.xform(shape->get_aabb());
+ aabb = aabb.grow(p_parameters.margin);
int amount = space->broadphase->cull_aabb(aabb, space->intersection_query_results, GodotSpace3D::INTERSECTION_QUERY_MAX, space->intersection_query_subindex_results);
@@ -382,19 +399,19 @@ bool GodotPhysicsDirectSpaceState3D::collide_shape(RID p_shape, const Transform3
GodotPhysicsServer3D::CollCbkData *cbkptr = &cbk;
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)) {
+ if (!_can_collide_with(space->intersection_query_results[i], p_parameters.collision_mask, p_parameters.collide_with_bodies, p_parameters.collide_with_areas)) {
continue;
}
const GodotCollisionObject3D *col_obj = space->intersection_query_results[i];
- if (p_exclude.has(col_obj->get_self())) {
+ if (p_parameters.exclude.has(col_obj->get_self())) {
continue;
}
int shape_idx = space->intersection_query_subindex_results[i];
- if (GodotCollisionSolver3D::solve_static(shape, p_shape_xform, col_obj->get_shape(shape_idx), col_obj->get_transform() * col_obj->get_shape_transform(shape_idx), cbkres, cbkptr, nullptr, p_margin)) {
+ if (GodotCollisionSolver3D::solve_static(shape, p_parameters.transform, col_obj->get_shape(shape_idx), col_obj->get_transform() * col_obj->get_shape_transform(shape_idx), cbkres, cbkptr, nullptr, p_parameters.margin)) {
collided = true;
}
}
@@ -428,7 +445,7 @@ struct _RestCallbackData {
};
static void _rest_cbk_result(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, void *p_userdata) {
- _RestCallbackData *rd = (_RestCallbackData *)p_userdata;
+ _RestCallbackData *rd = static_cast<_RestCallbackData *>(p_userdata);
Vector3 contact_rel = p_point_B - p_point_A;
real_t len = contact_rel.length();
@@ -487,28 +504,32 @@ static void _rest_cbk_result(const Vector3 &p_point_A, int p_index_A, const Vect
rd->best_result.local_shape = rd->local_shape;
}
-bool GodotPhysicsDirectSpaceState3D::rest_info(RID p_shape, const Transform3D &p_shape_xform, real_t p_margin, ShapeRestInfo *r_info, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) {
- GodotShape3D *shape = GodotPhysicsServer3D::godot_singleton->shape_owner.get_or_null(p_shape);
+bool GodotPhysicsDirectSpaceState3D::rest_info(const ShapeParameters &p_parameters, ShapeRestInfo *r_info) {
+ GodotShape3D *shape = GodotPhysicsServer3D::godot_singleton->shape_owner.get_or_null(p_parameters.shape_rid);
ERR_FAIL_COND_V(!shape, 0);
- real_t min_contact_depth = p_margin * TEST_MOTION_MIN_CONTACT_DEPTH_FACTOR;
+ real_t margin = MAX(p_parameters.margin, TEST_MOTION_MARGIN_MIN_VALUE);
- AABB aabb = p_shape_xform.xform(shape->get_aabb());
- aabb = aabb.grow(p_margin);
+ AABB aabb = p_parameters.transform.xform(shape->get_aabb());
+ aabb = aabb.grow(margin);
int amount = space->broadphase->cull_aabb(aabb, space->intersection_query_results, GodotSpace3D::INTERSECTION_QUERY_MAX, space->intersection_query_subindex_results);
_RestCallbackData rcd;
- rcd.min_allowed_depth = min_contact_depth;
+
+ // Allowed depth can't be lower than motion length, in order to handle contacts at low speed.
+ real_t motion_length = p_parameters.motion.length();
+ real_t min_contact_depth = margin * TEST_MOTION_MIN_CONTACT_DEPTH_FACTOR;
+ rcd.min_allowed_depth = MIN(motion_length, 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)) {
+ if (!_can_collide_with(space->intersection_query_results[i], p_parameters.collision_mask, p_parameters.collide_with_bodies, p_parameters.collide_with_areas)) {
continue;
}
const GodotCollisionObject3D *col_obj = space->intersection_query_results[i];
- if (p_exclude.has(col_obj->get_self())) {
+ if (p_parameters.exclude.has(col_obj->get_self())) {
continue;
}
@@ -516,7 +537,7 @@ bool GodotPhysicsDirectSpaceState3D::rest_info(RID p_shape, const Transform3D &p
rcd.object = col_obj;
rcd.shape = shape_idx;
- bool sc = GodotCollisionSolver3D::solve_static(shape, p_shape_xform, col_obj->get_shape(shape_idx), col_obj->get_transform() * col_obj->get_shape_transform(shape_idx), _rest_cbk_result, &rcd, nullptr, p_margin);
+ bool sc = GodotCollisionSolver3D::solve_static(shape, p_parameters.transform, col_obj->get_shape(shape_idx), col_obj->get_transform() * col_obj->get_shape_transform(shape_idx), _rest_cbk_result, &rcd, nullptr, margin);
if (!sc) {
continue;
}
@@ -659,11 +680,13 @@ bool GodotSpace3D::test_body_motion(GodotBody3D *p_body, const PhysicsServer3D::
return false;
}
+ real_t margin = MAX(p_parameters.margin, TEST_MOTION_MARGIN_MIN_VALUE);
+
// Undo the currently transform the physics server is aware of and apply the provided one
body_aabb = p_parameters.from.xform(p_body->get_inv_transform().xform(body_aabb));
- body_aabb = body_aabb.grow(p_parameters.margin);
+ body_aabb = body_aabb.grow(margin);
- real_t min_contact_depth = p_parameters.margin * TEST_MOTION_MIN_CONTACT_DEPTH_FACTOR;
+ real_t min_contact_depth = margin * TEST_MOTION_MIN_CONTACT_DEPTH_FACTOR;
real_t motion_length = p_parameters.motion.length();
Vector3 motion_normal = p_parameters.motion / motion_length;
@@ -678,6 +701,7 @@ bool GodotSpace3D::test_body_motion(GodotBody3D *p_body, const PhysicsServer3D::
const int max_results = 32;
int recover_attempts = 4;
Vector3 sr[max_results * 2];
+ real_t priorities[max_results];
do {
GodotPhysicsServer3D::CollCbkData cbk;
@@ -687,6 +711,7 @@ bool GodotSpace3D::test_body_motion(GodotBody3D *p_body, const PhysicsServer3D::
GodotPhysicsServer3D::CollCbkData *cbkptr = &cbk;
GodotCollisionSolver3D::CallbackResult cbkres = GodotPhysicsServer3D::_shape_col_cbk;
+ int priority_amount = 0;
bool collided = false;
@@ -711,9 +736,13 @@ bool GodotSpace3D::test_body_motion(GodotBody3D *p_body, const PhysicsServer3D::
int shape_idx = intersection_query_subindex_results[i];
- if (GodotCollisionSolver3D::solve_static(body_shape, body_shape_xform, col_obj->get_shape(shape_idx), col_obj->get_transform() * col_obj->get_shape_transform(shape_idx), cbkres, cbkptr, nullptr, p_parameters.margin)) {
+ if (GodotCollisionSolver3D::solve_static(body_shape, body_shape_xform, col_obj->get_shape(shape_idx), col_obj->get_transform() * col_obj->get_shape_transform(shape_idx), cbkres, cbkptr, nullptr, margin)) {
collided = cbk.amount > 0;
}
+ while (cbk.amount > priority_amount) {
+ priorities[priority_amount] = col_obj->get_collision_priority();
+ priority_amount++;
+ }
}
}
@@ -721,6 +750,12 @@ bool GodotSpace3D::test_body_motion(GodotBody3D *p_body, const PhysicsServer3D::
break;
}
+ real_t inv_total_weight = 0.0;
+ for (int i = 0; i < cbk.amount; i++) {
+ inv_total_weight += priorities[i];
+ }
+ inv_total_weight = Math::is_zero_approx(inv_total_weight) ? 1.0 : (real_t)cbk.amount / inv_total_weight;
+
recovered = true;
Vector3 recover_motion;
@@ -736,7 +771,7 @@ bool GodotSpace3D::test_body_motion(GodotBody3D *p_body, const PhysicsServer3D::
real_t depth = n.dot(a + recover_motion) - d;
if (depth > min_contact_depth + CMP_EPSILON) {
// Only recover if there is penetration.
- recover_motion -= n * (depth - min_contact_depth) * 0.4;
+ recover_motion -= n * (depth - min_contact_depth) * 0.4 * priorities[i] * inv_total_weight;
}
}
@@ -883,7 +918,7 @@ bool GodotSpace3D::test_body_motion(GodotBody3D *p_body, const PhysicsServer3D::
}
bool collided = false;
- if (recovered || (safe < 1)) {
+ if ((p_parameters.recovery_as_collision && recovered) || (safe < 1)) {
if (safe >= 1) {
best_shape = -1; //no best shape with cast, reset to -1
}
@@ -903,6 +938,9 @@ bool GodotSpace3D::test_body_motion(GodotBody3D *p_body, const PhysicsServer3D::
// Allowed depth can't be lower than motion length, in order to handle contacts at low speed.
rcd.min_allowed_depth = MIN(motion_length, min_contact_depth);
+ body_aabb.position += p_parameters.motion * unsafe;
+ int amount = _cull_aabb_for_body(p_body, body_aabb);
+
int from_shape = best_shape != -1 ? best_shape : 0;
int to_shape = best_shape != -1 ? best_shape + 1 : p_body->get_shape_count();
@@ -914,10 +952,6 @@ bool GodotSpace3D::test_body_motion(GodotBody3D *p_body, const PhysicsServer3D::
Transform3D body_shape_xform = ugt * p_body->get_shape_transform(j);
GodotShape3D *body_shape = p_body->get_shape(j);
- body_aabb.position += p_parameters.motion * unsafe;
-
- int amount = _cull_aabb_for_body(p_body, body_aabb);
-
for (int i = 0; i < amount; i++) {
const GodotCollisionObject3D *col_obj = intersection_query_results[i];
if (p_parameters.exclude_bodies.has(col_obj->get_self())) {
@@ -931,7 +965,7 @@ bool GodotSpace3D::test_body_motion(GodotBody3D *p_body, const PhysicsServer3D::
rcd.object = col_obj;
rcd.shape = shape_idx;
- bool sc = GodotCollisionSolver3D::solve_static(body_shape, body_shape_xform, col_obj->get_shape(shape_idx), col_obj->get_transform() * col_obj->get_shape_transform(shape_idx), _rest_cbk_result, &rcd, nullptr, p_parameters.margin);
+ bool sc = GodotCollisionSolver3D::solve_static(body_shape, body_shape_xform, col_obj->get_shape(shape_idx), col_obj->get_transform() * col_obj->get_shape_transform(shape_idx), _rest_cbk_result, &rcd, nullptr, margin);
if (!sc) {
continue;
}
@@ -967,6 +1001,7 @@ bool GodotSpace3D::test_body_motion(GodotBody3D *p_body, const PhysicsServer3D::
r_result->collision_unsafe_fraction = unsafe;
r_result->collision_count = rcd.result_count;
+ r_result->collision_depth = rcd.best_result.len;
}
collided = true;
@@ -980,16 +1015,14 @@ bool GodotSpace3D::test_body_motion(GodotBody3D *p_body, const PhysicsServer3D::
r_result->collision_safe_fraction = 1.0;
r_result->collision_unsafe_fraction = 1.0;
+ r_result->collision_depth = 0.0;
}
return collided;
}
+// Assumes a valid collision pair, this should have been checked beforehand in the BVH or octree.
void *GodotSpace3D::_broadphase_pair(GodotCollisionObject3D *A, int p_subindex_A, GodotCollisionObject3D *B, int p_subindex_B, void *p_self) {
- if (!A->interacts_with(B)) {
- return nullptr;
- }
-
GodotCollisionObject3D::Type type_A = A->get_type();
GodotCollisionObject3D::Type type_B = B->get_type();
if (type_A > type_B) {
@@ -998,7 +1031,7 @@ void *GodotSpace3D::_broadphase_pair(GodotCollisionObject3D *A, int p_subindex_A
SWAP(type_A, type_B);
}
- GodotSpace3D *self = (GodotSpace3D *)p_self;
+ GodotSpace3D *self = static_cast<GodotSpace3D *>(p_self);
self->collision_pairs++;
@@ -1019,10 +1052,10 @@ void *GodotSpace3D::_broadphase_pair(GodotCollisionObject3D *A, int p_subindex_A
}
} else if (type_A == GodotCollisionObject3D::TYPE_BODY) {
if (type_B == GodotCollisionObject3D::TYPE_SOFT_BODY) {
- GodotBodySoftBodyPair3D *soft_pair = memnew(GodotBodySoftBodyPair3D((GodotBody3D *)A, p_subindex_A, (GodotSoftBody3D *)B));
+ GodotBodySoftBodyPair3D *soft_pair = memnew(GodotBodySoftBodyPair3D(static_cast<GodotBody3D *>(A), p_subindex_A, static_cast<GodotSoftBody3D *>(B)));
return soft_pair;
} else {
- GodotBodyPair3D *b = memnew(GodotBodyPair3D((GodotBody3D *)A, p_subindex_A, (GodotBody3D *)B, p_subindex_B));
+ GodotBodyPair3D *b = memnew(GodotBodyPair3D(static_cast<GodotBody3D *>(A), p_subindex_A, static_cast<GodotBody3D *>(B), p_subindex_B));
return b;
}
} else {
@@ -1037,9 +1070,9 @@ void GodotSpace3D::_broadphase_unpair(GodotCollisionObject3D *A, int p_subindex_
return;
}
- GodotSpace3D *self = (GodotSpace3D *)p_self;
+ GodotSpace3D *self = static_cast<GodotSpace3D *>(p_self);
self->collision_pairs--;
- GodotConstraint3D *c = (GodotConstraint3D *)p_data;
+ GodotConstraint3D *c = static_cast<GodotConstraint3D *>(p_data);
memdelete(c);
}
@@ -1077,7 +1110,7 @@ void GodotSpace3D::remove_object(GodotCollisionObject3D *p_object) {
objects.erase(p_object);
}
-const Set<GodotCollisionObject3D *> &GodotSpace3D::get_objects() const {
+const HashSet<GodotCollisionObject3D *> &GodotSpace3D::get_objects() const {
return objects;
}
@@ -1155,9 +1188,12 @@ void GodotSpace3D::set_param(PhysicsServer3D::SpaceParameter p_param, real_t p_v
case PhysicsServer3D::SPACE_PARAM_CONTACT_MAX_SEPARATION:
contact_max_separation = p_value;
break;
- case PhysicsServer3D::SPACE_PARAM_BODY_MAX_ALLOWED_PENETRATION:
+ case PhysicsServer3D::SPACE_PARAM_CONTACT_MAX_ALLOWED_PENETRATION:
contact_max_allowed_penetration = p_value;
break;
+ case PhysicsServer3D::SPACE_PARAM_CONTACT_DEFAULT_BIAS:
+ contact_bias = p_value;
+ break;
case PhysicsServer3D::SPACE_PARAM_BODY_LINEAR_VELOCITY_SLEEP_THRESHOLD:
body_linear_velocity_sleep_threshold = p_value;
break;
@@ -1167,11 +1203,8 @@ void GodotSpace3D::set_param(PhysicsServer3D::SpaceParameter p_param, real_t p_v
case PhysicsServer3D::SPACE_PARAM_BODY_TIME_TO_SLEEP:
body_time_to_sleep = p_value;
break;
- case PhysicsServer3D::SPACE_PARAM_BODY_ANGULAR_VELOCITY_DAMP_RATIO:
- body_angular_velocity_damp_ratio = p_value;
- break;
- case PhysicsServer3D::SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS:
- constraint_bias = p_value;
+ case PhysicsServer3D::SPACE_PARAM_SOLVER_ITERATIONS:
+ solver_iterations = p_value;
break;
}
}
@@ -1182,18 +1215,18 @@ real_t GodotSpace3D::get_param(PhysicsServer3D::SpaceParameter p_param) const {
return contact_recycle_radius;
case PhysicsServer3D::SPACE_PARAM_CONTACT_MAX_SEPARATION:
return contact_max_separation;
- case PhysicsServer3D::SPACE_PARAM_BODY_MAX_ALLOWED_PENETRATION:
+ case PhysicsServer3D::SPACE_PARAM_CONTACT_MAX_ALLOWED_PENETRATION:
return contact_max_allowed_penetration;
+ case PhysicsServer3D::SPACE_PARAM_CONTACT_DEFAULT_BIAS:
+ return contact_bias;
case PhysicsServer3D::SPACE_PARAM_BODY_LINEAR_VELOCITY_SLEEP_THRESHOLD:
return body_linear_velocity_sleep_threshold;
case PhysicsServer3D::SPACE_PARAM_BODY_ANGULAR_VELOCITY_SLEEP_THRESHOLD:
return body_angular_velocity_sleep_threshold;
case PhysicsServer3D::SPACE_PARAM_BODY_TIME_TO_SLEEP:
return body_time_to_sleep;
- case PhysicsServer3D::SPACE_PARAM_BODY_ANGULAR_VELOCITY_DAMP_RATIO:
- return body_angular_velocity_damp_ratio;
- case PhysicsServer3D::SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS:
- return constraint_bias;
+ case PhysicsServer3D::SPACE_PARAM_SOLVER_ITERATIONS:
+ return solver_iterations;
}
return 0;
}
@@ -1219,7 +1252,21 @@ GodotSpace3D::GodotSpace3D() {
body_angular_velocity_sleep_threshold = GLOBAL_DEF("physics/3d/sleep_threshold_angular", Math::deg2rad(8.0));
body_time_to_sleep = GLOBAL_DEF("physics/3d/time_before_sleep", 0.5);
ProjectSettings::get_singleton()->set_custom_property_info("physics/3d/time_before_sleep", PropertyInfo(Variant::FLOAT, "physics/3d/time_before_sleep", PROPERTY_HINT_RANGE, "0,5,0.01,or_greater"));
- body_angular_velocity_damp_ratio = 10;
+
+ solver_iterations = GLOBAL_DEF("physics/3d/solver/solver_iterations", 16);
+ ProjectSettings::get_singleton()->set_custom_property_info("physics/3d/solver/solver_iterations", PropertyInfo(Variant::INT, "physics/3d/solver/solver_iterations", PROPERTY_HINT_RANGE, "1,32,1,or_greater"));
+
+ contact_recycle_radius = GLOBAL_DEF("physics/3d/solver/contact_recycle_radius", 0.01);
+ ProjectSettings::get_singleton()->set_custom_property_info("physics/3d/solver/contact_recycle_radius", PropertyInfo(Variant::FLOAT, "physics/3d/solver/contact_max_separation", PROPERTY_HINT_RANGE, "0,0.1,0.01,or_greater"));
+
+ contact_max_separation = GLOBAL_DEF("physics/3d/solver/contact_max_separation", 0.05);
+ ProjectSettings::get_singleton()->set_custom_property_info("physics/3d/solver/contact_max_separation", PropertyInfo(Variant::FLOAT, "physics/3d/solver/contact_max_separation", PROPERTY_HINT_RANGE, "0,0.1,0.01,or_greater"));
+
+ contact_max_allowed_penetration = GLOBAL_DEF("physics/3d/solver/contact_max_allowed_penetration", 0.01);
+ ProjectSettings::get_singleton()->set_custom_property_info("physics/3d/solver/contact_max_allowed_penetration", PropertyInfo(Variant::FLOAT, "physics/3d/solver/contact_max_allowed_penetration", PROPERTY_HINT_RANGE, "0,0.1,0.01,or_greater"));
+
+ contact_bias = GLOBAL_DEF("physics/3d/solver/default_contact_bias", 0.8);
+ ProjectSettings::get_singleton()->set_custom_property_info("physics/3d/solver/default_contact_bias", PropertyInfo(Variant::FLOAT, "physics/3d/solver/default_contact_bias", PROPERTY_HINT_RANGE, "0,1,0.01"));
broadphase = GodotBroadPhase3D::create_func();
broadphase->set_pair_callback(_broadphase_pair, this);