Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 2788964

Browse files
authored
[Impeller] Support projective transforms in matrix vector ops (#36398)
1 parent 349c064 commit 2788964

File tree

2 files changed

+49
-2
lines changed

2 files changed

+49
-2
lines changed

impeller/geometry/geometry_unittests.cc

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,36 @@ TEST(GeometryTest, MatrixVectorMultiplication) {
232232
auto expected = Point(60, 120);
233233
ASSERT_POINT_NEAR(result, expected);
234234
}
235+
236+
// Matrix Vector ops should respect perspective transforms.
237+
{
238+
auto matrix = Matrix::MakePerspective(Radians(kPiOver2), 1, 1, 100);
239+
auto vector = Vector3(3, 3, -3);
240+
241+
Vector3 result = matrix * vector;
242+
auto expected = Vector3(1, 1, 0.673401);
243+
ASSERT_VECTOR3_NEAR(result, expected);
244+
}
245+
246+
{
247+
auto matrix = Matrix::MakePerspective(Radians(kPiOver2), 1, 1, 100) *
248+
Matrix::MakeTranslation(Vector3(0, 0, -3));
249+
auto point = Point(3, 3);
250+
251+
Point result = matrix * point;
252+
auto expected = Point(1, 1);
253+
ASSERT_POINT_NEAR(result, expected);
254+
}
255+
256+
// Resolves to 0 on perspective singularity.
257+
{
258+
auto matrix = Matrix::MakePerspective(Radians(kPiOver2), 1, 1, 100);
259+
auto point = Point(3, 3);
260+
261+
Point result = matrix * point;
262+
auto expected = Point(0, 0);
263+
ASSERT_POINT_NEAR(result, expected);
264+
}
235265
}
236266

237267
TEST(GeometryTest, MatrixTransformDirection) {

impeller/geometry/matrix.h

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
#include <cmath>
88
#include <iomanip>
9+
#include <limits>
910
#include <optional>
1011
#include <ostream>
1112
#include <utility>
@@ -357,14 +358,30 @@ struct Matrix {
357358
}
358359

359360
constexpr Vector3 operator*(const Vector3& v) const {
360-
return Vector3(v.x * m[0] + v.y * m[4] + v.z * m[8] + m[12],
361+
Scalar w = v.x * m[3] + v.y * m[7] + v.z * m[11] + m[15];
362+
Vector3 result(v.x * m[0] + v.y * m[4] + v.z * m[8] + m[12],
361363
v.x * m[1] + v.y * m[5] + v.z * m[9] + m[13],
362364
v.x * m[2] + v.y * m[6] + v.z * m[10] + m[14]);
365+
366+
// This is Skia's behavior, but it may be reasonable to allow UB for the w=0
367+
// case.
368+
if (w) {
369+
w = 1 / w;
370+
}
371+
return result * w;
363372
}
364373

365374
constexpr Point operator*(const Point& v) const {
366-
return Point(v.x * m[0] + v.y * m[4] + m[12],
375+
Scalar w = v.x * m[3] + v.y * m[7] + m[15];
376+
Point result(v.x * m[0] + v.y * m[4] + m[12],
367377
v.x * m[1] + v.y * m[5] + m[13]);
378+
379+
// This is Skia's behavior, but it may be reasonable to allow UB for the w=0
380+
// case.
381+
if (w) {
382+
w = 1 / w;
383+
}
384+
return result * w;
368385
}
369386

370387
constexpr Vector4 TransformDirection(const Vector4& v) const {

0 commit comments

Comments
 (0)