Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactored Node3D rotation modes #54084

Merged
merged 1 commit into from
Oct 25, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
508 changes: 210 additions & 298 deletions core/math/basis.cpp

Large diffs are not rendered by default.

42 changes: 17 additions & 25 deletions core/math/basis.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,40 +85,35 @@ class Basis {
void rotate(const Quaternion &p_quaternion);
Basis rotated(const Quaternion &p_quaternion) const;

Vector3 get_rotation_euler() const;
enum EulerOrder {
EULER_ORDER_XYZ,
EULER_ORDER_XZY,
EULER_ORDER_YXZ,
EULER_ORDER_YZX,
EULER_ORDER_ZXY,
EULER_ORDER_ZYX
};

Vector3 get_euler_normalized(EulerOrder p_order = EULER_ORDER_YXZ) const;
void get_rotation_axis_angle(Vector3 &p_axis, real_t &p_angle) const;
void get_rotation_axis_angle_local(Vector3 &p_axis, real_t &p_angle) const;
Quaternion get_rotation_quaternion() const;
Vector3 get_rotation() const { return get_rotation_euler(); };

void rotate_to_align(Vector3 p_start_direction, Vector3 p_end_direction);

Vector3 rotref_posscale_decomposition(Basis &rotref) const;

Vector3 get_euler_xyz() const;
void set_euler_xyz(const Vector3 &p_euler);

Vector3 get_euler_xzy() const;
void set_euler_xzy(const Vector3 &p_euler);

Vector3 get_euler_yzx() const;
void set_euler_yzx(const Vector3 &p_euler);

Vector3 get_euler_yxz() const;
void set_euler_yxz(const Vector3 &p_euler);

Vector3 get_euler_zxy() const;
void set_euler_zxy(const Vector3 &p_euler);

Vector3 get_euler_zyx() const;
void set_euler_zyx(const Vector3 &p_euler);
Vector3 get_euler(EulerOrder p_order = EULER_ORDER_YXZ) const;
void set_euler(const Vector3 &p_euler, EulerOrder p_order = EULER_ORDER_YXZ);
static Basis from_euler(const Vector3 &p_euler, EulerOrder p_order = EULER_ORDER_YXZ) {
Basis b;
b.set_euler(p_euler, p_order);
return b;
}

Quaternion get_quaternion() const;
void set_quaternion(const Quaternion &p_quaternion);

Vector3 get_euler() const { return get_euler_yxz(); }
void set_euler(const Vector3 &p_euler) { set_euler_yxz(p_euler); }

void get_axis_angle(Vector3 &r_axis, real_t &r_angle) const;
void set_axis_angle(const Vector3 &p_axis, real_t p_phi);

Expand Down Expand Up @@ -250,9 +245,6 @@ class Basis {
Basis(const Quaternion &p_quaternion) { set_quaternion(p_quaternion); };
Basis(const Quaternion &p_quaternion, const Vector3 &p_scale) { set_quaternion_scale(p_quaternion, p_scale); }

Basis(const Vector3 &p_euler) { set_euler(p_euler); }
Basis(const Vector3 &p_euler, const Vector3 &p_scale) { set_euler_scale(p_euler, p_scale); }

Basis(const Vector3 &p_axis, real_t p_phi) { set_axis_angle(p_axis, p_phi); }
Basis(const Vector3 &p_axis, real_t p_phi, const Vector3 &p_scale) { set_axis_angle_scale(p_axis, p_phi, p_scale); }
static Basis from_scale(const Vector3 &p_scale);
Expand Down
4 changes: 2 additions & 2 deletions core/math/quaternion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ real_t Quaternion::angle_to(const Quaternion &p_to) const {
// This implementation uses XYZ convention (Z is the first rotation).
Vector3 Quaternion::get_euler_xyz() const {
Basis m(*this);
return m.get_euler_xyz();
return m.get_euler(Basis::EULER_ORDER_XYZ);
}

// get_euler_yxz returns a vector containing the Euler angles in the format
Expand All @@ -56,7 +56,7 @@ Vector3 Quaternion::get_euler_yxz() const {
ERR_FAIL_COND_V_MSG(!is_normalized(), Vector3(0, 0, 0), "The quaternion must be normalized.");
#endif
Basis m(*this);
return m.get_euler_yxz();
return m.get_euler(Basis::EULER_ORDER_YXZ);
}

void Quaternion::operator*=(const Quaternion &p_q) {
Expand Down
1 change: 1 addition & 0 deletions core/variant/binder_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ struct VariantCaster<const T &> {
VARIANT_ENUM_CAST(Object::ConnectFlags);

VARIANT_ENUM_CAST(Vector3::Axis);
VARIANT_ENUM_CAST(Basis::EulerOrder);

VARIANT_ENUM_CAST(Error);
VARIANT_ENUM_CAST(Side);
Expand Down
4 changes: 0 additions & 4 deletions core/variant/variant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,6 @@ bool Variant::can_convert(Variant::Type p_type_from, Variant::Type p_type_to) {
case BASIS: {
static const Type valid[] = {
QUATERNION,
VECTOR3,
NIL
};

Expand Down Expand Up @@ -620,7 +619,6 @@ bool Variant::can_convert_strict(Variant::Type p_type_from, Variant::Type p_type
case BASIS: {
static const Type valid[] = {
QUATERNION,
VECTOR3,
NIL
};

Expand Down Expand Up @@ -1889,8 +1887,6 @@ Variant::operator Basis() const {
return *_data._basis;
} else if (type == QUATERNION) {
return *reinterpret_cast<const Quaternion *>(_data._mem);
} else if (type == VECTOR3) {
return Basis(*reinterpret_cast<const Vector3 *>(_data._mem));
} else if (type == TRANSFORM3D) { // unexposed in Variant::can_convert?
return _data._transform3d->basis;
} else {
Expand Down
10 changes: 9 additions & 1 deletion core/variant/variant_call.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1731,7 +1731,7 @@ static void _register_variant_builtin_methods() {
bind_methodv(Basis, rotated, static_cast<Basis (Basis::*)(const Vector3 &, real_t) const>(&Basis::rotated), sarray("axis", "phi"), varray());
bind_method(Basis, scaled, sarray("scale"), varray());
bind_method(Basis, get_scale, sarray(), varray());
bind_method(Basis, get_euler, sarray(), varray());
bind_method(Basis, get_euler, sarray("order"), varray(Basis::EULER_ORDER_YXZ));
bind_method(Basis, tdotx, sarray("with"), varray());
bind_method(Basis, tdoty, sarray("with"), varray());
bind_method(Basis, tdotz, sarray("with"), varray());
Expand All @@ -1741,6 +1741,7 @@ static void _register_variant_builtin_methods() {
bind_method(Basis, get_rotation_quaternion, sarray(), varray());
bind_static_method(Basis, looking_at, sarray("target", "up"), varray(Vector3(0, 1, 0)));
bind_static_method(Basis, from_scale, sarray("scale"), varray());
bind_static_method(Basis, from_euler, sarray("euler", "order"), varray(Basis::EULER_ORDER_YXZ));

/* AABB */

Expand Down Expand Up @@ -2109,6 +2110,13 @@ static void _register_variant_builtin_methods() {
_VariantCall::add_variant_constant(Variant::VECTOR2I, "UP", Vector2i(0, -1));
_VariantCall::add_variant_constant(Variant::VECTOR2I, "DOWN", Vector2i(0, 1));

_VariantCall::add_constant(Variant::BASIS, "EULER_ORDER_XYZ", Basis::EULER_ORDER_XYZ);
_VariantCall::add_constant(Variant::BASIS, "EULER_ORDER_XZY", Basis::EULER_ORDER_XZY);
_VariantCall::add_constant(Variant::BASIS, "EULER_ORDER_YXZ", Basis::EULER_ORDER_YXZ);
_VariantCall::add_constant(Variant::BASIS, "EULER_ORDER_YZX", Basis::EULER_ORDER_YZX);
_VariantCall::add_constant(Variant::BASIS, "EULER_ORDER_ZXY", Basis::EULER_ORDER_ZXY);
_VariantCall::add_constant(Variant::BASIS, "EULER_ORDER_ZYX", Basis::EULER_ORDER_ZYX);

_VariantCall::add_variant_constant(Variant::TRANSFORM2D, "IDENTITY", Transform2D());
_VariantCall::add_variant_constant(Variant::TRANSFORM2D, "FLIP_X", Transform2D(-1, 0, 0, 1, 0, 0));
_VariantCall::add_variant_constant(Variant::TRANSFORM2D, "FLIP_Y", Transform2D(1, 0, 0, -1, 0, 0));
Expand Down
3 changes: 1 addition & 2 deletions core/variant/variant_construct.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,10 +128,10 @@ void Variant::_register_variant_constructors() {
add_constructor<VariantConstructNoArgs<Quaternion>>(sarray());
add_constructor<VariantConstructor<Quaternion, Quaternion>>(sarray("from"));
add_constructor<VariantConstructor<Quaternion, Basis>>(sarray("from"));
add_constructor<VariantConstructor<Quaternion, Vector3>>(sarray("euler"));
add_constructor<VariantConstructor<Quaternion, Vector3, double>>(sarray("axis", "angle"));
add_constructor<VariantConstructor<Quaternion, Vector3, Vector3>>(sarray("arc_from", "arc_to"));
add_constructor<VariantConstructor<Quaternion, double, double, double, double>>(sarray("x", "y", "z", "w"));
add_constructor<VariantConstructor<Quaternion, Vector3>>(sarray("euler_yxz"));

add_constructor<VariantConstructNoArgs<::AABB>>(sarray());
add_constructor<VariantConstructor<::AABB, ::AABB>>(sarray("from"));
Expand All @@ -140,7 +140,6 @@ void Variant::_register_variant_constructors() {
add_constructor<VariantConstructNoArgs<Basis>>(sarray());
add_constructor<VariantConstructor<Basis, Basis>>(sarray("from"));
add_constructor<VariantConstructor<Basis, Quaternion>>(sarray("from"));
add_constructor<VariantConstructor<Basis, Vector3>>(sarray("euler"));
add_constructor<VariantConstructor<Basis, Vector3, double>>(sarray("axis", "phi"));
add_constructor<VariantConstructor<Basis, Vector3, Vector3, Vector3>>(sarray("x_axis", "y_axis", "z_axis"));

Expand Down
6 changes: 6 additions & 0 deletions core/variant/variant_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -756,6 +756,12 @@ VARIANT_ACCESSOR_NUMBER(char32_t)
VARIANT_ACCESSOR_NUMBER(Error)
VARIANT_ACCESSOR_NUMBER(Side)

template <>
struct VariantInternalAccessor<Basis::EulerOrder> {
static _FORCE_INLINE_ Basis::EulerOrder get(const Variant *v) { return Basis::EulerOrder(*VariantInternal::get_int(v)); }
static _FORCE_INLINE_ void set(Variant *v, Basis::EulerOrder p_value) { *VariantInternal::get_int(v) = p_value; }
};

template <>
struct VariantInternalAccessor<ObjectID> {
static _FORCE_INLINE_ ObjectID get(const Variant *v) { return ObjectID(*VariantInternal::get_int(v)); }
Expand Down
28 changes: 20 additions & 8 deletions doc/classes/Basis.xml
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,6 @@
Constructs a pure rotation basis matrix, rotated around the given [code]axis[/code] by [code]phi[/code], in radians. The axis must be a normalized vector.
</description>
</method>
<method name="Basis" qualifiers="constructor">
<return type="Basis" />
<argument index="0" name="euler" type="Vector3" />
<description>
Constructs a pure rotation basis matrix from the given Euler angles (in the YXZ convention: when *composing*, first Y, then X, and Z last), given in the vector format as (X angle, Y angle, Z angle).
Consider using the [Quaternion] constructor instead, which uses a quaternion instead of Euler angles.
</description>
</method>
<method name="Basis" qualifiers="constructor">
<return type="Basis" />
<argument index="0" name="from" type="Quaternion" />
Expand All @@ -71,6 +63,13 @@
A negative determinant means the basis has a negative scale. A zero determinant means the basis isn't invertible, and is usually considered invalid.
</description>
</method>
<method name="from_euler" qualifiers="static">
<return type="Basis" />
<argument index="0" name="euler" type="Vector3" />
<argument index="1" name="order" type="int" default="2" />
<description>
</description>
</method>
<method name="from_scale" qualifiers="static">
<return type="Basis" />
<argument index="0" name="scale" type="Vector3" />
Expand All @@ -80,6 +79,7 @@
</method>
<method name="get_euler" qualifiers="const">
<return type="Vector3" />
<argument index="0" name="order" type="int" default="2" />
<description>
Returns the basis's rotation in the form of Euler angles (in the YXZ convention: when decomposing, first Z, then X, and Y last). The returned vector contains the rotation angles in the format (X angle, Y angle, Z angle).
Consider using the [method get_rotation_quaternion] method instead, which returns a [Quaternion] quaternion instead of Euler angles.
Expand Down Expand Up @@ -248,6 +248,18 @@
</member>
</members>
<constants>
<constant name="EULER_ORDER_XYZ" value="0">
</constant>
<constant name="EULER_ORDER_XZY" value="1">
</constant>
<constant name="EULER_ORDER_YXZ" value="2">
</constant>
<constant name="EULER_ORDER_YZX" value="3">
</constant>
<constant name="EULER_ORDER_ZXY" value="4">
</constant>
<constant name="EULER_ORDER_ZYX" value="5">
</constant>
<constant name="IDENTITY" value="Basis(1, 0, 0, 0, 1, 0, 0, 0, 1)">
The identity basis, with no rotation or scaling applied.
This is identical to calling [code]Basis()[/code] without any parameters. This constant can be used to make your code clearer, and for consistency with C#.
Expand Down
32 changes: 31 additions & 1 deletion doc/classes/Node3D.xml
Original file line number Diff line number Diff line change
Expand Up @@ -264,16 +264,28 @@
</method>
</methods>
<members>
<member name="basis" type="Basis" setter="set_basis" getter="get_basis">
Direct access to the 3x3 basis of the [Transform3D] property.
</member>
<member name="global_transform" type="Transform3D" setter="set_global_transform" getter="get_global_transform">
World3D space (global) [Transform3D] of this node.
</member>
<member name="position" type="Vector3" setter="set_position" getter="get_position" default="Vector3(0, 0, 0)">
Local position or translation of this node relative to the parent. This is equivalent to [code]transform.origin[/code].
</member>
<member name="quaternion" type="Quaternion" setter="set_quaternion" getter="get_quaternion">
Access to the node rotation as a [Quaternion]. This property is ideal for tweening complex rotations.
</member>
<member name="rotation" type="Vector3" setter="set_rotation" getter="get_rotation" default="Vector3(0, 0, 0)">
Rotation part of the local transformation in radians, specified in terms of YXZ-Euler angles in the format (X angle, Y angle, Z angle).
Rotation part of the local transformation in radians, specified in terms of Euler angles. The angles construct a rotaton in the order specified by the [member rotation_order] property.
[b]Note:[/b] In the mathematical sense, rotation is a matrix and not a vector. The three Euler angles, which are the three independent parameters of the Euler-angle parametrization of the rotation matrix, are stored in a [Vector3] data structure not because the rotation is a vector, but only because [Vector3] exists as a convenient data-structure to store 3 floating-point numbers. Therefore, applying affine operations on the rotation "vector" is not meaningful.
</member>
<member name="rotation_edit_mode" type="int" setter="set_rotation_edit_mode" getter="get_rotation_edit_mode" enum="Node3D.RotationEditMode" default="0">
Specify how rotation (and scale) will be presented in the editor.
</member>
<member name="rotation_order" type="int" setter="set_rotation_order" getter="get_rotation_order" enum="Node3D.RotationOrder" default="2">
Specify the axis rotation order of the [member rotation] property. The final orientation is constructed by rotating the Euler angles in the order specified by this property.
</member>
<member name="scale" type="Vector3" setter="set_scale" getter="get_scale" default="Vector3(1, 1, 1)">
Scale part of the local transformation.
</member>
Expand Down Expand Up @@ -311,5 +323,23 @@
<constant name="NOTIFICATION_VISIBILITY_CHANGED" value="43">
Node3D nodes receives this notification when their visibility changes.
</constant>
<constant name="ROTATION_EDIT_MODE_EULER" value="0" enum="RotationEditMode">
</constant>
<constant name="ROTATION_EDIT_MODE_QUATERNION" value="1" enum="RotationEditMode">
</constant>
<constant name="ROTATION_EDIT_MODE_BASIS" value="2" enum="RotationEditMode">
</constant>
<constant name="ROTATION_ORDER_XYZ" value="0" enum="RotationOrder">
</constant>
<constant name="ROTATION_ORDER_XZY" value="1" enum="RotationOrder">
</constant>
<constant name="ROTATION_ORDER_YXZ" value="2" enum="RotationOrder">
</constant>
<constant name="ROTATION_ORDER_YZX" value="3" enum="RotationOrder">
</constant>
<constant name="ROTATION_ORDER_ZXY" value="4" enum="RotationOrder">
</constant>
<constant name="ROTATION_ORDER_ZYX" value="5" enum="RotationOrder">
</constant>
</constants>
</class>
3 changes: 1 addition & 2 deletions doc/classes/Quaternion.xml
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,8 @@
</method>
<method name="Quaternion" qualifiers="constructor">
<return type="Quaternion" />
<argument index="0" name="euler" type="Vector3" />
<argument index="0" name="euler_yxz" type="Vector3" />
<description>
Constructs a quaternion that will perform a rotation specified by Euler angles (in the YXZ convention: when decomposing, first Z, then X, and Y last), given in the vector format as (X angle, Y angle, Z angle).
</description>
</method>
<method name="Quaternion" qualifiers="constructor">
Expand Down
2 changes: 1 addition & 1 deletion editor/plugins/node_3d_editor_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3253,7 +3253,7 @@ void Node3DEditorViewport::_menu_option(int p_option) {
continue;
}

undo_redo->add_do_method(sp, "set_rotation", camera_transform.basis.get_rotation());
undo_redo->add_do_method(sp, "set_rotation", camera_transform.basis.get_euler_normalized());
undo_redo->add_undo_method(sp, "set_rotation", sp->get_rotation());
}
undo_redo->commit_action();
Expand Down
1 change: 1 addition & 0 deletions modules/csg/csg_shape.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -576,6 +576,7 @@ void CSGShape3D::_validate_property(PropertyInfo &property) const {
} else if (is_collision_prefixed && !bool(get("use_collision"))) {
property.usage = PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL;
}
GeometryInstance3D::_validate_property(property);
}

Array CSGShape3D::get_meshes() const {
Expand Down
24 changes: 12 additions & 12 deletions modules/fbx/tools/import_utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,27 +45,27 @@ Basis ImportUtils::EulerToBasis(FBXDocParser::Model::RotOrder mode, const Vector
// by simply invert its order: https://www.cs.utexas.edu/~theshark/courses/cs354/lectures/cs354-14.pdf
switch (mode) {
case FBXDocParser::Model::RotOrder_EulerXYZ:
ret.set_euler_zyx(p_rotation);
ret.set_euler(p_rotation, Basis::EULER_ORDER_XYZ);
break;

case FBXDocParser::Model::RotOrder_EulerXZY:
ret.set_euler_yzx(p_rotation);
ret.set_euler(p_rotation, Basis::EULER_ORDER_XZY);
break;

case FBXDocParser::Model::RotOrder_EulerYZX:
ret.set_euler_xzy(p_rotation);
ret.set_euler(p_rotation, Basis::EULER_ORDER_YZX);
break;

case FBXDocParser::Model::RotOrder_EulerYXZ:
ret.set_euler_zxy(p_rotation);
ret.set_euler(p_rotation, Basis::EULER_ORDER_YXZ);
break;

case FBXDocParser::Model::RotOrder_EulerZXY:
ret.set_euler_yxz(p_rotation);
ret.set_euler(p_rotation, Basis::EULER_ORDER_ZXY);
break;

case FBXDocParser::Model::RotOrder_EulerZYX:
ret.set_euler_xyz(p_rotation);
ret.set_euler(p_rotation, Basis::EULER_ORDER_ZYX);
break;

case FBXDocParser::Model::RotOrder_SphericXYZ:
Expand All @@ -89,22 +89,22 @@ Vector3 ImportUtils::BasisToEuler(FBXDocParser::Model::RotOrder mode, const Basi
// by simply invert its order: https://www.cs.utexas.edu/~theshark/courses/cs354/lectures/cs354-14.pdf
switch (mode) {
case FBXDocParser::Model::RotOrder_EulerXYZ:
return p_rotation.get_euler_zyx();
return p_rotation.get_euler(Basis::EULER_ORDER_XYZ);

case FBXDocParser::Model::RotOrder_EulerXZY:
return p_rotation.get_euler_yzx();
return p_rotation.get_euler(Basis::EULER_ORDER_XZY);

case FBXDocParser::Model::RotOrder_EulerYZX:
return p_rotation.get_euler_xzy();
return p_rotation.get_euler(Basis::EULER_ORDER_YZX);

case FBXDocParser::Model::RotOrder_EulerYXZ:
return p_rotation.get_euler_zxy();
return p_rotation.get_euler(Basis::EULER_ORDER_YXZ);

case FBXDocParser::Model::RotOrder_EulerZXY:
return p_rotation.get_euler_yxz();
return p_rotation.get_euler(Basis::EULER_ORDER_ZXY);

case FBXDocParser::Model::RotOrder_EulerZYX:
return p_rotation.get_euler_xyz();
return p_rotation.get_euler(Basis::EULER_ORDER_ZYX);

case FBXDocParser::Model::RotOrder_SphericXYZ:
// TODO
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ func test():
print(Plane(1, 2, 3, 4))
print(Quaternion(1, 2, 3, 4))
print(AABB(Vector3.ZERO, Vector3.ONE))
print(Basis(Vector3(0, 0, 0)))
print(Basis.from_euler(Vector3(0, 0, 0)))
print(Transform3D.IDENTITY)

print(Color(1, 2, 3, 4))
Expand Down
Loading