diff options
Diffstat (limited to 'servers/physics_3d')
-rw-r--r-- | servers/physics_3d/godot_body_pair_3d.cpp | 130 | ||||
-rw-r--r-- | servers/physics_3d/godot_body_pair_3d.h | 1 | ||||
-rw-r--r-- | servers/physics_3d/godot_physics_server_3d.cpp | 21 | ||||
-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_3d/godot_space_3d.h | 5 | ||||
-rw-r--r-- | servers/physics_3d/godot_step_3d.cpp | 4 | ||||
-rw-r--r-- | servers/physics_3d/godot_step_3d.h | 2 |
8 files changed, 102 insertions, 78 deletions
diff --git a/servers/physics_3d/godot_body_pair_3d.cpp b/servers/physics_3d/godot_body_pair_3d.cpp index 8a701466ed..5c25ba9537 100644 --- a/servers/physics_3d/godot_body_pair_3d.cpp +++ b/servers/physics_3d/godot_body_pair_3d.cpp @@ -44,11 +44,6 @@ void GodotBodyPair3D::_contact_added_callback(const Vector3 &p_point_A, int p_in } void GodotBodyPair3D::contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B) { - // check if we already have the contact - - //Vector3 local_A = A->get_inv_transform().xform(p_point_A); - //Vector3 local_B = B->get_inv_transform().xform(p_point_B); - Vector3 local_A = A->get_inv_transform().basis.xform(p_point_A); Vector3 local_B = B->get_inv_transform().basis.xform(p_point_B - offset_B); @@ -57,19 +52,14 @@ void GodotBodyPair3D::contact_added_callback(const Vector3 &p_point_A, int p_ind ERR_FAIL_COND(new_index >= (MAX_CONTACTS + 1)); Contact contact; - - contact.acc_normal_impulse = 0; - contact.acc_bias_impulse = 0; - contact.acc_bias_impulse_center_of_mass = 0; - contact.acc_tangent_impulse = Vector3(); contact.index_A = p_index_A; contact.index_B = p_index_B; contact.local_A = local_A; contact.local_B = local_B; contact.normal = (p_point_A - p_point_B).normalized(); - contact.mass_normal = 0; // will be computed in setup() + contact.used = true; - // attempt to determine if the contact will be reused + // Attempt to determine if the contact will be reused. real_t contact_recycle_radius = space->get_contact_recycle_radius(); for (int i = 0; i < contact_count; i++) { @@ -80,23 +70,34 @@ void GodotBodyPair3D::contact_added_callback(const Vector3 &p_point_A, int p_ind contact.acc_bias_impulse = c.acc_bias_impulse; contact.acc_bias_impulse_center_of_mass = c.acc_bias_impulse_center_of_mass; contact.acc_tangent_impulse = c.acc_tangent_impulse; - new_index = i; - break; + c = contact; + return; } } - // figure out if the contact amount must be reduced to fit the new contact - + // Figure out if the contact amount must be reduced to fit the new contact. if (new_index == MAX_CONTACTS) { - // remove the contact with the minimum depth + // Remove the contact with the minimum depth. + + const Basis &basis_A = A->get_transform().basis; + const Basis &basis_B = B->get_transform().basis; int least_deep = -1; - real_t min_depth = 1e10; + real_t min_depth; + + // Start with depth for new contact. + { + Vector3 global_A = basis_A.xform(contact.local_A); + Vector3 global_B = basis_B.xform(contact.local_B) + offset_B; + + Vector3 axis = global_A - global_B; + min_depth = axis.dot(contact.normal); + } - for (int i = 0; i <= contact_count; i++) { - Contact &c = (i == contact_count) ? contact : contacts[i]; - Vector3 global_A = A->get_transform().basis.xform(c.local_A); - Vector3 global_B = B->get_transform().basis.xform(c.local_B) + offset_B; + for (int i = 0; i < contact_count; i++) { + const Contact &c = contacts[i]; + Vector3 global_A = basis_A.xform(c.local_A); + Vector3 global_B = basis_B.xform(c.local_B) + offset_B; Vector3 axis = global_A - global_B; real_t depth = axis.dot(c.normal); @@ -107,10 +108,8 @@ void GodotBodyPair3D::contact_added_callback(const Vector3 &p_point_A, int p_ind } } - ERR_FAIL_COND(least_deep == -1); - - if (least_deep < contact_count) { //replace the last deep contact by the new one - + if (least_deep > -1) { + // Replace the least deep contact by the new one. contacts[least_deep] = contact; } @@ -118,29 +117,41 @@ void GodotBodyPair3D::contact_added_callback(const Vector3 &p_point_A, int p_ind } contacts[new_index] = contact; - - if (new_index == contact_count) { - contact_count++; - } + contact_count++; } void GodotBodyPair3D::validate_contacts() { - //make sure to erase contacts that are no longer valid + // Make sure to erase contacts that are no longer valid. + real_t max_separation = space->get_contact_max_separation(); + real_t max_separation2 = max_separation * max_separation; + + const Basis &basis_A = A->get_transform().basis; + const Basis &basis_B = B->get_transform().basis; - real_t contact_max_separation = space->get_contact_max_separation(); for (int i = 0; i < contact_count; i++) { Contact &c = contacts[i]; - Vector3 global_A = A->get_transform().basis.xform(c.local_A); - Vector3 global_B = B->get_transform().basis.xform(c.local_B) + offset_B; - Vector3 axis = global_A - global_B; - real_t depth = axis.dot(c.normal); + bool erase = false; + if (!c.used) { + // Was left behind in previous frame. + erase = true; + } else { + c.used = false; + + Vector3 global_A = basis_A.xform(c.local_A); + Vector3 global_B = basis_B.xform(c.local_B) + offset_B; + Vector3 axis = global_A - global_B; + real_t depth = axis.dot(c.normal); - if (depth < -contact_max_separation || (global_B + c.normal * depth - global_A).length() > contact_max_separation) { - // contact no longer needed, remove + if (depth < -max_separation || (global_B + c.normal * depth - global_A).length_squared() > max_separation2) { + erase = true; + } + } + if (erase) { + // Contact no longer needed, remove. if ((i + 1) < contact_count) { - // swap with the last one + // Swap with the last one. SWAP(contacts[i], contacts[contact_count - 1]); } @@ -260,7 +271,7 @@ bool GodotBodyPair3D::pre_solve(real_t p_step) { real_t max_penetration = space->get_contact_max_allowed_penetration(); - real_t bias = (real_t)0.3; + real_t bias = 0.8; GodotShape3D *shape_A_ptr = A->get_shape(shape_A); GodotShape3D *shape_B_ptr = B->get_shape(shape_B); @@ -353,8 +364,6 @@ bool GodotBodyPair3D::pre_solve(real_t p_step) { if (collide_B) { B->apply_impulse(j_vec, c.rB + B->get_center_of_mass()); } - c.acc_bias_impulse = 0; - c.acc_bias_impulse_center_of_mass = 0; c.bounce = combine_bounce(A, B); if (c.bounce) { @@ -538,14 +547,10 @@ void GodotBodySoftBodyPair3D::contact_added_callback(const Vector3 &p_point_A, i Contact contact; contact.index_A = p_index_A; contact.index_B = p_index_B; - contact.acc_normal_impulse = 0; - contact.acc_bias_impulse = 0; - contact.acc_bias_impulse_center_of_mass = 0; - contact.acc_tangent_impulse = Vector3(); contact.local_A = local_A; contact.local_B = local_B; contact.normal = (p_point_A - p_point_B).normalized(); - contact.mass_normal = 0; + contact.used = true; // Attempt to determine if the contact will be reused. real_t contact_recycle_radius = space->get_contact_recycle_radius(); @@ -571,20 +576,33 @@ void GodotBodySoftBodyPair3D::contact_added_callback(const Vector3 &p_point_A, i void GodotBodySoftBodyPair3D::validate_contacts() { // Make sure to erase contacts that are no longer valid. - const Transform3D &transform_A = body->get_transform(); + real_t max_separation = space->get_contact_max_separation(); + real_t max_separation2 = max_separation * max_separation; - real_t contact_max_separation = space->get_contact_max_separation(); + const Transform3D &transform_A = body->get_transform(); uint32_t contact_count = contacts.size(); for (uint32_t contact_index = 0; contact_index < contact_count; ++contact_index) { Contact &c = contacts[contact_index]; - Vector3 global_A = transform_A.xform(c.local_A); - Vector3 global_B = soft_body->get_node_position(c.index_B) + c.local_B; - Vector3 axis = global_A - global_B; - real_t depth = axis.dot(c.normal); + bool erase = false; + if (!c.used) { + // Was left behind in previous frame. + erase = true; + } else { + c.used = false; + + Vector3 global_A = transform_A.xform(c.local_A); + Vector3 global_B = soft_body->get_node_position(c.index_B) + c.local_B; + Vector3 axis = global_A - global_B; + real_t depth = axis.dot(c.normal); + + if (depth < -max_separation || (global_B + c.normal * depth - global_A).length_squared() > max_separation2) { + erase = true; + } + } - if (depth < -contact_max_separation || (global_B + c.normal * depth - global_A).length() > contact_max_separation) { + if (erase) { // Contact no longer needed, remove. if ((contact_index + 1) < contact_count) { // Swap with the last one. @@ -640,7 +658,7 @@ bool GodotBodySoftBodyPair3D::pre_solve(real_t p_step) { real_t max_penetration = space->get_contact_max_allowed_penetration(); - real_t bias = (real_t)0.3; + real_t bias = space->get_contact_bias(); GodotShape3D *shape_A_ptr = body->get_shape(body_shape); @@ -723,8 +741,6 @@ bool GodotBodySoftBodyPair3D::pre_solve(real_t p_step) { if (soft_body_collides) { soft_body->apply_node_impulse(c.index_B, j_vec); } - c.acc_bias_impulse = 0; - c.acc_bias_impulse_center_of_mass = 0; c.bounce = body->get_bounce(); diff --git a/servers/physics_3d/godot_body_pair_3d.h b/servers/physics_3d/godot_body_pair_3d.h index c0a2424e05..7c2c31704b 100644 --- a/servers/physics_3d/godot_body_pair_3d.h +++ b/servers/physics_3d/godot_body_pair_3d.h @@ -54,6 +54,7 @@ protected: real_t depth = 0.0; bool active = false; + bool used = false; Vector3 rA, rB; // Offset in world orientation with respect to center of mass }; diff --git a/servers/physics_3d/godot_physics_server_3d.cpp b/servers/physics_3d/godot_physics_server_3d.cpp index 9acae62382..573a5d373f 100644 --- a/servers/physics_3d/godot_physics_server_3d.cpp +++ b/servers/physics_3d/godot_physics_server_3d.cpp @@ -1574,20 +1574,15 @@ void GodotPhysicsServer3D::free(RID p_rid) { } else { ERR_FAIL_MSG("Invalid ID."); } -}; +} void GodotPhysicsServer3D::set_active(bool p_active) { active = p_active; -}; - -void GodotPhysicsServer3D::set_collision_iterations(int p_iterations) { - iterations = p_iterations; -}; +} void GodotPhysicsServer3D::init() { - iterations = 8; // 8? stepper = memnew(GodotStep3D); -}; +} void GodotPhysicsServer3D::step(real_t p_step) { #ifndef _3D_DISABLED @@ -1602,7 +1597,7 @@ void GodotPhysicsServer3D::step(real_t p_step) { active_objects = 0; collision_pairs = 0; for (Set<const GodotSpace3D *>::Element *E = active_spaces.front(); E; E = E->next()) { - stepper->step((GodotSpace3D *)E->get(), p_step, iterations); + stepper->step((GodotSpace3D *)E->get(), p_step); island_count += E->get()->get_island_count(); active_objects += E->get()->get_active_objects(); collision_pairs += E->get()->get_collision_pairs(); @@ -1612,7 +1607,7 @@ void GodotPhysicsServer3D::step(real_t p_step) { void GodotPhysicsServer3D::sync() { doing_sync = true; -}; +} void GodotPhysicsServer3D::flush_queries() { #ifndef _3D_DISABLED @@ -1665,15 +1660,15 @@ void GodotPhysicsServer3D::flush_queries() { EngineDebugger::profiler_add_frame_data("servers", values); } #endif -}; +} void GodotPhysicsServer3D::end_sync() { doing_sync = false; -}; +} void GodotPhysicsServer3D::finish() { memdelete(stepper); -}; +} int GodotPhysicsServer3D::get_process_info(ProcessInfo p_info) { switch (p_info) { diff --git a/servers/physics_3d/godot_physics_server_3d.h b/servers/physics_3d/godot_physics_server_3d.h index f5c8e0f60d..be9bbea76b 100644 --- a/servers/physics_3d/godot_physics_server_3d.h +++ b/servers/physics_3d/godot_physics_server_3d.h @@ -44,7 +44,6 @@ class GodotPhysicsServer3D : public PhysicsServer3D { friend class GodotPhysicsDirectSpaceState3D; bool active = true; - int iterations = 0; int island_count = 0; int active_objects = 0; @@ -364,8 +363,6 @@ public: virtual void end_sync() override; virtual void finish() override; - virtual void set_collision_iterations(int p_iterations) override; - virtual bool is_flushing_queries() const override { return flushing_queries; } int get_process_info(ProcessInfo p_info) override; diff --git a/servers/physics_3d/godot_space_3d.cpp b/servers/physics_3d/godot_space_3d.cpp index f503273c88..b2a8b00bca 100644 --- a/servers/physics_3d/godot_space_3d.cpp +++ b/servers/physics_3d/godot_space_3d.cpp @@ -1173,9 +1173,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; @@ -1191,6 +1194,9 @@ void GodotSpace3D::set_param(PhysicsServer3D::SpaceParameter p_param, real_t p_v case PhysicsServer3D::SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS: constraint_bias = p_value; break; + case PhysicsServer3D::SPACE_PARAM_SOLVER_ITERATIONS: + solver_iterations = p_value; + break; } } @@ -1200,8 +1206,10 @@ 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: @@ -1212,6 +1220,8 @@ real_t GodotSpace3D::get_param(PhysicsServer3D::SpaceParameter p_param) const { 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; } diff --git a/servers/physics_3d/godot_space_3d.h b/servers/physics_3d/godot_space_3d.h index aa5e965751..b9aeee7583 100644 --- a/servers/physics_3d/godot_space_3d.h +++ b/servers/physics_3d/godot_space_3d.h @@ -93,9 +93,12 @@ private: GodotArea3D *area = nullptr; + int solver_iterations = 16; + real_t contact_recycle_radius = 0.01; real_t contact_max_separation = 0.05; real_t contact_max_allowed_penetration = 0.01; + real_t contact_bias = 0.8; real_t constraint_bias = 0.01; enum { @@ -159,9 +162,11 @@ public: void remove_object(GodotCollisionObject3D *p_object); const Set<GodotCollisionObject3D *> &get_objects() const; + _FORCE_INLINE_ int get_solver_iterations() const { return solver_iterations; } _FORCE_INLINE_ real_t get_contact_recycle_radius() const { return contact_recycle_radius; } _FORCE_INLINE_ real_t get_contact_max_separation() const { return contact_max_separation; } _FORCE_INLINE_ real_t get_contact_max_allowed_penetration() const { return contact_max_allowed_penetration; } + _FORCE_INLINE_ real_t get_contact_bias() const { return contact_bias; } _FORCE_INLINE_ real_t get_constraint_bias() const { return constraint_bias; } _FORCE_INLINE_ real_t get_body_linear_velocity_sleep_threshold() const { return body_linear_velocity_sleep_threshold; } _FORCE_INLINE_ real_t get_body_angular_velocity_sleep_threshold() const { return body_angular_velocity_sleep_threshold; } diff --git a/servers/physics_3d/godot_step_3d.cpp b/servers/physics_3d/godot_step_3d.cpp index 5453c4415c..6332532f6e 100644 --- a/servers/physics_3d/godot_step_3d.cpp +++ b/servers/physics_3d/godot_step_3d.cpp @@ -181,14 +181,14 @@ void GodotStep3D::_check_suspend(const LocalVector<GodotBody3D *> &p_body_island } } -void GodotStep3D::step(GodotSpace3D *p_space, real_t p_delta, int p_iterations) { +void GodotStep3D::step(GodotSpace3D *p_space, real_t p_delta) { p_space->lock(); // can't access space during this p_space->setup(); //update inertias, etc p_space->set_last_step(p_delta); - iterations = p_iterations; + iterations = p_space->get_solver_iterations(); delta = p_delta; const SelfList<GodotBody3D>::List *body_list = &p_space->get_active_body_list(); diff --git a/servers/physics_3d/godot_step_3d.h b/servers/physics_3d/godot_step_3d.h index 23ede4feff..10389713f6 100644 --- a/servers/physics_3d/godot_step_3d.h +++ b/servers/physics_3d/godot_step_3d.h @@ -56,7 +56,7 @@ class GodotStep3D { void _check_suspend(const LocalVector<GodotBody3D *> &p_body_island) const; public: - void step(GodotSpace3D *p_space, real_t p_delta, int p_iterations); + void step(GodotSpace3D *p_space, real_t p_delta); GodotStep3D(); ~GodotStep3D(); }; |