Skip to content

Commit

Permalink
Merge pull request #6 from MisterPuma80/better_look_at
Browse files Browse the repository at this point in the history
Test: Change look_at to have default up of Vector3.INF
  • Loading branch information
MisterPuma80 authored Oct 15, 2024
2 parents 1ee88a4 + 52f98d4 commit 38ea5c2
Show file tree
Hide file tree
Showing 13 changed files with 37 additions and 19 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

# Based on Godot 4.3 but with changes
* [x] Expose Engine.get_frame_ticks to GDScript
* [x] Change look_at to have default up of Vector3.INF and find appropriate axis itself if Vector3.INF is argument.

# Get code

Expand Down
18 changes: 16 additions & 2 deletions core/math/basis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1042,13 +1042,27 @@ void Basis::rotate_sh(real_t *p_values) {
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.");
ERR_FAIL_COND_V_MSG(p_up.is_finite() && p_up.is_zero_approx(), Basis(), "The up vector can't be zero.");
#endif
Vector3 v_z = p_target.normalized();
if (!p_use_model_front) {
v_z = -v_z;
}
Vector3 v_x = p_up.cross(v_z);

// Find an up vector that we can rotate around
Vector3 up = p_up;
if (! up.is_finite()) {
static const Vector3 up_candidates[3] = { Vector3(0, 1, 0), Vector3(1, 0, 0), Vector3(0, 0, 1) };
for (const Vector3 candidate : up_candidates) {
Vector3 v_x = candidate.cross(v_z).normalized();
if (! v_x.is_zero_approx()) {
up = candidate;
break;
}
}
}

Vector3 v_x = 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.");
#endif
Expand Down
2 changes: 1 addition & 1 deletion core/math/basis.h
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ struct [[nodiscard]] Basis {

operator Quaternion() const { return get_quaternion(); }

static Basis looking_at(const Vector3 &p_target, const Vector3 &p_up = Vector3(0, 1, 0), bool p_use_model_front = false);
static Basis looking_at(const Vector3 &p_target, const Vector3 &p_up = Vector3(INFINITY, INFINITY, INFINITY), 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); }
Expand Down
4 changes: 2 additions & 2 deletions core/math/transform_3d.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,8 @@ struct [[nodiscard]] 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), 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 set_look_at(const Vector3 &p_eye, const Vector3 &p_target, const Vector3 &p_up = Vector3(INFINITY, INFINITY, INFINITY), bool p_use_model_front = false);
Transform3D looking_at(const Vector3 &p_target, const Vector3 &p_up = Vector3(INFINITY, INFINITY, INFINITY), bool p_use_model_front = false) const;

