Add quaternion rotation targets to Generic6DOFJoint3D:
- SixDOF target orientations supported for Jolt, trivial fallback to identity quaternion is used when explicit angular rotation is unconfigured or unsupported - Conversion between BS and CS is handled inside, surface exposes BS Implements godotengine/godot-proposals#3891
This commit is contained in:
@@ -10,6 +10,18 @@
|
||||
<tutorials>
|
||||
</tutorials>
|
||||
<methods>
|
||||
<method name="clear_angular_target_rotation">
|
||||
<return type="void" />
|
||||
<description>
|
||||
Clears the quaternion angular target. After clearing, the joint is driven by [constant PARAM_ANGULAR_SPRING_EQUILIBRIUM_POINT] on each axis as configured.
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_angular_target_rotation" qualifiers="const">
|
||||
<return type="Quaternion" />
|
||||
<description>
|
||||
Returns the joint's current angular target as a body-space quaternion. If no explicit target was set via [method set_angular_target_rotation], the value is derived from [constant PARAM_ANGULAR_SPRING_EQUILIBRIUM_POINT] on backends that support it; other backends return the identity quaternion.
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_flag_x" qualifiers="const">
|
||||
<return type="bool" />
|
||||
<param index="0" name="flag" type="int" enum="Generic6DOFJoint3D.Flag" />
|
||||
@@ -46,6 +58,20 @@
|
||||
<description>
|
||||
</description>
|
||||
</method>
|
||||
<method name="has_target_rotation" qualifiers="const">
|
||||
<return type="bool" />
|
||||
<description>
|
||||
Returns [code]true[/code] if a quaternion angular target was explicitly set via [method set_angular_target_rotation] and has not been cleared. Returns [code]false[/code] when the joint is driven by [constant PARAM_ANGULAR_SPRING_EQUILIBRIUM_POINT] only.
|
||||
</description>
|
||||
</method>
|
||||
<method name="set_angular_target_rotation">
|
||||
<return type="void" />
|
||||
<param index="0" name="target_rotation" type="Quaternion" />
|
||||
<description>
|
||||
Sets the target angular orientation as a body-space quaternion describing the desired orientation of body B relative to body A. Replaces any previously set target and supersedes [constant PARAM_ANGULAR_SPRING_EQUILIBRIUM_POINT] until [method clear_angular_target_rotation] is called.
|
||||
[b]Note:[/b] Only for Jolt backend. Other 3D physics backends may ignore this value.
|
||||
</description>
|
||||
</method>
|
||||
<method name="set_flag_x">
|
||||
<return type="void" />
|
||||
<param index="0" name="flag" type="int" enum="Generic6DOFJoint3D.Flag" />
|
||||
|
||||
@@ -759,6 +759,14 @@
|
||||
Destroys any of the objects created by PhysicsServer3D. If the [RID] passed is not one of the objects that can be created by PhysicsServer3D, an error will be sent to the console.
|
||||
</description>
|
||||
</method>
|
||||
<method name="generic_6dof_joint_get_angular_target_rotation" qualifiers="const">
|
||||
<return type="Quaternion" />
|
||||
<param index="0" name="joint" type="RID" />
|
||||
<description>
|
||||
Returns the target angular orientation of a generic 6DOF joint as a body-space quaternion describing the desired orientation of body B relative to body A.
|
||||
[b]Note:[/b] Only for Jolt backend. Other 3D physics backends return the identity quaternion.
|
||||
</description>
|
||||
</method>
|
||||
<method name="generic_6dof_joint_get_flag" qualifiers="const">
|
||||
<return type="bool" />
|
||||
<param index="0" name="joint" type="RID" />
|
||||
@@ -777,6 +785,15 @@
|
||||
Returns the value of a generic 6DOF joint parameter.
|
||||
</description>
|
||||
</method>
|
||||
<method name="generic_6dof_joint_set_angular_target_rotation">
|
||||
<return type="void" />
|
||||
<param index="0" name="joint" type="RID" />
|
||||
<param index="1" name="target_rotation" type="Quaternion" />
|
||||
<description>
|
||||
Sets the target angular orientation of a generic 6DOF joint as a body-space quaternion describing the desired orientation of body B relative to body A.
|
||||
[b]Note:[/b] Only for Jolt backend. Other 3D physics backends may ignore this value.
|
||||
</description>
|
||||
</method>
|
||||
<method name="generic_6dof_joint_set_flag">
|
||||
<return type="void" />
|
||||
<param index="0" name="joint" type="RID" />
|
||||
|
||||
@@ -680,6 +680,12 @@
|
||||
<description>
|
||||
</description>
|
||||
</method>
|
||||
<method name="_generic_6dof_joint_get_angular_target_rotation" qualifiers="virtual required const">
|
||||
<return type="Quaternion" />
|
||||
<param index="0" name="joint" type="RID" />
|
||||
<description>
|
||||
</description>
|
||||
</method>
|
||||
<method name="_generic_6dof_joint_get_flag" qualifiers="virtual required const">
|
||||
<return type="bool" />
|
||||
<param index="0" name="joint" type="RID" />
|
||||
@@ -696,6 +702,13 @@
|
||||
<description>
|
||||
</description>
|
||||
</method>
|
||||
<method name="_generic_6dof_joint_set_angular_target_rotation" qualifiers="virtual required">
|
||||
<return type="void" />
|
||||
<param index="0" name="joint" type="RID" />
|
||||
<param index="1" name="target_rotation" type="Quaternion" />
|
||||
<description>
|
||||
</description>
|
||||
</method>
|
||||
<method name="_generic_6dof_joint_set_flag" qualifiers="virtual required">
|
||||
<return type="void" />
|
||||
<param index="0" name="joint" type="RID" />
|
||||
|
||||
@@ -1596,6 +1596,25 @@ bool GodotPhysicsServer3D::generic_6dof_joint_get_flag(RID p_joint, Vector3::Axi
|
||||
return generic_6dof_joint->get_flag(p_axis, p_flag);
|
||||
}
|
||||
|
||||
void GodotPhysicsServer3D::generic_6dof_joint_set_angular_target_rotation(RID p_joint, const Quaternion &p_target_rotation) {
|
||||
ERR_FAIL_COND_MSG(!p_target_rotation.is_finite() || p_target_rotation.length_squared() <= CMP_EPSILON, "Angular target rotation must be a finite, non-zero quaternion.");
|
||||
|
||||
GodotJoint3D *joint = joint_owner.get_or_null(p_joint);
|
||||
ERR_FAIL_NULL(joint);
|
||||
ERR_FAIL_COND(joint->get_type() != JOINT_TYPE_6DOF);
|
||||
WARN_PRINT_ONCE("Quaternion angular target rotations for Generic6DOFJoint3D are only supported by Jolt Physics. This value will be ignored by GodotPhysics3D.");
|
||||
}
|
||||
|
||||
Quaternion GodotPhysicsServer3D::generic_6dof_joint_get_angular_target_rotation(RID p_joint) const {
|
||||
const GodotJoint3D *joint = joint_owner.get_or_null(p_joint);
|
||||
ERR_FAIL_NULL_V(joint, Quaternion());
|
||||
ERR_FAIL_COND_V(joint->get_type() != JOINT_TYPE_6DOF, Quaternion());
|
||||
|
||||
// GodotPhysics3D does not apply angular spring equilibrium points, so there is no body-space target to return.
|
||||
WARN_PRINT_ONCE("Quaternion angular target rotations for Generic6DOFJoint3D are only supported by Jolt Physics. GodotPhysics3D returns the identity quaternion.");
|
||||
return Quaternion();
|
||||
}
|
||||
|
||||
void GodotPhysicsServer3D::free_rid(RID p_rid) {
|
||||
_update_shapes(); //just in case
|
||||
|
||||
|
||||
@@ -361,6 +361,9 @@ public:
|
||||
virtual void generic_6dof_joint_set_flag(RID p_joint, Vector3::Axis, G6DOFJointAxisFlag p_flag, bool p_enable) override;
|
||||
virtual bool generic_6dof_joint_get_flag(RID p_joint, Vector3::Axis, G6DOFJointAxisFlag p_flag) const override;
|
||||
|
||||
virtual void generic_6dof_joint_set_angular_target_rotation(RID p_joint, const Quaternion &p_target_rotation) override;
|
||||
virtual Quaternion generic_6dof_joint_get_angular_target_rotation(RID p_joint) const override;
|
||||
|
||||
virtual JointType joint_get_type(RID p_joint) const override;
|
||||
|
||||
virtual void joint_set_solver_priority(RID p_joint, int p_priority) override;
|
||||
|
||||
@@ -208,6 +208,20 @@ void JoltGeneric6DOFJoint3D::_update_spring_equilibrium(int p_axis) {
|
||||
}
|
||||
}
|
||||
|
||||
void JoltGeneric6DOFJoint3D::_update_angular_target_rotation() {
|
||||
if (!has_angular_target_rotation) {
|
||||
return;
|
||||
}
|
||||
|
||||
JPH::SixDOFConstraint *constraint = static_cast<JPH::SixDOFConstraint *>(jolt_ref.GetPtr());
|
||||
if (unlikely(constraint == nullptr)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const JPH::Quat target_orientation = to_jolt(angular_target_rotation);
|
||||
constraint->SetTargetOrientationBS(target_orientation);
|
||||
}
|
||||
|
||||
void JoltGeneric6DOFJoint3D::_limits_changed() {
|
||||
rebuild();
|
||||
_wake_up_bodies();
|
||||
@@ -435,6 +449,7 @@ void JoltGeneric6DOFJoint3D::set_param(Axis p_axis, Param p_param, double p_valu
|
||||
} break;
|
||||
case JoltPhysicsServer3D::G6DOF_JOINT_ANGULAR_SPRING_EQUILIBRIUM_POINT: {
|
||||
spring_equilibrium[axis_ang] = p_value;
|
||||
has_angular_target_rotation = false;
|
||||
_spring_equilibrium_changed(axis_ang);
|
||||
} break;
|
||||
default: {
|
||||
@@ -507,6 +522,36 @@ void JoltGeneric6DOFJoint3D::set_flag(Axis p_axis, Flag p_flag, bool p_enabled)
|
||||
}
|
||||
}
|
||||
|
||||
void JoltGeneric6DOFJoint3D::set_angular_target_rotation(const Quaternion &p_target_rotation) {
|
||||
ERR_FAIL_COND_MSG(!p_target_rotation.is_finite() || p_target_rotation.length_squared() <= CMP_EPSILON, "Angular target rotation must be a finite, non-zero quaternion.");
|
||||
|
||||
angular_target_rotation = p_target_rotation.normalized();
|
||||
has_angular_target_rotation = true;
|
||||
_update_angular_target_rotation();
|
||||
_wake_up_bodies();
|
||||
}
|
||||
|
||||
Quaternion JoltGeneric6DOFJoint3D::get_angular_target_rotation() const {
|
||||
if (has_angular_target_rotation) {
|
||||
return angular_target_rotation;
|
||||
}
|
||||
|
||||
const JPH::SixDOFConstraint *constraint = static_cast<const JPH::SixDOFConstraint *>(jolt_ref.GetPtr());
|
||||
if (unlikely(constraint == nullptr)) {
|
||||
return Quaternion();
|
||||
}
|
||||
|
||||
const Basis target_orientation_cs = Basis::from_euler(
|
||||
Vector3(static_cast<real_t>(-spring_equilibrium[AXIS_ANGULAR_X]),
|
||||
static_cast<real_t>(-spring_equilibrium[AXIS_ANGULAR_Y]),
|
||||
static_cast<real_t>(-spring_equilibrium[AXIS_ANGULAR_Z])),
|
||||
EulerOrder::ZYX);
|
||||
const Basis constraint_to_body_1 = to_godot(constraint->GetConstraintToBody1Matrix()).basis;
|
||||
const Basis constraint_to_body_2 = to_godot(constraint->GetConstraintToBody2Matrix()).basis;
|
||||
|
||||
return (constraint_to_body_1 * target_orientation_cs * constraint_to_body_2.inverse()).get_quaternion();
|
||||
}
|
||||
|
||||
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;
|
||||
@@ -683,4 +728,6 @@ void JoltGeneric6DOFJoint3D::rebuild() {
|
||||
_update_spring_parameters(axis);
|
||||
_update_spring_equilibrium(axis);
|
||||
}
|
||||
|
||||
_update_angular_target_rotation();
|
||||
}
|
||||
|
||||
@@ -72,6 +72,9 @@ class JoltGeneric6DOFJoint3D final : public JoltJoint3D {
|
||||
double spring_equilibrium[AXIS_COUNT] = {};
|
||||
double spring_limit[AXIS_COUNT] = { FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX };
|
||||
|
||||
Quaternion angular_target_rotation;
|
||||
bool has_angular_target_rotation = false;
|
||||
|
||||
bool limit_enabled[AXIS_COUNT] = {};
|
||||
|
||||
bool limit_spring_enabled[AXIS_COUNT] = {};
|
||||
@@ -89,6 +92,7 @@ class JoltGeneric6DOFJoint3D final : public JoltJoint3D {
|
||||
void _update_motor_limit(int p_axis);
|
||||
void _update_spring_parameters(int p_axis);
|
||||
void _update_spring_equilibrium(int p_axis);
|
||||
void _update_angular_target_rotation();
|
||||
|
||||
void _limits_changed();
|
||||
void _limit_spring_parameters_changed(int p_axis);
|
||||
@@ -111,6 +115,9 @@ public:
|
||||
bool get_flag(Axis p_axis, Flag p_flag) const;
|
||||
void set_flag(Axis p_axis, Flag p_flag, bool p_enabled);
|
||||
|
||||
void set_angular_target_rotation(const Quaternion &p_target_rotation);
|
||||
Quaternion get_angular_target_rotation() const;
|
||||
|
||||
double get_jolt_param(Axis p_axis, JoltParam p_param) const;
|
||||
void set_jolt_param(Axis p_axis, JoltParam p_param, double p_value);
|
||||
|
||||
|
||||
@@ -1546,6 +1546,26 @@ bool JoltPhysicsServer3D::generic_6dof_joint_get_flag(RID p_joint, Vector3::Axis
|
||||
return g6dof_joint->get_flag(p_axis, p_flag);
|
||||
}
|
||||
|
||||
void JoltPhysicsServer3D::generic_6dof_joint_set_angular_target_rotation(RID p_joint, const Quaternion &p_target_rotation) {
|
||||
JoltJoint3D *joint = joint_owner.get_or_null(p_joint);
|
||||
ERR_FAIL_NULL(joint);
|
||||
|
||||
ERR_FAIL_COND(joint->get_type() != JOINT_TYPE_6DOF);
|
||||
JoltGeneric6DOFJoint3D *g6dof_joint = static_cast<JoltGeneric6DOFJoint3D *>(joint);
|
||||
|
||||
g6dof_joint->set_angular_target_rotation(p_target_rotation);
|
||||
}
|
||||
|
||||
Quaternion JoltPhysicsServer3D::generic_6dof_joint_get_angular_target_rotation(RID p_joint) const {
|
||||
const JoltJoint3D *joint = joint_owner.get_or_null(p_joint);
|
||||
ERR_FAIL_NULL_V(joint, Quaternion());
|
||||
|
||||
ERR_FAIL_COND_V(joint->get_type() != JOINT_TYPE_6DOF, Quaternion());
|
||||
const JoltGeneric6DOFJoint3D *g6dof_joint = static_cast<const JoltGeneric6DOFJoint3D *>(joint);
|
||||
|
||||
return g6dof_joint->get_angular_target_rotation();
|
||||
}
|
||||
|
||||
PhysicsServer3D::JointType JoltPhysicsServer3D::joint_get_type(RID p_joint) const {
|
||||
const JoltJoint3D *joint = joint_owner.get_or_null(p_joint);
|
||||
ERR_FAIL_NULL_V(joint, JOINT_TYPE_PIN);
|
||||
|
||||
@@ -405,6 +405,9 @@ public:
|
||||
virtual void generic_6dof_joint_set_flag(RID p_joint, Vector3::Axis p_axis, PhysicsServer3D::G6DOFJointAxisFlag p_flag, bool p_enable) override;
|
||||
virtual bool generic_6dof_joint_get_flag(RID p_joint, Vector3::Axis p_axis, PhysicsServer3D::G6DOFJointAxisFlag p_flag) const override;
|
||||
|
||||
virtual void generic_6dof_joint_set_angular_target_rotation(RID p_joint, const Quaternion &p_target_rotation) override;
|
||||
virtual Quaternion generic_6dof_joint_get_angular_target_rotation(RID p_joint) const override;
|
||||
|
||||
virtual PhysicsServer3D::JointType joint_get_type(RID p_joint) const override;
|
||||
|
||||
virtual void joint_set_solver_priority(RID p_joint, int p_priority) override;
|
||||
|
||||
@@ -95,9 +95,12 @@ _FORCE_INLINE_ JPH::Vec3 to_jolt(const Vector3 &p_vec) {
|
||||
return JPH::Vec3((float)p_vec.x, (float)p_vec.y, (float)p_vec.z);
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ JPH::Quat to_jolt(const Quaternion &p_quat) {
|
||||
return JPH::Quat((float)p_quat.x, (float)p_quat.y, (float)p_quat.z, (float)p_quat.w);
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ JPH::Quat to_jolt(const Basis &p_basis) {
|
||||
const Quaternion quat = p_basis.get_quaternion().normalized();
|
||||
return JPH::Quat((float)quat.x, (float)quat.y, (float)quat.z, (float)quat.w);
|
||||
return to_jolt(p_basis.get_quaternion().normalized());
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ JPH::Mat44 to_jolt(const Transform3D &p_transform) {
|
||||
|
||||
@@ -51,6 +51,11 @@ void Generic6DOFJoint3D::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("set_flag_z", "flag", "value"), &Generic6DOFJoint3D::set_flag_z);
|
||||
ClassDB::bind_method(D_METHOD("get_flag_z", "flag"), &Generic6DOFJoint3D::get_flag_z);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_angular_target_rotation", "target_rotation"), &Generic6DOFJoint3D::set_angular_target_rotation);
|
||||
ClassDB::bind_method(D_METHOD("get_angular_target_rotation"), &Generic6DOFJoint3D::get_angular_target_rotation);
|
||||
ClassDB::bind_method(D_METHOD("has_target_rotation"), &Generic6DOFJoint3D::has_target_rotation);
|
||||
ClassDB::bind_method(D_METHOD("clear_angular_target_rotation"), &Generic6DOFJoint3D::clear_angular_target_rotation);
|
||||
|
||||
ADD_GROUP("Linear Limit", "linear_limit_");
|
||||
|
||||
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "linear_limit_x/enabled"), "set_flag_x", "get_flag_x", FLAG_ENABLE_LINEAR_LIMIT);
|
||||
@@ -201,6 +206,9 @@ void Generic6DOFJoint3D::_bind_methods() {
|
||||
void Generic6DOFJoint3D::set_param_x(Param p_param, real_t p_value) {
|
||||
ERR_FAIL_INDEX(p_param, PARAM_MAX);
|
||||
params_x[p_param] = p_value;
|
||||
if (p_param == PARAM_ANGULAR_SPRING_EQUILIBRIUM_POINT) {
|
||||
has_angular_target_rotation = false;
|
||||
}
|
||||
if (is_configured()) {
|
||||
PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(get_rid(), Vector3::AXIS_X, PhysicsServer3D::G6DOFJointAxisParam(p_param), p_value);
|
||||
}
|
||||
@@ -216,6 +224,9 @@ real_t Generic6DOFJoint3D::get_param_x(Param p_param) const {
|
||||
void Generic6DOFJoint3D::set_param_y(Param p_param, real_t p_value) {
|
||||
ERR_FAIL_INDEX(p_param, PARAM_MAX);
|
||||
params_y[p_param] = p_value;
|
||||
if (p_param == PARAM_ANGULAR_SPRING_EQUILIBRIUM_POINT) {
|
||||
has_angular_target_rotation = false;
|
||||
}
|
||||
if (is_configured()) {
|
||||
PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(get_rid(), Vector3::AXIS_Y, PhysicsServer3D::G6DOFJointAxisParam(p_param), p_value);
|
||||
}
|
||||
@@ -230,6 +241,9 @@ real_t Generic6DOFJoint3D::get_param_y(Param p_param) const {
|
||||
void Generic6DOFJoint3D::set_param_z(Param p_param, real_t p_value) {
|
||||
ERR_FAIL_INDEX(p_param, PARAM_MAX);
|
||||
params_z[p_param] = p_value;
|
||||
if (p_param == PARAM_ANGULAR_SPRING_EQUILIBRIUM_POINT) {
|
||||
has_angular_target_rotation = false;
|
||||
}
|
||||
if (is_configured()) {
|
||||
PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(get_rid(), Vector3::AXIS_Z, PhysicsServer3D::G6DOFJointAxisParam(p_param), p_value);
|
||||
}
|
||||
@@ -283,6 +297,58 @@ bool Generic6DOFJoint3D::get_flag_z(Flag p_flag) const {
|
||||
return flags_z[p_flag];
|
||||
}
|
||||
|
||||
bool Generic6DOFJoint3D::_is_valid_angular_target_rotation(const Quaternion &p_target_rotation) {
|
||||
return p_target_rotation.is_finite() && p_target_rotation.length_squared() > CMP_EPSILON;
|
||||
}
|
||||
|
||||
void Generic6DOFJoint3D::set_angular_target_rotation(const Quaternion &p_target_rotation) {
|
||||
ERR_FAIL_COND_MSG(!_is_valid_angular_target_rotation(p_target_rotation), "Angular target rotation must be a finite, non-zero quaternion.");
|
||||
|
||||
angular_target_rotation = p_target_rotation.normalized();
|
||||
has_angular_target_rotation = true;
|
||||
|
||||
if (!is_configured()) {
|
||||
return;
|
||||
}
|
||||
|
||||
PhysicsServer3D::get_singleton()->generic_6dof_joint_set_angular_target_rotation(get_rid(), angular_target_rotation);
|
||||
}
|
||||
|
||||
Quaternion Generic6DOFJoint3D::get_angular_target_rotation() const {
|
||||
if (has_angular_target_rotation) {
|
||||
return angular_target_rotation;
|
||||
}
|
||||
|
||||
if (is_configured()) {
|
||||
return PhysicsServer3D::get_singleton()->generic_6dof_joint_get_angular_target_rotation(get_rid());
|
||||
}
|
||||
|
||||
// Equilibrium point is in constraint space; body-space conversion requires the constraint frame.
|
||||
ERR_PRINT("Cannot derive a body-space angular target rotation from Generic6DOFJoint3D equilibrium points before the joint is configured. Returning the identity quaternion.");
|
||||
return Quaternion();
|
||||
}
|
||||
|
||||
bool Generic6DOFJoint3D::has_target_rotation() const {
|
||||
return has_angular_target_rotation;
|
||||
}
|
||||
|
||||
void Generic6DOFJoint3D::clear_angular_target_rotation() {
|
||||
if (!has_angular_target_rotation) {
|
||||
return;
|
||||
}
|
||||
has_angular_target_rotation = false;
|
||||
angular_target_rotation = Quaternion();
|
||||
|
||||
if (!is_configured()) {
|
||||
return;
|
||||
}
|
||||
|
||||
PhysicsServer3D *server = PhysicsServer3D::get_singleton();
|
||||
server->generic_6dof_joint_set_param(get_rid(), Vector3::AXIS_X, PhysicsServer3D::G6DOF_JOINT_ANGULAR_SPRING_EQUILIBRIUM_POINT, params_x[PARAM_ANGULAR_SPRING_EQUILIBRIUM_POINT]);
|
||||
server->generic_6dof_joint_set_param(get_rid(), Vector3::AXIS_Y, PhysicsServer3D::G6DOF_JOINT_ANGULAR_SPRING_EQUILIBRIUM_POINT, params_y[PARAM_ANGULAR_SPRING_EQUILIBRIUM_POINT]);
|
||||
server->generic_6dof_joint_set_param(get_rid(), Vector3::AXIS_Z, PhysicsServer3D::G6DOF_JOINT_ANGULAR_SPRING_EQUILIBRIUM_POINT, params_z[PARAM_ANGULAR_SPRING_EQUILIBRIUM_POINT]);
|
||||
}
|
||||
|
||||
void Generic6DOFJoint3D::_configure_joint(RID p_joint, PhysicsBody3D *body_a, PhysicsBody3D *body_b) {
|
||||
Transform3D gt = get_global_transform();
|
||||
//Vector3 cone_twistpos = gt.origin;
|
||||
@@ -312,6 +378,10 @@ void Generic6DOFJoint3D::_configure_joint(RID p_joint, PhysicsBody3D *body_a, Ph
|
||||
PhysicsServer3D::get_singleton()->generic_6dof_joint_set_flag(p_joint, Vector3::AXIS_Y, PhysicsServer3D::G6DOFJointAxisFlag(i), flags_y[i]);
|
||||
PhysicsServer3D::get_singleton()->generic_6dof_joint_set_flag(p_joint, Vector3::AXIS_Z, PhysicsServer3D::G6DOFJointAxisFlag(i), flags_z[i]);
|
||||
}
|
||||
|
||||
if (has_angular_target_rotation) {
|
||||
PhysicsServer3D::get_singleton()->generic_6dof_joint_set_angular_target_rotation(p_joint, angular_target_rotation);
|
||||
}
|
||||
}
|
||||
|
||||
Generic6DOFJoint3D::Generic6DOFJoint3D() {
|
||||
|
||||
@@ -79,10 +79,14 @@ protected:
|
||||
bool flags_y[FLAG_MAX];
|
||||
real_t params_z[PARAM_MAX];
|
||||
bool flags_z[FLAG_MAX];
|
||||
Quaternion angular_target_rotation;
|
||||
bool has_angular_target_rotation = false;
|
||||
|
||||
virtual void _configure_joint(RID p_joint, PhysicsBody3D *body_a, PhysicsBody3D *body_b) override;
|
||||
static void _bind_methods();
|
||||
|
||||
static bool _is_valid_angular_target_rotation(const Quaternion &p_target_rotation);
|
||||
|
||||
public:
|
||||
void set_param_x(Param p_param, real_t p_value);
|
||||
real_t get_param_x(Param p_param) const;
|
||||
@@ -102,6 +106,11 @@ public:
|
||||
void set_flag_z(Flag p_flag, bool p_enabled);
|
||||
bool get_flag_z(Flag p_flag) const;
|
||||
|
||||
void set_angular_target_rotation(const Quaternion &p_target_rotation);
|
||||
Quaternion get_angular_target_rotation() const;
|
||||
bool has_target_rotation() const;
|
||||
void clear_angular_target_rotation();
|
||||
|
||||
Generic6DOFJoint3D();
|
||||
};
|
||||
|
||||
|
||||
@@ -1044,6 +1044,9 @@ void PhysicsServer3D::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("generic_6dof_joint_set_flag", "joint", "axis", "flag", "enable"), &PhysicsServer3D::generic_6dof_joint_set_flag);
|
||||
ClassDB::bind_method(D_METHOD("generic_6dof_joint_get_flag", "joint", "axis", "flag"), &PhysicsServer3D::generic_6dof_joint_get_flag);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("generic_6dof_joint_set_angular_target_rotation", "joint", "target_rotation"), &PhysicsServer3D::generic_6dof_joint_set_angular_target_rotation);
|
||||
ClassDB::bind_method(D_METHOD("generic_6dof_joint_get_angular_target_rotation", "joint"), &PhysicsServer3D::generic_6dof_joint_get_angular_target_rotation);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("free_rid", "rid"), &PhysicsServer3D::free_rid);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_active", "active"), &PhysicsServer3D::set_active);
|
||||
|
||||
@@ -794,6 +794,9 @@ public:
|
||||
virtual void generic_6dof_joint_set_flag(RID p_joint, Vector3::Axis, G6DOFJointAxisFlag p_flag, bool p_enable) = 0;
|
||||
virtual bool generic_6dof_joint_get_flag(RID p_joint, Vector3::Axis, G6DOFJointAxisFlag p_flag) const = 0;
|
||||
|
||||
virtual void generic_6dof_joint_set_angular_target_rotation(RID p_joint, const Quaternion &p_target_rotation) = 0;
|
||||
virtual Quaternion generic_6dof_joint_get_angular_target_rotation(RID p_joint) const = 0;
|
||||
|
||||
/* QUERY API */
|
||||
|
||||
enum AreaBodyStatus {
|
||||
|
||||
@@ -423,6 +423,9 @@ public:
|
||||
virtual void generic_6dof_joint_set_flag(RID p_joint, Vector3::Axis, G6DOFJointAxisFlag p_flag, bool p_enable) override {}
|
||||
virtual bool generic_6dof_joint_get_flag(RID p_joint, Vector3::Axis, G6DOFJointAxisFlag p_flag) const override { return false; }
|
||||
|
||||
virtual void generic_6dof_joint_set_angular_target_rotation(RID p_joint, const Quaternion &p_target_rotation) override {}
|
||||
virtual Quaternion generic_6dof_joint_get_angular_target_rotation(RID p_joint) const override { return Quaternion(); }
|
||||
|
||||
/* MISC */
|
||||
|
||||
virtual void free_rid(RID p_rid) override {}
|
||||
|
||||
@@ -417,6 +417,9 @@ void PhysicsServer3DExtension::_bind_methods() {
|
||||
GDVIRTUAL_BIND(_generic_6dof_joint_set_flag, "joint", "axis", "flag", "enable");
|
||||
GDVIRTUAL_BIND(_generic_6dof_joint_get_flag, "joint", "axis", "flag");
|
||||
|
||||
GDVIRTUAL_BIND(_generic_6dof_joint_set_angular_target_rotation, "joint", "target_rotation");
|
||||
GDVIRTUAL_BIND(_generic_6dof_joint_get_angular_target_rotation, "joint");
|
||||
|
||||
GDVIRTUAL_BIND(_joint_get_type, "joint");
|
||||
|
||||
GDVIRTUAL_BIND(_joint_set_solver_priority, "joint", "priority");
|
||||
|
||||
@@ -522,6 +522,9 @@ public:
|
||||
EXBIND4(generic_6dof_joint_set_flag, RID, Vector3::Axis, G6DOFJointAxisFlag, bool)
|
||||
EXBIND3RC(bool, generic_6dof_joint_get_flag, RID, Vector3::Axis, G6DOFJointAxisFlag)
|
||||
|
||||
EXBIND2(generic_6dof_joint_set_angular_target_rotation, RID, const Quaternion &)
|
||||
EXBIND1RC(Quaternion, generic_6dof_joint_get_angular_target_rotation, RID)
|
||||
|
||||
EXBIND1RC(JointType, joint_get_type, RID)
|
||||
|
||||
EXBIND2(joint_set_solver_priority, RID, int)
|
||||
|
||||
@@ -383,6 +383,9 @@ public:
|
||||
FUNC4(generic_6dof_joint_set_flag, RID, Vector3::Axis, G6DOFJointAxisFlag, bool)
|
||||
FUNC3RC(bool, generic_6dof_joint_get_flag, RID, Vector3::Axis, G6DOFJointAxisFlag)
|
||||
|
||||
FUNC2(generic_6dof_joint_set_angular_target_rotation, RID, const Quaternion &)
|
||||
FUNC1RC(Quaternion, generic_6dof_joint_get_angular_target_rotation, RID)
|
||||
|
||||
FUNC1RC(JointType, joint_get_type, RID);
|
||||
|
||||
FUNC2(joint_set_solver_priority, RID, int);
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
/**************************************************************************/
|
||||
/* test_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 "tests/test_macros.h"
|
||||
|
||||
TEST_FORCE_LINK(test_generic_6dof_joint_3d)
|
||||
|
||||
#ifndef PHYSICS_3D_DISABLED
|
||||
|
||||
#include "scene/3d/physics/joints/generic_6dof_joint_3d.h"
|
||||
|
||||
namespace TestGeneric6DOFJoint3D {
|
||||
|
||||
TEST_CASE("[SceneTree][Generic6DOFJoint3D] Quaternion angular target is normalized and stored") {
|
||||
Generic6DOFJoint3D *joint = memnew(Generic6DOFJoint3D);
|
||||
|
||||
const Quaternion target_rotation(Vector3(0, 1, 0), 0.5);
|
||||
joint->set_angular_target_rotation(target_rotation * 2.0);
|
||||
|
||||
CHECK(joint->get_angular_target_rotation().is_normalized());
|
||||
CHECK(joint->get_angular_target_rotation().is_equal_approx(target_rotation));
|
||||
CHECK(joint->has_target_rotation());
|
||||
|
||||
memdelete(joint);
|
||||
}
|
||||
|
||||
TEST_CASE("[SceneTree][Generic6DOFJoint3D] Euler equilibrium setter clears stored quaternion target") {
|
||||
Generic6DOFJoint3D *joint = memnew(Generic6DOFJoint3D);
|
||||
|
||||
joint->set_angular_target_rotation(Quaternion(Vector3(0, 0, 1), 0.25));
|
||||
CHECK(joint->has_target_rotation());
|
||||
|
||||
joint->set_param_x(Generic6DOFJoint3D::PARAM_ANGULAR_SPRING_EQUILIBRIUM_POINT, 0.1);
|
||||
CHECK_FALSE(joint->has_target_rotation());
|
||||
|
||||
memdelete(joint);
|
||||
}
|
||||
|
||||
TEST_CASE("[SceneTree][Generic6DOFJoint3D] clear_angular_target_rotation resets state") {
|
||||
Generic6DOFJoint3D *joint = memnew(Generic6DOFJoint3D);
|
||||
|
||||
joint->set_angular_target_rotation(Quaternion(Vector3(1, 0, 0), 0.5));
|
||||
CHECK(joint->has_target_rotation());
|
||||
|
||||
joint->clear_angular_target_rotation();
|
||||
CHECK_FALSE(joint->has_target_rotation());
|
||||
ERR_PRINT_OFF;
|
||||
CHECK(joint->get_angular_target_rotation().is_equal_approx(Quaternion()));
|
||||
ERR_PRINT_ON;
|
||||
|
||||
memdelete(joint);
|
||||
}
|
||||
|
||||
TEST_CASE("[SceneTree][Generic6DOFJoint3D] Getter returns identity before configuration when no explicit target is set") {
|
||||
Generic6DOFJoint3D *joint = memnew(Generic6DOFJoint3D);
|
||||
|
||||
joint->set_param_x(Generic6DOFJoint3D::PARAM_ANGULAR_SPRING_EQUILIBRIUM_POINT, 0.3);
|
||||
joint->set_param_y(Generic6DOFJoint3D::PARAM_ANGULAR_SPRING_EQUILIBRIUM_POINT, -0.2);
|
||||
joint->set_param_z(Generic6DOFJoint3D::PARAM_ANGULAR_SPRING_EQUILIBRIUM_POINT, 0.4);
|
||||
|
||||
CHECK_FALSE(joint->has_target_rotation());
|
||||
ERR_PRINT_OFF;
|
||||
CHECK(joint->get_angular_target_rotation().is_equal_approx(Quaternion()));
|
||||
ERR_PRINT_ON;
|
||||
|
||||
memdelete(joint);
|
||||
}
|
||||
|
||||
TEST_CASE("[SceneTree][Generic6DOFJoint3D] Explicit quaternion target shadows Euler equilibrium derivation") {
|
||||
Generic6DOFJoint3D *joint = memnew(Generic6DOFJoint3D);
|
||||
|
||||
joint->set_param_x(Generic6DOFJoint3D::PARAM_ANGULAR_SPRING_EQUILIBRIUM_POINT, 0.3);
|
||||
const Quaternion explicit_target(Vector3(0, 1, 0), 0.7);
|
||||
joint->set_angular_target_rotation(explicit_target);
|
||||
|
||||
CHECK(joint->has_target_rotation());
|
||||
CHECK(joint->get_angular_target_rotation().is_equal_approx(explicit_target));
|
||||
|
||||
memdelete(joint);
|
||||
}
|
||||
|
||||
} // namespace TestGeneric6DOFJoint3D
|
||||
|
||||
#endif // PHYSICS_3D_DISABLED
|
||||
Reference in New Issue
Block a user