diff --git a/impeller/geometry/geometry_unittests.cc b/impeller/geometry/geometry_unittests.cc index 84eec3be14703..76f34073fdf9a 100644 --- a/impeller/geometry/geometry_unittests.cc +++ b/impeller/geometry/geometry_unittests.cc @@ -302,6 +302,53 @@ TEST(GeometryTest, MatrixMakePerspective) { } } +TEST(GeometryTest, MatrixGetBasisVectors) { + { + auto m = Matrix(); + Vector3 x = m.GetBasisX(); + Vector3 y = m.GetBasisY(); + Vector3 z = m.GetBasisZ(); + ASSERT_VECTOR3_NEAR(x, Vector3(1, 0, 0)); + ASSERT_VECTOR3_NEAR(y, Vector3(0, 1, 0)); + ASSERT_VECTOR3_NEAR(z, Vector3(0, 0, 1)); + } + + { + auto m = Matrix::MakeRotationZ(Radians{kPiOver2}) * + Matrix::MakeRotationX(Radians{kPiOver2}) * + Matrix::MakeScale(Vector3(2, 3, 4)); + Vector3 x = m.GetBasisX(); + Vector3 y = m.GetBasisY(); + Vector3 z = m.GetBasisZ(); + ASSERT_VECTOR3_NEAR(x, Vector3(0, 2, 0)); + ASSERT_VECTOR3_NEAR(y, Vector3(0, 0, 3)); + ASSERT_VECTOR3_NEAR(z, Vector3(4, 0, 0)); + } +} + +TEST(GeometryTest, MatrixGetDirectionScale) { + { + auto m = Matrix(); + Scalar result = m.GetDirectionScale(Vector3{1, 0, 0}); + ASSERT_FLOAT_EQ(result, 1); + } + + { + auto m = Matrix::MakeRotationX(Degrees{10}) * + Matrix::MakeRotationY(Degrees{83}) * + Matrix::MakeRotationZ(Degrees{172}); + Scalar result = m.GetDirectionScale(Vector3{0, 1, 0}); + ASSERT_FLOAT_EQ(result, 1); + } + + { + auto m = Matrix::MakeRotationZ(Radians{kPiOver2}) * + Matrix::MakeScale(Vector3(3, 4, 5)); + Scalar result = m.GetDirectionScale(Vector3{2, 0, 0}); + ASSERT_FLOAT_EQ(result, 8); + } +} + 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 a3c300dda1830..8bdb250b61b56 100644 --- a/impeller/geometry/matrix.h +++ b/impeller/geometry/matrix.h @@ -236,10 +236,20 @@ struct Matrix { Scalar GetMaxBasisLength() const; + constexpr Vector3 GetBasisX() const { return Vector3(m[0], m[1], m[2]); } + + constexpr Vector3 GetBasisY() const { return Vector3(m[4], m[5], m[6]); } + + constexpr Vector3 GetBasisZ() const { return Vector3(m[8], m[9], m[10]); } + constexpr Vector3 GetScale() const { - return Vector3(Vector3(m[0], m[1], m[2]).Length(), - Vector3(m[4], m[5], m[6]).Length(), - Vector3(m[8], m[9], m[10]).Length()); + return Vector3(GetBasisX().Length(), GetBasisY().Length(), + GetBasisZ().Length()); + } + + constexpr Scalar GetDirectionScale(Vector3 direction) const { + return 1.0 / (this->Invert() * direction.Normalize()).Length() * + direction.Length(); } constexpr bool IsAffine() const { diff --git a/impeller/geometry/vector.h b/impeller/geometry/vector.h index ad59f91d89edc..b1621f0147a1b 100644 --- a/impeller/geometry/vector.h +++ b/impeller/geometry/vector.h @@ -41,7 +41,7 @@ struct Vector3 { * * @return the calculated length. */ - Scalar Length() const { return sqrt(x * x + y * y + z * z); } + constexpr Scalar Length() const { return sqrt(x * x + y * y + z * z); } constexpr Vector3 Normalize() const { const auto len = Length(); @@ -130,6 +130,18 @@ struct Vector3 { std::string ToString() const; }; +// RHS algebraic operations with arithmetic types. + +template >> +constexpr Vector3 operator*(U s, const Vector3& p) { + return p * s; +} + +template >> +constexpr Vector3 operator/(U s, const Vector3& p) { + return {static_cast(s) / p.x, static_cast(s) / p.y}; +} + struct Vector4 { union { struct {