void scale(const Vector3 &p_scale);
Transform3D scaled(const Vector3 &p_scale) const;
Expand Down
3 changes: 2 additions & 1 deletion doc/classes/Basis.xml
Original file line number Diff line number Diff line change
Expand Up @@ -202,12 +202,13 @@
<method name="looking_at" qualifiers="static">
<return type="Basis" />
<param index="0" name="target" type="Vector3" />
<param index="1" name="up" type="Vector3" default="Vector3(0, 1, 0)" />
<param index="1" name="up" type="Vector3" default="Vector3.INF" />
<param index="2" name="use_model_front" type="bool" default="false" />
<description>
Creates a new [Basis] with a rotation such that the forward axis (-Z) points towards the [param target] position.
By default, the -Z axis (camera forward) is treated as forward (implies +X is right). If [param use_model_front] is [code]true[/code], the +Z axis (asset front) is treated as forward (implies +X is left) and points toward 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 returned basis is orthonormalized (see [method orthonormalized]). The [param target] and [param up] vectors cannot be [constant Vector3.ZERO], and cannot be parallel to each other.
If the [param up] is Vector3.INF, it will use Vector3.UP, Vector3.RIGHT, or Vector3.BACK to rotate around.
</description>
</method>
<method name="orthonormalized" qualifiers="const">
Expand Down
7 changes: 4 additions & 3 deletions doc/classes/Node3D.xml
Original file line number Diff line number Diff line change
Expand Up @@ -114,12 +114,13 @@
<method name="look_at">
<return type="void" />
<param index="0" name="target" type="Vector3" />
<param index="1" name="up" type="Vector3" default="Vector3(0, 1, 0)" />
<param index="1" name="up" type="Vector3" default="Vector3.INF" />
<param index="2" name="use_model_front" type="bool" default="false" />
<description>
Rotates the node so that the local forward axis (-Z, [constant Vector3.FORWARD]) points toward the [param target] position.
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.
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. If the
[param up] is Vector3.INF, it will use Vector3.UP, Vector3.RIGHT, or Vector3.BACK to rotate around.
Operations take place in global space, which means that the node must be in the scene tree.
If [param use_model_front] is [code]true[/code], the +Z axis (asset front) is treated as forward (implies +X is left) and points toward the [param target] position. By default, the -Z axis (camera forward) is treated as forward (implies +X is right).
</description>
Expand All @@ -128,7 +129,7 @@
<return type="void" />
<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="2" name="up" type="Vector3" default="Vector3.INF" />
<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.
Expand Down
3 changes: 2 additions & 1 deletion doc/classes/Transform3D.xml
Original file line number Diff line number Diff line change
Expand Up @@ -97,11 +97,12 @@
<method name="looking_at" qualifiers="const">
<return type="Transform3D" />
<param index="0" name="target" type="Vector3" />
<param index="1" name="up" type="Vector3" default="Vector3(0, 1, 0)" />
<param index="1" name="up" type="Vector3" default="Vector3.INF" />
<param index="2" name="use_model_front" type="bool" default="false" />
<description>
Returns a copy of this transform rotated so 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.
If the [param up] is Vector3.INF, it will use Vector3.UP, Vector3.RIGHT, or Vector3.BACK to rotate around.
If [param use_model_front] is [code]true[/code], the +Z axis (asset front) is treated as forward (implies +X is left) and points toward the [param target] position. By default, the -Z axis (camera forward) is treated as forward (implies +X is right).
</description>
</method>
Expand Down
2 changes: 1 addition & 1 deletion editor/import/3d/scene_import_settings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1735,7 +1735,7 @@ SceneImportSettingsDialog::SceneImportSettingsDialog() {
camera->set_environment(environment);

light1 = memnew(DirectionalLight3D);
light1->set_transform(Transform3D(Basis::looking_at(Vector3(-1, -1, -1))));
light1->set_transform(Transform3D(Basis::looking_at(Vector3(-1, -1, -1), Vector3(INFINITY, INFINITY, INFINITY))));
light1->set_shadow(true);
camera->add_child(light1);

Expand Down
4 changes: 2 additions & 2 deletions editor/plugins/node_3d_editor_gizmos.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -655,7 +655,7 @@ bool EditorNode3DGizmo::intersect_ray(Camera3D *p_camera, const Point2 &p_point,
Transform3D t = spatial_node->get_global_transform();
Vector3 camera_position = p_camera->get_camera_transform().origin;
if (!camera_position.is_equal_approx(t.origin)) {
t.set_look_at(t.origin, camera_position);
t.set_look_at(t.origin, camera_position, Vector3(INFINITY, INFINITY, INFINITY));
}

float scale = t.origin.distance_to(p_camera->get_camera_transform().origin);
Expand All @@ -672,7 +672,7 @@ bool EditorNode3DGizmo::intersect_ray(Camera3D *p_camera, const Point2 &p_point,

if (!orig_camera_transform.origin.is_equal_approx(t.origin) &&
ABS(orig_camera_transform.basis.get_column(Vector3::AXIS_Z).dot(Vector3(0, 1, 0))) < 0.99) {
p_camera->look_at(t.origin);
p_camera->look_at(t.origin, Vector3(INFINITY, INFINITY, INFINITY));
}

Vector3 c0 = t.xform(Vector3(selectable_icon_size, selectable_icon_size, 0) * scale);
Expand Down
4 changes: 2 additions & 2 deletions scene/3d/node_3d.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1195,8 +1195,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", "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("look_at", "target", "up", "use_model_front"), &Node3D::look_at, DEFVAL(Vector3(INFINITY, INFINITY, INFINITY)), DEFVAL(false));
ClassDB::bind_method(D_METHOD("look_at_from_position", "position", "target", "up", "use_model_front"), &Node3D::look_at_from_position, DEFVAL(Vector3(INFINITY, INFINITY, INFINITY)), 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);
Expand Down
4 changes: 2 additions & 2 deletions scene/3d/node_3d.h
Original file line number Diff line number Diff line change
Expand Up @@ -252,8 +252,8 @@ class Node3D : public Node {
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), 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);
void look_at(const Vector3 &p_target, const Vector3 &p_up = Vector3(INFINITY, INFINITY, INFINITY), bool p_use_model_front = false);
void look_at_from_position(const Vector3 &p_pos, const Vector3 &p_target, const Vector3 &p_up = Vector3(INFINITY, INFINITY, INFINITY), bool p_use_model_front = false);

Vector3 to_local(Vector3 p_global) const;
Vector3 to_global(Vector3 p_local) const;
Expand Down
2 changes: 1 addition & 1 deletion scene/3d/path_3d.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,7 @@ Transform3D PathFollow3D::correct_posture(Transform3D p_transform, PathFollow3D:
Vector3 tangent = -t.basis.get_column(2);

// Y-axis points up by default.
t.basis = Basis::looking_at(tangent);
t.basis = Basis::looking_at(tangent, Vector3(INFINITY, INFINITY, INFINITY));
} else {
// Lock some euler axes.
Vector3 euler = t.basis.get_euler_normalized(EulerOrder::YXZ);
Expand Down
2 changes: 1 addition & 1 deletion tests/scene/test_camera_3d.h
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ TEST_CASE("[SceneTree][Camera3D] Position queries") {
// The orthogonal case is simpler, so we test a more random position + rotation combination here.
// For the other cases we'll use zero translation and rotation instead.
test_camera->set_global_position(Vector3(1, 2, 3));
test_camera->look_at(Vector3(-4, 5, 1));
test_camera->look_at(Vector3(-4, 5, 1), Vector3(INFINITY, INFINITY, INFINITY));
// Width = 5, Aspect Ratio = 400 / 200 = 2, so Height is 2.5.
test_camera->set_orthogonal(5.0f, 0.5f, 1000.0f);
const Basis basis = test_camera->get_global_basis();
Expand Down

0 comments on commit 38ea5c2

Please sign in to comment.