Path: blob/master/modules/jolt_physics/joints/jolt_cone_twist_joint_3d.cpp
10278 views
/**************************************************************************/1/* jolt_cone_twist_joint_3d.cpp */2/**************************************************************************/3/* This file is part of: */4/* GODOT ENGINE */5/* https://godotengine.org */6/**************************************************************************/7/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */8/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */9/* */10/* Permission is hereby granted, free of charge, to any person obtaining */11/* a copy of this software and associated documentation files (the */12/* "Software"), to deal in the Software without restriction, including */13/* without limitation the rights to use, copy, modify, merge, publish, */14/* distribute, sublicense, and/or sell copies of the Software, and to */15/* permit persons to whom the Software is furnished to do so, subject to */16/* the following conditions: */17/* */18/* The above copyright notice and this permission notice shall be */19/* included in all copies or substantial portions of the Software. */20/* */21/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */22/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */23/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */24/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */25/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */26/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */27/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */28/**************************************************************************/2930#include "jolt_cone_twist_joint_3d.h"3132#include "../misc/jolt_type_conversions.h"33#include "../objects/jolt_body_3d.h"34#include "../spaces/jolt_space_3d.h"3536#include "Jolt/Physics/Constraints/SwingTwistConstraint.h"3738namespace {3940constexpr double CONE_TWIST_DEFAULT_BIAS = 0.3;41constexpr double CONE_TWIST_DEFAULT_SOFTNESS = 0.8;42constexpr double CONE_TWIST_DEFAULT_RELAXATION = 1.0;4344} // namespace4546JPH::Constraint *JoltConeTwistJoint3D::_build_swing_twist(JPH::Body *p_jolt_body_a, JPH::Body *p_jolt_body_b, const Transform3D &p_shifted_ref_a, const Transform3D &p_shifted_ref_b, float p_swing_limit_span, float p_twist_limit_span) const {47JPH::SwingTwistConstraintSettings constraint_settings;4849const bool twist_span_valid = p_twist_limit_span >= 0 && p_twist_limit_span <= JPH::JPH_PI;50const bool swing_span_valid = p_swing_limit_span >= 0 && p_swing_limit_span <= JPH::JPH_PI;5152if (twist_limit_enabled && twist_span_valid) {53constraint_settings.mTwistMinAngle = -p_twist_limit_span;54constraint_settings.mTwistMaxAngle = p_twist_limit_span;55} else {56constraint_settings.mTwistMinAngle = -JPH::JPH_PI;57constraint_settings.mTwistMaxAngle = JPH::JPH_PI;58}5960if (swing_limit_enabled && swing_span_valid) {61constraint_settings.mNormalHalfConeAngle = p_swing_limit_span;62constraint_settings.mPlaneHalfConeAngle = p_swing_limit_span;63} else {64constraint_settings.mNormalHalfConeAngle = JPH::JPH_PI;65constraint_settings.mPlaneHalfConeAngle = JPH::JPH_PI;6667if (!swing_span_valid) {68constraint_settings.mTwistMinAngle = -JPH::JPH_PI;69constraint_settings.mTwistMaxAngle = JPH::JPH_PI;70}71}7273constraint_settings.mSpace = JPH::EConstraintSpace::LocalToBodyCOM;74constraint_settings.mPosition1 = to_jolt_r(p_shifted_ref_a.origin);75constraint_settings.mTwistAxis1 = to_jolt(p_shifted_ref_a.basis.get_column(Vector3::AXIS_X));76constraint_settings.mPlaneAxis1 = to_jolt(p_shifted_ref_a.basis.get_column(Vector3::AXIS_Z));77constraint_settings.mPosition2 = to_jolt_r(p_shifted_ref_b.origin);78constraint_settings.mTwistAxis2 = to_jolt(p_shifted_ref_b.basis.get_column(Vector3::AXIS_X));79constraint_settings.mPlaneAxis2 = to_jolt(p_shifted_ref_b.basis.get_column(Vector3::AXIS_Z));80constraint_settings.mSwingType = JPH::ESwingType::Pyramid;8182if (p_jolt_body_a == nullptr) {83return constraint_settings.Create(JPH::Body::sFixedToWorld, *p_jolt_body_b);84} else if (p_jolt_body_b == nullptr) {85return constraint_settings.Create(*p_jolt_body_a, JPH::Body::sFixedToWorld);86} else {87return constraint_settings.Create(*p_jolt_body_a, *p_jolt_body_b);88}89}9091void JoltConeTwistJoint3D::_update_swing_motor_state() {92if (JPH::SwingTwistConstraint *constraint = static_cast<JPH::SwingTwistConstraint *>(jolt_ref.GetPtr())) {93constraint->SetSwingMotorState(swing_motor_enabled ? JPH::EMotorState::Velocity : JPH::EMotorState::Off);94}95}9697void JoltConeTwistJoint3D::_update_twist_motor_state() {98if (JPH::SwingTwistConstraint *constraint = static_cast<JPH::SwingTwistConstraint *>(jolt_ref.GetPtr())) {99constraint->SetTwistMotorState(twist_motor_enabled ? JPH::EMotorState::Velocity : JPH::EMotorState::Off);100}101}102103void JoltConeTwistJoint3D::_update_motor_velocity() {104if (JPH::SwingTwistConstraint *constraint = static_cast<JPH::SwingTwistConstraint *>(jolt_ref.GetPtr())) {105// We flip the direction since Jolt is CCW but Godot is CW.106constraint->SetTargetAngularVelocityCS({ (float)-twist_motor_target_speed, (float)-swing_motor_target_speed_y, (float)-swing_motor_target_speed_z });107}108}109110void JoltConeTwistJoint3D::_update_swing_motor_limit() {111if (JPH::SwingTwistConstraint *constraint = static_cast<JPH::SwingTwistConstraint *>(jolt_ref.GetPtr())) {112JPH::MotorSettings &motor_settings = constraint->GetSwingMotorSettings();113motor_settings.mMinTorqueLimit = (float)-swing_motor_max_torque;114motor_settings.mMaxTorqueLimit = (float)swing_motor_max_torque;115}116}117118void JoltConeTwistJoint3D::_update_twist_motor_limit() {119if (JPH::SwingTwistConstraint *constraint = static_cast<JPH::SwingTwistConstraint *>(jolt_ref.GetPtr())) {120JPH::MotorSettings &motor_settings = constraint->GetTwistMotorSettings();121motor_settings.mMinTorqueLimit = (float)-twist_motor_max_torque;122motor_settings.mMaxTorqueLimit = (float)twist_motor_max_torque;123}124}125126void JoltConeTwistJoint3D::_limits_changed() {127rebuild();128_wake_up_bodies();129}130131void JoltConeTwistJoint3D::_swing_motor_state_changed() {132_update_swing_motor_state();133_wake_up_bodies();134}135136void JoltConeTwistJoint3D::_twist_motor_state_changed() {137_update_twist_motor_state();138_wake_up_bodies();139}140141void JoltConeTwistJoint3D::_motor_velocity_changed() {142_update_motor_velocity();143_wake_up_bodies();144}145146void JoltConeTwistJoint3D::_swing_motor_limit_changed() {147_update_swing_motor_limit();148_wake_up_bodies();149}150151void JoltConeTwistJoint3D::_twist_motor_limit_changed() {152_update_twist_motor_limit();153_wake_up_bodies();154}155156JoltConeTwistJoint3D::JoltConeTwistJoint3D(const JoltJoint3D &p_old_joint, JoltBody3D *p_body_a, JoltBody3D *p_body_b, const Transform3D &p_local_ref_a, const Transform3D &p_local_ref_b) :157JoltJoint3D(p_old_joint, p_body_a, p_body_b, p_local_ref_a, p_local_ref_b) {158rebuild();159}160161double JoltConeTwistJoint3D::get_param(PhysicsServer3D::ConeTwistJointParam p_param) const {162switch (p_param) {163case PhysicsServer3D::CONE_TWIST_JOINT_SWING_SPAN: {164return swing_limit_span;165}166case PhysicsServer3D::CONE_TWIST_JOINT_TWIST_SPAN: {167return twist_limit_span;168}169case PhysicsServer3D::CONE_TWIST_JOINT_BIAS: {170return CONE_TWIST_DEFAULT_BIAS;171}172case PhysicsServer3D::CONE_TWIST_JOINT_SOFTNESS: {173return CONE_TWIST_DEFAULT_SOFTNESS;174}175case PhysicsServer3D::CONE_TWIST_JOINT_RELAXATION: {176return CONE_TWIST_DEFAULT_RELAXATION;177}178default: {179ERR_FAIL_V_MSG(0.0, vformat("Unhandled cone twist joint parameter: '%d'. This should not happen. Please report this.", p_param));180}181}182}183184void JoltConeTwistJoint3D::set_param(PhysicsServer3D::ConeTwistJointParam p_param, double p_value) {185switch (p_param) {186case PhysicsServer3D::CONE_TWIST_JOINT_SWING_SPAN: {187swing_limit_span = p_value;188_limits_changed();189} break;190case PhysicsServer3D::CONE_TWIST_JOINT_TWIST_SPAN: {191twist_limit_span = p_value;192_limits_changed();193} break;194case PhysicsServer3D::CONE_TWIST_JOINT_BIAS: {195if (!Math::is_equal_approx(p_value, CONE_TWIST_DEFAULT_BIAS)) {196WARN_PRINT(vformat("Cone twist joint bias is not supported when using Jolt Physics. Any such value will be ignored. This joint connects %s.", _bodies_to_string()));197}198} break;199case PhysicsServer3D::CONE_TWIST_JOINT_SOFTNESS: {200if (!Math::is_equal_approx(p_value, CONE_TWIST_DEFAULT_SOFTNESS)) {201WARN_PRINT(vformat("Cone twist joint softness is not supported when using Jolt Physics. Any such value will be ignored. This joint connects %s.", _bodies_to_string()));202}203} break;204case PhysicsServer3D::CONE_TWIST_JOINT_RELAXATION: {205if (!Math::is_equal_approx(p_value, CONE_TWIST_DEFAULT_RELAXATION)) {206WARN_PRINT(vformat("Cone twist joint relaxation is not supported when using Jolt Physics. Any such value will be ignored. This joint connects %s.", _bodies_to_string()));207}208} break;209default: {210ERR_FAIL_MSG(vformat("Unhandled cone twist joint parameter: '%d'. This should not happen. Please report this.", p_param));211} break;212}213}214215double JoltConeTwistJoint3D::get_jolt_param(JoltParameter p_param) const {216switch (p_param) {217case JoltPhysicsServer3D::CONE_TWIST_JOINT_SWING_MOTOR_TARGET_VELOCITY_Y: {218return swing_motor_target_speed_y;219}220case JoltPhysicsServer3D::CONE_TWIST_JOINT_SWING_MOTOR_TARGET_VELOCITY_Z: {221return swing_motor_target_speed_z;222}223case JoltPhysicsServer3D::CONE_TWIST_JOINT_TWIST_MOTOR_TARGET_VELOCITY: {224return twist_motor_target_speed;225}226case JoltPhysicsServer3D::CONE_TWIST_JOINT_SWING_MOTOR_MAX_TORQUE: {227return swing_motor_max_torque;228}229case JoltPhysicsServer3D::CONE_TWIST_JOINT_TWIST_MOTOR_MAX_TORQUE: {230return twist_motor_max_torque;231}232default: {233ERR_FAIL_V_MSG(0.0, vformat("Unhandled parameter: '%d'. This should not happen. Please report this.", p_param));234}235}236}237238void JoltConeTwistJoint3D::set_jolt_param(JoltParameter p_param, double p_value) {239switch (p_param) {240case JoltPhysicsServer3D::CONE_TWIST_JOINT_SWING_MOTOR_TARGET_VELOCITY_Y: {241swing_motor_target_speed_y = p_value;242_motor_velocity_changed();243} break;244case JoltPhysicsServer3D::CONE_TWIST_JOINT_SWING_MOTOR_TARGET_VELOCITY_Z: {245swing_motor_target_speed_z = p_value;246_motor_velocity_changed();247} break;248case JoltPhysicsServer3D::CONE_TWIST_JOINT_TWIST_MOTOR_TARGET_VELOCITY: {249twist_motor_target_speed = p_value;250_motor_velocity_changed();251} break;252case JoltPhysicsServer3D::CONE_TWIST_JOINT_SWING_MOTOR_MAX_TORQUE: {253swing_motor_max_torque = p_value;254_swing_motor_limit_changed();255} break;256case JoltPhysicsServer3D::CONE_TWIST_JOINT_TWIST_MOTOR_MAX_TORQUE: {257twist_motor_max_torque = p_value;258_twist_motor_limit_changed();259} break;260default: {261ERR_FAIL_MSG(vformat("Unhandled parameter: '%d'. This should not happen. Please report this.", p_param));262} break;263}264}265266bool JoltConeTwistJoint3D::get_jolt_flag(JoltFlag p_flag) const {267switch (p_flag) {268case JoltPhysicsServer3D::CONE_TWIST_JOINT_FLAG_USE_SWING_LIMIT: {269return swing_limit_enabled;270}271case JoltPhysicsServer3D::CONE_TWIST_JOINT_FLAG_USE_TWIST_LIMIT: {272return twist_limit_enabled;273}274case JoltPhysicsServer3D::CONE_TWIST_JOINT_FLAG_ENABLE_SWING_MOTOR: {275return swing_motor_enabled;276}277case JoltPhysicsServer3D::CONE_TWIST_JOINT_FLAG_ENABLE_TWIST_MOTOR: {278return twist_motor_enabled;279}280default: {281ERR_FAIL_V_MSG(false, vformat("Unhandled flag: '%d'. This should not happen. Please report this.", p_flag));282}283}284}285286void JoltConeTwistJoint3D::set_jolt_flag(JoltFlag p_flag, bool p_enabled) {287switch (p_flag) {288case JoltPhysicsServer3D::CONE_TWIST_JOINT_FLAG_USE_SWING_LIMIT: {289swing_limit_enabled = p_enabled;290_limits_changed();291} break;292case JoltPhysicsServer3D::CONE_TWIST_JOINT_FLAG_USE_TWIST_LIMIT: {293twist_limit_enabled = p_enabled;294_limits_changed();295} break;296case JoltPhysicsServer3D::CONE_TWIST_JOINT_FLAG_ENABLE_SWING_MOTOR: {297swing_motor_enabled = p_enabled;298_swing_motor_state_changed();299} break;300case JoltPhysicsServer3D::CONE_TWIST_JOINT_FLAG_ENABLE_TWIST_MOTOR: {301twist_motor_enabled = p_enabled;302_twist_motor_state_changed();303} break;304default: {305ERR_FAIL_MSG(vformat("Unhandled flag: '%d'. This should not happen. Please report this.", p_flag));306} break;307}308}309310float JoltConeTwistJoint3D::get_applied_force() const {311JPH::SwingTwistConstraint *constraint = static_cast<JPH::SwingTwistConstraint *>(jolt_ref.GetPtr());312ERR_FAIL_NULL_V(constraint, 0.0f);313314JoltSpace3D *space = get_space();315ERR_FAIL_NULL_V(space, 0.0f);316317const float last_step = space->get_last_step();318if (unlikely(last_step == 0.0f)) {319return 0.0f;320}321322return constraint->GetTotalLambdaPosition().Length() / last_step;323}324325float JoltConeTwistJoint3D::get_applied_torque() const {326JPH::SwingTwistConstraint *constraint = static_cast<JPH::SwingTwistConstraint *>(jolt_ref.GetPtr());327ERR_FAIL_NULL_V(constraint, 0.0f);328329JoltSpace3D *space = get_space();330ERR_FAIL_NULL_V(space, 0.0f);331332const float last_step = space->get_last_step();333if (unlikely(last_step == 0.0f)) {334return 0.0f;335}336337const JPH::Vec3 swing_twist_lambda = JPH::Vec3(constraint->GetTotalLambdaTwist(), constraint->GetTotalLambdaSwingY(), constraint->GetTotalLambdaSwingZ());338339// Note that the motor lambda is in a different space than the swing twist lambda, and since the two forces can cancel each other it is340// technically incorrect to just add them. The bodies themselves have moved, so we can't transform one into the space of the other anymore.341const float total_lambda = swing_twist_lambda.Length() + constraint->GetTotalLambdaMotor().Length();342343return total_lambda / last_step;344}345346void JoltConeTwistJoint3D::rebuild() {347destroy();348349JoltSpace3D *space = get_space();350if (space == nullptr) {351return;352}353354JPH::Body *jolt_body_a = body_a != nullptr ? body_a->get_jolt_body() : nullptr;355JPH::Body *jolt_body_b = body_b != nullptr ? body_b->get_jolt_body() : nullptr;356ERR_FAIL_COND(jolt_body_a == nullptr && jolt_body_b == nullptr);357358Transform3D shifted_ref_a;359Transform3D shifted_ref_b;360361_shift_reference_frames(Vector3(), Vector3(), shifted_ref_a, shifted_ref_b);362363jolt_ref = _build_swing_twist(jolt_body_a, jolt_body_b, shifted_ref_a, shifted_ref_b, (float)swing_limit_span, (float)twist_limit_span);364365space->add_joint(this);366367_update_enabled();368_update_iterations();369_update_swing_motor_state();370_update_twist_motor_state();371_update_motor_velocity();372_update_swing_motor_limit();373_update_twist_motor_limit();374}375376377