diff options
author | Silc Renew <tokage.it.lab@gmail.com> | 2022-08-11 01:45:36 +0900 |
---|---|---|
committer | Silc Renew <tokage.it.lab@gmail.com> | 2022-08-18 08:10:31 +0900 |
commit | b31115cdc1c635e0e33f7a1e053dc2d944bcf521 (patch) | |
tree | 7ccae68b9b7a5888b5215d415827043b16d52699 /servers | |
parent | dbd15243621ec595742b18abc4c26f3cb2e00f3d (diff) |
Add collision weight to PhysicsBody for penetrations must be avoided
Co-authored-by: Juan Linietsky <reduzio@gmail.com>
Diffstat (limited to 'servers')
-rw-r--r-- | servers/extensions/physics_server_3d_extension.cpp | 3 | ||||
-rw-r--r-- | servers/extensions/physics_server_3d_extension.h | 3 | ||||
-rw-r--r-- | servers/physics_2d/godot_collision_object_2d.h | 8 | ||||
-rw-r--r-- | servers/physics_2d/godot_physics_server_2d.cpp | 14 | ||||
-rw-r--r-- | servers/physics_2d/godot_physics_server_2d.h | 3 | ||||
-rw-r--r-- | servers/physics_2d/godot_space_2d.cpp | 14 | ||||
-rw-r--r-- | servers/physics_3d/godot_collision_object_3d.h | 8 | ||||
-rw-r--r-- | servers/physics_3d/godot_physics_server_3d.cpp | 14 | ||||
-rw-r--r-- | servers/physics_3d/godot_physics_server_3d.h | 3 | ||||
-rw-r--r-- | servers/physics_3d/godot_space_3d.cpp | 14 | ||||
-rw-r--r-- | servers/physics_server_2d.cpp | 3 | ||||
-rw-r--r-- | servers/physics_server_2d.h | 3 | ||||
-rw-r--r-- | servers/physics_server_2d_wrap_mt.h | 3 | ||||
-rw-r--r-- | servers/physics_server_3d.cpp | 3 | ||||
-rw-r--r-- | servers/physics_server_3d.h | 3 | ||||
-rw-r--r-- | servers/physics_server_3d_wrap_mt.h | 3 |
16 files changed, 100 insertions, 2 deletions
diff --git a/servers/extensions/physics_server_3d_extension.cpp b/servers/extensions/physics_server_3d_extension.cpp index 3694dcdb9a..7d797bf611 100644 --- a/servers/extensions/physics_server_3d_extension.cpp +++ b/servers/extensions/physics_server_3d_extension.cpp @@ -196,6 +196,9 @@ void PhysicsServer3DExtension::_bind_methods() { GDVIRTUAL_BIND(_body_set_collision_mask, "body", "mask"); GDVIRTUAL_BIND(_body_get_collision_mask, "body"); + GDVIRTUAL_BIND(_body_set_collision_priority, "body", "priority"); + GDVIRTUAL_BIND(_body_get_collision_priority, "body"); + GDVIRTUAL_BIND(_body_add_shape, "body", "shape", "transform", "disabled"); GDVIRTUAL_BIND(_body_set_shape, "body", "shape_idx", "shape"); GDVIRTUAL_BIND(_body_set_shape_transform, "body", "shape_idx", "transform"); diff --git a/servers/extensions/physics_server_3d_extension.h b/servers/extensions/physics_server_3d_extension.h index c4b4a00eaf..3200438253 100644 --- a/servers/extensions/physics_server_3d_extension.h +++ b/servers/extensions/physics_server_3d_extension.h @@ -319,6 +319,9 @@ public: EXBIND2(body_set_collision_mask, RID, uint32_t) EXBIND1RC(uint32_t, body_get_collision_mask, RID) + EXBIND2(body_set_collision_priority, RID, real_t) + EXBIND1RC(real_t, body_get_collision_priority, RID) + EXBIND2(body_set_user_flags, RID, uint32_t) EXBIND1RC(uint32_t, body_get_user_flags, RID) diff --git a/servers/physics_2d/godot_collision_object_2d.h b/servers/physics_2d/godot_collision_object_2d.h index 1a683a7b0f..7965e8a94d 100644 --- a/servers/physics_2d/godot_collision_object_2d.h +++ b/servers/physics_2d/godot_collision_object_2d.h @@ -70,6 +70,7 @@ private: Transform2D inv_transform; uint32_t collision_mask = 1; uint32_t collision_layer = 1; + real_t collision_priority = 1.0; bool _static = true; SelfList<GodotCollisionObject2D> pending_shape_update_list; @@ -166,6 +167,13 @@ public: } _FORCE_INLINE_ uint32_t get_collision_layer() const { return collision_layer; } + _FORCE_INLINE_ void set_collision_priority(real_t p_priority) { + ERR_FAIL_COND_MSG(p_priority <= 0, "Priority must be greater than 0."); + collision_priority = p_priority; + _shape_changed(); + } + _FORCE_INLINE_ real_t get_collision_priority() const { return collision_priority; } + void remove_shape(GodotShape2D *p_shape) override; void remove_shape(int p_index); diff --git a/servers/physics_2d/godot_physics_server_2d.cpp b/servers/physics_2d/godot_physics_server_2d.cpp index 99e68de07c..c728dccd4f 100644 --- a/servers/physics_2d/godot_physics_server_2d.cpp +++ b/servers/physics_2d/godot_physics_server_2d.cpp @@ -718,6 +718,20 @@ uint32_t GodotPhysicsServer2D::body_get_collision_mask(RID p_body) const { return body->get_collision_mask(); } +void GodotPhysicsServer2D::body_set_collision_priority(RID p_body, real_t p_priority) { + GodotBody2D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND(!body); + + body->set_collision_priority(p_priority); +} + +real_t GodotPhysicsServer2D::body_get_collision_priority(RID p_body) const { + const GodotBody2D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND_V(!body, 0); + + return body->get_collision_priority(); +} + void GodotPhysicsServer2D::body_set_param(RID p_body, BodyParameter p_param, const Variant &p_value) { GodotBody2D *body = body_owner.get_or_null(p_body); ERR_FAIL_COND(!body); diff --git a/servers/physics_2d/godot_physics_server_2d.h b/servers/physics_2d/godot_physics_server_2d.h index 2af6e5c97c..20e492d87a 100644 --- a/servers/physics_2d/godot_physics_server_2d.h +++ b/servers/physics_2d/godot_physics_server_2d.h @@ -199,6 +199,9 @@ public: virtual void body_set_collision_mask(RID p_body, uint32_t p_mask) override; virtual uint32_t body_get_collision_mask(RID p_body) const override; + virtual void body_set_collision_priority(RID p_body, real_t p_priority) override; + virtual real_t body_get_collision_priority(RID p_body) const override; + virtual void body_set_param(RID p_body, BodyParameter p_param, const Variant &p_value) override; virtual Variant body_get_param(RID p_body, BodyParameter p_param) const override; diff --git a/servers/physics_2d/godot_space_2d.cpp b/servers/physics_2d/godot_space_2d.cpp index 166ec3049e..4166191be8 100644 --- a/servers/physics_2d/godot_space_2d.cpp +++ b/servers/physics_2d/godot_space_2d.cpp @@ -594,6 +594,7 @@ bool GodotSpace2D::test_body_motion(GodotBody2D *p_body, const PhysicsServer2D:: const int max_results = 32; int recover_attempts = 4; Vector2 sr[max_results * 2]; + real_t priorities[max_results]; do { GodotPhysicsServer2D::CollCbkData cbk; @@ -606,6 +607,7 @@ bool GodotSpace2D::test_body_motion(GodotBody2D *p_body, const PhysicsServer2D:: GodotPhysicsServer2D::CollCbkData *cbkptr = &cbk; GodotCollisionSolver2D::CallbackResult cbkres = GodotPhysicsServer2D::_shape_col_cbk; + int priority_amount = 0; bool collided = false; @@ -664,6 +666,10 @@ bool GodotSpace2D::test_body_motion(GodotBody2D *p_body, const PhysicsServer2D:: if (GodotCollisionSolver2D::solve(body_shape, body_shape_xform, Vector2(), against_shape, col_obj_shape_xform, Vector2(), cbkres, cbkptr, nullptr, margin)) { did_collide = cbk.passed > current_passed; //more passed, so collision actually existed } + while (cbk.amount > priority_amount) { + priorities[priority_amount] = col_obj->get_collision_priority(); + priority_amount++; + } if (!did_collide && cbk.invalid_by_dir > 0) { //this shape must be excluded @@ -686,6 +692,12 @@ bool GodotSpace2D::test_body_motion(GodotBody2D *p_body, const PhysicsServer2D:: 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; Vector2 recover_motion; @@ -701,7 +713,7 @@ bool GodotSpace2D::test_body_motion(GodotBody2D *p_body, const PhysicsServer2D:: 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; } } diff --git a/servers/physics_3d/godot_collision_object_3d.h b/servers/physics_3d/godot_collision_object_3d.h index 0f09f21962..2d342f65f3 100644 --- a/servers/physics_3d/godot_collision_object_3d.h +++ b/servers/physics_3d/godot_collision_object_3d.h @@ -59,6 +59,7 @@ private: ObjectID instance_id; uint32_t collision_layer = 1; uint32_t collision_mask = 1; + real_t collision_priority = 1.0; struct Shape { Transform3D xform; @@ -165,6 +166,13 @@ public: } _FORCE_INLINE_ uint32_t get_collision_mask() const { return collision_mask; } + _FORCE_INLINE_ void set_collision_priority(real_t p_priority) { + ERR_FAIL_COND_MSG(p_priority <= 0, "Priority must be greater than 0."); + collision_priority = p_priority; + _shape_changed(); + } + _FORCE_INLINE_ real_t get_collision_priority() const { return collision_priority; } + _FORCE_INLINE_ bool collides_with(GodotCollisionObject3D *p_other) const { return p_other->collision_layer & collision_mask; } diff --git a/servers/physics_3d/godot_physics_server_3d.cpp b/servers/physics_3d/godot_physics_server_3d.cpp index b735283ebe..9c1535f561 100644 --- a/servers/physics_3d/godot_physics_server_3d.cpp +++ b/servers/physics_3d/godot_physics_server_3d.cpp @@ -593,6 +593,20 @@ uint32_t GodotPhysicsServer3D::body_get_collision_mask(RID p_body) const { return body->get_collision_mask(); } +void GodotPhysicsServer3D::body_set_collision_priority(RID p_body, real_t p_priority) { + GodotBody3D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND(!body); + + body->set_collision_priority(p_priority); +} + +real_t GodotPhysicsServer3D::body_get_collision_priority(RID p_body) const { + const GodotBody3D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND_V(!body, 0); + + return body->get_collision_priority(); +} + void GodotPhysicsServer3D::body_attach_object_instance_id(RID p_body, ObjectID p_id) { GodotBody3D *body = body_owner.get_or_null(p_body); if (body) { diff --git a/servers/physics_3d/godot_physics_server_3d.h b/servers/physics_3d/godot_physics_server_3d.h index 1d57451925..b429f23a0c 100644 --- a/servers/physics_3d/godot_physics_server_3d.h +++ b/servers/physics_3d/godot_physics_server_3d.h @@ -192,6 +192,9 @@ public: virtual void body_set_collision_mask(RID p_body, uint32_t p_mask) override; virtual uint32_t body_get_collision_mask(RID p_body) const override; + virtual void body_set_collision_priority(RID p_body, real_t p_priority) override; + virtual real_t body_get_collision_priority(RID p_body) const override; + virtual void body_set_user_flags(RID p_body, uint32_t p_flags) override; virtual uint32_t body_get_user_flags(RID p_body) const override; diff --git a/servers/physics_3d/godot_space_3d.cpp b/servers/physics_3d/godot_space_3d.cpp index 13e9a89b2e..074232dd66 100644 --- a/servers/physics_3d/godot_space_3d.cpp +++ b/servers/physics_3d/godot_space_3d.cpp @@ -701,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; @@ -710,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; @@ -737,6 +739,10 @@ bool GodotSpace3D::test_body_motion(GodotBody3D *p_body, const PhysicsServer3D:: 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++; + } } } @@ -744,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; @@ -759,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; } } diff --git a/servers/physics_server_2d.cpp b/servers/physics_server_2d.cpp index 26768e300c..ee6764d8e1 100644 --- a/servers/physics_server_2d.cpp +++ b/servers/physics_server_2d.cpp @@ -706,6 +706,9 @@ void PhysicsServer2D::_bind_methods() { ClassDB::bind_method(D_METHOD("body_set_collision_mask", "body", "mask"), &PhysicsServer2D::body_set_collision_mask); ClassDB::bind_method(D_METHOD("body_get_collision_mask", "body"), &PhysicsServer2D::body_get_collision_mask); + ClassDB::bind_method(D_METHOD("body_set_collision_priority", "body", "priority"), &PhysicsServer2D::body_set_collision_priority); + ClassDB::bind_method(D_METHOD("body_get_collision_priority", "body"), &PhysicsServer2D::body_get_collision_priority); + ClassDB::bind_method(D_METHOD("body_set_param", "body", "param", "value"), &PhysicsServer2D::body_set_param); ClassDB::bind_method(D_METHOD("body_get_param", "body", "param"), &PhysicsServer2D::body_get_param); diff --git a/servers/physics_server_2d.h b/servers/physics_server_2d.h index 6d95c591c2..df8b641ffc 100644 --- a/servers/physics_server_2d.h +++ b/servers/physics_server_2d.h @@ -393,6 +393,9 @@ public: virtual void body_set_collision_mask(RID p_body, uint32_t p_mask) = 0; virtual uint32_t body_get_collision_mask(RID p_body) const = 0; + virtual void body_set_collision_priority(RID p_body, real_t p_priority) = 0; + virtual real_t body_get_collision_priority(RID p_body) const = 0; + // common body variables enum BodyParameter { BODY_PARAM_BOUNCE, diff --git a/servers/physics_server_2d_wrap_mt.h b/servers/physics_server_2d_wrap_mt.h index ddb071f603..d080aac438 100644 --- a/servers/physics_server_2d_wrap_mt.h +++ b/servers/physics_server_2d_wrap_mt.h @@ -205,6 +205,9 @@ public: FUNC2(body_set_collision_mask, RID, uint32_t); FUNC1RC(uint32_t, body_get_collision_mask, RID); + FUNC2(body_set_collision_priority, RID, real_t); + FUNC1RC(real_t, body_get_collision_priority, RID); + FUNC3(body_set_param, RID, BodyParameter, const Variant &); FUNC2RC(Variant, body_get_param, RID, BodyParameter); diff --git a/servers/physics_server_3d.cpp b/servers/physics_server_3d.cpp index f25db22e66..c985df83b2 100644 --- a/servers/physics_server_3d.cpp +++ b/servers/physics_server_3d.cpp @@ -750,6 +750,9 @@ void PhysicsServer3D::_bind_methods() { ClassDB::bind_method(D_METHOD("body_set_collision_mask", "body", "mask"), &PhysicsServer3D::body_set_collision_mask); ClassDB::bind_method(D_METHOD("body_get_collision_mask", "body"), &PhysicsServer3D::body_get_collision_mask); + ClassDB::bind_method(D_METHOD("body_set_collision_priority", "body", "priority"), &PhysicsServer3D::body_set_collision_priority); + ClassDB::bind_method(D_METHOD("body_get_collision_priority", "body"), &PhysicsServer3D::body_get_collision_priority); + ClassDB::bind_method(D_METHOD("body_add_shape", "body", "shape", "transform", "disabled"), &PhysicsServer3D::body_add_shape, DEFVAL(Transform3D()), DEFVAL(false)); ClassDB::bind_method(D_METHOD("body_set_shape", "body", "shape_idx", "shape"), &PhysicsServer3D::body_set_shape); ClassDB::bind_method(D_METHOD("body_set_shape_transform", "body", "shape_idx", "transform"), &PhysicsServer3D::body_set_shape_transform); diff --git a/servers/physics_server_3d.h b/servers/physics_server_3d.h index 12497c0bdf..01324be0f5 100644 --- a/servers/physics_server_3d.h +++ b/servers/physics_server_3d.h @@ -421,6 +421,9 @@ public: virtual void body_set_collision_mask(RID p_body, uint32_t p_mask) = 0; virtual uint32_t body_get_collision_mask(RID p_body) const = 0; + virtual void body_set_collision_priority(RID p_body, real_t p_priority) = 0; + virtual real_t body_get_collision_priority(RID p_body) const = 0; + virtual void body_set_user_flags(RID p_body, uint32_t p_flags) = 0; virtual uint32_t body_get_user_flags(RID p_body) const = 0; diff --git a/servers/physics_server_3d_wrap_mt.h b/servers/physics_server_3d_wrap_mt.h index d4a4ad3132..ed4546b240 100644 --- a/servers/physics_server_3d_wrap_mt.h +++ b/servers/physics_server_3d_wrap_mt.h @@ -202,6 +202,9 @@ public: FUNC2(body_set_collision_mask, RID, uint32_t); FUNC1RC(uint32_t, body_get_collision_mask, RID); + FUNC2(body_set_collision_priority, RID, real_t); + FUNC1RC(real_t, body_get_collision_priority, RID); + FUNC2(body_set_user_flags, RID, uint32_t); FUNC1RC(uint32_t, body_get_user_flags, RID); |