From 3caf33ec1250978c38f47be34cbd206f168f2052 Mon Sep 17 00:00:00 2001 From: Brandon DeRosier Date: Sun, 6 Nov 2022 05:27:08 -0800 Subject: [PATCH] Add Matrix::LookAt --- impeller/geometry/geometry_unittests.cc | 46 +++++++++++++++++++++++++ impeller/geometry/matrix.h | 17 +++++++++ 2 files changed, 63 insertions(+) diff --git a/impeller/geometry/geometry_unittests.cc b/impeller/geometry/geometry_unittests.cc index 42da1d65b324c..9392b12947cbb 100644 --- a/impeller/geometry/geometry_unittests.cc +++ b/impeller/geometry/geometry_unittests.cc @@ -424,6 +424,52 @@ TEST(GeometryTest, MatrixIsAligned) { } } +TEST(GeometryTest, MatrixLookAt) { + { + auto m = Matrix::MakeLookAt(Vector3(0, 0, -1), Vector3(0, 0, 1), + Vector3(0, 1, 0)); + auto expected = Matrix{ + 1, 0, 0, 0, // + 0, 1, 0, 0, // + 0, 0, 1, 0, // + 0, 0, 1, 1, // + }; + ASSERT_MATRIX_NEAR(m, expected); + } + + // Sideways tilt. + { + auto m = Matrix::MakeLookAt(Vector3(0, 0, -1), Vector3(0, 0, 1), + Vector3(1, 1, 0).Normalize()); + + // clang-format off + auto expected = Matrix{ + k1OverSqrt2, k1OverSqrt2, 0, 0, + -k1OverSqrt2, k1OverSqrt2, 0, 0, + 0, 0, 1, 0, + 0, 0, 1, 1, + }; + // clang-format on + ASSERT_MATRIX_NEAR(m, expected); + } + + // Half way between +x and -y, yaw 90 + { + auto m = + Matrix::MakeLookAt(Vector3(), Vector3(10, -10, 0), Vector3(0, 0, -1)); + + // clang-format off + auto expected = Matrix{ + -k1OverSqrt2, 0, k1OverSqrt2, 0, + -k1OverSqrt2, 0, -k1OverSqrt2, 0, + 0, -1, 0, 0, + 0, 0, 0, 1, + }; + // clang-format on + ASSERT_MATRIX_NEAR(m, expected); + } +} + TEST(GeometryTest, QuaternionLerp) { auto q1 = Quaternion{{0.0, 0.0, 1.0}, 0.0}; auto q2 = Quaternion{{0.0, 0.0, 1.0}, kPiOver4}; diff --git a/impeller/geometry/matrix.h b/impeller/geometry/matrix.h index c5025336b08b4..2d50f3045007b 100644 --- a/impeller/geometry/matrix.h +++ b/impeller/geometry/matrix.h @@ -435,6 +435,23 @@ struct Matrix { return MakePerspective(fov_y, static_cast(size.width) / size.height, z_near, z_far); } + + static constexpr Matrix MakeLookAt(Vector3 position, + Vector3 target, + Vector3 up) { + Vector3 forward = (target - position).Normalize(); + Vector3 right = up.Cross(forward); + up = forward.Cross(right); + + // clang-format off + return { + right.x, up.x, forward.x, 0.0f, + right.y, up.y, forward.y, 0.0f, + right.z, up.z, forward.z, 0.0f, + -right.Dot(position), -up.Dot(position), -forward.Dot(position), 1.0f + }; + // clang-format on + } }; static_assert(sizeof(struct Matrix) == sizeof(Scalar) * 16,