diff --git a/src/Avalonia.Build.Tasks/Avalonia.Build.Tasks.csproj b/src/Avalonia.Build.Tasks/Avalonia.Build.Tasks.csproj
index e864ea2007..7e4272f5d2 100644
--- a/src/Avalonia.Build.Tasks/Avalonia.Build.Tasks.csproj
+++ b/src/Avalonia.Build.Tasks/Avalonia.Build.Tasks.csproj
@@ -94,5 +94,6 @@
+
diff --git a/src/Avalonia.Visuals/Matrix.cs b/src/Avalonia.Visuals/Matrix.cs
index 4326dc3670..38d0508ffb 100644
--- a/src/Avalonia.Visuals/Matrix.cs
+++ b/src/Avalonia.Visuals/Matrix.cs
@@ -357,7 +357,7 @@ namespace Avalonia
///
/// Determines if the current matrix contains perspective (non-affine) transforms (true) or only (affine) transforms that could be mapped into an 2x3 matrix (false).
///
- private bool ContainsPerspective()
+ public bool ContainsPerspective()
{
// ReSharper disable CompareOfFloatsByEqualityOperator
diff --git a/src/Avalonia.Visuals/Point.cs b/src/Avalonia.Visuals/Point.cs
index 67e7d71fbc..473de8e501 100644
--- a/src/Avalonia.Visuals/Point.cs
+++ b/src/Avalonia.Visuals/Point.cs
@@ -1,5 +1,6 @@
using System;
using System.Globalization;
+using System.Numerics;
#if !BUILDTASK
using Avalonia.Animation.Animators;
#endif
@@ -244,6 +245,22 @@ namespace Avalonia
/// The transformed point.
public Point Transform(Matrix transform)
{
+ if (transform.ContainsPerspective())
+ {
+ var m44 = new Matrix4x4(
+ (float)transform.M11, (float)transform.M12, (float)transform.M13, 0,
+ (float)transform.M21, (float)transform.M22, (float)transform.M23, 0,
+ (float)transform.M31, (float)transform.M32, (float)transform.M33, 0,
+ 0, 0, 0, 1
+ );
+
+ var vector = new Vector3((float)X, (float)Y, 1);
+ var transformedVector = Vector3.Transform(vector, m44);
+ var z = 1 / transformedVector.Z;
+
+ return new Point(transformedVector.X * z, transformedVector.Y * z);
+ }
+
var x = X;
var y = Y;
var xadd = y * transform.M21 + transform.M31;