summaryrefslogtreecommitdiff
path: root/servers/physics_3d
diff options
context:
space:
mode:
Diffstat (limited to 'servers/physics_3d')
-rw-r--r--servers/physics_3d/area_3d_sw.cpp20
-rw-r--r--servers/physics_3d/area_3d_sw.h9
-rw-r--r--servers/physics_3d/area_pair_3d_sw.cpp69
-rw-r--r--servers/physics_3d/area_pair_3d_sw.h6
-rw-r--r--servers/physics_3d/body_3d_sw.cpp21
-rw-r--r--servers/physics_3d/body_3d_sw.h2
-rw-r--r--servers/physics_3d/collision_solver_3d_sat.cpp6
-rw-r--r--servers/physics_3d/collision_solver_3d_sw.cpp87
-rw-r--r--servers/physics_3d/collision_solver_3d_sw.h8
-rw-r--r--servers/physics_3d/physics_server_3d_sw.cpp10
-rw-r--r--servers/physics_3d/physics_server_3d_sw.h3
-rw-r--r--servers/physics_3d/physics_server_3d_wrap_mt.h5
-rw-r--r--servers/physics_3d/shape_3d_sw.cpp116
-rw-r--r--servers/physics_3d/shape_3d_sw.h64
-rw-r--r--servers/physics_3d/soft_body_3d_sw.cpp13
-rw-r--r--servers/physics_3d/space_3d_sw.cpp14
-rw-r--r--servers/physics_3d/space_3d_sw.h2
17 files changed, 338 insertions, 117 deletions
diff --git a/servers/physics_3d/area_3d_sw.cpp b/servers/physics_3d/area_3d_sw.cpp
index c292abad48..c9e8bcb8ca 100644
--- a/servers/physics_3d/area_3d_sw.cpp
+++ b/servers/physics_3d/area_3d_sw.cpp
@@ -304,6 +304,26 @@ void Area3DSW::call_queries() {
}
}
+void Area3DSW::compute_gravity(const Vector3 &p_position, Vector3 &r_gravity) const {
+ if (is_gravity_point()) {
+ const real_t gravity_distance_scale = get_gravity_distance_scale();
+ Vector3 v = get_transform().xform(get_gravity_vector()) - p_position;
+ if (gravity_distance_scale > 0) {
+ const real_t v_length = v.length();
+ if (v_length > 0) {
+ const real_t v_scaled = v_length * gravity_distance_scale;
+ r_gravity = (v.normalized() * (get_gravity() / (v_scaled * v_scaled)));
+ } else {
+ r_gravity = Vector3();
+ }
+ } else {
+ r_gravity = v.normalized() * get_gravity();
+ }
+ } else {
+ r_gravity = get_gravity_vector() * get_gravity();
+ }
+}
+
Area3DSW::Area3DSW() :
CollisionObject3DSW(TYPE_AREA),
monitor_query_list(this),
diff --git a/servers/physics_3d/area_3d_sw.h b/servers/physics_3d/area_3d_sw.h
index 814472885c..d5f1e60119 100644
--- a/servers/physics_3d/area_3d_sw.h
+++ b/servers/physics_3d/area_3d_sw.h
@@ -34,7 +34,6 @@
#include "collision_object_3d_sw.h"
#include "core/templates/self_list.h"
#include "servers/physics_server_3d.h"
-//#include "servers/physics_3d/query_sw.h"
class Space3DSW;
class Body3DSW;
@@ -101,18 +100,12 @@ class Area3DSW : public CollisionObject3DSW {
Map<BodyKey, BodyState> monitored_bodies;
Map<BodyKey, BodyState> monitored_areas;
- //virtual void shape_changed_notify(ShapeSW *p_shape);
- //virtual void shape_deleted_notify(ShapeSW *p_shape);
-
Set<Constraint3DSW *> constraints;
virtual void _shapes_changed();
void _queue_monitor_update();
public:
- //_FORCE_INLINE_ const Transform& get_inverse_transform() const { return inverse_transform; }
- //_FORCE_INLINE_ SpaceSW* get_owner() { return owner; }
-
void set_monitor_callback(ObjectID p_id, const StringName &p_method);
_FORCE_INLINE_ bool has_monitor_callback() const { return monitor_callback_id.is_valid(); }
@@ -184,6 +177,8 @@ public:
void call_queries();
+ void compute_gravity(const Vector3 &p_position, Vector3 &r_gravity) const;
+
Area3DSW();
~Area3DSW();
};
diff --git a/servers/physics_3d/area_pair_3d_sw.cpp b/servers/physics_3d/area_pair_3d_sw.cpp
index e740565da6..bf4f0035b4 100644
--- a/servers/physics_3d/area_pair_3d_sw.cpp
+++ b/servers/physics_3d/area_pair_3d_sw.cpp
@@ -33,7 +33,7 @@
bool AreaPair3DSW::setup(real_t p_step) {
bool result = false;
- if (area->interacts_with(body) && CollisionSolver3DSW::solve_static(body->get_shape(body_shape), body->get_transform() * body->get_shape_transform(body_shape), area->get_shape(area_shape), area->get_transform() * area->get_shape_transform(area_shape), nullptr, this)) {
+ if (area->collides_with(body) && CollisionSolver3DSW::solve_static(body->get_shape(body_shape), body->get_transform() * body->get_shape_transform(body_shape), area->get_shape(area_shape), area->get_transform() * area->get_shape_transform(area_shape), nullptr, this)) {
result = true;
}
@@ -109,46 +109,51 @@ AreaPair3DSW::~AreaPair3DSW() {
////////////////////////////////////////////////////
bool Area2Pair3DSW::setup(real_t p_step) {
- bool result = false;
- if (area_a->interacts_with(area_b) && CollisionSolver3DSW::solve_static(area_a->get_shape(shape_a), area_a->get_transform() * area_a->get_shape_transform(shape_a), area_b->get_shape(shape_b), area_b->get_transform() * area_b->get_shape_transform(shape_b), nullptr, this)) {
- result = true;
+ bool result_a = area_a->collides_with(area_b);
+ bool result_b = area_b->collides_with(area_a);
+ if ((result_a || result_b) && !CollisionSolver3DSW::solve_static(area_a->get_shape(shape_a), area_a->get_transform() * area_a->get_shape_transform(shape_a), area_b->get_shape(shape_b), area_b->get_transform() * area_b->get_shape_transform(shape_b), nullptr, this)) {
+ result_a = false;
+ result_b = false;
}
- process_collision = false;
- if (result != colliding) {
- if (area_b->has_area_monitor_callback() && area_a->is_monitorable()) {
- process_collision = true;
- } else if (area_a->has_area_monitor_callback() && area_b->is_monitorable()) {
+ bool process_collision = false;
+
+ process_collision_a = false;
+ if (result_a != colliding_a) {
+ if (area_a->has_area_monitor_callback() && area_b->is_monitorable()) {
+ process_collision_a = true;
process_collision = true;
}
+ colliding_a = result_a;
+ }
- colliding = result;
+ process_collision_b = false;
+ if (result_b != colliding_b) {
+ if (area_b->has_area_monitor_callback() && area_a->is_monitorable()) {
+ process_collision_b = true;
+ process_collision = true;
+ }
+ colliding_b = result_b;
}
return process_collision;
}
bool Area2Pair3DSW::pre_solve(real_t p_step) {
- if (!process_collision) {
- return false;
+ if (process_collision_a) {
+ if (colliding_a) {
+ area_a->add_area_to_query(area_b, shape_b, shape_a);
+ } else {
+ area_a->remove_area_from_query(area_b, shape_b, shape_a);
+ }
}
- if (colliding) {
- if (area_b->has_area_monitor_callback() && area_a->is_monitorable()) {
+ if (process_collision_b) {
+ if (colliding_b) {
area_b->add_area_to_query(area_a, shape_a, shape_b);
- }
-
- if (area_a->has_area_monitor_callback() && area_b->is_monitorable()) {
- area_a->add_area_to_query(area_b, shape_b, shape_a);
- }
- } else {
- if (area_b->has_area_monitor_callback() && area_a->is_monitorable()) {
+ } else {
area_b->remove_area_from_query(area_a, shape_a, shape_b);
}
-
- if (area_a->has_area_monitor_callback() && area_b->is_monitorable()) {
- area_a->remove_area_from_query(area_b, shape_b, shape_a);
- }
}
return false; // Never do any post solving.
@@ -168,16 +173,18 @@ Area2Pair3DSW::Area2Pair3DSW(Area3DSW *p_area_a, int p_shape_a, Area3DSW *p_area
}
Area2Pair3DSW::~Area2Pair3DSW() {
- if (colliding) {
- if (area_b->has_area_monitor_callback()) {
- area_b->remove_area_from_query(area_a, shape_a, shape_b);
- }
-
+ if (colliding_a) {
if (area_a->has_area_monitor_callback()) {
area_a->remove_area_from_query(area_b, shape_b, shape_a);
}
}
+ if (colliding_b) {
+ if (area_b->has_area_monitor_callback()) {
+ area_b->remove_area_from_query(area_a, shape_a, shape_b);
+ }
+ }
+
area_a->remove_constraint(this);
area_b->remove_constraint(this);
}
@@ -187,7 +194,7 @@ Area2Pair3DSW::~Area2Pair3DSW() {
bool AreaSoftBodyPair3DSW::setup(real_t p_step) {
bool result = false;
if (
- area->interacts_with(soft_body) &&
+ area->collides_with(soft_body) &&
CollisionSolver3DSW::solve_static(
soft_body->get_shape(soft_body_shape),
soft_body->get_transform() * soft_body->get_shape_transform(soft_body_shape),
diff --git a/servers/physics_3d/area_pair_3d_sw.h b/servers/physics_3d/area_pair_3d_sw.h
index 8cc9e9ad63..4572dcbb23 100644
--- a/servers/physics_3d/area_pair_3d_sw.h
+++ b/servers/physics_3d/area_pair_3d_sw.h
@@ -58,8 +58,10 @@ class Area2Pair3DSW : public Constraint3DSW {
Area3DSW *area_b;
int shape_a;
int shape_b;
- bool colliding = false;
- bool process_collision = false;
+ bool colliding_a = false;
+ bool colliding_b = false;
+ bool process_collision_a = false;
+ bool process_collision_b = false;
public:
virtual bool setup(real_t p_step) override;
diff --git a/servers/physics_3d/body_3d_sw.cpp b/servers/physics_3d/body_3d_sw.cpp
index 556f1f85c6..7f62e4eb85 100644
--- a/servers/physics_3d/body_3d_sw.cpp
+++ b/servers/physics_3d/body_3d_sw.cpp
@@ -381,17 +381,10 @@ void Body3DSW::set_space(Space3DSW *p_space) {
first_integration = true;
}
-void Body3DSW::_compute_area_gravity_and_dampenings(const Area3DSW *p_area) {
- if (p_area->is_gravity_point()) {
- if (p_area->get_gravity_distance_scale() > 0) {
- Vector3 v = p_area->get_transform().xform(p_area->get_gravity_vector()) - get_transform().get_origin();
- gravity += v.normalized() * (p_area->get_gravity() / Math::pow(v.length() * p_area->get_gravity_distance_scale() + 1, 2));
- } else {
- gravity += (p_area->get_transform().xform(p_area->get_gravity_vector()) - get_transform().get_origin()).normalized() * p_area->get_gravity();
- }
- } else {
- gravity += p_area->get_gravity_vector() * p_area->get_gravity();
- }
+void Body3DSW::_compute_area_gravity_and_damping(const Area3DSW *p_area) {
+ Vector3 area_gravity;
+ p_area->compute_gravity(get_transform().get_origin(), area_gravity);
+ gravity += area_gravity;
area_linear_damp += p_area->get_linear_damp();
area_angular_damp += p_area->get_angular_damp();
@@ -433,7 +426,7 @@ void Body3DSW::integrate_forces(real_t p_step) {
switch (mode) {
case PhysicsServer3D::AREA_SPACE_OVERRIDE_COMBINE:
case PhysicsServer3D::AREA_SPACE_OVERRIDE_COMBINE_REPLACE: {
- _compute_area_gravity_and_dampenings(aa[i].area);
+ _compute_area_gravity_and_damping(aa[i].area);
stopped = mode == PhysicsServer3D::AREA_SPACE_OVERRIDE_COMBINE_REPLACE;
} break;
case PhysicsServer3D::AREA_SPACE_OVERRIDE_REPLACE:
@@ -441,7 +434,7 @@ void Body3DSW::integrate_forces(real_t p_step) {
gravity = Vector3(0, 0, 0);
area_angular_damp = 0;
area_linear_damp = 0;
- _compute_area_gravity_and_dampenings(aa[i].area);
+ _compute_area_gravity_and_damping(aa[i].area);
stopped = mode == PhysicsServer3D::AREA_SPACE_OVERRIDE_REPLACE;
} break;
default: {
@@ -451,7 +444,7 @@ void Body3DSW::integrate_forces(real_t p_step) {
}
if (!stopped) {
- _compute_area_gravity_and_dampenings(def_area);
+ _compute_area_gravity_and_damping(def_area);
}
gravity *= gravity_scale;
diff --git a/servers/physics_3d/body_3d_sw.h b/servers/physics_3d/body_3d_sw.h
index 0acf334826..f58f40652b 100644
--- a/servers/physics_3d/body_3d_sw.h
+++ b/servers/physics_3d/body_3d_sw.h
@@ -128,7 +128,7 @@ class Body3DSW : public CollisionObject3DSW {
uint64_t island_step;
- _FORCE_INLINE_ void _compute_area_gravity_and_dampenings(const Area3DSW *p_area);
+ _FORCE_INLINE_ void _compute_area_gravity_and_damping(const Area3DSW *p_area);
_FORCE_INLINE_ void _update_transform_dependant();
diff --git a/servers/physics_3d/collision_solver_3d_sat.cpp b/servers/physics_3d/collision_solver_3d_sat.cpp
index 6e6a2cb9e7..de81348b4e 100644
--- a/servers/physics_3d/collision_solver_3d_sat.cpp
+++ b/servers/physics_3d/collision_solver_3d_sat.cpp
@@ -2273,11 +2273,13 @@ bool sat_calculate_penetration(const Shape3DSW *p_shape_A, const Transform3D &p_
PhysicsServer3D::ShapeType type_A = p_shape_A->get_type();
ERR_FAIL_COND_V(type_A == PhysicsServer3D::SHAPE_PLANE, false);
+ ERR_FAIL_COND_V(type_A == PhysicsServer3D::SHAPE_SEPARATION_RAY, false);
ERR_FAIL_COND_V(p_shape_A->is_concave(), false);
PhysicsServer3D::ShapeType type_B = p_shape_B->get_type();
ERR_FAIL_COND_V(type_B == PhysicsServer3D::SHAPE_PLANE, false);
+ ERR_FAIL_COND_V(type_B == PhysicsServer3D::SHAPE_SEPARATION_RAY, false);
ERR_FAIL_COND_V(p_shape_B->is_concave(), false);
static const CollisionFunc collision_table[6][6] = {
@@ -2382,10 +2384,10 @@ bool sat_calculate_penetration(const Shape3DSW *p_shape_A, const Transform3D &p_
CollisionFunc collision_func;
if (margin_A != 0.0 || margin_B != 0.0) {
- collision_func = collision_table_margin[type_A - 1][type_B - 1];
+ collision_func = collision_table_margin[type_A - 2][type_B - 2];
} else {
- collision_func = collision_table[type_A - 1][type_B - 1];
+ collision_func = collision_table[type_A - 2][type_B - 2];
}
ERR_FAIL_COND_V(!collision_func, false);
diff --git a/servers/physics_3d/collision_solver_3d_sw.cpp b/servers/physics_3d/collision_solver_3d_sw.cpp
index dcecac1c73..4a4a8164d3 100644
--- a/servers/physics_3d/collision_solver_3d_sw.cpp
+++ b/servers/physics_3d/collision_solver_3d_sw.cpp
@@ -89,6 +89,49 @@ bool CollisionSolver3DSW::solve_static_plane(const Shape3DSW *p_shape_A, const T
return found;
}
+bool CollisionSolver3DSW::solve_separation_ray(const Shape3DSW *p_shape_A, const Transform3D &p_transform_A, const Shape3DSW *p_shape_B, const Transform3D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result, real_t p_margin) {
+ const SeparationRayShape3DSW *ray = static_cast<const SeparationRayShape3DSW *>(p_shape_A);
+
+ Vector3 from = p_transform_A.origin;
+ Vector3 to = from + p_transform_A.basis.get_axis(2) * (ray->get_length() + p_margin);
+ Vector3 support_A = to;
+
+ Transform3D ai = p_transform_B.affine_inverse();
+
+ from = ai.xform(from);
+ to = ai.xform(to);
+
+ Vector3 p, n;
+ if (!p_shape_B->intersect_segment(from, to, p, n)) {
+ return false;
+ }
+
+ // Discard contacts when the ray is fully contained inside the shape.
+ if (n == Vector3()) {
+ return false;
+ }
+
+ // Discard contacts in the wrong direction.
+ if (n.dot(from - to) < CMP_EPSILON) {
+ return false;
+ }
+
+ Vector3 support_B = p_transform_B.xform(p);
+ if (ray->get_slide_on_slope()) {
+ Vector3 global_n = ai.basis.xform_inv(n).normalized();
+ support_B = support_A + (support_B - support_A).length() * global_n;
+ }
+
+ if (p_result_callback) {
+ if (p_swap_result) {
+ p_result_callback(support_B, 0, support_A, 0, p_userdata);
+ } else {
+ p_result_callback(support_A, 0, support_B, 0, p_userdata);
+ }
+ }
+ return true;
+}
+
struct _SoftBodyContactCollisionInfo {
int node_index = 0;
CollisionSolver3DSW::CallbackResult result_callback = nullptr;
@@ -135,17 +178,17 @@ bool CollisionSolver3DSW::soft_body_query_callback(uint32_t p_node_index, void *
transform_B.origin = query_cinfo.node_transform.xform(node_position);
query_cinfo.contact_info.node_index = p_node_index;
- solve_static(query_cinfo.shape_A, query_cinfo.transform_A, query_cinfo.shape_B, transform_B, soft_body_contact_callback, &query_cinfo.contact_info);
+ bool collided = solve_static(query_cinfo.shape_A, query_cinfo.transform_A, query_cinfo.shape_B, transform_B, soft_body_contact_callback, &query_cinfo.contact_info);
#ifdef DEBUG_ENABLED
++query_cinfo.node_query_count;
#endif
- // Continue with the query.
- return false;
+ // Stop at first collision if contacts are not needed.
+ return (collided && !query_cinfo.contact_info.result_callback);
}
-void CollisionSolver3DSW::soft_body_concave_callback(void *p_userdata, Shape3DSW *p_convex) {
+bool CollisionSolver3DSW::soft_body_concave_callback(void *p_userdata, Shape3DSW *p_convex) {
_SoftBodyQueryInfo &query_cinfo = *(_SoftBodyQueryInfo *)(p_userdata);
query_cinfo.shape_A = p_convex;
@@ -167,9 +210,14 @@ void CollisionSolver3DSW::soft_body_concave_callback(void *p_userdata, Shape3DSW
query_cinfo.soft_body->query_aabb(shape_aabb, soft_body_query_callback, &query_cinfo);
+ bool collided = (query_cinfo.contact_info.contact_count > 0);
+
#ifdef DEBUG_ENABLED
++query_cinfo.convex_query_count;
#endif
+
+ // Stop at first collision if contacts are not needed.
+ return (collided && !query_cinfo.contact_info.result_callback);
}
bool CollisionSolver3DSW::solve_soft_body(const Shape3DSW *p_shape_A, const Transform3D &p_transform_A, const Shape3DSW *p_shape_B, const Transform3D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result) {
@@ -243,17 +291,20 @@ struct _ConcaveCollisionInfo {
Vector3 close_A, close_B;
};
-void CollisionSolver3DSW::concave_callback(void *p_userdata, Shape3DSW *p_convex) {
+bool CollisionSolver3DSW::concave_callback(void *p_userdata, Shape3DSW *p_convex) {
_ConcaveCollisionInfo &cinfo = *(_ConcaveCollisionInfo *)(p_userdata);
cinfo.aabb_tests++;
bool collided = collision_solver(cinfo.shape_A, *cinfo.transform_A, p_convex, *cinfo.transform_B, cinfo.result_callback, cinfo.userdata, cinfo.swap_result, nullptr, cinfo.margin_A, cinfo.margin_B);
if (!collided) {
- return;
+ return false;
}
cinfo.collided = true;
cinfo.collisions++;
+
+ // Stop at first collision if contacts are not needed.
+ return !cinfo.result_callback;
}
bool CollisionSolver3DSW::solve_concave(const Shape3DSW *p_shape_A, const Transform3D &p_transform_A, const Shape3DSW *p_shape_B, const Transform3D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result, real_t p_margin_A, real_t p_margin_B) {
@@ -318,6 +369,9 @@ bool CollisionSolver3DSW::solve_static(const Shape3DSW *p_shape_A, const Transfo
if (type_B == PhysicsServer3D::SHAPE_PLANE) {
return false;
}
+ if (type_B == PhysicsServer3D::SHAPE_SEPARATION_RAY) {
+ return false;
+ }
if (type_B == PhysicsServer3D::SHAPE_SOFT_BODY) {
return false;
}
@@ -328,6 +382,17 @@ bool CollisionSolver3DSW::solve_static(const Shape3DSW *p_shape_A, const Transfo
return solve_static_plane(p_shape_A, p_transform_A, p_shape_B, p_transform_B, p_result_callback, p_userdata, false);
}
+ } else if (type_A == PhysicsServer3D::SHAPE_SEPARATION_RAY) {
+ if (type_B == PhysicsServer3D::SHAPE_SEPARATION_RAY) {
+ return false;
+ }
+
+ if (swap) {
+ return solve_separation_ray(p_shape_B, p_transform_B, p_shape_A, p_transform_A, p_result_callback, p_userdata, true, p_margin_B);
+ } else {
+ return solve_separation_ray(p_shape_A, p_transform_A, p_shape_B, p_transform_B, p_result_callback, p_userdata, false, p_margin_A);
+ }
+
} else if (type_B == PhysicsServer3D::SHAPE_SOFT_BODY) {
if (type_A == PhysicsServer3D::SHAPE_SOFT_BODY) {
// Soft Body / Soft Body not supported.
@@ -356,19 +421,18 @@ bool CollisionSolver3DSW::solve_static(const Shape3DSW *p_shape_A, const Transfo
}
}
-void CollisionSolver3DSW::concave_distance_callback(void *p_userdata, Shape3DSW *p_convex) {
+bool CollisionSolver3DSW::concave_distance_callback(void *p_userdata, Shape3DSW *p_convex) {
_ConcaveCollisionInfo &cinfo = *(_ConcaveCollisionInfo *)(p_userdata);
cinfo.aabb_tests++;
- if (cinfo.collided) {
- return;
- }
Vector3 close_A, close_B;
cinfo.collided = !gjk_epa_calculate_distance(cinfo.shape_A, *cinfo.transform_A, p_convex, *cinfo.transform_B, close_A, close_B);
if (cinfo.collided) {
- return;
+ // No need to process any more result.
+ return true;
}
+
if (!cinfo.tested || close_A.distance_squared_to(close_B) < cinfo.close_A.distance_squared_to(cinfo.close_B)) {
cinfo.close_A = close_A;
cinfo.close_B = close_B;
@@ -376,6 +440,7 @@ void CollisionSolver3DSW::concave_distance_callback(void *p_userdata, Shape3DSW
}
cinfo.collisions++;
+ return false;
}
bool CollisionSolver3DSW::solve_distance_plane(const Shape3DSW *p_shape_A, const Transform3D &p_transform_A, const Shape3DSW *p_shape_B, const Transform3D &p_transform_B, Vector3 &r_point_A, Vector3 &r_point_B) {
diff --git a/servers/physics_3d/collision_solver_3d_sw.h b/servers/physics_3d/collision_solver_3d_sw.h
index a5dd7d48eb..c13614ab3e 100644
--- a/servers/physics_3d/collision_solver_3d_sw.h
+++ b/servers/physics_3d/collision_solver_3d_sw.h
@@ -40,13 +40,13 @@ public:
private:
static bool soft_body_query_callback(uint32_t p_node_index, void *p_userdata);
static void soft_body_contact_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, void *p_userdata);
- static void soft_body_concave_callback(void *p_userdata, Shape3DSW *p_convex);
- static void concave_callback(void *p_userdata, Shape3DSW *p_convex);
+ static bool soft_body_concave_callback(void *p_userdata, Shape3DSW *p_convex);
+ static bool concave_callback(void *p_userdata, Shape3DSW *p_convex);
static bool solve_static_plane(const Shape3DSW *p_shape_A, const Transform3D &p_transform_A, const Shape3DSW *p_shape_B, const Transform3D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result);
- static bool solve_ray(const Shape3DSW *p_shape_A, const Transform3D &p_transform_A, const Shape3DSW *p_shape_B, const Transform3D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result);
+ static bool solve_separation_ray(const Shape3DSW *p_shape_A, const Transform3D &p_transform_A, const Shape3DSW *p_shape_B, const Transform3D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result, real_t p_margin = 0);
static bool solve_soft_body(const Shape3DSW *p_shape_A, const Transform3D &p_transform_A, const Shape3DSW *p_shape_B, const Transform3D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result);
static bool solve_concave(const Shape3DSW *p_shape_A, const Transform3D &p_transform_A, const Shape3DSW *p_shape_B, const Transform3D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result, real_t p_margin_A = 0, real_t p_margin_B = 0);
- static void concave_distance_callback(void *p_userdata, Shape3DSW *p_convex);
+ static bool concave_distance_callback(void *p_userdata, Shape3DSW *p_convex);
static bool solve_distance_plane(const Shape3DSW *p_shape_A, const Transform3D &p_transform_A, const Shape3DSW *p_shape_B, const Transform3D &p_transform_B, Vector3 &r_point_A, Vector3 &r_point_B);
public:
diff --git a/servers/physics_3d/physics_server_3d_sw.cpp b/servers/physics_3d/physics_server_3d_sw.cpp
index e52a3bec2d..a214e80c6c 100644
--- a/servers/physics_3d/physics_server_3d_sw.cpp
+++ b/servers/physics_3d/physics_server_3d_sw.cpp
@@ -49,6 +49,12 @@ RID PhysicsServer3DSW::plane_shape_create() {
shape->set_self(rid);
return rid;
}
+RID PhysicsServer3DSW::separation_ray_shape_create() {
+ Shape3DSW *shape = memnew(SeparationRayShape3DSW);
+ RID rid = shape_owner.make_rid(shape);
+ shape->set_self(rid);
+ return rid;
+}
RID PhysicsServer3DSW::sphere_shape_create() {
Shape3DSW *shape = memnew(SphereShape3DSW);
RID rid = shape_owner.make_rid(shape);
@@ -855,7 +861,7 @@ void PhysicsServer3DSW::body_set_ray_pickable(RID p_body, bool p_enable) {
body->set_ray_pickable(p_enable);
}
-bool PhysicsServer3DSW::body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, real_t p_margin, MotionResult *r_result, const Set<RID> &p_exclude) {
+bool PhysicsServer3DSW::body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, real_t p_margin, MotionResult *r_result, bool p_collide_separation_ray, const Set<RID> &p_exclude) {
Body3DSW *body = body_owner.getornull(p_body);
ERR_FAIL_COND_V(!body, false);
ERR_FAIL_COND_V(!body->get_space(), false);
@@ -863,7 +869,7 @@ bool PhysicsServer3DSW::body_test_motion(RID p_body, const Transform3D &p_from,
_update_shapes();
- return body->get_space()->test_body_motion(body, p_from, p_motion, p_margin, r_result, p_exclude);
+ return body->get_space()->test_body_motion(body, p_from, p_motion, p_margin, r_result, p_collide_separation_ray, p_exclude);
}
PhysicsDirectBodyState3D *PhysicsServer3DSW::body_get_direct_state(RID p_body) {
diff --git a/servers/physics_3d/physics_server_3d_sw.h b/servers/physics_3d/physics_server_3d_sw.h
index 758cd0aa2f..f283f83112 100644
--- a/servers/physics_3d/physics_server_3d_sw.h
+++ b/servers/physics_3d/physics_server_3d_sw.h
@@ -80,6 +80,7 @@ public:
static void _shape_col_cbk(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, void *p_userdata);
virtual RID plane_shape_create() override;
+ virtual RID separation_ray_shape_create() override;
virtual RID sphere_shape_create() override;
virtual RID box_shape_create() override;
virtual RID capsule_shape_create() override;
@@ -239,7 +240,7 @@ public:
virtual void body_set_ray_pickable(RID p_body, bool p_enable) override;
- virtual bool body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, real_t p_margin = 0.001, MotionResult *r_result = nullptr, const Set<RID> &p_exclude = Set<RID>()) override;
+ virtual bool body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, real_t p_margin = 0.001, MotionResult *r_result = nullptr, bool p_collide_separation_ray = false, const Set<RID> &p_exclude = Set<RID>()) override;
// this function only works on physics process, errors and returns null otherwise
virtual PhysicsDirectBodyState3D *body_get_direct_state(RID p_body) override;
diff --git a/servers/physics_3d/physics_server_3d_wrap_mt.h b/servers/physics_3d/physics_server_3d_wrap_mt.h
index c336747db8..8865bd4bd2 100644
--- a/servers/physics_3d/physics_server_3d_wrap_mt.h
+++ b/servers/physics_3d/physics_server_3d_wrap_mt.h
@@ -79,6 +79,7 @@ public:
//FUNC1RID(shape,ShapeType); todo fix
FUNCRID(plane_shape)
+ FUNCRID(separation_ray_shape)
FUNCRID(sphere_shape)
FUNCRID(box_shape)
FUNCRID(capsule_shape)
@@ -250,9 +251,9 @@ public:
FUNC2(body_set_ray_pickable, RID, bool);
- bool body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, real_t p_margin = 0.001, MotionResult *r_result = nullptr, const Set<RID> &p_exclude = Set<RID>()) override {
+ bool body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, real_t p_margin = 0.001, MotionResult *r_result = nullptr, bool p_collide_separation_ray = false, const Set<RID> &p_exclude = Set<RID>()) override {
ERR_FAIL_COND_V(main_thread != Thread::get_caller_id(), false);
- return physics_3d_server->body_test_motion(p_body, p_from, p_motion, p_margin, r_result, p_exclude);
+ return physics_3d_server->body_test_motion(p_body, p_from, p_motion, p_margin, r_result, p_collide_separation_ray, p_exclude);
}
// this function only works on physics process, errors and returns null otherwise
diff --git a/servers/physics_3d/shape_3d_sw.cpp b/servers/physics_3d/shape_3d_sw.cpp
index 664308ed7b..b81d3272c3 100644
--- a/servers/physics_3d/shape_3d_sw.cpp
+++ b/servers/physics_3d/shape_3d_sw.cpp
@@ -164,6 +164,91 @@ Variant PlaneShape3DSW::get_data() const {
PlaneShape3DSW::PlaneShape3DSW() {
}
+//
+
+real_t SeparationRayShape3DSW::get_length() const {
+ return length;
+}
+
+bool SeparationRayShape3DSW::get_slide_on_slope() const {
+ return slide_on_slope;
+}
+
+void SeparationRayShape3DSW::project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const {
+ // don't think this will be even used
+ r_min = 0;
+ r_max = 1;
+}
+
+Vector3 SeparationRayShape3DSW::get_support(const Vector3 &p_normal) const {
+ if (p_normal.z > 0) {
+ return Vector3(0, 0, length);
+ } else {
+ return Vector3(0, 0, 0);
+ }
+}
+
+void SeparationRayShape3DSW::get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const {
+ if (Math::abs(p_normal.z) < _EDGE_IS_VALID_SUPPORT_THRESHOLD) {
+ r_amount = 2;
+ r_type = FEATURE_EDGE;
+ r_supports[0] = Vector3(0, 0, 0);
+ r_supports[1] = Vector3(0, 0, length);
+ } else if (p_normal.z > 0) {
+ r_amount = 1;
+ r_type = FEATURE_POINT;
+ *r_supports = Vector3(0, 0, length);
+ } else {
+ r_amount = 1;
+ r_type = FEATURE_POINT;
+ *r_supports = Vector3(0, 0, 0);
+ }
+}
+
+bool SeparationRayShape3DSW::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const {
+ return false; //simply not possible
+}
+
+bool SeparationRayShape3DSW::intersect_point(const Vector3 &p_point) const {
+ return false; //simply not possible
+}
+
+Vector3 SeparationRayShape3DSW::get_closest_point_to(const Vector3 &p_point) const {
+ Vector3 s[2] = {
+ Vector3(0, 0, 0),
+ Vector3(0, 0, length)
+ };
+
+ return Geometry3D::get_closest_point_to_segment(p_point, s);
+}
+
+Vector3 SeparationRayShape3DSW::get_moment_of_inertia(real_t p_mass) const {
+ return Vector3();
+}
+
+void SeparationRayShape3DSW::_setup(real_t p_length, bool p_slide_on_slope) {
+ length = p_length;
+ slide_on_slope = p_slide_on_slope;
+ configure(AABB(Vector3(0, 0, 0), Vector3(0.1, 0.1, length)));
+}
+
+void SeparationRayShape3DSW::set_data(const Variant &p_data) {
+ Dictionary d = p_data;
+ _setup(d["length"], d["slide_on_slope"]);
+}
+
+Variant SeparationRayShape3DSW::get_data() const {
+ Dictionary d;
+ d["length"] = length;
+ d["slide_on_slope"] = slide_on_slope;
+ return d;
+}
+
+SeparationRayShape3DSW::SeparationRayShape3DSW() {
+ length = 1;
+ slide_on_slope = false;
+}
+
/********** SPHERE *************/
real_t SphereShape3DSW::get_radius() const {
@@ -1297,11 +1382,11 @@ Vector3 ConcavePolygonShape3DSW::get_closest_point_to(const Vector3 &p_point) co
return Vector3();
}
-void ConcavePolygonShape3DSW::_cull(int p_idx, _CullParams *p_params) const {
+bool ConcavePolygonShape3DSW::_cull(int p_idx, _CullParams *p_params) const {
const BVH *bvh = &p_params->bvh[p_idx];
if (!p_params->aabb.intersects(bvh->aabb)) {
- return;
+ return false;
}
if (bvh->face_index >= 0) {
@@ -1311,20 +1396,27 @@ void ConcavePolygonShape3DSW::_cull(int p_idx, _CullParams *p_params) const {
face->vertex[0] = p_params->vertices[f->indices[0]];
face->vertex[1] = p_params->vertices[f->indices[1]];
face->vertex[2] = p_params->vertices[f->indices[2]];
- p_params->callback(p_params->userdata, face);
-
+ if (p_params->callback(p_params->userdata, face)) {
+ return true;
+ }
} else {
if (bvh->left >= 0) {
- _cull(bvh->left, p_params);
+ if (_cull(bvh->left, p_params)) {
+ return true;
+ }
}
if (bvh->right >= 0) {
- _cull(bvh->right, p_params);
+ if (_cull(bvh->right, p_params)) {
+ return true;
+ }
}
}
+
+ return false;
}
-void ConcavePolygonShape3DSW::cull(const AABB &p_local_aabb, Callback p_callback, void *p_userdata) const {
+void ConcavePolygonShape3DSW::cull(const AABB &p_local_aabb, QueryCallback p_callback, void *p_userdata) const {
// make matrix local to concave
if (faces.size() == 0) {
return;
@@ -1790,7 +1882,7 @@ void HeightMapShape3DSW::_get_cell(const Vector3 &p_point, int &r_x, int &r_y, i
r_z = (clamped_point.z < 0.0) ? (clamped_point.z - 0.5) : (clamped_point.z + 0.5);
}
-void HeightMapShape3DSW::cull(const AABB &p_local_aabb, Callback p_callback, void *p_userdata) const {
+void HeightMapShape3DSW::cull(const AABB &p_local_aabb, QueryCallback p_callback, void *p_userdata) const {
if (heights.is_empty()) {
return;
}
@@ -1826,13 +1918,17 @@ void HeightMapShape3DSW::cull(const AABB &p_local_aabb, Callback p_callback, voi
_get_point(x + 1, z, face.vertex[1]);
_get_point(x, z + 1, face.vertex[2]);
face.normal = Plane(face.vertex[0], face.vertex[2], face.vertex[1]).normal;
- p_callback(p_userdata, &face);
+ if (p_callback(p_userdata, &face)) {
+ return;
+ }
// Second triangle.
face.vertex[0] = face.vertex[1];
_get_point(x + 1, z + 1, face.vertex[1]);
face.normal = Plane(face.vertex[0], face.vertex[2], face.vertex[1]).normal;
- p_callback(p_userdata, &face);
+ if (p_callback(p_userdata, &face)) {
+ return;
+ }
}
}
}
diff --git a/servers/physics_3d/shape_3d_sw.h b/servers/physics_3d/shape_3d_sw.h
index ca58900111..b05f65f268 100644
--- a/servers/physics_3d/shape_3d_sw.h
+++ b/servers/physics_3d/shape_3d_sw.h
@@ -101,10 +101,12 @@ public:
class ConcaveShape3DSW : public Shape3DSW {
public:
virtual bool is_concave() const override { return true; }
- typedef void (*Callback)(void *p_userdata, Shape3DSW *p_convex);
virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const override { r_amount = 0; }
- virtual void cull(const AABB &p_local_aabb, Callback p_callback, void *p_userdata) const = 0;
+ // Returns true to stop the query.
+ typedef bool (*QueryCallback)(void *p_userdata, Shape3DSW *p_convex);
+
+ virtual void cull(const AABB &p_local_aabb, QueryCallback p_callback, void *p_userdata) const = 0;
ConcaveShape3DSW() {}
};
@@ -117,23 +119,51 @@ class PlaneShape3DSW : public Shape3DSW {
public:
Plane get_plane() const;
- virtual real_t get_area() const { return INFINITY; }
- virtual PhysicsServer3D::ShapeType get_type() const { return PhysicsServer3D::SHAPE_PLANE; }
- virtual void project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const;
- virtual Vector3 get_support(const Vector3 &p_normal) const;
- virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const { r_amount = 0; }
+ virtual real_t get_area() const override { return INFINITY; }
+ virtual PhysicsServer3D::ShapeType get_type() const override { return PhysicsServer3D::SHAPE_PLANE; }
+ virtual void project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const override;
+ virtual Vector3 get_support(const Vector3 &p_normal) const override;
+ virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const override { r_amount = 0; }
- virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const;
- virtual bool intersect_point(const Vector3 &p_point) const;
- virtual Vector3 get_closest_point_to(const Vector3 &p_point) const;
- virtual Vector3 get_moment_of_inertia(real_t p_mass) const;
+ virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const override;
+ virtual bool intersect_point(const Vector3 &p_point) const override;
+ virtual Vector3 get_closest_point_to(const Vector3 &p_point) const override;
+ virtual Vector3 get_moment_of_inertia(real_t p_mass) const override;
- virtual void set_data(const Variant &p_data);
- virtual Variant get_data() const;
+ virtual void set_data(const Variant &p_data) override;
+ virtual Variant get_data() const override;
PlaneShape3DSW();
};
+class SeparationRayShape3DSW : public Shape3DSW {
+ real_t length;
+ bool slide_on_slope;
+
+ void _setup(real_t p_length, bool p_slide_on_slope);
+
+public:
+ real_t get_length() const;
+ bool get_slide_on_slope() const;
+
+ virtual real_t get_area() const override { return 0.0; }
+ virtual PhysicsServer3D::ShapeType get_type() const override { return PhysicsServer3D::SHAPE_SEPARATION_RAY; }
+ virtual void project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const override;
+ virtual Vector3 get_support(const Vector3 &p_normal) const override;
+ virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const override;
+
+ virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const override;
+ virtual bool intersect_point(const Vector3 &p_point) const override;
+ virtual Vector3 get_closest_point_to(const Vector3 &p_point) const override;
+
+ virtual Vector3 get_moment_of_inertia(real_t p_mass) const override;
+
+ virtual void set_data(const Variant &p_data) override;
+ virtual Variant get_data() const override;
+
+ SeparationRayShape3DSW();
+};
+
class SphereShape3DSW : public Shape3DSW {
real_t radius;
@@ -295,7 +325,7 @@ struct ConcavePolygonShape3DSW : public ConcaveShape3DSW {
struct _CullParams {
AABB aabb;
- Callback callback = nullptr;
+ QueryCallback callback = nullptr;
void *userdata = nullptr;
const Face *faces = nullptr;
const Vector3 *vertices = nullptr;
@@ -321,7 +351,7 @@ struct ConcavePolygonShape3DSW : public ConcaveShape3DSW {
bool backface_collision = false;
void _cull_segment(int p_idx, _SegmentCullParams *p_params) const;
- void _cull(int p_idx, _CullParams *p_params) const;
+ bool _cull(int p_idx, _CullParams *p_params) const;
void _fill_bvh(_VolumeSW_BVH *p_bvh_tree, BVH *p_bvh_array, int &p_idx);
@@ -339,7 +369,7 @@ public:
virtual bool intersect_point(const Vector3 &p_point) const override;
virtual Vector3 get_closest_point_to(const Vector3 &p_point) const override;
- virtual void cull(const AABB &p_local_aabb, Callback p_callback, void *p_userdata) const override;
+ virtual void cull(const AABB &p_local_aabb, QueryCallback p_callback, void *p_userdata) const override;
virtual Vector3 get_moment_of_inertia(real_t p_mass) const override;
@@ -382,7 +412,7 @@ public:
virtual bool intersect_point(const Vector3 &p_point) const override;
virtual Vector3 get_closest_point_to(const Vector3 &p_point) const override;
- virtual void cull(const AABB &p_local_aabb, Callback p_callback, void *p_userdata) const override;
+ virtual void cull(const AABB &p_local_aabb, QueryCallback p_callback, void *p_userdata) const override;
virtual Vector3 get_moment_of_inertia(real_t p_mass) const override;
diff --git a/servers/physics_3d/soft_body_3d_sw.cpp b/servers/physics_3d/soft_body_3d_sw.cpp
index ead6497f1f..d7e13867bf 100644
--- a/servers/physics_3d/soft_body_3d_sw.cpp
+++ b/servers/physics_3d/soft_body_3d_sw.cpp
@@ -964,16 +964,9 @@ void SoftBody3DSW::apply_forces(bool p_has_wind_forces) {
}
void SoftBody3DSW::_compute_area_gravity(const Area3DSW *p_area) {
- if (p_area->is_gravity_point()) {
- if (p_area->get_gravity_distance_scale() > 0) {
- Vector3 v = p_area->get_transform().xform(p_area->get_gravity_vector()) - get_transform().get_origin();
- gravity += v.normalized() * (p_area->get_gravity() / Math::pow(v.length() * p_area->get_gravity_distance_scale() + 1, 2));
- } else {
- gravity += (p_area->get_transform().xform(p_area->get_gravity_vector()) - get_transform().get_origin()).normalized() * p_area->get_gravity();
- }
- } else {
- gravity += p_area->get_gravity_vector() * p_area->get_gravity();
- }
+ Vector3 area_gravity;
+ p_area->compute_gravity(get_transform().get_origin(), area_gravity);
+ gravity += area_gravity;
}
Vector3 SoftBody3DSW::_compute_area_windforce(const Area3DSW *p_area, const Face *p_face) {
diff --git a/servers/physics_3d/space_3d_sw.cpp b/servers/physics_3d/space_3d_sw.cpp
index f9e55ad525..37dee436df 100644
--- a/servers/physics_3d/space_3d_sw.cpp
+++ b/servers/physics_3d/space_3d_sw.cpp
@@ -569,7 +569,7 @@ int Space3DSW::_cull_aabb_for_body(Body3DSW *p_body, const AABB &p_aabb) {
return amount;
}
-bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform3D &p_from, const Vector3 &p_motion, real_t p_margin, PhysicsServer3D::MotionResult *r_result, const Set<RID> &p_exclude) {
+bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform3D &p_from, const Vector3 &p_motion, real_t p_margin, PhysicsServer3D::MotionResult *r_result, bool p_collide_separation_ray, const Set<RID> &p_exclude) {
//give me back regular physics engine logic
//this is madness
//and most people using this function will think
@@ -714,9 +714,19 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform3D &p_from, co
continue;
}
- Transform3D body_shape_xform = body_transform * p_body->get_shape_transform(j);
Shape3DSW *body_shape = p_body->get_shape(j);
+ // Colliding separation rays allows to properly snap to the ground,
+ // otherwise it's not needed in regular motion.
+ if (!p_collide_separation_ray && (body_shape->get_type() == PhysicsServer3D::SHAPE_SEPARATION_RAY)) {
+ // When slide on slope is on, separation ray shape acts like a regular shape.
+ if (!static_cast<SeparationRayShape3DSW *>(body_shape)->get_slide_on_slope()) {
+ continue;
+ }
+ }
+
+ Transform3D body_shape_xform = body_transform * p_body->get_shape_transform(j);
+
Transform3D body_shape_xform_inv = body_shape_xform.affine_inverse();
MotionShape3DSW mshape;
mshape.shape = body_shape;
diff --git a/servers/physics_3d/space_3d_sw.h b/servers/physics_3d/space_3d_sw.h
index 70faf0c1da..eff494a7bc 100644
--- a/servers/physics_3d/space_3d_sw.h
+++ b/servers/physics_3d/space_3d_sw.h
@@ -208,7 +208,7 @@ public:
void set_elapsed_time(ElapsedTime p_time, uint64_t p_msec) { elapsed_time[p_time] = p_msec; }
uint64_t get_elapsed_time(ElapsedTime p_time) const { return elapsed_time[p_time]; }
- bool test_body_motion(Body3DSW *p_body, const Transform3D &p_from, const Vector3 &p_motion, real_t p_margin, PhysicsServer3D::MotionResult *r_result, const Set<RID> &p_exclude = Set<RID>());
+ bool test_body_motion(Body3DSW *p_body, const Transform3D &p_from, const Vector3 &p_motion, real_t p_margin, PhysicsServer3D::MotionResult *r_result, bool p_collide_separation_ray = false, const Set<RID> &p_exclude = Set<RID>());
Space3DSW();
~Space3DSW();