initial commit, 4.5 stable
Some checks failed
🔗 GHA / 📊 Static checks (push) Has been cancelled
🔗 GHA / 🤖 Android (push) Has been cancelled
🔗 GHA / 🍏 iOS (push) Has been cancelled
🔗 GHA / 🐧 Linux (push) Has been cancelled
🔗 GHA / 🍎 macOS (push) Has been cancelled
🔗 GHA / 🏁 Windows (push) Has been cancelled
🔗 GHA / 🌐 Web (push) Has been cancelled

This commit is contained in:
2025-09-16 20:46:46 -04:00
commit 9d30169a8d
13378 changed files with 7050105 additions and 0 deletions

View File

@@ -0,0 +1,375 @@
/**************************************************************************/
/* jolt_cone_twist_joint_3d.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include "jolt_cone_twist_joint_3d.h"
#include "../misc/jolt_type_conversions.h"
#include "../objects/jolt_body_3d.h"
#include "../spaces/jolt_space_3d.h"
#include "Jolt/Physics/Constraints/SwingTwistConstraint.h"
namespace {
constexpr double CONE_TWIST_DEFAULT_BIAS = 0.3;
constexpr double CONE_TWIST_DEFAULT_SOFTNESS = 0.8;
constexpr double CONE_TWIST_DEFAULT_RELAXATION = 1.0;
} // namespace
JPH::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 {
JPH::SwingTwistConstraintSettings constraint_settings;
const bool twist_span_valid = p_twist_limit_span >= 0 && p_twist_limit_span <= JPH::JPH_PI;
const bool swing_span_valid = p_swing_limit_span >= 0 && p_swing_limit_span <= JPH::JPH_PI;
if (twist_limit_enabled && twist_span_valid) {
constraint_settings.mTwistMinAngle = -p_twist_limit_span;
constraint_settings.mTwistMaxAngle = p_twist_limit_span;
} else {
constraint_settings.mTwistMinAngle = -JPH::JPH_PI;
constraint_settings.mTwistMaxAngle = JPH::JPH_PI;
}
if (swing_limit_enabled && swing_span_valid) {
constraint_settings.mNormalHalfConeAngle = p_swing_limit_span;
constraint_settings.mPlaneHalfConeAngle = p_swing_limit_span;
} else {
constraint_settings.mNormalHalfConeAngle = JPH::JPH_PI;
constraint_settings.mPlaneHalfConeAngle = JPH::JPH_PI;
if (!swing_span_valid) {
constraint_settings.mTwistMinAngle = -JPH::JPH_PI;
constraint_settings.mTwistMaxAngle = JPH::JPH_PI;
}
}
constraint_settings.mSpace = JPH::EConstraintSpace::LocalToBodyCOM;
constraint_settings.mPosition1 = to_jolt_r(p_shifted_ref_a.origin);
constraint_settings.mTwistAxis1 = to_jolt(p_shifted_ref_a.basis.get_column(Vector3::AXIS_X));
constraint_settings.mPlaneAxis1 = to_jolt(p_shifted_ref_a.basis.get_column(Vector3::AXIS_Z));
constraint_settings.mPosition2 = to_jolt_r(p_shifted_ref_b.origin);
constraint_settings.mTwistAxis2 = to_jolt(p_shifted_ref_b.basis.get_column(Vector3::AXIS_X));
constraint_settings.mPlaneAxis2 = to_jolt(p_shifted_ref_b.basis.get_column(Vector3::AXIS_Z));
constraint_settings.mSwingType = JPH::ESwingType::Pyramid;
if (p_jolt_body_a == nullptr) {
return constraint_settings.Create(JPH::Body::sFixedToWorld, *p_jolt_body_b);
} else if (p_jolt_body_b == nullptr) {
return constraint_settings.Create(*p_jolt_body_a, JPH::Body::sFixedToWorld);
} else {
return constraint_settings.Create(*p_jolt_body_a, *p_jolt_body_b);
}
}
void JoltConeTwistJoint3D::_update_swing_motor_state() {
if (JPH::SwingTwistConstraint *constraint = static_cast<JPH::SwingTwistConstraint *>(jolt_ref.GetPtr())) {
constraint->SetSwingMotorState(swing_motor_enabled ? JPH::EMotorState::Velocity : JPH::EMotorState::Off);
}
}
void JoltConeTwistJoint3D::_update_twist_motor_state() {
if (JPH::SwingTwistConstraint *constraint = static_cast<JPH::SwingTwistConstraint *>(jolt_ref.GetPtr())) {
constraint->SetTwistMotorState(twist_motor_enabled ? JPH::EMotorState::Velocity : JPH::EMotorState::Off);
}
}
void JoltConeTwistJoint3D::_update_motor_velocity() {
if (JPH::SwingTwistConstraint *constraint = static_cast<JPH::SwingTwistConstraint *>(jolt_ref.GetPtr())) {
// We flip the direction since Jolt is CCW but Godot is CW.
constraint->SetTargetAngularVelocityCS({ (float)-twist_motor_target_speed, (float)-swing_motor_target_speed_y, (float)-swing_motor_target_speed_z });
}
}
void JoltConeTwistJoint3D::_update_swing_motor_limit() {
if (JPH::SwingTwistConstraint *constraint = static_cast<JPH::SwingTwistConstraint *>(jolt_ref.GetPtr())) {
JPH::MotorSettings &motor_settings = constraint->GetSwingMotorSettings();
motor_settings.mMinTorqueLimit = (float)-swing_motor_max_torque;
motor_settings.mMaxTorqueLimit = (float)swing_motor_max_torque;
}
}
void JoltConeTwistJoint3D::_update_twist_motor_limit() {
if (JPH::SwingTwistConstraint *constraint = static_cast<JPH::SwingTwistConstraint *>(jolt_ref.GetPtr())) {
JPH::MotorSettings &motor_settings = constraint->GetTwistMotorSettings();
motor_settings.mMinTorqueLimit = (float)-twist_motor_max_torque;
motor_settings.mMaxTorqueLimit = (float)twist_motor_max_torque;
}
}
void JoltConeTwistJoint3D::_limits_changed() {
rebuild();
_wake_up_bodies();
}
void JoltConeTwistJoint3D::_swing_motor_state_changed() {
_update_swing_motor_state();
_wake_up_bodies();
}
void JoltConeTwistJoint3D::_twist_motor_state_changed() {
_update_twist_motor_state();
_wake_up_bodies();
}
void JoltConeTwistJoint3D::_motor_velocity_changed() {
_update_motor_velocity();
_wake_up_bodies();
}
void JoltConeTwistJoint3D::_swing_motor_limit_changed() {
_update_swing_motor_limit();
_wake_up_bodies();
}
void JoltConeTwistJoint3D::_twist_motor_limit_changed() {
_update_twist_motor_limit();
_wake_up_bodies();
}
JoltConeTwistJoint3D::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) :
JoltJoint3D(p_old_joint, p_body_a, p_body_b, p_local_ref_a, p_local_ref_b) {
rebuild();
}
double JoltConeTwistJoint3D::get_param(PhysicsServer3D::ConeTwistJointParam p_param) const {
switch (p_param) {
case PhysicsServer3D::CONE_TWIST_JOINT_SWING_SPAN: {
return swing_limit_span;
}
case PhysicsServer3D::CONE_TWIST_JOINT_TWIST_SPAN: {
return twist_limit_span;
}
case PhysicsServer3D::CONE_TWIST_JOINT_BIAS: {
return CONE_TWIST_DEFAULT_BIAS;
}
case PhysicsServer3D::CONE_TWIST_JOINT_SOFTNESS: {
return CONE_TWIST_DEFAULT_SOFTNESS;
}
case PhysicsServer3D::CONE_TWIST_JOINT_RELAXATION: {
return CONE_TWIST_DEFAULT_RELAXATION;
}
default: {
ERR_FAIL_V_MSG(0.0, vformat("Unhandled cone twist joint parameter: '%d'. This should not happen. Please report this.", p_param));
}
}
}
void JoltConeTwistJoint3D::set_param(PhysicsServer3D::ConeTwistJointParam p_param, double p_value) {
switch (p_param) {
case PhysicsServer3D::CONE_TWIST_JOINT_SWING_SPAN: {
swing_limit_span = p_value;
_limits_changed();
} break;
case PhysicsServer3D::CONE_TWIST_JOINT_TWIST_SPAN: {
twist_limit_span = p_value;
_limits_changed();
} break;
case PhysicsServer3D::CONE_TWIST_JOINT_BIAS: {
if (!Math::is_equal_approx(p_value, CONE_TWIST_DEFAULT_BIAS)) {
WARN_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()));
}
} break;
case PhysicsServer3D::CONE_TWIST_JOINT_SOFTNESS: {
if (!Math::is_equal_approx(p_value, CONE_TWIST_DEFAULT_SOFTNESS)) {
WARN_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()));
}
} break;
case PhysicsServer3D::CONE_TWIST_JOINT_RELAXATION: {
if (!Math::is_equal_approx(p_value, CONE_TWIST_DEFAULT_RELAXATION)) {
WARN_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()));
}
} break;
default: {
ERR_FAIL_MSG(vformat("Unhandled cone twist joint parameter: '%d'. This should not happen. Please report this.", p_param));
} break;
}
}
double JoltConeTwistJoint3D::get_jolt_param(JoltParameter p_param) const {
switch (p_param) {
case JoltPhysicsServer3D::CONE_TWIST_JOINT_SWING_MOTOR_TARGET_VELOCITY_Y: {
return swing_motor_target_speed_y;
}
case JoltPhysicsServer3D::CONE_TWIST_JOINT_SWING_MOTOR_TARGET_VELOCITY_Z: {
return swing_motor_target_speed_z;
}
case JoltPhysicsServer3D::CONE_TWIST_JOINT_TWIST_MOTOR_TARGET_VELOCITY: {
return twist_motor_target_speed;
}
case JoltPhysicsServer3D::CONE_TWIST_JOINT_SWING_MOTOR_MAX_TORQUE: {
return swing_motor_max_torque;
}
case JoltPhysicsServer3D::CONE_TWIST_JOINT_TWIST_MOTOR_MAX_TORQUE: {
return twist_motor_max_torque;
}
default: {
ERR_FAIL_V_MSG(0.0, vformat("Unhandled parameter: '%d'. This should not happen. Please report this.", p_param));
}
}
}
void JoltConeTwistJoint3D::set_jolt_param(JoltParameter p_param, double p_value) {
switch (p_param) {
case JoltPhysicsServer3D::CONE_TWIST_JOINT_SWING_MOTOR_TARGET_VELOCITY_Y: {
swing_motor_target_speed_y = p_value;
_motor_velocity_changed();
} break;
case JoltPhysicsServer3D::CONE_TWIST_JOINT_SWING_MOTOR_TARGET_VELOCITY_Z: {
swing_motor_target_speed_z = p_value;
_motor_velocity_changed();
} break;
case JoltPhysicsServer3D::CONE_TWIST_JOINT_TWIST_MOTOR_TARGET_VELOCITY: {
twist_motor_target_speed = p_value;
_motor_velocity_changed();
} break;
case JoltPhysicsServer3D::CONE_TWIST_JOINT_SWING_MOTOR_MAX_TORQUE: {
swing_motor_max_torque = p_value;
_swing_motor_limit_changed();
} break;
case JoltPhysicsServer3D::CONE_TWIST_JOINT_TWIST_MOTOR_MAX_TORQUE: {
twist_motor_max_torque = p_value;
_twist_motor_limit_changed();
} break;
default: {
ERR_FAIL_MSG(vformat("Unhandled parameter: '%d'. This should not happen. Please report this.", p_param));
} break;
}
}
bool JoltConeTwistJoint3D::get_jolt_flag(JoltFlag p_flag) const {
switch (p_flag) {
case JoltPhysicsServer3D::CONE_TWIST_JOINT_FLAG_USE_SWING_LIMIT: {
return swing_limit_enabled;
}
case JoltPhysicsServer3D::CONE_TWIST_JOINT_FLAG_USE_TWIST_LIMIT: {
return twist_limit_enabled;
}
case JoltPhysicsServer3D::CONE_TWIST_JOINT_FLAG_ENABLE_SWING_MOTOR: {
return swing_motor_enabled;
}
case JoltPhysicsServer3D::CONE_TWIST_JOINT_FLAG_ENABLE_TWIST_MOTOR: {
return twist_motor_enabled;
}
default: {
ERR_FAIL_V_MSG(false, vformat("Unhandled flag: '%d'. This should not happen. Please report this.", p_flag));
}
}
}
void JoltConeTwistJoint3D::set_jolt_flag(JoltFlag p_flag, bool p_enabled) {
switch (p_flag) {
case JoltPhysicsServer3D::CONE_TWIST_JOINT_FLAG_USE_SWING_LIMIT: {
swing_limit_enabled = p_enabled;
_limits_changed();
} break;
case JoltPhysicsServer3D::CONE_TWIST_JOINT_FLAG_USE_TWIST_LIMIT: {
twist_limit_enabled = p_enabled;
_limits_changed();
} break;
case JoltPhysicsServer3D::CONE_TWIST_JOINT_FLAG_ENABLE_SWING_MOTOR: {
swing_motor_enabled = p_enabled;
_swing_motor_state_changed();
} break;
case JoltPhysicsServer3D::CONE_TWIST_JOINT_FLAG_ENABLE_TWIST_MOTOR: {
twist_motor_enabled = p_enabled;
_twist_motor_state_changed();
} break;
default: {
ERR_FAIL_MSG(vformat("Unhandled flag: '%d'. This should not happen. Please report this.", p_flag));
} break;
}
}
float JoltConeTwistJoint3D::get_applied_force() const {
JPH::SwingTwistConstraint *constraint = static_cast<JPH::SwingTwistConstraint *>(jolt_ref.GetPtr());
ERR_FAIL_NULL_V(constraint, 0.0f);
JoltSpace3D *space = get_space();
ERR_FAIL_NULL_V(space, 0.0f);
const float last_step = space->get_last_step();
if (unlikely(last_step == 0.0f)) {
return 0.0f;
}
return constraint->GetTotalLambdaPosition().Length() / last_step;
}
float JoltConeTwistJoint3D::get_applied_torque() const {
JPH::SwingTwistConstraint *constraint = static_cast<JPH::SwingTwistConstraint *>(jolt_ref.GetPtr());
ERR_FAIL_NULL_V(constraint, 0.0f);
JoltSpace3D *space = get_space();
ERR_FAIL_NULL_V(space, 0.0f);
const float last_step = space->get_last_step();
if (unlikely(last_step == 0.0f)) {
return 0.0f;
}
const JPH::Vec3 swing_twist_lambda = JPH::Vec3(constraint->GetTotalLambdaTwist(), constraint->GetTotalLambdaSwingY(), constraint->GetTotalLambdaSwingZ());
// 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 is
// technically incorrect to just add them. The bodies themselves have moved, so we can't transform one into the space of the other anymore.
const float total_lambda = swing_twist_lambda.Length() + constraint->GetTotalLambdaMotor().Length();
return total_lambda / last_step;
}
void JoltConeTwistJoint3D::rebuild() {
destroy();
JoltSpace3D *space = get_space();
if (space == nullptr) {
return;
}
JPH::Body *jolt_body_a = body_a != nullptr ? body_a->get_jolt_body() : nullptr;
JPH::Body *jolt_body_b = body_b != nullptr ? body_b->get_jolt_body() : nullptr;
ERR_FAIL_COND(jolt_body_a == nullptr && jolt_body_b == nullptr);
Transform3D shifted_ref_a;
Transform3D shifted_ref_b;
_shift_reference_frames(Vector3(), Vector3(), shifted_ref_a, shifted_ref_b);
jolt_ref = _build_swing_twist(jolt_body_a, jolt_body_b, shifted_ref_a, shifted_ref_b, (float)swing_limit_span, (float)twist_limit_span);
space->add_joint(this);
_update_enabled();
_update_iterations();
_update_swing_motor_state();
_update_twist_motor_state();
_update_motor_velocity();
_update_swing_motor_limit();
_update_twist_motor_limit();
}

View File

@@ -0,0 +1,94 @@
/**************************************************************************/
/* jolt_cone_twist_joint_3d.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#include "../jolt_physics_server_3d.h"
#include "jolt_joint_3d.h"
#include "Jolt/Jolt.h"
#include "Jolt/Physics/Body/Body.h"
class JoltConeTwistJoint3D final : public JoltJoint3D {
typedef PhysicsServer3D::ConeTwistJointParam Parameter;
typedef JoltPhysicsServer3D::ConeTwistJointParamJolt JoltParameter;
typedef JoltPhysicsServer3D::ConeTwistJointFlagJolt JoltFlag;
double swing_limit_span = 0.0;
double twist_limit_span = 0.0;
double swing_motor_target_speed_y = 0.0;
double swing_motor_target_speed_z = 0.0;
double twist_motor_target_speed = 0.0;
double swing_motor_max_torque = FLT_MAX;
double twist_motor_max_torque = FLT_MAX;
bool swing_limit_enabled = true;
bool twist_limit_enabled = true;
bool swing_motor_enabled = false;
bool twist_motor_enabled = false;
JPH::Constraint *_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;
void _update_swing_motor_state();
void _update_twist_motor_state();
void _update_motor_velocity();
void _update_swing_motor_limit();
void _update_twist_motor_limit();
void _limits_changed();
void _swing_motor_state_changed();
void _twist_motor_state_changed();
void _motor_velocity_changed();
void _swing_motor_limit_changed();
void _twist_motor_limit_changed();
public:
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);
virtual PhysicsServer3D::JointType get_type() const override { return PhysicsServer3D::JOINT_TYPE_CONE_TWIST; }
double get_param(PhysicsServer3D::ConeTwistJointParam p_param) const;
void set_param(PhysicsServer3D::ConeTwistJointParam p_param, double p_value);
double get_jolt_param(JoltParameter p_param) const;
void set_jolt_param(JoltParameter p_param, double p_value);
bool get_jolt_flag(JoltFlag p_flag) const;
void set_jolt_flag(JoltFlag p_flag, bool p_enabled);
float get_applied_force() const;
float get_applied_torque() const;
virtual void rebuild() override;
};

View File

@@ -0,0 +1,686 @@
/**************************************************************************/
/* jolt_generic_6dof_joint_3d.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include "jolt_generic_6dof_joint_3d.h"
#include "../misc/jolt_type_conversions.h"
#include "../objects/jolt_body_3d.h"
#include "../spaces/jolt_space_3d.h"
#include "Jolt/Physics/Constraints/SixDOFConstraint.h"
namespace {
constexpr double G6DOF_DEFAULT_LINEAR_LIMIT_SOFTNESS = 0.7;
constexpr double G6DOF_DEFAULT_LINEAR_RESTITUTION = 0.5;
constexpr double G6DOF_DEFAULT_LINEAR_DAMPING = 1.0;
constexpr double G6DOF_DEFAULT_ANGULAR_LIMIT_SOFTNESS = 0.5;
constexpr double G6DOF_DEFAULT_ANGULAR_DAMPING = 1.0;
constexpr double G6DOF_DEFAULT_ANGULAR_RESTITUTION = 0.0;
constexpr double G6DOF_DEFAULT_ANGULAR_FORCE_LIMIT = 0.0;
constexpr double G6DOF_DEFAULT_ANGULAR_ERP = 0.5;
} // namespace
JPH::Constraint *JoltGeneric6DOFJoint3D::_build_6dof(JPH::Body *p_jolt_body_a, JPH::Body *p_jolt_body_b, const Transform3D &p_shifted_ref_a, const Transform3D &p_shifted_ref_b) const {
JPH::SixDOFConstraintSettings constraint_settings;
for (int axis = 0; axis < AXIS_COUNT; ++axis) {
double lower = limit_lower[axis];
double upper = limit_upper[axis];
if (axis >= AXIS_ANGULAR_X && axis <= AXIS_ANGULAR_Z) {
const double temp = lower;
lower = -upper;
upper = -temp;
}
if (!limit_enabled[axis] || lower > upper) {
constraint_settings.MakeFreeAxis((JoltAxis)axis);
} else {
constraint_settings.SetLimitedAxis((JoltAxis)axis, (float)lower, (float)upper);
}
}
constraint_settings.mSpace = JPH::EConstraintSpace::LocalToBodyCOM;
constraint_settings.mPosition1 = to_jolt_r(p_shifted_ref_a.origin);
constraint_settings.mAxisX1 = to_jolt(p_shifted_ref_a.basis.get_column(Vector3::AXIS_X));
constraint_settings.mAxisY1 = to_jolt(p_shifted_ref_a.basis.get_column(Vector3::AXIS_Y));
constraint_settings.mPosition2 = to_jolt_r(p_shifted_ref_b.origin);
constraint_settings.mAxisX2 = to_jolt(p_shifted_ref_b.basis.get_column(Vector3::AXIS_X));
constraint_settings.mAxisY2 = to_jolt(p_shifted_ref_b.basis.get_column(Vector3::AXIS_Y));
constraint_settings.mSwingType = JPH::ESwingType::Pyramid;
if (p_jolt_body_a == nullptr) {
return constraint_settings.Create(JPH::Body::sFixedToWorld, *p_jolt_body_b);
} else if (p_jolt_body_b == nullptr) {
return constraint_settings.Create(*p_jolt_body_a, JPH::Body::sFixedToWorld);
} else {
return constraint_settings.Create(*p_jolt_body_a, *p_jolt_body_b);
}
}
void JoltGeneric6DOFJoint3D::_update_limit_spring_parameters(int p_axis) {
JPH::SixDOFConstraint *constraint = static_cast<JPH::SixDOFConstraint *>(jolt_ref.GetPtr());
if (unlikely(constraint == nullptr)) {
return;
}
JPH::SpringSettings settings = constraint->GetLimitsSpringSettings((JoltAxis)p_axis);
settings.mMode = JPH::ESpringMode::FrequencyAndDamping;
if (limit_spring_enabled[p_axis]) {
settings.mFrequency = (float)limit_spring_frequency[p_axis];
settings.mDamping = (float)limit_spring_damping[p_axis];
} else {
settings.mFrequency = 0.0f;
settings.mDamping = 0.0f;
}
constraint->SetLimitsSpringSettings((JoltAxis)p_axis, settings);
}
void JoltGeneric6DOFJoint3D::_update_motor_state(int p_axis) {
if (JPH::SixDOFConstraint *constraint = static_cast<JPH::SixDOFConstraint *>(jolt_ref.GetPtr())) {
if (motor_enabled[p_axis]) {
constraint->SetMotorState((JoltAxis)p_axis, JPH::EMotorState::Velocity);
} else if (spring_enabled[p_axis]) {
constraint->SetMotorState((JoltAxis)p_axis, JPH::EMotorState::Position);
} else {
constraint->SetMotorState((JoltAxis)p_axis, JPH::EMotorState::Off);
}
}
}
void JoltGeneric6DOFJoint3D::_update_motor_velocity(int p_axis) {
JPH::SixDOFConstraint *constraint = static_cast<JPH::SixDOFConstraint *>(jolt_ref.GetPtr());
if (unlikely(constraint == nullptr)) {
return;
}
if (p_axis >= AXIS_LINEAR_X && p_axis <= AXIS_LINEAR_Z) {
constraint->SetTargetVelocityCS(JPH::Vec3(
(float)motor_speed[AXIS_LINEAR_X],
(float)motor_speed[AXIS_LINEAR_Y],
(float)motor_speed[AXIS_LINEAR_Z]));
} else {
// We flip the direction since Jolt is CCW but Godot is CW.
constraint->SetTargetAngularVelocityCS(JPH::Vec3(
(float)-motor_speed[AXIS_ANGULAR_X],
(float)-motor_speed[AXIS_ANGULAR_Y],
(float)-motor_speed[AXIS_ANGULAR_Z]));
}
}
void JoltGeneric6DOFJoint3D::_update_motor_limit(int p_axis) {
JPH::SixDOFConstraint *constraint = static_cast<JPH::SixDOFConstraint *>(jolt_ref.GetPtr());
if (unlikely(constraint == nullptr)) {
return;
}
JPH::MotorSettings &motor_settings = constraint->GetMotorSettings((JoltAxis)p_axis);
float limit = FLT_MAX;
if (motor_enabled[p_axis]) {
limit = (float)motor_limit[p_axis];
} else if (spring_enabled[p_axis]) {
limit = (float)spring_limit[p_axis];
}
if (p_axis >= AXIS_LINEAR_X && p_axis <= AXIS_LINEAR_Z) {
motor_settings.SetForceLimit(limit);
} else {
motor_settings.SetTorqueLimit(limit);
}
}
void JoltGeneric6DOFJoint3D::_update_spring_parameters(int p_axis) {
JPH::SixDOFConstraint *constraint = static_cast<JPH::SixDOFConstraint *>(jolt_ref.GetPtr());
if (unlikely(constraint == nullptr)) {
return;
}
JPH::MotorSettings &motor_settings = constraint->GetMotorSettings((JoltAxis)p_axis);
if (spring_use_frequency[p_axis]) {
motor_settings.mSpringSettings.mMode = JPH::ESpringMode::FrequencyAndDamping;
motor_settings.mSpringSettings.mFrequency = (float)spring_frequency[p_axis];
} else {
motor_settings.mSpringSettings.mMode = JPH::ESpringMode::StiffnessAndDamping;
motor_settings.mSpringSettings.mStiffness = (float)spring_stiffness[p_axis];
}
motor_settings.mSpringSettings.mDamping = (float)spring_damping[p_axis];
}
void JoltGeneric6DOFJoint3D::_update_spring_equilibrium(int p_axis) {
JPH::SixDOFConstraint *constraint = static_cast<JPH::SixDOFConstraint *>(jolt_ref.GetPtr());
if (unlikely(constraint == nullptr)) {
return;
}
if (p_axis >= AXIS_LINEAR_X && p_axis <= AXIS_LINEAR_Z) {
const Vector3 target_position = Vector3(
(float)spring_equilibrium[AXIS_LINEAR_X],
(float)spring_equilibrium[AXIS_LINEAR_Y],
(float)spring_equilibrium[AXIS_LINEAR_Z]);
constraint->SetTargetPositionCS(to_jolt(target_position));
} else {
// We flip the direction since Jolt is CCW but Godot is CW.
const Basis target_orientation = Basis::from_euler(
Vector3((float)-spring_equilibrium[AXIS_ANGULAR_X],
(float)-spring_equilibrium[AXIS_ANGULAR_Y],
(float)-spring_equilibrium[AXIS_ANGULAR_Z]),
EulerOrder::ZYX);
constraint->SetTargetOrientationCS(to_jolt(target_orientation));
}
}
void JoltGeneric6DOFJoint3D::_limits_changed() {
rebuild();
_wake_up_bodies();
}
void JoltGeneric6DOFJoint3D::_limit_spring_parameters_changed(int p_axis) {
_update_limit_spring_parameters(p_axis);
_wake_up_bodies();
}
void JoltGeneric6DOFJoint3D::_motor_state_changed(int p_axis) {
_update_motor_state(p_axis);
_update_motor_limit(p_axis);
_wake_up_bodies();
}
void JoltGeneric6DOFJoint3D::_motor_speed_changed(int p_axis) {
_update_motor_velocity(p_axis);
_wake_up_bodies();
}
void JoltGeneric6DOFJoint3D::_motor_limit_changed(int p_axis) {
_update_motor_limit(p_axis);
_wake_up_bodies();
}
void JoltGeneric6DOFJoint3D::_spring_state_changed(int p_axis) {
_update_motor_state(p_axis);
_wake_up_bodies();
}
void JoltGeneric6DOFJoint3D::_spring_parameters_changed(int p_axis) {
_update_spring_parameters(p_axis);
_wake_up_bodies();
}
void JoltGeneric6DOFJoint3D::_spring_equilibrium_changed(int p_axis) {
_update_spring_equilibrium(p_axis);
_wake_up_bodies();
}
void JoltGeneric6DOFJoint3D::_spring_limit_changed(int p_axis) {
_update_motor_limit(p_axis);
_wake_up_bodies();
}
JoltGeneric6DOFJoint3D::JoltGeneric6DOFJoint3D(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) :
JoltJoint3D(p_old_joint, p_body_a, p_body_b, p_local_ref_a, p_local_ref_b) {
rebuild();
}
double JoltGeneric6DOFJoint3D::get_param(Axis p_axis, Param p_param) const {
const int axis_lin = AXES_LINEAR + (int)p_axis;
const int axis_ang = AXES_ANGULAR + (int)p_axis;
switch ((int)p_param) {
case PhysicsServer3D::G6DOF_JOINT_LINEAR_LOWER_LIMIT: {
return limit_lower[axis_lin];
}
case PhysicsServer3D::G6DOF_JOINT_LINEAR_UPPER_LIMIT: {
return limit_upper[axis_lin];
}
case PhysicsServer3D::G6DOF_JOINT_LINEAR_LIMIT_SOFTNESS: {
return G6DOF_DEFAULT_LINEAR_LIMIT_SOFTNESS;
}
case PhysicsServer3D::G6DOF_JOINT_LINEAR_RESTITUTION: {
return G6DOF_DEFAULT_LINEAR_RESTITUTION;
}
case PhysicsServer3D::G6DOF_JOINT_LINEAR_DAMPING: {
return G6DOF_DEFAULT_LINEAR_DAMPING;
}
case PhysicsServer3D::G6DOF_JOINT_LINEAR_MOTOR_TARGET_VELOCITY: {
return motor_speed[axis_lin];
}
case PhysicsServer3D::G6DOF_JOINT_LINEAR_MOTOR_FORCE_LIMIT: {
return motor_limit[axis_lin];
}
case JoltPhysicsServer3D::G6DOF_JOINT_LINEAR_SPRING_STIFFNESS: {
return spring_stiffness[axis_lin];
}
case JoltPhysicsServer3D::G6DOF_JOINT_LINEAR_SPRING_DAMPING: {
return spring_damping[axis_lin];
}
case JoltPhysicsServer3D::G6DOF_JOINT_LINEAR_SPRING_EQUILIBRIUM_POINT: {
return spring_equilibrium[axis_lin];
}
case PhysicsServer3D::G6DOF_JOINT_ANGULAR_LOWER_LIMIT: {
return limit_lower[axis_ang];
}
case PhysicsServer3D::G6DOF_JOINT_ANGULAR_UPPER_LIMIT: {
return limit_upper[axis_ang];
}
case PhysicsServer3D::G6DOF_JOINT_ANGULAR_LIMIT_SOFTNESS: {
return G6DOF_DEFAULT_ANGULAR_LIMIT_SOFTNESS;
}
case PhysicsServer3D::G6DOF_JOINT_ANGULAR_DAMPING: {
return G6DOF_DEFAULT_ANGULAR_DAMPING;
}
case PhysicsServer3D::G6DOF_JOINT_ANGULAR_RESTITUTION: {
return G6DOF_DEFAULT_ANGULAR_RESTITUTION;
}
case PhysicsServer3D::G6DOF_JOINT_ANGULAR_FORCE_LIMIT: {
return G6DOF_DEFAULT_ANGULAR_FORCE_LIMIT;
}
case PhysicsServer3D::G6DOF_JOINT_ANGULAR_ERP: {
return G6DOF_DEFAULT_ANGULAR_ERP;
}
case PhysicsServer3D::G6DOF_JOINT_ANGULAR_MOTOR_TARGET_VELOCITY: {
return motor_speed[axis_ang];
}
case PhysicsServer3D::G6DOF_JOINT_ANGULAR_MOTOR_FORCE_LIMIT: {
return motor_limit[axis_ang];
}
case JoltPhysicsServer3D::G6DOF_JOINT_ANGULAR_SPRING_STIFFNESS: {
return spring_stiffness[axis_ang];
}
case JoltPhysicsServer3D::G6DOF_JOINT_ANGULAR_SPRING_DAMPING: {
return spring_damping[axis_ang];
}
case JoltPhysicsServer3D::G6DOF_JOINT_ANGULAR_SPRING_EQUILIBRIUM_POINT: {
return spring_equilibrium[axis_ang];
}
default: {
ERR_FAIL_V_MSG(0.0, vformat("Unhandled parameter: '%d'. This should not happen. Please report this.", p_param));
}
}
}
void JoltGeneric6DOFJoint3D::set_param(Axis p_axis, Param p_param, double p_value) {
const int axis_lin = AXES_LINEAR + (int)p_axis;
const int axis_ang = AXES_ANGULAR + (int)p_axis;
switch ((int)p_param) {
case PhysicsServer3D::G6DOF_JOINT_LINEAR_LOWER_LIMIT: {
limit_lower[axis_lin] = p_value;
_limits_changed();
} break;
case PhysicsServer3D::G6DOF_JOINT_LINEAR_UPPER_LIMIT: {
limit_upper[axis_lin] = p_value;
_limits_changed();
} break;
case PhysicsServer3D::G6DOF_JOINT_LINEAR_LIMIT_SOFTNESS: {
if (!Math::is_equal_approx(p_value, G6DOF_DEFAULT_LINEAR_LIMIT_SOFTNESS)) {
WARN_PRINT(vformat("6DOF joint linear limit softness is not supported when using Jolt Physics. Any such value will be ignored. This joint connects %s.", _bodies_to_string()));
}
} break;
case PhysicsServer3D::G6DOF_JOINT_LINEAR_RESTITUTION: {
if (!Math::is_equal_approx(p_value, G6DOF_DEFAULT_LINEAR_RESTITUTION)) {
WARN_PRINT(vformat("6DOF joint linear restitution is not supported when using Jolt Physics. Any such value will be ignored. This joint connects %s.", _bodies_to_string()));
}
} break;
case PhysicsServer3D::G6DOF_JOINT_LINEAR_DAMPING: {
if (!Math::is_equal_approx(p_value, G6DOF_DEFAULT_LINEAR_DAMPING)) {
WARN_PRINT(vformat("6DOF joint linear damping is not supported when using Jolt Physics. Any such value will be ignored. This joint connects %s.", _bodies_to_string()));
}
} break;
case PhysicsServer3D::G6DOF_JOINT_LINEAR_MOTOR_TARGET_VELOCITY: {
motor_speed[axis_lin] = p_value;
_motor_speed_changed(axis_lin);
} break;
case PhysicsServer3D::G6DOF_JOINT_LINEAR_MOTOR_FORCE_LIMIT: {
motor_limit[axis_lin] = p_value;
_motor_limit_changed(axis_lin);
} break;
case JoltPhysicsServer3D::G6DOF_JOINT_LINEAR_SPRING_STIFFNESS: {
spring_stiffness[axis_lin] = p_value;
_spring_parameters_changed(axis_lin);
} break;
case JoltPhysicsServer3D::G6DOF_JOINT_LINEAR_SPRING_DAMPING: {
spring_damping[axis_lin] = p_value;
_spring_parameters_changed(axis_lin);
} break;
case JoltPhysicsServer3D::G6DOF_JOINT_LINEAR_SPRING_EQUILIBRIUM_POINT: {
spring_equilibrium[axis_lin] = p_value;
_spring_equilibrium_changed(axis_lin);
} break;
case PhysicsServer3D::G6DOF_JOINT_ANGULAR_LOWER_LIMIT: {
limit_lower[axis_ang] = p_value;
_limits_changed();
} break;
case PhysicsServer3D::G6DOF_JOINT_ANGULAR_UPPER_LIMIT: {
limit_upper[axis_ang] = p_value;
_limits_changed();
} break;
case PhysicsServer3D::G6DOF_JOINT_ANGULAR_LIMIT_SOFTNESS: {
if (!Math::is_equal_approx(p_value, G6DOF_DEFAULT_ANGULAR_LIMIT_SOFTNESS)) {
WARN_PRINT(vformat("6DOF joint angular limit softness is not supported when using Jolt Physics. Any such value will be ignored. This joint connects %s.", _bodies_to_string()));
}
} break;
case PhysicsServer3D::G6DOF_JOINT_ANGULAR_DAMPING: {
if (!Math::is_equal_approx(p_value, G6DOF_DEFAULT_ANGULAR_DAMPING)) {
WARN_PRINT(vformat("6DOF joint angular damping is not supported when using Jolt Physics. Any such value will be ignored. This joint connects %s.", _bodies_to_string()));
}
} break;
case PhysicsServer3D::G6DOF_JOINT_ANGULAR_RESTITUTION: {
if (!Math::is_equal_approx(p_value, G6DOF_DEFAULT_ANGULAR_RESTITUTION)) {
WARN_PRINT(vformat("6DOF joint angular restitution is not supported when using Jolt Physics. Any such value will be ignored. This joint connects %s.", _bodies_to_string()));
}
} break;
case PhysicsServer3D::G6DOF_JOINT_ANGULAR_FORCE_LIMIT: {
if (!Math::is_equal_approx(p_value, G6DOF_DEFAULT_ANGULAR_FORCE_LIMIT)) {
WARN_PRINT(vformat("6DOF joint angular force limit is not supported when using Jolt Physics. Any such value will be ignored. This joint connects %s.", _bodies_to_string()));
}
} break;
case PhysicsServer3D::G6DOF_JOINT_ANGULAR_ERP: {
if (!Math::is_equal_approx(p_value, G6DOF_DEFAULT_ANGULAR_ERP)) {
WARN_PRINT(vformat("6DOF joint angular ERP is not supported when using Jolt Physics. Any such value will be ignored. This joint connects %s.", _bodies_to_string()));
}
} break;
case PhysicsServer3D::G6DOF_JOINT_ANGULAR_MOTOR_TARGET_VELOCITY: {
motor_speed[axis_ang] = p_value;
_motor_speed_changed(axis_ang);
} break;
case PhysicsServer3D::G6DOF_JOINT_ANGULAR_MOTOR_FORCE_LIMIT: {
motor_limit[axis_ang] = p_value;
_motor_limit_changed(axis_ang);
} break;
case JoltPhysicsServer3D::G6DOF_JOINT_ANGULAR_SPRING_STIFFNESS: {
spring_stiffness[axis_ang] = p_value;
_spring_parameters_changed(axis_ang);
} break;
case JoltPhysicsServer3D::G6DOF_JOINT_ANGULAR_SPRING_DAMPING: {
spring_damping[axis_ang] = p_value;
_spring_parameters_changed(axis_ang);
} break;
case JoltPhysicsServer3D::G6DOF_JOINT_ANGULAR_SPRING_EQUILIBRIUM_POINT: {
spring_equilibrium[axis_ang] = p_value;
_spring_equilibrium_changed(axis_ang);
} break;
default: {
ERR_FAIL_MSG(vformat("Unhandled parameter: '%d'. This should not happen. Please report this.", p_param));
} break;
}
}
bool JoltGeneric6DOFJoint3D::get_flag(Axis p_axis, Flag p_flag) const {
const int axis_lin = AXES_LINEAR + (int)p_axis;
const int axis_ang = AXES_ANGULAR + (int)p_axis;
switch ((int)p_flag) {
case PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_LINEAR_LIMIT: {
return limit_enabled[axis_lin];
}
case PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_LIMIT: {
return limit_enabled[axis_ang];
}
case JoltPhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_SPRING: {
return spring_enabled[axis_ang];
}
case JoltPhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_LINEAR_SPRING: {
return spring_enabled[axis_lin];
}
case PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_MOTOR: {
return motor_enabled[axis_ang];
}
case PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_LINEAR_MOTOR: {
return motor_enabled[axis_lin];
}
default: {
ERR_FAIL_V_MSG(false, vformat("Unhandled flag: '%d'. This should not happen. Please report this.", p_flag));
}
}
}
void JoltGeneric6DOFJoint3D::set_flag(Axis p_axis, Flag p_flag, bool p_enabled) {
const int axis_lin = AXES_LINEAR + (int)p_axis;
const int axis_ang = AXES_ANGULAR + (int)p_axis;
switch ((int)p_flag) {
case PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_LINEAR_LIMIT: {
limit_enabled[axis_lin] = p_enabled;
_limits_changed();
} break;
case PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_LIMIT: {
limit_enabled[axis_ang] = p_enabled;
_limits_changed();
} break;
case JoltPhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_SPRING: {
spring_enabled[axis_ang] = p_enabled;
_spring_state_changed(axis_ang);
} break;
case JoltPhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_LINEAR_SPRING: {
spring_enabled[axis_lin] = p_enabled;
_spring_state_changed(axis_lin);
} break;
case PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_MOTOR: {
motor_enabled[axis_ang] = p_enabled;
_motor_state_changed(axis_ang);
} break;
case PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_LINEAR_MOTOR: {
motor_enabled[axis_lin] = p_enabled;
_motor_state_changed(axis_lin);
} break;
default: {
ERR_FAIL_MSG(vformat("Unhandled flag: '%d'. This should not happen. Please report this.", p_flag));
} break;
}
}
double JoltGeneric6DOFJoint3D::get_jolt_param(Axis p_axis, JoltParam p_param) const {
const int axis_lin = AXES_LINEAR + (int)p_axis;
const int axis_ang = AXES_ANGULAR + (int)p_axis;
switch ((int)p_param) {
case JoltPhysicsServer3D::G6DOF_JOINT_LINEAR_SPRING_FREQUENCY: {
return spring_frequency[axis_lin];
}
case JoltPhysicsServer3D::G6DOF_JOINT_LINEAR_SPRING_MAX_FORCE: {
return spring_limit[axis_lin];
}
case JoltPhysicsServer3D::G6DOF_JOINT_LINEAR_LIMIT_SPRING_FREQUENCY: {
return limit_spring_frequency[axis_lin];
}
case JoltPhysicsServer3D::G6DOF_JOINT_LINEAR_LIMIT_SPRING_DAMPING: {
return limit_spring_damping[axis_lin];
}
case JoltPhysicsServer3D::G6DOF_JOINT_ANGULAR_SPRING_FREQUENCY: {
return spring_frequency[axis_ang];
}
case JoltPhysicsServer3D::G6DOF_JOINT_ANGULAR_SPRING_MAX_TORQUE: {
return spring_limit[axis_ang];
}
default: {
ERR_FAIL_V_MSG(0.0, vformat("Unhandled parameter: '%d'. This should not happen. Please report this.", p_param));
}
}
}
void JoltGeneric6DOFJoint3D::set_jolt_param(Axis p_axis, JoltParam p_param, double p_value) {
const int axis_lin = AXES_LINEAR + (int)p_axis;
const int axis_ang = AXES_ANGULAR + (int)p_axis;
switch ((int)p_param) {
case JoltPhysicsServer3D::G6DOF_JOINT_LINEAR_SPRING_FREQUENCY: {
spring_frequency[axis_lin] = p_value;
_spring_parameters_changed(axis_lin);
} break;
case JoltPhysicsServer3D::G6DOF_JOINT_LINEAR_SPRING_MAX_FORCE: {
spring_limit[axis_lin] = p_value;
_spring_limit_changed(axis_lin);
} break;
case JoltPhysicsServer3D::G6DOF_JOINT_LINEAR_LIMIT_SPRING_FREQUENCY: {
limit_spring_frequency[axis_lin] = p_value;
_limit_spring_parameters_changed(axis_lin);
} break;
case JoltPhysicsServer3D::G6DOF_JOINT_LINEAR_LIMIT_SPRING_DAMPING: {
limit_spring_damping[axis_lin] = p_value;
_limit_spring_parameters_changed(axis_lin);
} break;
case JoltPhysicsServer3D::G6DOF_JOINT_ANGULAR_SPRING_FREQUENCY: {
spring_frequency[axis_ang] = p_value;
_spring_parameters_changed(axis_ang);
} break;
case JoltPhysicsServer3D::G6DOF_JOINT_ANGULAR_SPRING_MAX_TORQUE: {
spring_limit[axis_ang] = p_value;
_spring_limit_changed(axis_ang);
} break;
default: {
ERR_FAIL_MSG(vformat("Unhandled parameter: '%d'. This should not happen. Please report this.", p_param));
} break;
}
}
bool JoltGeneric6DOFJoint3D::get_jolt_flag(Axis p_axis, JoltFlag p_flag) const {
const int axis_lin = AXES_LINEAR + (int)p_axis;
const int axis_ang = AXES_ANGULAR + (int)p_axis;
switch ((int)p_flag) {
case JoltPhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_LINEAR_LIMIT_SPRING: {
return limit_spring_enabled[axis_lin];
}
case JoltPhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_LINEAR_SPRING_FREQUENCY: {
return spring_use_frequency[axis_lin];
}
case JoltPhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_SPRING_FREQUENCY: {
return spring_use_frequency[axis_ang];
}
default: {
ERR_FAIL_V_MSG(false, vformat("Unhandled flag: '%d'. This should not happen. Please report this.", p_flag));
}
}
}
void JoltGeneric6DOFJoint3D::set_jolt_flag(Axis p_axis, JoltFlag p_flag, bool p_enabled) {
const int axis_lin = AXES_LINEAR + (int)p_axis;
const int axis_ang = AXES_ANGULAR + (int)p_axis;
switch ((int)p_flag) {
case JoltPhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_LINEAR_LIMIT_SPRING: {
limit_spring_enabled[axis_lin] = p_enabled;
_limit_spring_parameters_changed(axis_lin);
} break;
case JoltPhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_LINEAR_SPRING_FREQUENCY: {
spring_use_frequency[axis_lin] = p_enabled;
_spring_parameters_changed(axis_lin);
} break;
case JoltPhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_SPRING_FREQUENCY: {
spring_use_frequency[axis_ang] = p_enabled;
_spring_parameters_changed(axis_ang);
} break;
default: {
ERR_FAIL_MSG(vformat("Unhandled flag: '%d'. This should not happen. Please report this.", p_flag));
} break;
}
}
float JoltGeneric6DOFJoint3D::get_applied_force() const {
JPH::SixDOFConstraint *constraint = static_cast<JPH::SixDOFConstraint *>(jolt_ref.GetPtr());
ERR_FAIL_NULL_V(constraint, 0.0f);
JoltSpace3D *space = get_space();
ERR_FAIL_NULL_V(space, 0.0f);
const float last_step = space->get_last_step();
if (unlikely(last_step == 0.0f)) {
return 0.0f;
}
const JPH::Vec3 total_lambda = constraint->GetTotalLambdaPosition() + constraint->GetTotalLambdaMotorTranslation();
return total_lambda.Length() / last_step;
}
float JoltGeneric6DOFJoint3D::get_applied_torque() const {
JPH::SixDOFConstraint *constraint = static_cast<JPH::SixDOFConstraint *>(jolt_ref.GetPtr());
ERR_FAIL_NULL_V(constraint, 0.0f);
JoltSpace3D *space = get_space();
ERR_FAIL_NULL_V(space, 0.0f);
const float last_step = space->get_last_step();
if (unlikely(last_step == 0.0f)) {
return 0.0f;
}
const JPH::Vec3 total_lambda = constraint->GetTotalLambdaRotation() + constraint->GetTotalLambdaMotorRotation();
return total_lambda.Length() / last_step;
}
void JoltGeneric6DOFJoint3D::rebuild() {
destroy();
JoltSpace3D *space = get_space();
if (space == nullptr) {
return;
}
JPH::Body *jolt_body_a = body_a != nullptr ? body_a->get_jolt_body() : nullptr;
JPH::Body *jolt_body_b = body_b != nullptr ? body_b->get_jolt_body() : nullptr;
ERR_FAIL_COND(jolt_body_a == nullptr && jolt_body_b == nullptr);
Transform3D shifted_ref_a;
Transform3D shifted_ref_b;
_shift_reference_frames(Vector3(), Vector3(), shifted_ref_a, shifted_ref_b);
jolt_ref = _build_6dof(jolt_body_a, jolt_body_b, shifted_ref_a, shifted_ref_b);
space->add_joint(this);
_update_enabled();
_update_iterations();
_update_limit_spring_parameters(AXIS_LINEAR_X);
_update_limit_spring_parameters(AXIS_LINEAR_Y);
_update_limit_spring_parameters(AXIS_LINEAR_Z);
for (int axis = 0; axis < AXIS_COUNT; ++axis) {
_update_motor_state(axis);
_update_motor_velocity(axis);
_update_motor_limit(axis);
_update_spring_parameters(axis);
_update_spring_equilibrium(axis);
}
}

View File

@@ -0,0 +1,124 @@
/**************************************************************************/
/* jolt_generic_6dof_joint_3d.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#include "../jolt_physics_server_3d.h"
#include "jolt_joint_3d.h"
#include "Jolt/Jolt.h"
#include "Jolt/Physics/Constraints/SixDOFConstraint.h"
class JoltGeneric6DOFJoint3D final : public JoltJoint3D {
typedef Vector3::Axis Axis;
typedef JPH::SixDOFConstraintSettings::EAxis JoltAxis;
typedef PhysicsServer3D::G6DOFJointAxisParam Param;
typedef JoltPhysicsServer3D::G6DOFJointAxisParamJolt JoltParam;
typedef PhysicsServer3D::G6DOFJointAxisFlag Flag;
typedef JoltPhysicsServer3D::G6DOFJointAxisFlagJolt JoltFlag;
enum {
AXIS_LINEAR_X = JoltAxis::TranslationX,
AXIS_LINEAR_Y = JoltAxis::TranslationY,
AXIS_LINEAR_Z = JoltAxis::TranslationZ,
AXIS_ANGULAR_X = JoltAxis::RotationX,
AXIS_ANGULAR_Y = JoltAxis::RotationY,
AXIS_ANGULAR_Z = JoltAxis::RotationZ,
AXIS_COUNT = JoltAxis::Num,
AXES_LINEAR = AXIS_LINEAR_X,
AXES_ANGULAR = AXIS_ANGULAR_X,
};
double limit_lower[AXIS_COUNT] = {};
double limit_upper[AXIS_COUNT] = {};
double limit_spring_frequency[AXIS_COUNT] = {};
double limit_spring_damping[AXIS_COUNT] = {};
double motor_speed[AXIS_COUNT] = {};
double motor_limit[AXIS_COUNT] = { FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX };
double spring_stiffness[AXIS_COUNT] = {};
double spring_frequency[AXIS_COUNT] = {};
double spring_damping[AXIS_COUNT] = {};
double spring_equilibrium[AXIS_COUNT] = {};
double spring_limit[AXIS_COUNT] = { FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX };
bool limit_enabled[AXIS_COUNT] = {};
bool limit_spring_enabled[AXIS_COUNT] = {};
bool motor_enabled[AXIS_COUNT] = {};
bool spring_enabled[AXIS_COUNT] = {};
bool spring_use_frequency[AXIS_COUNT] = {};
JPH::Constraint *_build_6dof(JPH::Body *p_jolt_body_a, JPH::Body *p_jolt_body_b, const Transform3D &p_shifted_ref_a, const Transform3D &p_shifted_ref_b) const;
void _update_limit_spring_parameters(int p_axis);
void _update_motor_state(int p_axis);
void _update_motor_velocity(int p_axis);
void _update_motor_limit(int p_axis);
void _update_spring_parameters(int p_axis);
void _update_spring_equilibrium(int p_axis);
void _limits_changed();
void _limit_spring_parameters_changed(int p_axis);
void _motor_state_changed(int p_axis);
void _motor_speed_changed(int p_axis);
void _motor_limit_changed(int p_axis);
void _spring_state_changed(int p_axis);
void _spring_parameters_changed(int p_axis);
void _spring_equilibrium_changed(int p_axis);
void _spring_limit_changed(int p_axis);
public:
JoltGeneric6DOFJoint3D(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);
virtual PhysicsServer3D::JointType get_type() const override { return PhysicsServer3D::JOINT_TYPE_6DOF; }
double get_param(Axis p_axis, Param p_param) const;
void set_param(Axis p_axis, Param p_param, double p_value);
bool get_flag(Axis p_axis, Flag p_flag) const;
void set_flag(Axis p_axis, Flag p_flag, bool p_enabled);
double get_jolt_param(Axis p_axis, JoltParam p_param) const;
void set_jolt_param(Axis p_axis, JoltParam p_param, double p_value);
bool get_jolt_flag(Axis p_axis, JoltFlag p_flag) const;
void set_jolt_flag(Axis p_axis, JoltFlag p_flag, bool p_enabled);
float get_applied_force() const;
float get_applied_torque() const;
virtual void rebuild() override;
};

View File

@@ -0,0 +1,420 @@
/**************************************************************************/
/* jolt_hinge_joint_3d.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include "jolt_hinge_joint_3d.h"
#include "../misc/jolt_type_conversions.h"
#include "../objects/jolt_body_3d.h"
#include "../spaces/jolt_space_3d.h"
#include "core/config/engine.h"
#include "Jolt/Physics/Constraints/FixedConstraint.h"
#include "Jolt/Physics/Constraints/HingeConstraint.h"
namespace {
constexpr double HINGE_DEFAULT_BIAS = 0.3;
constexpr double HINGE_DEFAULT_LIMIT_BIAS = 0.3;
constexpr double HINGE_DEFAULT_SOFTNESS = 0.9;
constexpr double HINGE_DEFAULT_RELAXATION = 1.0;
double estimate_physics_step() {
Engine *engine = Engine::get_singleton();
const double step = 1.0 / engine->get_physics_ticks_per_second();
const double step_scaled = step * engine->get_time_scale();
return step_scaled;
}
} // namespace
JPH::Constraint *JoltHingeJoint3D::_build_hinge(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_limit) const {
JPH::HingeConstraintSettings constraint_settings;
constraint_settings.mSpace = JPH::EConstraintSpace::LocalToBodyCOM;
constraint_settings.mPoint1 = to_jolt_r(p_shifted_ref_a.origin);
constraint_settings.mHingeAxis1 = to_jolt(p_shifted_ref_a.basis.get_column(Vector3::AXIS_Z));
constraint_settings.mNormalAxis1 = to_jolt(p_shifted_ref_a.basis.get_column(Vector3::AXIS_X));
constraint_settings.mPoint2 = to_jolt_r(p_shifted_ref_b.origin);
constraint_settings.mHingeAxis2 = to_jolt(p_shifted_ref_b.basis.get_column(Vector3::AXIS_Z));
constraint_settings.mNormalAxis2 = to_jolt(p_shifted_ref_b.basis.get_column(Vector3::AXIS_X));
constraint_settings.mLimitsMin = -p_limit;
constraint_settings.mLimitsMax = p_limit;
if (limit_spring_enabled) {
constraint_settings.mLimitsSpringSettings.mFrequency = (float)limit_spring_frequency;
constraint_settings.mLimitsSpringSettings.mDamping = (float)limit_spring_damping;
}
if (p_jolt_body_a == nullptr) {
return constraint_settings.Create(JPH::Body::sFixedToWorld, *p_jolt_body_b);
} else if (p_jolt_body_b == nullptr) {
return constraint_settings.Create(*p_jolt_body_a, JPH::Body::sFixedToWorld);
} else {
return constraint_settings.Create(*p_jolt_body_a, *p_jolt_body_b);
}
}
JPH::Constraint *JoltHingeJoint3D::_build_fixed(JPH::Body *p_jolt_body_a, JPH::Body *p_jolt_body_b, const Transform3D &p_shifted_ref_a, const Transform3D &p_shifted_ref_b) const {
JPH::FixedConstraintSettings constraint_settings;
constraint_settings.mSpace = JPH::EConstraintSpace::LocalToBodyCOM;
constraint_settings.mAutoDetectPoint = false;
constraint_settings.mPoint1 = to_jolt_r(p_shifted_ref_a.origin);
constraint_settings.mAxisX1 = to_jolt(p_shifted_ref_a.basis.get_column(Vector3::AXIS_X));
constraint_settings.mAxisY1 = to_jolt(p_shifted_ref_a.basis.get_column(Vector3::AXIS_Y));
constraint_settings.mPoint2 = to_jolt_r(p_shifted_ref_b.origin);
constraint_settings.mAxisX2 = to_jolt(p_shifted_ref_b.basis.get_column(Vector3::AXIS_X));
constraint_settings.mAxisY2 = to_jolt(p_shifted_ref_b.basis.get_column(Vector3::AXIS_Y));
if (p_jolt_body_a == nullptr) {
return constraint_settings.Create(JPH::Body::sFixedToWorld, *p_jolt_body_b);
} else if (p_jolt_body_b == nullptr) {
return constraint_settings.Create(*p_jolt_body_a, JPH::Body::sFixedToWorld);
} else {
return constraint_settings.Create(*p_jolt_body_a, *p_jolt_body_b);
}
}
void JoltHingeJoint3D::_update_motor_state() {
if (unlikely(_is_fixed())) {
return;
}
if (JPH::HingeConstraint *constraint = static_cast<JPH::HingeConstraint *>(jolt_ref.GetPtr())) {
constraint->SetMotorState(motor_enabled ? JPH::EMotorState::Velocity : JPH::EMotorState::Off);
}
}
void JoltHingeJoint3D::_update_motor_velocity() {
if (unlikely(_is_fixed())) {
return;
}
if (JPH::HingeConstraint *constraint = static_cast<JPH::HingeConstraint *>(jolt_ref.GetPtr())) {
// We flip the direction since Jolt is CCW but Godot is CW.
constraint->SetTargetAngularVelocity((float)-motor_target_speed);
}
}
void JoltHingeJoint3D::_update_motor_limit() {
if (unlikely(_is_fixed())) {
return;
}
if (JPH::HingeConstraint *constraint = static_cast<JPH::HingeConstraint *>(jolt_ref.GetPtr())) {
JPH::MotorSettings &motor_settings = constraint->GetMotorSettings();
motor_settings.mMinTorqueLimit = (float)-motor_max_torque;
motor_settings.mMaxTorqueLimit = (float)motor_max_torque;
}
}
void JoltHingeJoint3D::_limits_changed() {
rebuild();
_wake_up_bodies();
}
void JoltHingeJoint3D::_limit_spring_changed() {
rebuild();
_wake_up_bodies();
}
void JoltHingeJoint3D::_motor_state_changed() {
_update_motor_state();
_wake_up_bodies();
}
void JoltHingeJoint3D::_motor_speed_changed() {
_update_motor_velocity();
_wake_up_bodies();
}
void JoltHingeJoint3D::_motor_limit_changed() {
_update_motor_limit();
_wake_up_bodies();
}
JoltHingeJoint3D::JoltHingeJoint3D(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) :
JoltJoint3D(p_old_joint, p_body_a, p_body_b, p_local_ref_a, p_local_ref_b) {
rebuild();
}
double JoltHingeJoint3D::get_param(Parameter p_param) const {
switch (p_param) {
case PhysicsServer3D::HINGE_JOINT_BIAS: {
return HINGE_DEFAULT_BIAS;
}
case PhysicsServer3D::HINGE_JOINT_LIMIT_UPPER: {
return limit_upper;
}
case PhysicsServer3D::HINGE_JOINT_LIMIT_LOWER: {
return limit_lower;
}
case PhysicsServer3D::HINGE_JOINT_LIMIT_BIAS: {
return HINGE_DEFAULT_LIMIT_BIAS;
}
case PhysicsServer3D::HINGE_JOINT_LIMIT_SOFTNESS: {
return HINGE_DEFAULT_SOFTNESS;
}
case PhysicsServer3D::HINGE_JOINT_LIMIT_RELAXATION: {
return HINGE_DEFAULT_RELAXATION;
}
case PhysicsServer3D::HINGE_JOINT_MOTOR_TARGET_VELOCITY: {
return motor_target_speed;
}
case PhysicsServer3D::HINGE_JOINT_MOTOR_MAX_IMPULSE: {
// With Godot using max impulse instead of max torque we don't have much choice but to calculate this and hope the timestep doesn't change.
return motor_max_torque * estimate_physics_step();
}
default: {
ERR_FAIL_V_MSG(0.0, vformat("Unhandled parameter: '%d'. This should not happen. Please report this.", p_param));
}
}
}
void JoltHingeJoint3D::set_param(Parameter p_param, double p_value) {
switch (p_param) {
case PhysicsServer3D::HINGE_JOINT_BIAS: {
if (!Math::is_equal_approx(p_value, HINGE_DEFAULT_BIAS)) {
WARN_PRINT(vformat("Hinge joint bias is not supported when using Jolt Physics. Any such value will be ignored. This joint connects %s.", _bodies_to_string()));
}
} break;
case PhysicsServer3D::HINGE_JOINT_LIMIT_UPPER: {
limit_upper = p_value;
_limits_changed();
} break;
case PhysicsServer3D::HINGE_JOINT_LIMIT_LOWER: {
limit_lower = p_value;
_limits_changed();
} break;
case PhysicsServer3D::HINGE_JOINT_LIMIT_BIAS: {
if (!Math::is_equal_approx(p_value, HINGE_DEFAULT_LIMIT_BIAS)) {
WARN_PRINT(vformat("Hinge joint bias limit is not supported when using Jolt Physics. Any such value will be ignored. This joint connects %s.", _bodies_to_string()));
}
} break;
case PhysicsServer3D::HINGE_JOINT_LIMIT_SOFTNESS: {
if (!Math::is_equal_approx(p_value, HINGE_DEFAULT_SOFTNESS)) {
WARN_PRINT(vformat("Hinge joint softness is not supported when using Jolt Physics. Any such value will be ignored. This joint connects %s.", _bodies_to_string()));
}
} break;
case PhysicsServer3D::HINGE_JOINT_LIMIT_RELAXATION: {
if (!Math::is_equal_approx(p_value, HINGE_DEFAULT_RELAXATION)) {
WARN_PRINT(vformat("Hinge joint relaxation is not supported when using Jolt Physics. Any such value will be ignored. This joint connects %s.", _bodies_to_string()));
}
} break;
case PhysicsServer3D::HINGE_JOINT_MOTOR_TARGET_VELOCITY: {
motor_target_speed = p_value;
_motor_speed_changed();
} break;
case PhysicsServer3D::HINGE_JOINT_MOTOR_MAX_IMPULSE: {
// With Godot using max impulse instead of max torque we don't have much choice but to calculate this and hope the timestep doesn't change.
motor_max_torque = p_value / estimate_physics_step();
_motor_limit_changed();
} break;
default: {
ERR_FAIL_MSG(vformat("Unhandled parameter: '%d'. This should not happen. Please report this.", p_param));
} break;
}
}
double JoltHingeJoint3D::get_jolt_param(JoltParameter p_param) const {
switch (p_param) {
case JoltPhysicsServer3D::HINGE_JOINT_LIMIT_SPRING_FREQUENCY: {
return limit_spring_frequency;
}
case JoltPhysicsServer3D::HINGE_JOINT_LIMIT_SPRING_DAMPING: {
return limit_spring_damping;
}
case JoltPhysicsServer3D::HINGE_JOINT_MOTOR_MAX_TORQUE: {
return motor_max_torque;
}
default: {
ERR_FAIL_V_MSG(0.0, vformat("Unhandled parameter: '%d'. This should not happen. Please report this.", p_param));
}
}
}
void JoltHingeJoint3D::set_jolt_param(JoltParameter p_param, double p_value) {
switch (p_param) {
case JoltPhysicsServer3D::HINGE_JOINT_LIMIT_SPRING_FREQUENCY: {
limit_spring_frequency = p_value;
_limit_spring_changed();
} break;
case JoltPhysicsServer3D::HINGE_JOINT_LIMIT_SPRING_DAMPING: {
limit_spring_damping = p_value;
_limit_spring_changed();
} break;
case JoltPhysicsServer3D::HINGE_JOINT_MOTOR_MAX_TORQUE: {
motor_max_torque = p_value;
_motor_limit_changed();
} break;
default: {
ERR_FAIL_MSG(vformat("Unhandled parameter: '%d'. This should not happen. Please report this.", p_param));
} break;
}
}
bool JoltHingeJoint3D::get_flag(Flag p_flag) const {
switch (p_flag) {
case PhysicsServer3D::HINGE_JOINT_FLAG_USE_LIMIT: {
return limits_enabled;
}
case PhysicsServer3D::HINGE_JOINT_FLAG_ENABLE_MOTOR: {
return motor_enabled;
}
default: {
ERR_FAIL_V_MSG(false, vformat("Unhandled flag: '%d'. This should not happen. Please report this.", p_flag));
}
}
}
void JoltHingeJoint3D::set_flag(Flag p_flag, bool p_enabled) {
switch (p_flag) {
case PhysicsServer3D::HINGE_JOINT_FLAG_USE_LIMIT: {
limits_enabled = p_enabled;
_limits_changed();
} break;
case PhysicsServer3D::HINGE_JOINT_FLAG_ENABLE_MOTOR: {
motor_enabled = p_enabled;
_motor_state_changed();
} break;
default: {
ERR_FAIL_MSG(vformat("Unhandled flag: '%d'. This should not happen. Please report this.", p_flag));
} break;
}
}
bool JoltHingeJoint3D::get_jolt_flag(JoltFlag p_flag) const {
switch (p_flag) {
case JoltPhysicsServer3D::HINGE_JOINT_FLAG_USE_LIMIT_SPRING: {
return limit_spring_enabled;
}
default: {
ERR_FAIL_V_MSG(false, vformat("Unhandled flag: '%d'. This should not happen. Please report this.", p_flag));
}
}
}
void JoltHingeJoint3D::set_jolt_flag(JoltFlag p_flag, bool p_enabled) {
switch (p_flag) {
case JoltPhysicsServer3D::HINGE_JOINT_FLAG_USE_LIMIT_SPRING: {
limit_spring_enabled = p_enabled;
_limit_spring_changed();
} break;
default: {
ERR_FAIL_MSG(vformat("Unhandled flag: '%d'. This should not happen. Please report this.", p_flag));
} break;
}
}
float JoltHingeJoint3D::get_applied_force() const {
ERR_FAIL_NULL_V(jolt_ref, 0.0f);
JoltSpace3D *space = get_space();
ERR_FAIL_NULL_V(space, 0.0f);
const float last_step = space->get_last_step();
if (unlikely(last_step == 0.0f)) {
return 0.0f;
}
if (_is_fixed()) {
JPH::FixedConstraint *constraint = static_cast<JPH::FixedConstraint *>(jolt_ref.GetPtr());
return constraint->GetTotalLambdaPosition().Length() / last_step;
} else {
JPH::HingeConstraint *constraint = static_cast<JPH::HingeConstraint *>(jolt_ref.GetPtr());
const JPH::Vec3 total_lambda = JPH::Vec3(constraint->GetTotalLambdaRotation()[0], constraint->GetTotalLambdaRotation()[1], constraint->GetTotalLambdaRotationLimits() + constraint->GetTotalLambdaMotor());
return total_lambda.Length() / last_step;
}
}
float JoltHingeJoint3D::get_applied_torque() const {
ERR_FAIL_NULL_V(jolt_ref, 0.0f);
JoltSpace3D *space = get_space();
ERR_FAIL_NULL_V(space, 0.0f);
const float last_step = space->get_last_step();
if (unlikely(last_step == 0.0f)) {
return 0.0f;
}
if (_is_fixed()) {
JPH::FixedConstraint *constraint = static_cast<JPH::FixedConstraint *>(jolt_ref.GetPtr());
return constraint->GetTotalLambdaRotation().Length() / last_step;
} else {
JPH::HingeConstraint *constraint = static_cast<JPH::HingeConstraint *>(jolt_ref.GetPtr());
return constraint->GetTotalLambdaRotation().Length() / last_step;
}
}
void JoltHingeJoint3D::rebuild() {
destroy();
JoltSpace3D *space = get_space();
if (space == nullptr) {
return;
}
JPH::Body *jolt_body_a = body_a != nullptr ? body_a->get_jolt_body() : nullptr;
JPH::Body *jolt_body_b = body_b != nullptr ? body_b->get_jolt_body() : nullptr;
ERR_FAIL_COND(jolt_body_a == nullptr && jolt_body_b == nullptr);
float ref_shift = 0.0f;
float limit = JPH::JPH_PI;
if (limits_enabled && limit_lower <= limit_upper) {
const double limit_midpoint = (limit_lower + limit_upper) / 2.0f;
ref_shift = float(-limit_midpoint);
limit = float(limit_upper - limit_midpoint);
}
Transform3D shifted_ref_a;
Transform3D shifted_ref_b;
_shift_reference_frames(Vector3(), Vector3(0.0f, 0.0f, ref_shift), shifted_ref_a, shifted_ref_b);
if (_is_fixed()) {
jolt_ref = _build_fixed(jolt_body_a, jolt_body_b, shifted_ref_a, shifted_ref_b);
} else {
jolt_ref = _build_hinge(jolt_body_a, jolt_body_b, shifted_ref_a, shifted_ref_b, limit);
}
space->add_joint(this);
_update_enabled();
_update_iterations();
_update_motor_state();
_update_motor_velocity();
_update_motor_limit();
}

View File

@@ -0,0 +1,97 @@
/**************************************************************************/
/* jolt_hinge_joint_3d.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#include "../jolt_physics_server_3d.h"
#include "jolt_joint_3d.h"
#include "Jolt/Jolt.h"
#include "Jolt/Physics/Constraints/SliderConstraint.h"
class JoltHingeJoint3D final : public JoltJoint3D {
typedef PhysicsServer3D::HingeJointParam Parameter;
typedef JoltPhysicsServer3D::HingeJointParamJolt JoltParameter;
typedef PhysicsServer3D::HingeJointFlag Flag;
typedef JoltPhysicsServer3D::HingeJointFlagJolt JoltFlag;
double limit_lower = 0.0;
double limit_upper = 0.0;
double limit_spring_frequency = 0.0;
double limit_spring_damping = 0.0;
double motor_target_speed = 0.0f;
double motor_max_torque = FLT_MAX;
bool limits_enabled = false;
bool limit_spring_enabled = false;
bool motor_enabled = false;
JPH::Constraint *_build_hinge(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_limit) const;
JPH::Constraint *_build_fixed(JPH::Body *p_jolt_body_a, JPH::Body *p_jolt_body_b, const Transform3D &p_shifted_ref_a, const Transform3D &p_shifted_ref_b) const;
bool _is_sprung() const { return limit_spring_enabled && limit_spring_frequency > 0.0; }
bool _is_fixed() const { return limits_enabled && limit_lower == limit_upper && !_is_sprung(); }
void _update_motor_state();
void _update_motor_velocity();
void _update_motor_limit();
void _limits_changed();
void _limit_spring_changed();
void _motor_state_changed();
void _motor_speed_changed();
void _motor_limit_changed();
public:
JoltHingeJoint3D(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);
virtual PhysicsServer3D::JointType get_type() const override { return PhysicsServer3D::JOINT_TYPE_HINGE; }
double get_param(Parameter p_param) const;
void set_param(Parameter p_param, double p_value);
double get_jolt_param(JoltParameter p_param) const;
void set_jolt_param(JoltParameter p_param, double p_value);
bool get_flag(Flag p_flag) const;
void set_flag(Flag p_flag, bool p_enabled);
bool get_jolt_flag(JoltFlag p_flag) const;
void set_jolt_flag(JoltFlag p_flag, bool p_enabled);
float get_applied_force() const;
float get_applied_torque() const;
virtual void rebuild() override;
};

View File

@@ -0,0 +1,235 @@
/**************************************************************************/
/* jolt_joint_3d.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include "jolt_joint_3d.h"
#include "../jolt_project_settings.h"
#include "../misc/jolt_type_conversions.h"
#include "../objects/jolt_body_3d.h"
#include "../spaces/jolt_space_3d.h"
namespace {
constexpr int JOINT_DEFAULT_SOLVER_PRIORITY = 1;
} // namespace
void JoltJoint3D::_shift_reference_frames(const Vector3 &p_linear_shift, const Vector3 &p_angular_shift, Transform3D &r_shifted_ref_a, Transform3D &r_shifted_ref_b) {
Vector3 origin_a = local_ref_a.origin;
Vector3 origin_b = local_ref_b.origin;
if (body_a != nullptr) {
origin_a *= body_a->get_scale();
origin_a -= to_godot(body_a->get_jolt_shape()->GetCenterOfMass());
}
if (body_b != nullptr) {
origin_b *= body_b->get_scale();
origin_b -= to_godot(body_b->get_jolt_shape()->GetCenterOfMass());
}
const Basis &basis_a = local_ref_a.basis;
const Basis &basis_b = local_ref_b.basis;
const Basis shifted_basis_a = basis_a * Basis::from_euler(p_angular_shift, EulerOrder::ZYX);
const Vector3 shifted_origin_a = origin_a - basis_a.xform(p_linear_shift);
r_shifted_ref_a = Transform3D(shifted_basis_a, shifted_origin_a);
r_shifted_ref_b = Transform3D(basis_b, origin_b);
}
void JoltJoint3D::_wake_up_bodies() {
if (body_a != nullptr) {
body_a->wake_up();
}
if (body_b != nullptr) {
body_b->wake_up();
}
}
void JoltJoint3D::_update_enabled() {
if (jolt_ref != nullptr) {
jolt_ref->SetEnabled(enabled);
}
}
void JoltJoint3D::_update_iterations() {
if (jolt_ref != nullptr) {
jolt_ref->SetNumVelocityStepsOverride((JPH::uint)velocity_iterations);
jolt_ref->SetNumPositionStepsOverride((JPH::uint)position_iterations);
}
}
void JoltJoint3D::_enabled_changed() {
_update_enabled();
_wake_up_bodies();
}
void JoltJoint3D::_iterations_changed() {
_update_iterations();
_wake_up_bodies();
}
String JoltJoint3D::_bodies_to_string() const {
return vformat("'%s' and '%s'", body_a != nullptr ? body_a->to_string() : "<unknown>", body_b != nullptr ? body_b->to_string() : "<World>");
}
JoltJoint3D::JoltJoint3D(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) :
enabled(p_old_joint.enabled),
collision_disabled(p_old_joint.collision_disabled),
body_a(p_body_a),
body_b(p_body_b),
rid(p_old_joint.rid),
local_ref_a(p_local_ref_a),
local_ref_b(p_local_ref_b) {
if (body_a != nullptr) {
body_a->add_joint(this);
}
if (body_b != nullptr) {
body_b->add_joint(this);
}
if (body_b == nullptr && JoltProjectSettings::joint_world_node == JOLT_JOINT_WORLD_NODE_A) {
// The joint scene nodes will, when omitting one of the two body nodes, always pass in a
// null `body_b` to indicate it being the "world node", regardless of which body node you
// leave blank. So we need to correct for that if we wish to use the arguably more intuitive
// alternative where `body_a` is the "world node" instead.
SWAP(body_a, body_b);
SWAP(local_ref_a, local_ref_b);
}
}
JoltJoint3D::~JoltJoint3D() {
if (body_a != nullptr) {
body_a->remove_joint(this);
}
if (body_b != nullptr) {
body_b->remove_joint(this);
}
destroy();
}
JoltSpace3D *JoltJoint3D::get_space() const {
if (body_a != nullptr && body_b != nullptr) {
JoltSpace3D *space_a = body_a->get_space();
JoltSpace3D *space_b = body_b->get_space();
if (space_a == nullptr || space_b == nullptr) {
return nullptr;
}
ERR_FAIL_COND_V_MSG(space_a != space_b, nullptr, vformat("Joint was found to connect bodies in different physics spaces. This joint will effectively be disabled. This joint connects %s.", _bodies_to_string()));
return space_a;
} else if (body_a != nullptr) {
return body_a->get_space();
} else if (body_b != nullptr) {
return body_b->get_space();
}
return nullptr;
}
void JoltJoint3D::set_enabled(bool p_enabled) {
if (enabled == p_enabled) {
return;
}
enabled = p_enabled;
_enabled_changed();
}
int JoltJoint3D::get_solver_priority() const {
return JOINT_DEFAULT_SOLVER_PRIORITY;
}
void JoltJoint3D::set_solver_priority(int p_priority) {
if (p_priority != JOINT_DEFAULT_SOLVER_PRIORITY) {
WARN_PRINT(vformat("Joint solver priority is not supported when using Jolt Physics. Any such value will be ignored. This joint connects %s.", _bodies_to_string()));
}
}
void JoltJoint3D::set_solver_velocity_iterations(int p_iterations) {
if (velocity_iterations == p_iterations) {
return;
}
velocity_iterations = p_iterations;
_iterations_changed();
}
void JoltJoint3D::set_solver_position_iterations(int p_iterations) {
if (position_iterations == p_iterations) {
return;
}
position_iterations = p_iterations;
_iterations_changed();
}
void JoltJoint3D::set_collision_disabled(bool p_disabled) {
collision_disabled = p_disabled;
if (body_a == nullptr || body_b == nullptr) {
return;
}
PhysicsServer3D *physics_server = PhysicsServer3D::get_singleton();
if (collision_disabled) {
physics_server->body_add_collision_exception(body_a->get_rid(), body_b->get_rid());
physics_server->body_add_collision_exception(body_b->get_rid(), body_a->get_rid());
} else {
physics_server->body_remove_collision_exception(body_a->get_rid(), body_b->get_rid());
physics_server->body_remove_collision_exception(body_b->get_rid(), body_a->get_rid());
}
}
void JoltJoint3D::destroy() {
if (jolt_ref == nullptr) {
return;
}
JoltSpace3D *space = get_space();
if (space != nullptr) {
space->remove_joint(this);
}
jolt_ref = nullptr;
}

View File

@@ -0,0 +1,104 @@
/**************************************************************************/
/* jolt_joint_3d.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#include "servers/physics_server_3d.h"
#include "Jolt/Jolt.h"
#include "Jolt/Physics/Constraints/Constraint.h"
class JoltBody3D;
class JoltSpace3D;
class JoltJoint3D {
protected:
bool enabled = true;
bool collision_disabled = false;
int velocity_iterations = 0;
int position_iterations = 0;
JPH::Ref<JPH::Constraint> jolt_ref;
JoltBody3D *body_a = nullptr;
JoltBody3D *body_b = nullptr;
RID rid;
Transform3D local_ref_a;
Transform3D local_ref_b;
void _shift_reference_frames(const Vector3 &p_linear_shift, const Vector3 &p_angular_shift, Transform3D &r_shifted_ref_a, Transform3D &r_shifted_ref_b);
void _wake_up_bodies();
void _update_enabled();
void _update_iterations();
void _enabled_changed();
void _iterations_changed();
String _bodies_to_string() const;
public:
JoltJoint3D() = default;
JoltJoint3D(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);
virtual ~JoltJoint3D();
virtual PhysicsServer3D::JointType get_type() const { return PhysicsServer3D::JOINT_TYPE_MAX; }
RID get_rid() const { return rid; }
void set_rid(const RID &p_rid) { rid = p_rid; }
JoltSpace3D *get_space() const;
JPH::Constraint *get_jolt_ref() const { return jolt_ref; }
bool is_enabled() const { return enabled; }
void set_enabled(bool p_enabled);
int get_solver_priority() const;
void set_solver_priority(int p_priority);
int get_solver_velocity_iterations() const { return velocity_iterations; }
void set_solver_velocity_iterations(int p_iterations);
int get_solver_position_iterations() const { return position_iterations; }
void set_solver_position_iterations(int p_iterations);
bool is_collision_disabled() const { return collision_disabled; }
void set_collision_disabled(bool p_disabled);
void destroy();
virtual void rebuild() {}
};

View File

@@ -0,0 +1,160 @@
/**************************************************************************/
/* jolt_pin_joint_3d.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include "jolt_pin_joint_3d.h"
#include "../misc/jolt_type_conversions.h"
#include "../objects/jolt_body_3d.h"
#include "../spaces/jolt_space_3d.h"
#include "Jolt/Physics/Constraints/PointConstraint.h"
namespace {
constexpr double PIN_DEFAULT_BIAS = 0.3;
constexpr double PIN_DEFAULT_DAMPING = 1.0;
constexpr double PIN_DEFAULT_IMPULSE_CLAMP = 0.0;
} // namespace
JPH::Constraint *JoltPinJoint3D::_build_pin(JPH::Body *p_jolt_body_a, JPH::Body *p_jolt_body_b, const Transform3D &p_shifted_ref_a, const Transform3D &p_shifted_ref_b) {
JPH::PointConstraintSettings constraint_settings;
constraint_settings.mSpace = JPH::EConstraintSpace::LocalToBodyCOM;
constraint_settings.mPoint1 = to_jolt_r(p_shifted_ref_a.origin);
constraint_settings.mPoint2 = to_jolt_r(p_shifted_ref_b.origin);
if (p_jolt_body_a == nullptr) {
return constraint_settings.Create(JPH::Body::sFixedToWorld, *p_jolt_body_b);
} else if (p_jolt_body_b == nullptr) {
return constraint_settings.Create(*p_jolt_body_a, JPH::Body::sFixedToWorld);
} else {
return constraint_settings.Create(*p_jolt_body_a, *p_jolt_body_b);
}
}
void JoltPinJoint3D::_points_changed() {
rebuild();
_wake_up_bodies();
}
JoltPinJoint3D::JoltPinJoint3D(const JoltJoint3D &p_old_joint, JoltBody3D *p_body_a, JoltBody3D *p_body_b, const Vector3 &p_local_a, const Vector3 &p_local_b) :
JoltJoint3D(p_old_joint, p_body_a, p_body_b, Transform3D({}, p_local_a), Transform3D({}, p_local_b)) {
rebuild();
}
void JoltPinJoint3D::set_local_a(const Vector3 &p_local_a) {
local_ref_a = Transform3D({}, p_local_a);
_points_changed();
}
void JoltPinJoint3D::set_local_b(const Vector3 &p_local_b) {
local_ref_b = Transform3D({}, p_local_b);
_points_changed();
}
double JoltPinJoint3D::get_param(PhysicsServer3D::PinJointParam p_param) const {
switch (p_param) {
case PhysicsServer3D::PIN_JOINT_BIAS: {
return PIN_DEFAULT_BIAS;
}
case PhysicsServer3D::PIN_JOINT_DAMPING: {
return PIN_DEFAULT_DAMPING;
}
case PhysicsServer3D::PIN_JOINT_IMPULSE_CLAMP: {
return PIN_DEFAULT_IMPULSE_CLAMP;
}
default: {
ERR_FAIL_V_MSG(0.0, vformat("Unhandled pin joint parameter: '%d'. This should not happen. Please report this.", p_param));
}
}
}
void JoltPinJoint3D::set_param(PhysicsServer3D::PinJointParam p_param, double p_value) {
switch (p_param) {
case PhysicsServer3D::PIN_JOINT_BIAS: {
if (!Math::is_equal_approx(p_value, PIN_DEFAULT_BIAS)) {
WARN_PRINT(vformat("Pin joint bias is not supported when using Jolt Physics. Any such value will be ignored. This joint connects %s.", _bodies_to_string()));
}
} break;
case PhysicsServer3D::PIN_JOINT_DAMPING: {
if (!Math::is_equal_approx(p_value, PIN_DEFAULT_DAMPING)) {
WARN_PRINT(vformat("Pin joint damping is not supported when using Jolt Physics. Any such value will be ignored. This joint connects %s.", _bodies_to_string()));
}
} break;
case PhysicsServer3D::PIN_JOINT_IMPULSE_CLAMP: {
if (!Math::is_equal_approx(p_value, PIN_DEFAULT_IMPULSE_CLAMP)) {
WARN_PRINT(vformat("Pin joint impulse clamp is not supported when using Jolt Physics. Any such value will be ignored. This joint connects %s.", _bodies_to_string()));
}
} break;
default: {
ERR_FAIL_MSG(vformat("Unhandled pin joint parameter: '%d'. This should not happen. Please report this.", p_param));
} break;
}
}
float JoltPinJoint3D::get_applied_force() const {
JPH::PointConstraint *constraint = static_cast<JPH::PointConstraint *>(jolt_ref.GetPtr());
ERR_FAIL_NULL_V(constraint, 0.0f);
JoltSpace3D *space = get_space();
ERR_FAIL_NULL_V(space, 0.0f);
const float last_step = space->get_last_step();
if (unlikely(last_step == 0.0f)) {
return 0.0f;
}
return constraint->GetTotalLambdaPosition().Length() / last_step;
}
void JoltPinJoint3D::rebuild() {
destroy();
JoltSpace3D *space = get_space();
if (space == nullptr) {
return;
}
JPH::Body *jolt_body_a = body_a != nullptr ? body_a->get_jolt_body() : nullptr;
JPH::Body *jolt_body_b = body_b != nullptr ? body_b->get_jolt_body() : nullptr;
ERR_FAIL_COND(jolt_body_a == nullptr && jolt_body_b == nullptr);
Transform3D shifted_ref_a;
Transform3D shifted_ref_b;
_shift_reference_frames(Vector3(), Vector3(), shifted_ref_a, shifted_ref_b);
jolt_ref = _build_pin(jolt_body_a, jolt_body_b, shifted_ref_a, shifted_ref_b);
space->add_joint(this);
_update_enabled();
_update_iterations();
}

View File

@@ -0,0 +1,61 @@
/**************************************************************************/
/* jolt_pin_joint_3d.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#include "jolt_joint_3d.h"
#include "Jolt/Jolt.h"
#include "Jolt/Physics/Constraints/SliderConstraint.h"
class JoltPinJoint3D final : public JoltJoint3D {
static JPH::Constraint *_build_pin(JPH::Body *p_jolt_body_a, JPH::Body *p_jolt_body_b, const Transform3D &p_shifted_ref_a, const Transform3D &p_shifted_ref_b);
void _points_changed();
public:
JoltPinJoint3D(const JoltJoint3D &p_old_joint, JoltBody3D *p_body_a, JoltBody3D *p_body_b, const Vector3 &p_local_a, const Vector3 &p_local_b);
virtual PhysicsServer3D::JointType get_type() const override { return PhysicsServer3D::JOINT_TYPE_PIN; }
Vector3 get_local_a() const { return local_ref_a.origin; }
void set_local_a(const Vector3 &p_local_a);
Vector3 get_local_b() const { return local_ref_b.origin; }
void set_local_b(const Vector3 &p_local_b);
double get_param(PhysicsServer3D::PinJointParam p_param) const;
void set_param(PhysicsServer3D::PinJointParam p_param, double p_value);
float get_applied_force() const;
virtual void rebuild() override;
};

View File

@@ -0,0 +1,533 @@
/**************************************************************************/
/* jolt_slider_joint_3d.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include "jolt_slider_joint_3d.h"
#include "../misc/jolt_type_conversions.h"
#include "../objects/jolt_body_3d.h"
#include "../spaces/jolt_space_3d.h"
#include "Jolt/Physics/Constraints/FixedConstraint.h"
#include "Jolt/Physics/Constraints/SliderConstraint.h"
namespace {
constexpr double SLIDER_DEFAULT_LINEAR_LIMIT_SOFTNESS = 1.0;
constexpr double SLIDER_DEFAULT_LINEAR_LIMIT_RESTITUTION = 0.7;
constexpr double SLIDER_DEFAULT_LINEAR_LIMIT_DAMPING = 1.0;
constexpr double SLIDER_DEFAULT_LINEAR_MOTION_SOFTNESS = 1.0;
constexpr double SLIDER_DEFAULT_LINEAR_MOTION_RESTITUTION = 0.7;
constexpr double SLIDER_DEFAULT_LINEAR_MOTION_DAMPING = 0.0;
constexpr double SLIDER_DEFAULT_LINEAR_ORTHO_SOFTNESS = 1.0;
constexpr double SLIDER_DEFAULT_LINEAR_ORTHO_RESTITUTION = 0.7;
constexpr double SLIDER_DEFAULT_LINEAR_ORTHO_DAMPING = 1.0;
constexpr double SLIDER_DEFAULT_ANGULAR_LIMIT_UPPER = 0.0;
constexpr double SLIDER_DEFAULT_ANGULAR_LIMIT_LOWER = 0.0;
constexpr double SLIDER_DEFAULT_ANGULAR_LIMIT_SOFTNESS = 1.0;
constexpr double SLIDER_DEFAULT_ANGULAR_LIMIT_RESTITUTION = 0.7;
constexpr double SLIDER_DEFAULT_ANGULAR_LIMIT_DAMPING = 0.0;
constexpr double SLIDER_DEFAULT_ANGULAR_MOTION_SOFTNESS = 1.0;
constexpr double SLIDER_DEFAULT_ANGULAR_MOTION_RESTITUTION = 0.7;
constexpr double SLIDER_DEFAULT_ANGULAR_MOTION_DAMPING = 1.0;
constexpr double SLIDER_DEFAULT_ANGULAR_ORTHO_SOFTNESS = 1.0;
constexpr double SLIDER_DEFAULT_ANGULAR_ORTHO_RESTITUTION = 0.7;
constexpr double SLIDER_DEFAULT_ANGULAR_ORTHO_DAMPING = 1.0;
} // namespace
JPH::Constraint *JoltSliderJoint3D::_build_slider(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_limit) const {
JPH::SliderConstraintSettings constraint_settings;
constraint_settings.mSpace = JPH::EConstraintSpace::LocalToBodyCOM;
constraint_settings.mAutoDetectPoint = false;
constraint_settings.mPoint1 = to_jolt_r(p_shifted_ref_a.origin);
constraint_settings.mSliderAxis1 = to_jolt(p_shifted_ref_a.basis.get_column(Vector3::AXIS_X));
constraint_settings.mNormalAxis1 = to_jolt(p_shifted_ref_a.basis.get_column(Vector3::AXIS_Z));
constraint_settings.mPoint2 = to_jolt_r(p_shifted_ref_b.origin);
constraint_settings.mSliderAxis2 = to_jolt(p_shifted_ref_b.basis.get_column(Vector3::AXIS_X));
constraint_settings.mNormalAxis2 = to_jolt(p_shifted_ref_b.basis.get_column(Vector3::AXIS_Z));
constraint_settings.mLimitsMin = -p_limit;
constraint_settings.mLimitsMax = p_limit;
if (limit_spring_enabled) {
constraint_settings.mLimitsSpringSettings.mFrequency = (float)limit_spring_frequency;
constraint_settings.mLimitsSpringSettings.mDamping = (float)limit_spring_damping;
}
if (p_jolt_body_a == nullptr) {
return constraint_settings.Create(JPH::Body::sFixedToWorld, *p_jolt_body_b);
} else if (p_jolt_body_b == nullptr) {
return constraint_settings.Create(*p_jolt_body_a, JPH::Body::sFixedToWorld);
} else {
return constraint_settings.Create(*p_jolt_body_a, *p_jolt_body_b);
}
}
JPH::Constraint *JoltSliderJoint3D::_build_fixed(JPH::Body *p_jolt_body_a, JPH::Body *p_jolt_body_b, const Transform3D &p_shifted_ref_a, const Transform3D &p_shifted_ref_b) const {
JPH::FixedConstraintSettings constraint_settings;
constraint_settings.mSpace = JPH::EConstraintSpace::LocalToBodyCOM;
constraint_settings.mAutoDetectPoint = false;
constraint_settings.mPoint1 = to_jolt_r(p_shifted_ref_a.origin);
constraint_settings.mAxisX1 = to_jolt(p_shifted_ref_a.basis.get_column(Vector3::AXIS_X));
constraint_settings.mAxisY1 = to_jolt(p_shifted_ref_a.basis.get_column(Vector3::AXIS_Y));
constraint_settings.mPoint2 = to_jolt_r(p_shifted_ref_b.origin);
constraint_settings.mAxisX2 = to_jolt(p_shifted_ref_b.basis.get_column(Vector3::AXIS_X));
constraint_settings.mAxisY2 = to_jolt(p_shifted_ref_b.basis.get_column(Vector3::AXIS_Y));
if (p_jolt_body_a == nullptr) {
return constraint_settings.Create(JPH::Body::sFixedToWorld, *p_jolt_body_b);
} else if (p_jolt_body_b == nullptr) {
return constraint_settings.Create(*p_jolt_body_a, JPH::Body::sFixedToWorld);
} else {
return constraint_settings.Create(*p_jolt_body_a, *p_jolt_body_b);
}
}
void JoltSliderJoint3D::_update_motor_state() {
if (unlikely(_is_fixed())) {
return;
}
if (JPH::SliderConstraint *constraint = static_cast<JPH::SliderConstraint *>(jolt_ref.GetPtr())) {
constraint->SetMotorState(motor_enabled ? JPH::EMotorState::Velocity : JPH::EMotorState::Off);
}
}
void JoltSliderJoint3D::_update_motor_velocity() {
if (unlikely(_is_fixed())) {
return;
}
if (JPH::SliderConstraint *constraint = static_cast<JPH::SliderConstraint *>(jolt_ref.GetPtr())) {
constraint->SetTargetVelocity((float)motor_target_speed);
}
}
void JoltSliderJoint3D::_update_motor_limit() {
if (unlikely(_is_fixed())) {
return;
}
if (JPH::SliderConstraint *constraint = static_cast<JPH::SliderConstraint *>(jolt_ref.GetPtr())) {
JPH::MotorSettings &motor_settings = constraint->GetMotorSettings();
motor_settings.mMinForceLimit = (float)-motor_max_force;
motor_settings.mMaxForceLimit = (float)motor_max_force;
}
}
void JoltSliderJoint3D::_limits_changed() {
rebuild();
_wake_up_bodies();
}
void JoltSliderJoint3D::_limit_spring_changed() {
rebuild();
_wake_up_bodies();
}
void JoltSliderJoint3D::_motor_state_changed() {
_update_motor_state();
_wake_up_bodies();
}
void JoltSliderJoint3D::_motor_speed_changed() {
_update_motor_velocity();
_wake_up_bodies();
}
void JoltSliderJoint3D::_motor_limit_changed() {
_update_motor_limit();
_wake_up_bodies();
}
JoltSliderJoint3D::JoltSliderJoint3D(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) :
JoltJoint3D(p_old_joint, p_body_a, p_body_b, p_local_ref_a, p_local_ref_b) {
rebuild();
}
double JoltSliderJoint3D::get_param(PhysicsServer3D::SliderJointParam p_param) const {
switch (p_param) {
case PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_UPPER: {
return limit_upper;
}
case PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_LOWER: {
return limit_lower;
}
case PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_SOFTNESS: {
return SLIDER_DEFAULT_LINEAR_LIMIT_SOFTNESS;
}
case PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_RESTITUTION: {
return SLIDER_DEFAULT_LINEAR_LIMIT_RESTITUTION;
}
case PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_DAMPING: {
return SLIDER_DEFAULT_LINEAR_LIMIT_DAMPING;
}
case PhysicsServer3D::SLIDER_JOINT_LINEAR_MOTION_SOFTNESS: {
return SLIDER_DEFAULT_LINEAR_MOTION_SOFTNESS;
}
case PhysicsServer3D::SLIDER_JOINT_LINEAR_MOTION_RESTITUTION: {
return SLIDER_DEFAULT_LINEAR_MOTION_RESTITUTION;
}
case PhysicsServer3D::SLIDER_JOINT_LINEAR_MOTION_DAMPING: {
return SLIDER_DEFAULT_LINEAR_MOTION_DAMPING;
}
case PhysicsServer3D::SLIDER_JOINT_LINEAR_ORTHOGONAL_SOFTNESS: {
return SLIDER_DEFAULT_LINEAR_ORTHO_SOFTNESS;
}
case PhysicsServer3D::SLIDER_JOINT_LINEAR_ORTHOGONAL_RESTITUTION: {
return SLIDER_DEFAULT_LINEAR_ORTHO_RESTITUTION;
}
case PhysicsServer3D::SLIDER_JOINT_LINEAR_ORTHOGONAL_DAMPING: {
return SLIDER_DEFAULT_LINEAR_ORTHO_DAMPING;
}
case PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_UPPER: {
return SLIDER_DEFAULT_ANGULAR_LIMIT_UPPER;
}
case PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_LOWER: {
return SLIDER_DEFAULT_ANGULAR_LIMIT_LOWER;
}
case PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_SOFTNESS: {
return SLIDER_DEFAULT_ANGULAR_LIMIT_SOFTNESS;
}
case PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_RESTITUTION: {
return SLIDER_DEFAULT_ANGULAR_LIMIT_RESTITUTION;
}
case PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_DAMPING: {
return SLIDER_DEFAULT_ANGULAR_LIMIT_DAMPING;
}
case PhysicsServer3D::SLIDER_JOINT_ANGULAR_MOTION_SOFTNESS: {
return SLIDER_DEFAULT_ANGULAR_MOTION_SOFTNESS;
}
case PhysicsServer3D::SLIDER_JOINT_ANGULAR_MOTION_RESTITUTION: {
return SLIDER_DEFAULT_ANGULAR_MOTION_RESTITUTION;
}
case PhysicsServer3D::SLIDER_JOINT_ANGULAR_MOTION_DAMPING: {
return SLIDER_DEFAULT_ANGULAR_MOTION_DAMPING;
}
case PhysicsServer3D::SLIDER_JOINT_ANGULAR_ORTHOGONAL_SOFTNESS: {
return SLIDER_DEFAULT_ANGULAR_ORTHO_SOFTNESS;
}
case PhysicsServer3D::SLIDER_JOINT_ANGULAR_ORTHOGONAL_RESTITUTION: {
return SLIDER_DEFAULT_ANGULAR_ORTHO_RESTITUTION;
}
case PhysicsServer3D::SLIDER_JOINT_ANGULAR_ORTHOGONAL_DAMPING: {
return SLIDER_DEFAULT_ANGULAR_ORTHO_DAMPING;
}
default: {
ERR_FAIL_V_MSG(0.0, vformat("Unhandled slider joint parameter: '%d'. This should not happen. Please report this.", p_param));
}
}
}
void JoltSliderJoint3D::set_param(PhysicsServer3D::SliderJointParam p_param, double p_value) {
switch (p_param) {
case PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_UPPER: {
limit_upper = p_value;
_limits_changed();
} break;
case PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_LOWER: {
limit_lower = p_value;
_limits_changed();
} break;
case PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_SOFTNESS: {
if (!Math::is_equal_approx(p_value, SLIDER_DEFAULT_LINEAR_LIMIT_SOFTNESS)) {
WARN_PRINT(vformat("Slider joint linear limit softness is not supported when using Jolt Physics. Any such value will be ignored. This joint connects %s.", _bodies_to_string()));
}
} break;
case PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_RESTITUTION: {
if (!Math::is_equal_approx(p_value, SLIDER_DEFAULT_LINEAR_LIMIT_RESTITUTION)) {
WARN_PRINT(vformat("Slider joint linear limit restitution is not supported when using Jolt Physics. Any such value will be ignored. This joint connects %s.", _bodies_to_string()));
}
} break;
case PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_DAMPING: {
if (!Math::is_equal_approx(p_value, SLIDER_DEFAULT_LINEAR_LIMIT_DAMPING)) {
WARN_PRINT(vformat("Slider joint linear limit damping is not supported when using Jolt Physics. Any such value will be ignored. This joint connects %s.", _bodies_to_string()));
}
} break;
case PhysicsServer3D::SLIDER_JOINT_LINEAR_MOTION_SOFTNESS: {
if (!Math::is_equal_approx(p_value, SLIDER_DEFAULT_LINEAR_MOTION_SOFTNESS)) {
WARN_PRINT(vformat("Slider joint linear motion softness is not supported when using Jolt Physics. Any such value will be ignored. This joint connects %s.", _bodies_to_string()));
}
} break;
case PhysicsServer3D::SLIDER_JOINT_LINEAR_MOTION_RESTITUTION: {
if (!Math::is_equal_approx(p_value, SLIDER_DEFAULT_LINEAR_MOTION_RESTITUTION)) {
WARN_PRINT(vformat("Slider joint linear motion restitution is not supported when using Jolt Physics. Any such value will be ignored. This joint connects %s.", _bodies_to_string()));
}
} break;
case PhysicsServer3D::SLIDER_JOINT_LINEAR_MOTION_DAMPING: {
if (!Math::is_equal_approx(p_value, SLIDER_DEFAULT_LINEAR_MOTION_DAMPING)) {
WARN_PRINT(vformat("Slider joint linear motion damping is not supported when using Jolt Physics. Any such value will be ignored. This joint connects %s.", _bodies_to_string()));
}
} break;
case PhysicsServer3D::SLIDER_JOINT_LINEAR_ORTHOGONAL_SOFTNESS: {
if (!Math::is_equal_approx(p_value, SLIDER_DEFAULT_LINEAR_ORTHO_SOFTNESS)) {
WARN_PRINT(vformat("Slider joint linear ortho softness is not supported when using Jolt Physics. Any such value will be ignored. This joint connects %s.", _bodies_to_string()));
}
} break;
case PhysicsServer3D::SLIDER_JOINT_LINEAR_ORTHOGONAL_RESTITUTION: {
if (!Math::is_equal_approx(p_value, SLIDER_DEFAULT_LINEAR_ORTHO_RESTITUTION)) {
WARN_PRINT(vformat("Slider joint linear ortho restitution is not supported when using Jolt Physics. Any such value will be ignored. This joint connects %s.", _bodies_to_string()));
}
} break;
case PhysicsServer3D::SLIDER_JOINT_LINEAR_ORTHOGONAL_DAMPING: {
if (!Math::is_equal_approx(p_value, SLIDER_DEFAULT_LINEAR_ORTHO_DAMPING)) {
WARN_PRINT(vformat("Slider joint linear ortho damping is not supported when using Jolt Physics. Any such value will be ignored. This joint connects %s.", _bodies_to_string()));
}
} break;
case PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_UPPER: {
if (!Math::is_equal_approx(p_value, SLIDER_DEFAULT_ANGULAR_LIMIT_UPPER)) {
WARN_PRINT(vformat("Slider joint angular limits are not supported when using Jolt Physics. Any such value will be ignored. Try using Generic6DOFJoint3D instead. This joint connects %s.", _bodies_to_string()));
}
} break;
case PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_LOWER: {
if (!Math::is_equal_approx(p_value, SLIDER_DEFAULT_ANGULAR_LIMIT_LOWER)) {
WARN_PRINT(vformat("Slider joint angular limits are not supported when using Jolt Physics. Any such value will be ignored. Try using Generic6DOFJoint3D instead. This joint connects %s.", _bodies_to_string()));
}
} break;
case PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_SOFTNESS: {
if (!Math::is_equal_approx(p_value, SLIDER_DEFAULT_ANGULAR_LIMIT_SOFTNESS)) {
WARN_PRINT(vformat("Slider joint angular limit softness is not supported when using Jolt Physics. Any such value will be ignored. This joint connects %s.", _bodies_to_string()));
}
} break;
case PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_RESTITUTION: {
if (!Math::is_equal_approx(p_value, SLIDER_DEFAULT_ANGULAR_LIMIT_RESTITUTION)) {
WARN_PRINT(vformat("Slider joint angular limit restitution is not supported when using Jolt Physics. Any such value will be ignored. This joint connects %s.", _bodies_to_string()));
}
} break;
case PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_DAMPING: {
if (!Math::is_equal_approx(p_value, SLIDER_DEFAULT_ANGULAR_LIMIT_DAMPING)) {
WARN_PRINT(vformat("Slider joint angular limit damping is not supported when using Jolt Physics. Any such value will be ignored. This joint connects %s.", _bodies_to_string()));
}
} break;
case PhysicsServer3D::SLIDER_JOINT_ANGULAR_MOTION_SOFTNESS: {
if (!Math::is_equal_approx(p_value, SLIDER_DEFAULT_ANGULAR_MOTION_SOFTNESS)) {
WARN_PRINT(vformat("Slider joint angular motion softness is not supported when using Jolt Physics. Any such value will be ignored. This joint connects %s.", _bodies_to_string()));
}
} break;
case PhysicsServer3D::SLIDER_JOINT_ANGULAR_MOTION_RESTITUTION: {
if (!Math::is_equal_approx(p_value, SLIDER_DEFAULT_ANGULAR_MOTION_RESTITUTION)) {
WARN_PRINT(vformat("Slider joint angular motion restitution is not supported when using Jolt Physics. Any such value will be ignored. This joint connects %s.", _bodies_to_string()));
}
} break;
case PhysicsServer3D::SLIDER_JOINT_ANGULAR_MOTION_DAMPING: {
if (!Math::is_equal_approx(p_value, SLIDER_DEFAULT_ANGULAR_MOTION_DAMPING)) {
WARN_PRINT(vformat("Slider joint angular motion damping is not supported when using Jolt Physics. Any such value will be ignored. This joint connects %s.", _bodies_to_string()));
}
} break;
case PhysicsServer3D::SLIDER_JOINT_ANGULAR_ORTHOGONAL_SOFTNESS: {
if (!Math::is_equal_approx(p_value, SLIDER_DEFAULT_ANGULAR_ORTHO_SOFTNESS)) {
WARN_PRINT(vformat("Slider joint angular ortho softness is not supported when using Jolt Physics. Any such value will be ignored. This joint connects %s.", _bodies_to_string()));
}
} break;
case PhysicsServer3D::SLIDER_JOINT_ANGULAR_ORTHOGONAL_RESTITUTION: {
if (!Math::is_equal_approx(p_value, SLIDER_DEFAULT_ANGULAR_ORTHO_RESTITUTION)) {
WARN_PRINT(vformat("Slider joint angular ortho restitution is not supported when using Jolt Physics. Any such value will be ignored. This joint connects %s.", _bodies_to_string()));
}
} break;
case PhysicsServer3D::SLIDER_JOINT_ANGULAR_ORTHOGONAL_DAMPING: {
if (!Math::is_equal_approx(p_value, SLIDER_DEFAULT_ANGULAR_ORTHO_DAMPING)) {
WARN_PRINT(vformat("Slider joint angular ortho damping is not supported when using Jolt Physics. Any such value will be ignored. This joint connects %s.", _bodies_to_string()));
}
} break;
default: {
ERR_FAIL_MSG(vformat("Unhandled slider joint parameter: '%d'. This should not happen. Please report this.", p_param));
} break;
}
}
double JoltSliderJoint3D::get_jolt_param(JoltParameter p_param) const {
switch (p_param) {
case JoltPhysicsServer3D::SLIDER_JOINT_LIMIT_SPRING_FREQUENCY: {
return limit_spring_frequency;
}
case JoltPhysicsServer3D::SLIDER_JOINT_LIMIT_SPRING_DAMPING: {
return limit_spring_damping;
}
case JoltPhysicsServer3D::SLIDER_JOINT_MOTOR_TARGET_VELOCITY: {
return motor_target_speed;
}
case JoltPhysicsServer3D::SLIDER_JOINT_MOTOR_MAX_FORCE: {
return motor_max_force;
}
default: {
ERR_FAIL_V_MSG(0.0, vformat("Unhandled parameter: '%d'. This should not happen. Please report this.", p_param));
}
}
}
void JoltSliderJoint3D::set_jolt_param(JoltParameter p_param, double p_value) {
switch (p_param) {
case JoltPhysicsServer3D::SLIDER_JOINT_LIMIT_SPRING_FREQUENCY: {
limit_spring_frequency = p_value;
_limit_spring_changed();
} break;
case JoltPhysicsServer3D::SLIDER_JOINT_LIMIT_SPRING_DAMPING: {
limit_spring_damping = p_value;
_limit_spring_changed();
} break;
case JoltPhysicsServer3D::SLIDER_JOINT_MOTOR_TARGET_VELOCITY: {
motor_target_speed = p_value;
_motor_speed_changed();
} break;
case JoltPhysicsServer3D::SLIDER_JOINT_MOTOR_MAX_FORCE: {
motor_max_force = p_value;
_motor_limit_changed();
} break;
default: {
ERR_FAIL_MSG(vformat("Unhandled parameter: '%d'. This should not happen. Please report this.", p_param));
} break;
}
}
bool JoltSliderJoint3D::get_jolt_flag(JoltFlag p_flag) const {
switch (p_flag) {
case JoltPhysicsServer3D::SLIDER_JOINT_FLAG_USE_LIMIT: {
return limits_enabled;
}
case JoltPhysicsServer3D::SLIDER_JOINT_FLAG_USE_LIMIT_SPRING: {
return limit_spring_enabled;
}
case JoltPhysicsServer3D::SLIDER_JOINT_FLAG_ENABLE_MOTOR: {
return motor_enabled;
}
default: {
ERR_FAIL_V_MSG(false, vformat("Unhandled flag: '%d'. This should not happen. Please report this.", p_flag));
}
}
}
void JoltSliderJoint3D::set_jolt_flag(JoltFlag p_flag, bool p_enabled) {
switch (p_flag) {
case JoltPhysicsServer3D::SLIDER_JOINT_FLAG_USE_LIMIT: {
limits_enabled = p_enabled;
_limits_changed();
} break;
case JoltPhysicsServer3D::SLIDER_JOINT_FLAG_USE_LIMIT_SPRING: {
limit_spring_enabled = p_enabled;
_limit_spring_changed();
} break;
case JoltPhysicsServer3D::SLIDER_JOINT_FLAG_ENABLE_MOTOR: {
motor_enabled = p_enabled;
_motor_state_changed();
} break;
default: {
ERR_FAIL_MSG(vformat("Unhandled flag: '%d'. This should not happen. Please report this.", p_flag));
} break;
}
}
float JoltSliderJoint3D::get_applied_force() const {
ERR_FAIL_NULL_V(jolt_ref, 0.0f);
JoltSpace3D *space = get_space();
ERR_FAIL_NULL_V(space, 0.0f);
const float last_step = space->get_last_step();
if (unlikely(last_step == 0.0f)) {
return 0.0f;
}
if (_is_fixed()) {
JPH::FixedConstraint *constraint = static_cast<JPH::FixedConstraint *>(jolt_ref.GetPtr());
return constraint->GetTotalLambdaPosition().Length() / last_step;
} else {
JPH::SliderConstraint *constraint = static_cast<JPH::SliderConstraint *>(jolt_ref.GetPtr());
const JPH::Vec3 total_lambda = JPH::Vec3(constraint->GetTotalLambdaPosition()[0], constraint->GetTotalLambdaPosition()[1], constraint->GetTotalLambdaPositionLimits() + constraint->GetTotalLambdaMotor());
return total_lambda.Length() / last_step;
}
}
float JoltSliderJoint3D::get_applied_torque() const {
ERR_FAIL_NULL_V(jolt_ref, 0.0f);
JoltSpace3D *space = get_space();
ERR_FAIL_NULL_V(space, 0.0f);
const float last_step = space->get_last_step();
if (unlikely(last_step == 0.0f)) {
return 0.0f;
}
if (_is_fixed()) {
JPH::FixedConstraint *constraint = static_cast<JPH::FixedConstraint *>(jolt_ref.GetPtr());
return constraint->GetTotalLambdaRotation().Length() / last_step;
} else {
JPH::SliderConstraint *constraint = static_cast<JPH::SliderConstraint *>(jolt_ref.GetPtr());
return constraint->GetTotalLambdaRotation().Length() / last_step;
}
}
void JoltSliderJoint3D::rebuild() {
destroy();
JoltSpace3D *space = get_space();
if (space == nullptr) {
return;
}
JPH::Body *jolt_body_a = body_a != nullptr ? body_a->get_jolt_body() : nullptr;
JPH::Body *jolt_body_b = body_b != nullptr ? body_b->get_jolt_body() : nullptr;
ERR_FAIL_COND(jolt_body_a == nullptr && jolt_body_b == nullptr);
float ref_shift = 0.0f;
float limit = FLT_MAX;
if (limits_enabled && limit_lower <= limit_upper) {
const double limit_midpoint = (limit_lower + limit_upper) / 2.0f;
ref_shift = float(-limit_midpoint);
limit = float(limit_upper - limit_midpoint);
}
Transform3D shifted_ref_a;
Transform3D shifted_ref_b;
_shift_reference_frames(Vector3(ref_shift, 0.0f, 0.0f), Vector3(), shifted_ref_a, shifted_ref_b);
if (_is_fixed()) {
jolt_ref = _build_fixed(jolt_body_a, jolt_body_b, shifted_ref_a, shifted_ref_b);
} else {
jolt_ref = _build_slider(jolt_body_a, jolt_body_b, shifted_ref_a, shifted_ref_b, limit);
}
space->add_joint(this);
_update_enabled();
_update_iterations();
_update_motor_state();
_update_motor_velocity();
_update_motor_limit();
}

View File

@@ -0,0 +1,93 @@
/**************************************************************************/
/* jolt_slider_joint_3d.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#include "../jolt_physics_server_3d.h"
#include "jolt_joint_3d.h"
#include "Jolt/Jolt.h"
#include "Jolt/Physics/Constraints/SliderConstraint.h"
class JoltSliderJoint3D final : public JoltJoint3D {
typedef PhysicsServer3D::SliderJointParam Parameter;
typedef JoltPhysicsServer3D::SliderJointParamJolt JoltParameter;
typedef JoltPhysicsServer3D::SliderJointFlagJolt JoltFlag;
double limit_upper = 0.0;
double limit_lower = 0.0;
double limit_spring_frequency = 0.0;
double limit_spring_damping = 0.0;
double motor_target_speed = 0.0f;
double motor_max_force = FLT_MAX;
bool limits_enabled = true;
bool limit_spring_enabled = false;
bool motor_enabled = false;
JPH::Constraint *_build_slider(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_limit) const;
JPH::Constraint *_build_fixed(JPH::Body *p_jolt_body_a, JPH::Body *p_jolt_body_b, const Transform3D &p_shifted_ref_a, const Transform3D &p_shifted_ref_b) const;
bool _is_sprung() const { return limit_spring_enabled && limit_spring_frequency > 0.0; }
bool _is_fixed() const { return limits_enabled && limit_lower == limit_upper && !_is_sprung(); }
void _update_motor_state();
void _update_motor_velocity();
void _update_motor_limit();
void _limits_changed();
void _limit_spring_changed();
void _motor_state_changed();
void _motor_speed_changed();
void _motor_limit_changed();
public:
JoltSliderJoint3D(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);
virtual PhysicsServer3D::JointType get_type() const override { return PhysicsServer3D::JOINT_TYPE_SLIDER; }
double get_param(PhysicsServer3D::SliderJointParam p_param) const;
void set_param(PhysicsServer3D::SliderJointParam p_param, double p_value);
double get_jolt_param(JoltParameter p_param) const;
void set_jolt_param(JoltParameter p_param, double p_value);
bool get_jolt_flag(JoltFlag p_flag) const;
void set_jolt_flag(JoltFlag p_flag, bool p_enabled);
float get_applied_force() const;
float get_applied_torque() const;
virtual void rebuild() override;
};