diff options
Diffstat (limited to 'servers')
-rw-r--r-- | servers/physics_3d/area_3d_sw.cpp | 8 | ||||
-rw-r--r-- | servers/physics_3d/area_3d_sw.h | 34 | ||||
-rw-r--r-- | servers/physics_3d/area_pair_3d_sw.cpp | 82 | ||||
-rw-r--r-- | servers/physics_3d/area_pair_3d_sw.h | 18 | ||||
-rw-r--r-- | servers/physics_3d/body_3d_sw.h | 12 | ||||
-rw-r--r-- | servers/physics_3d/collision_solver_3d_sw.cpp | 4 | ||||
-rw-r--r-- | servers/physics_3d/soft_body_3d_sw.cpp | 41 | ||||
-rw-r--r-- | servers/physics_3d/soft_body_3d_sw.h | 26 | ||||
-rw-r--r-- | servers/physics_3d/space_3d_sw.cpp | 4 |
9 files changed, 215 insertions, 14 deletions
diff --git a/servers/physics_3d/area_3d_sw.cpp b/servers/physics_3d/area_3d_sw.cpp index a9f5c4aec3..364f63e4ad 100644 --- a/servers/physics_3d/area_3d_sw.cpp +++ b/servers/physics_3d/area_3d_sw.cpp @@ -30,8 +30,16 @@ #include "area_3d_sw.h" #include "body_3d_sw.h" +#include "soft_body_3d_sw.h" #include "space_3d_sw.h" +Area3DSW::BodyKey::BodyKey(SoftBody3DSW *p_body, uint32_t p_body_shape, uint32_t p_area_shape) { + rid = p_body->get_self(); + instance_id = p_body->get_instance_id(); + body_shape = p_body_shape; + area_shape = p_area_shape; +} + Area3DSW::BodyKey::BodyKey(Body3DSW *p_body, uint32_t p_body_shape, uint32_t p_area_shape) { rid = p_body->get_self(); instance_id = p_body->get_instance_id(); diff --git a/servers/physics_3d/area_3d_sw.h b/servers/physics_3d/area_3d_sw.h index 12f7545c08..5959ee1e95 100644 --- a/servers/physics_3d/area_3d_sw.h +++ b/servers/physics_3d/area_3d_sw.h @@ -38,6 +38,7 @@ class Space3DSW; class Body3DSW; +class SoftBody3DSW; class Constraint3DSW; class Area3DSW : public CollisionObject3DSW { @@ -80,6 +81,7 @@ class Area3DSW : public CollisionObject3DSW { } _FORCE_INLINE_ BodyKey() {} + BodyKey(SoftBody3DSW *p_body, uint32_t p_body_shape, uint32_t p_area_shape); BodyKey(Body3DSW *p_body, uint32_t p_body_shape, uint32_t p_area_shape); BodyKey(Area3DSW *p_body, uint32_t p_body_shape, uint32_t p_area_shape); }; @@ -91,6 +93,7 @@ class Area3DSW : public CollisionObject3DSW { _FORCE_INLINE_ BodyState() { state = 0; } }; + Map<BodyKey, BodyState> monitored_soft_bodies; Map<BodyKey, BodyState> monitored_bodies; Map<BodyKey, BodyState> monitored_areas; @@ -115,6 +118,9 @@ public: _FORCE_INLINE_ void add_body_to_query(Body3DSW *p_body, uint32_t p_body_shape, uint32_t p_area_shape); _FORCE_INLINE_ void remove_body_from_query(Body3DSW *p_body, uint32_t p_body_shape, uint32_t p_area_shape); + _FORCE_INLINE_ void add_soft_body_to_query(SoftBody3DSW *p_soft_body, uint32_t p_soft_body_shape, uint32_t p_area_shape); + _FORCE_INLINE_ void remove_soft_body_from_query(SoftBody3DSW *p_soft_body, uint32_t p_soft_body_shape, uint32_t p_area_shape); + _FORCE_INLINE_ void add_area_to_query(Area3DSW *p_area, uint32_t p_area_shape, uint32_t p_self_shape); _FORCE_INLINE_ void remove_area_from_query(Area3DSW *p_area, uint32_t p_area_shape, uint32_t p_self_shape); @@ -166,6 +172,22 @@ public: ~Area3DSW(); }; +void Area3DSW::add_soft_body_to_query(SoftBody3DSW *p_soft_body, uint32_t p_soft_body_shape, uint32_t p_area_shape) { + BodyKey bk(p_soft_body, p_soft_body_shape, p_area_shape); + monitored_soft_bodies[bk].inc(); + if (!monitor_query_list.in_list()) { + _queue_monitor_update(); + } +} + +void Area3DSW::remove_soft_body_from_query(SoftBody3DSW *p_soft_body, uint32_t p_soft_body_shape, uint32_t p_area_shape) { + BodyKey bk(p_soft_body, p_soft_body_shape, p_area_shape); + monitored_soft_bodies[bk].dec(); + if (!monitor_query_list.in_list()) { + _queue_monitor_update(); + } +} + void Area3DSW::add_body_to_query(Body3DSW *p_body, uint32_t p_body_shape, uint32_t p_area_shape) { BodyKey bk(p_body, p_body_shape, p_area_shape); monitored_bodies[bk].inc(); @@ -198,4 +220,16 @@ void Area3DSW::remove_area_from_query(Area3DSW *p_area, uint32_t p_area_shape, u } } +struct AreaCMP { + Area3DSW *area; + int refCount; + _FORCE_INLINE_ bool operator==(const AreaCMP &p_cmp) const { return area->get_self() == p_cmp.area->get_self(); } + _FORCE_INLINE_ bool operator<(const AreaCMP &p_cmp) const { return area->get_priority() < p_cmp.area->get_priority(); } + _FORCE_INLINE_ AreaCMP() {} + _FORCE_INLINE_ AreaCMP(Area3DSW *p_area) { + area = p_area; + refCount = 1; + } +}; + #endif // AREA__SW_H diff --git a/servers/physics_3d/area_pair_3d_sw.cpp b/servers/physics_3d/area_pair_3d_sw.cpp index f43c2c965e..e740565da6 100644 --- a/servers/physics_3d/area_pair_3d_sw.cpp +++ b/servers/physics_3d/area_pair_3d_sw.cpp @@ -181,3 +181,85 @@ Area2Pair3DSW::~Area2Pair3DSW() { area_a->remove_constraint(this); area_b->remove_constraint(this); } + +//////////////////////////////////////////////////// + +bool AreaSoftBodyPair3DSW::setup(real_t p_step) { + bool result = false; + if ( + area->interacts_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), + area->get_shape(area_shape), + area->get_transform() * area->get_shape_transform(area_shape), + nullptr, + this)) { + result = true; + } + + process_collision = false; + if (result != colliding) { + if (area->get_space_override_mode() != PhysicsServer3D::AREA_SPACE_OVERRIDE_DISABLED) { + process_collision = true; + } else if (area->has_monitor_callback()) { + process_collision = true; + } + + colliding = result; + } + + return process_collision; +} + +bool AreaSoftBodyPair3DSW::pre_solve(real_t p_step) { + if (!process_collision) { + return false; + } + + if (colliding) { + if (area->get_space_override_mode() != PhysicsServer3D::AREA_SPACE_OVERRIDE_DISABLED) { + soft_body->add_area(area); + } + + if (area->has_monitor_callback()) { + area->add_soft_body_to_query(soft_body, soft_body_shape, area_shape); + } + } else { + if (area->get_space_override_mode() != PhysicsServer3D::AREA_SPACE_OVERRIDE_DISABLED) { + soft_body->remove_area(area); + } + + if (area->has_monitor_callback()) { + area->remove_soft_body_from_query(soft_body, soft_body_shape, area_shape); + } + } + + return false; // Never do any post solving. +} + +void AreaSoftBodyPair3DSW::solve(real_t p_step) { + // Nothing to do. +} + +AreaSoftBodyPair3DSW::AreaSoftBodyPair3DSW(SoftBody3DSW *p_soft_body, int p_soft_body_shape, Area3DSW *p_area, int p_area_shape) { + soft_body = p_soft_body; + area = p_area; + soft_body_shape = p_soft_body_shape; + area_shape = p_area_shape; + soft_body->add_constraint(this); + area->add_constraint(this); +} + +AreaSoftBodyPair3DSW::~AreaSoftBodyPair3DSW() { + if (colliding) { + if (area->get_space_override_mode() != PhysicsServer3D::AREA_SPACE_OVERRIDE_DISABLED) { + soft_body->remove_area(area); + } + if (area->has_monitor_callback()) { + area->remove_soft_body_from_query(soft_body, soft_body_shape, area_shape); + } + } + soft_body->remove_constraint(this); + area->remove_constraint(this); +} diff --git a/servers/physics_3d/area_pair_3d_sw.h b/servers/physics_3d/area_pair_3d_sw.h index 596d893082..8cc9e9ad63 100644 --- a/servers/physics_3d/area_pair_3d_sw.h +++ b/servers/physics_3d/area_pair_3d_sw.h @@ -34,6 +34,7 @@ #include "area_3d_sw.h" #include "body_3d_sw.h" #include "constraint_3d_sw.h" +#include "soft_body_3d_sw.h" class AreaPair3DSW : public Constraint3DSW { Body3DSW *body; @@ -69,4 +70,21 @@ public: ~Area2Pair3DSW(); }; +class AreaSoftBodyPair3DSW : public Constraint3DSW { + SoftBody3DSW *soft_body; + Area3DSW *area; + int soft_body_shape; + int area_shape; + bool colliding = false; + bool process_collision = false; + +public: + virtual bool setup(real_t p_step) override; + virtual bool pre_solve(real_t p_step) override; + virtual void solve(real_t p_step) override; + + AreaSoftBodyPair3DSW(SoftBody3DSW *p_sof_body, int p_soft_body_shape, Area3DSW *p_area, int p_area_shape); + ~AreaSoftBodyPair3DSW(); +}; + #endif // AREA_PAIR__SW_H diff --git a/servers/physics_3d/body_3d_sw.h b/servers/physics_3d/body_3d_sw.h index bdc615ab6c..efb114a325 100644 --- a/servers/physics_3d/body_3d_sw.h +++ b/servers/physics_3d/body_3d_sw.h @@ -96,18 +96,6 @@ class Body3DSW : public CollisionObject3DSW { Map<Constraint3DSW *, int> constraint_map; - struct AreaCMP { - Area3DSW *area; - int refCount; - _FORCE_INLINE_ bool operator==(const AreaCMP &p_cmp) const { return area->get_self() == p_cmp.area->get_self(); } - _FORCE_INLINE_ bool operator<(const AreaCMP &p_cmp) const { return area->get_priority() < p_cmp.area->get_priority(); } - _FORCE_INLINE_ AreaCMP() {} - _FORCE_INLINE_ AreaCMP(Area3DSW *p_area) { - area = p_area; - refCount = 1; - } - }; - Vector<AreaCMP> areas; struct Contact { diff --git a/servers/physics_3d/collision_solver_3d_sw.cpp b/servers/physics_3d/collision_solver_3d_sw.cpp index 161e7e101b..dcecac1c73 100644 --- a/servers/physics_3d/collision_solver_3d_sw.cpp +++ b/servers/physics_3d/collision_solver_3d_sw.cpp @@ -102,6 +102,10 @@ void CollisionSolver3DSW::soft_body_contact_callback(const Vector3 &p_point_A, i ++cinfo.contact_count; + if (!cinfo.result_callback) { + return; + } + if (cinfo.swap_result) { cinfo.result_callback(p_point_B, cinfo.node_index, p_point_A, p_index_A, cinfo.userdata); } else { diff --git a/servers/physics_3d/soft_body_3d_sw.cpp b/servers/physics_3d/soft_body_3d_sw.cpp index 724125bea8..73b81444e1 100644 --- a/servers/physics_3d/soft_body_3d_sw.cpp +++ b/servers/physics_3d/soft_body_3d_sw.cpp @@ -928,6 +928,19 @@ void SoftBody3DSW::apply_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(); + } +} + void SoftBody3DSW::predict_motion(real_t p_delta) { const real_t inv_delta = 1.0 / p_delta; @@ -935,9 +948,35 @@ void SoftBody3DSW::predict_motion(real_t p_delta) { Area3DSW *def_area = get_space()->get_default_area(); ERR_FAIL_COND(!def_area); + gravity = def_area->get_gravity_vector() * def_area->get_gravity(); + + int ac = areas.size(); + bool stopped = false; + + if (ac) { + areas.sort(); + const AreaCMP *aa = &areas[0]; + for (int i = ac - 1; i >= 0 && !stopped; i--) { + PhysicsServer3D::AreaSpaceOverrideMode mode = aa[i].area->get_space_override_mode(); + switch (mode) { + case PhysicsServer3D::AREA_SPACE_OVERRIDE_COMBINE: + case PhysicsServer3D::AREA_SPACE_OVERRIDE_COMBINE_REPLACE: { + _compute_area_gravity(aa[i].area); + stopped = mode == PhysicsServer3D::AREA_SPACE_OVERRIDE_COMBINE_REPLACE; + } break; + case PhysicsServer3D::AREA_SPACE_OVERRIDE_REPLACE: + case PhysicsServer3D::AREA_SPACE_OVERRIDE_REPLACE_COMBINE: { + gravity = Vector3(0, 0, 0); + _compute_area_gravity(aa[i].area); + stopped = mode == PhysicsServer3D::AREA_SPACE_OVERRIDE_REPLACE; + } break; + default: { + } + } + } + } // Apply forces. - Vector3 gravity = def_area->get_gravity_vector() * def_area->get_gravity(); add_velocity(gravity * p_delta); apply_forces(); diff --git a/servers/physics_3d/soft_body_3d_sw.h b/servers/physics_3d/soft_body_3d_sw.h index ac8bcbf0b9..be0620c506 100644 --- a/servers/physics_3d/soft_body_3d_sw.h +++ b/servers/physics_3d/soft_body_3d_sw.h @@ -31,6 +31,7 @@ #ifndef SOFT_BODY_3D_SW_H #define SOFT_BODY_3D_SW_H +#include "area_3d_sw.h" #include "collision_object_3d_sw.h" #include "core/math/aabb.h" @@ -100,14 +101,20 @@ class SoftBody3DSW : public CollisionObject3DSW { real_t drag_coefficient = 0.0; // [0,1] LocalVector<int> pinned_vertices; + Vector3 gravity; + SelfList<SoftBody3DSW> active_list; Set<Constraint3DSW *> constraints; + Vector<AreaCMP> areas; + VSet<RID> exceptions; uint64_t island_step = 0; + _FORCE_INLINE_ void _compute_area_gravity(const Area3DSW *p_area); + public: SoftBody3DSW(); @@ -129,6 +136,25 @@ public: _FORCE_INLINE_ uint64_t get_island_step() const { return island_step; } _FORCE_INLINE_ void set_island_step(uint64_t p_step) { island_step = p_step; } + _FORCE_INLINE_ void add_area(Area3DSW *p_area) { + int index = areas.find(AreaCMP(p_area)); + if (index > -1) { + areas.write[index].refCount += 1; + } else { + areas.ordered_insert(AreaCMP(p_area)); + } + } + + _FORCE_INLINE_ void remove_area(Area3DSW *p_area) { + int index = areas.find(AreaCMP(p_area)); + if (index > -1) { + areas.write[index].refCount -= 1; + if (areas[index].refCount < 1) { + areas.remove(index); + } + } + } + virtual void set_space(Space3DSW *p_space); void set_mesh(const Ref<Mesh> &p_mesh); diff --git a/servers/physics_3d/space_3d_sw.cpp b/servers/physics_3d/space_3d_sw.cpp index 730460d66a..b90730ad23 100644 --- a/servers/physics_3d/space_3d_sw.cpp +++ b/servers/physics_3d/space_3d_sw.cpp @@ -921,7 +921,9 @@ void *Space3DSW::_broadphase_pair(CollisionObject3DSW *A, int p_subindex_A, Coll Area2Pair3DSW *area2_pair = memnew(Area2Pair3DSW(area_b, p_subindex_B, area, p_subindex_A)); return area2_pair; } else if (type_B == CollisionObject3DSW::TYPE_SOFT_BODY) { - // Area/Soft Body, not supported. + SoftBody3DSW *softbody = static_cast<SoftBody3DSW *>(B); + AreaSoftBodyPair3DSW *soft_area_pair = memnew(AreaSoftBodyPair3DSW(softbody, p_subindex_B, area, p_subindex_A)); + return soft_area_pair; } else { Body3DSW *body = static_cast<Body3DSW *>(B); AreaPair3DSW *area_pair = memnew(AreaPair3DSW(body, p_subindex_B, area, p_subindex_A)); |