diff options
author | Rémi Verschelde <rverschelde@gmail.com> | 2023-05-24 08:46:53 +0200 |
---|---|---|
committer | Rémi Verschelde <rverschelde@gmail.com> | 2023-05-24 08:46:53 +0200 |
commit | 6f34a234397b9c536efa3d9eb90b9e521135301e (patch) | |
tree | 3db1e2feb2355631d9655d38e2020e1236d3f236 | |
parent | 852740a6272fb5366c66f7fe47595997b16c3014 (diff) | |
parent | 5fdc1232eff45e31ee53f58e618de6c58d3f7203 (diff) | |
download | redot-engine-6f34a234397b9c536efa3d9eb90b9e521135301e.tar.gz |
Merge pull request #76082 from reduz/ability-to-look-at-in-model-space
Add the ability to look-at in model-space.
-rw-r--r-- | core/math/basis.cpp | 7 | ||||
-rw-r--r-- | core/math/basis.h | 2 | ||||
-rw-r--r-- | core/math/transform_3d.cpp | 8 | ||||
-rw-r--r-- | core/math/transform_3d.h | 4 | ||||
-rw-r--r-- | core/variant/variant_call.cpp | 11 | ||||
-rw-r--r-- | doc/classes/Basis.xml | 1 | ||||
-rw-r--r-- | doc/classes/Node3D.xml | 4 | ||||
-rw-r--r-- | doc/classes/Transform3D.xml | 1 | ||||
-rw-r--r-- | doc/classes/Vector3.xml | 20 | ||||
-rw-r--r-- | scene/3d/node_3d.cpp | 15 | ||||
-rw-r--r-- | scene/3d/node_3d.h | 4 |
11 files changed, 55 insertions, 22 deletions
diff --git a/core/math/basis.cpp b/core/math/basis.cpp index bfd902c7e2..1481dbc32e 100644 --- a/core/math/basis.cpp +++ b/core/math/basis.cpp @@ -1016,12 +1016,15 @@ void Basis::rotate_sh(real_t *p_values) { p_values[8] = d4 * s_scale_dst4; } -Basis Basis::looking_at(const Vector3 &p_target, const Vector3 &p_up) { +Basis Basis::looking_at(const Vector3 &p_target, const Vector3 &p_up, bool p_use_model_front) { #ifdef MATH_CHECKS ERR_FAIL_COND_V_MSG(p_target.is_zero_approx(), Basis(), "The target vector can't be zero."); ERR_FAIL_COND_V_MSG(p_up.is_zero_approx(), Basis(), "The up vector can't be zero."); #endif - Vector3 v_z = -p_target.normalized(); + Vector3 v_z = p_target.normalized(); + if (!p_use_model_front) { + v_z = -v_z; + } Vector3 v_x = p_up.cross(v_z); #ifdef MATH_CHECKS ERR_FAIL_COND_V_MSG(v_x.is_zero_approx(), Basis(), "The target vector and up vector can't be parallel to each other."); diff --git a/core/math/basis.h b/core/math/basis.h index bbc1d40469..1a68bee686 100644 --- a/core/math/basis.h +++ b/core/math/basis.h @@ -217,7 +217,7 @@ struct _NO_DISCARD_ Basis { operator Quaternion() const { return get_quaternion(); } - static Basis looking_at(const Vector3 &p_target, const Vector3 &p_up = Vector3(0, 1, 0)); + static Basis looking_at(const Vector3 &p_target, const Vector3 &p_up = Vector3(0, 1, 0), bool p_use_model_front = false); 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); } diff --git a/core/math/transform_3d.cpp b/core/math/transform_3d.cpp index 8d497209f1..cdc94676c9 100644 --- a/core/math/transform_3d.cpp +++ b/core/math/transform_3d.cpp @@ -77,20 +77,20 @@ void Transform3D::rotate_basis(const Vector3 &p_axis, real_t p_angle) { basis.rotate(p_axis, p_angle); } -Transform3D Transform3D::looking_at(const Vector3 &p_target, const Vector3 &p_up) const { +Transform3D Transform3D::looking_at(const Vector3 &p_target, const Vector3 &p_up, bool p_use_model_front) const { #ifdef MATH_CHECKS ERR_FAIL_COND_V_MSG(origin.is_equal_approx(p_target), Transform3D(), "The transform's origin and target can't be equal."); #endif Transform3D t = *this; - t.basis = Basis::looking_at(p_target - origin, p_up); + t.basis = Basis::looking_at(p_target - origin, p_up, p_use_model_front); return t; } -void Transform3D::set_look_at(const Vector3 &p_eye, const Vector3 &p_target, const Vector3 &p_up) { +void Transform3D::set_look_at(const Vector3 &p_eye, const Vector3 &p_target, const Vector3 &p_up, bool p_use_model_front) { #ifdef MATH_CHECKS ERR_FAIL_COND_MSG(p_eye.is_equal_approx(p_target), "The eye and target vectors can't be equal."); #endif - basis = Basis::looking_at(p_target - p_eye, p_up); + basis = Basis::looking_at(p_target - p_eye, p_up, p_use_model_front); origin = p_eye; } diff --git a/core/math/transform_3d.h b/core/math/transform_3d.h index bf1b4cdb63..70141a3dbe 100644 --- a/core/math/transform_3d.h +++ b/core/math/transform_3d.h @@ -52,8 +52,8 @@ struct _NO_DISCARD_ Transform3D { void rotate(const Vector3 &p_axis, real_t p_angle); void rotate_basis(const Vector3 &p_axis, real_t p_angle); - void set_look_at(const Vector3 &p_eye, const Vector3 &p_target, const Vector3 &p_up = Vector3(0, 1, 0)); - Transform3D looking_at(const Vector3 &p_target, const Vector3 &p_up = Vector3(0, 1, 0)) const; + void set_look_at(const Vector3 &p_eye, const Vector3 &p_target, const Vector3 &p_up = Vector3(0, 1, 0), bool p_use_model_front = false); + Transform3D looking_at(const Vector3 &p_target, const Vector3 &p_up = Vector3(0, 1, 0), bool p_use_model_front = false) const; void scale(const Vector3 &p_scale); Transform3D scaled(const Vector3 &p_scale) const; diff --git a/core/variant/variant_call.cpp b/core/variant/variant_call.cpp index 0a836c125a..dad9183216 100644 --- a/core/variant/variant_call.cpp +++ b/core/variant/variant_call.cpp @@ -2101,7 +2101,7 @@ static void _register_variant_builtin_methods() { bind_method(Basis, is_equal_approx, sarray("b"), varray()); bind_method(Basis, is_finite, sarray(), varray()); 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, looking_at, sarray("target", "up", "use_model_front"), varray(Vector3(0, 1, 0), false)); bind_static_method(Basis, from_scale, sarray("scale"), varray()); bind_static_method(Basis, from_euler, sarray("euler", "order"), varray((int64_t)EulerOrder::YXZ)); @@ -2144,7 +2144,7 @@ static void _register_variant_builtin_methods() { bind_method(Transform3D, scaled_local, sarray("scale"), varray()); bind_method(Transform3D, translated, sarray("offset"), varray()); bind_method(Transform3D, translated_local, sarray("offset"), varray()); - bind_method(Transform3D, looking_at, sarray("target", "up"), varray(Vector3(0, 1, 0))); + bind_method(Transform3D, looking_at, sarray("target", "up", "use_model_front"), varray(Vector3(0, 1, 0), false)); bind_method(Transform3D, interpolate_with, sarray("xform", "weight"), varray()); bind_method(Transform3D, is_equal_approx, sarray("xform"), varray()); bind_method(Transform3D, is_finite, sarray(), varray()); @@ -2532,6 +2532,13 @@ static void _register_variant_builtin_methods() { _VariantCall::add_variant_constant(Variant::VECTOR3, "FORWARD", Vector3(0, 0, -1)); _VariantCall::add_variant_constant(Variant::VECTOR3, "BACK", Vector3(0, 0, 1)); + _VariantCall::add_variant_constant(Variant::VECTOR3, "MODEL_LEFT", Vector3(1, 0, 0)); + _VariantCall::add_variant_constant(Variant::VECTOR3, "MODEL_RIGHT", Vector3(-1, 0, 0)); + _VariantCall::add_variant_constant(Variant::VECTOR3, "MODEL_TOP", Vector3(0, 1, 0)); + _VariantCall::add_variant_constant(Variant::VECTOR3, "MODEL_BOTTOM", Vector3(0, -1, 0)); + _VariantCall::add_variant_constant(Variant::VECTOR3, "MODEL_FRONT", Vector3(0, 0, 1)); + _VariantCall::add_variant_constant(Variant::VECTOR3, "MODEL_REAR", Vector3(0, 0, -1)); + _VariantCall::add_constant(Variant::VECTOR4, "AXIS_X", Vector4::AXIS_X); _VariantCall::add_constant(Variant::VECTOR4, "AXIS_Y", Vector4::AXIS_Y); _VariantCall::add_constant(Variant::VECTOR4, "AXIS_Z", Vector4::AXIS_Z); diff --git a/doc/classes/Basis.xml b/doc/classes/Basis.xml index 53dde5a286..7de626e477 100644 --- a/doc/classes/Basis.xml +++ b/doc/classes/Basis.xml @@ -123,6 +123,7 @@ <return type="Basis" /> <param index="0" name="target" type="Vector3" /> <param index="1" name="up" type="Vector3" default="Vector3(0, 1, 0)" /> + <param index="2" name="use_model_front" type="bool" default="false" /> <description> Creates a Basis with a rotation such that the forward axis (-Z) points towards the [param target] position. The up axis (+Y) points as close to the [param up] vector as possible while staying perpendicular to the forward axis. The resulting Basis is orthonormalized. The [param target] and [param up] vectors cannot be zero, and cannot be parallel to each other. diff --git a/doc/classes/Node3D.xml b/doc/classes/Node3D.xml index b4857bacde..cad0e056e7 100644 --- a/doc/classes/Node3D.xml +++ b/doc/classes/Node3D.xml @@ -113,8 +113,9 @@ <return type="void" /> <param index="0" name="target" type="Vector3" /> <param index="1" name="up" type="Vector3" default="Vector3(0, 1, 0)" /> + <param index="2" name="use_model_front" type="bool" default="false" /> <description> - Rotates the node so that the local forward axis (-Z) points toward the [param target] position. + Rotates the node so that the local forward axis (-Z, [constant Vector3.FORWARD]) points toward the [param target] position. If the [param use_model_front] options is specified, then the model is oriented in reverse, towards the model front axis (+Z, [constant Vector3.MODEL_FRONT]), which is more useful for orienting 3D models. The local up axis (+Y) points as close to the [param up] vector as possible while staying perpendicular to the local forward axis. The resulting transform is orthogonal, and the scale is preserved. Non-uniform scaling may not work correctly. The [param target] position cannot be the same as the node's position, the [param up] vector cannot be zero, and the direction from the node's position to the [param target] vector cannot be parallel to the [param up] vector. Operations take place in global space, which means that the node must be in the scene tree. @@ -125,6 +126,7 @@ <param index="0" name="position" type="Vector3" /> <param index="1" name="target" type="Vector3" /> <param index="2" name="up" type="Vector3" default="Vector3(0, 1, 0)" /> + <param index="3" name="use_model_front" type="bool" default="false" /> <description> Moves the node to the specified [param position], and then rotates the node to point toward the [param target] as per [method look_at]. Operations take place in global space. </description> diff --git a/doc/classes/Transform3D.xml b/doc/classes/Transform3D.xml index fb5c8559b6..d375838a68 100644 --- a/doc/classes/Transform3D.xml +++ b/doc/classes/Transform3D.xml @@ -93,6 +93,7 @@ <return type="Transform3D" /> <param index="0" name="target" type="Vector3" /> <param index="1" name="up" type="Vector3" default="Vector3(0, 1, 0)" /> + <param index="2" name="use_model_front" type="bool" default="false" /> <description> Returns a copy of the transform rotated such that the forward axis (-Z) points towards the [param target] position. The up axis (+Y) points as close to the [param up] vector as possible while staying perpendicular to the forward axis. The resulting transform is orthonormalized. The existing rotation, scale, and skew information from the original transform is discarded. The [param target] and [param up] vectors cannot be zero, cannot be parallel to each other, and are defined in global/parent space. diff --git a/doc/classes/Vector3.xml b/doc/classes/Vector3.xml index d55e31f7b7..511d84d24d 100644 --- a/doc/classes/Vector3.xml +++ b/doc/classes/Vector3.xml @@ -404,11 +404,29 @@ Down unit vector. </constant> <constant name="FORWARD" value="Vector3(0, 0, -1)"> - Forward unit vector. Represents the local direction of forward, and the global direction of north. + Forward unit vector. Represents the local direction of forward, and the global direction of north. Keep in mind that the forward direction for lights, cameras, etc is different from 3D assets like characters, which face towards the camera by convention. Use [constant Vector3.MODEL_FRONT] and similar constants when working in 3D asset space. </constant> <constant name="BACK" value="Vector3(0, 0, 1)"> Back unit vector. Represents the local direction of back, and the global direction of south. </constant> + <constant name="MODEL_LEFT" value="Vector3(1, 0, 0)"> + Unit vector pointing towards the left side of imported 3D assets. + </constant> + <constant name="MODEL_RIGHT" value="Vector3(-1, 0, 0)"> + Unit vector pointing towards the right side of imported 3D assets. + </constant> + <constant name="MODEL_TOP" value="Vector3(0, 1, 0)"> + Unit vector pointing towards the top side (up) of imported 3D assets. + </constant> + <constant name="MODEL_BOTTOM" value="Vector3(0, -1, 0)"> + Unit vector pointing towards the bottom side (down) of imported 3D assets. + </constant> + <constant name="MODEL_FRONT" value="Vector3(0, 0, 1)"> + Unit vector pointing towards the front side (facing forward) of imported 3D assets. + </constant> + <constant name="MODEL_REAR" value="Vector3(0, 0, -1)"> + Unit vector pointing towards the rear side (back) of imported 3D assets. + </constant> </constants> <operators> <operator name="operator !="> diff --git a/scene/3d/node_3d.cpp b/scene/3d/node_3d.cpp index 80289bac52..4f2ee5a3b2 100644 --- a/scene/3d/node_3d.cpp +++ b/scene/3d/node_3d.cpp @@ -908,22 +908,23 @@ void Node3D::set_identity() { set_transform(Transform3D()); } -void Node3D::look_at(const Vector3 &p_target, const Vector3 &p_up) { +void Node3D::look_at(const Vector3 &p_target, const Vector3 &p_up, bool p_use_model_front) { ERR_THREAD_GUARD; ERR_FAIL_COND_MSG(!is_inside_tree(), "Node not inside tree. Use look_at_from_position() instead."); Vector3 origin = get_global_transform().origin; - look_at_from_position(origin, p_target, p_up); + look_at_from_position(origin, p_target, p_up, p_use_model_front); } -void Node3D::look_at_from_position(const Vector3 &p_pos, const Vector3 &p_target, const Vector3 &p_up) { +void Node3D::look_at_from_position(const Vector3 &p_pos, const Vector3 &p_target, const Vector3 &p_up, bool p_use_model_front) { ERR_THREAD_GUARD; ERR_FAIL_COND_MSG(p_pos.is_equal_approx(p_target), "Node origin and target are in the same position, look_at() failed."); ERR_FAIL_COND_MSG(p_up.is_zero_approx(), "The up vector can't be zero, look_at() failed."); ERR_FAIL_COND_MSG(p_up.cross(p_target - p_pos).is_zero_approx(), "Up vector and direction between node origin and target are aligned, look_at() failed."); - Transform3D lookat = Transform3D(Basis::looking_at(p_target - p_pos, p_up), p_pos); + Vector3 forward = p_target - p_pos; + Basis lookat_basis = Basis::looking_at(forward, p_up, p_use_model_front); Vector3 original_scale = get_scale(); - set_global_transform(lookat); + set_global_transform(Transform3D(lookat_basis, p_pos)); set_scale(original_scale); } @@ -1166,8 +1167,8 @@ void Node3D::_bind_methods() { ClassDB::bind_method(D_METHOD("orthonormalize"), &Node3D::orthonormalize); ClassDB::bind_method(D_METHOD("set_identity"), &Node3D::set_identity); - ClassDB::bind_method(D_METHOD("look_at", "target", "up"), &Node3D::look_at, DEFVAL(Vector3(0, 1, 0))); - ClassDB::bind_method(D_METHOD("look_at_from_position", "position", "target", "up"), &Node3D::look_at_from_position, DEFVAL(Vector3(0, 1, 0))); + ClassDB::bind_method(D_METHOD("look_at", "target", "up", "use_model_front"), &Node3D::look_at, DEFVAL(Vector3(0, 1, 0)), DEFVAL(false)); + ClassDB::bind_method(D_METHOD("look_at_from_position", "position", "target", "up", "use_model_front"), &Node3D::look_at_from_position, DEFVAL(Vector3(0, 1, 0)), DEFVAL(false)); ClassDB::bind_method(D_METHOD("to_local", "global_point"), &Node3D::to_local); ClassDB::bind_method(D_METHOD("to_global", "local_point"), &Node3D::to_global); diff --git a/scene/3d/node_3d.h b/scene/3d/node_3d.h index b274a6af88..935f0b149a 100644 --- a/scene/3d/node_3d.h +++ b/scene/3d/node_3d.h @@ -250,8 +250,8 @@ public: void global_scale(const Vector3 &p_scale); void global_translate(const Vector3 &p_offset); - void look_at(const Vector3 &p_target, const Vector3 &p_up = Vector3(0, 1, 0)); - void look_at_from_position(const Vector3 &p_pos, const Vector3 &p_target, const Vector3 &p_up = Vector3(0, 1, 0)); + void look_at(const Vector3 &p_target, const Vector3 &p_up = Vector3(0, 1, 0), bool p_use_model_front = false); + void look_at_from_position(const Vector3 &p_pos, const Vector3 &p_target, const Vector3 &p_up = Vector3(0, 1, 0), bool p_use_model_front = false); Vector3 to_local(Vector3 p_global) const; Vector3 to_global(Vector3 p_local) const; |