I have a set of 3D points. All these points are on the same plane. I have the normal of the plane.

Now I need to rotate them in such a way that the Z value of all these points become zero. (that is, 3D to XY plane)

I have Googled a lot. I got very few results and most of them are very much mathematical. Few are about projection and few are with solution with OpenGL APIs.

I have seen this solution: Rotating 3d plane to XY plane

Based on this, I have implemented something like this:

public static List<Vector3D> RotateCoplanar3DPointsToXY(IList<Vector3D> points, Vector3D planeNormal)
            var zAxis = new Vector3D(0, 0, 1);
            var rotationAxis = zAxis.Cross(planeNormal);
            var rotationAngle = (float)Math.Acos(zAxis.Dot(planeNormal));
            var matrix = Matrix4x4.FromAngleAxis(rotationAngle, rotationAxis);
            var newPoints = new List<Vector3D>();
            for (var i = 0; i < points.Count; i++)
                var p = points[i];
                var newPoint = p.Transform(matrix);
            return newPoints;

But this implementation is not working.

I have another implementation below based on @Bálint's comment. This is also not working.

public static Vector3D Cross(Vector3D a, Vector3D b)
            return new Vector3D(
                a.Y * b.Z - a.Z * b.Y,
                a.Z * b.X - a.X * b.Z,
                a.X * b.Y - a.Y * b.X);

        public static Matrix4x4 GetMatrixForRotatingCoplanar3DPointsToXY(Vector3D planeNormal)
            var Z_NORMAL = new Vector3D(1, 0, 0);
            var d = planeNormal;
            var u = Z_NORMAL;

            var r = Cross(d, u);
            var t = Cross(r, d);
            var matrix = new Matrix4x4(
             r.X, t.X, d.X, 0,
             r.Y, t.Y, d.Y, 0,
             r.Z, t.Z, d.Z, 0,
             0, 0, 0, 1);

            return matrix;
  • 2
    \$\begingroup\$ At first glance it looks ok. Are you getting wrong results? If so, what results are you getting? Otherwise, please clarify the problem. \$\endgroup\$
    – Theraot
    Jul 16, 2019 at 22:54
  • \$\begingroup\$ I think, it is working fine after checking a condition like if(planeNormal==zAxis) { return new List<Vector3D>(points); } \$\endgroup\$ Jul 16, 2019 at 23:10
  • \$\begingroup\$ Hi @Bálint, Thanks for your solution. I have implemented your suggestion. Somewhere I am wrong. I have updated the question with your answer. Can you please look into this? \$\endgroup\$ Jul 18, 2019 at 23:18
  • \$\begingroup\$ "not working" is never enough information to diagnose a specific problem. Always be sure to include the exact symptoms you're observing, like a test case for which the output differs from the desired output. \$\endgroup\$
    – DMGregory
    Jul 18, 2019 at 23:19

1 Answer 1


Doing this requires high-level mathematics (college/university), so it's no wonder those are the only solutions you found. If you know how matrices work, it's pretty simple.

I already described how you can get a rotation matrix from a normal in this post. Your problem is the exact inverse of this: instead of going from points in the XY plane to a rotated version, you need to go from the rotated version back to the XY plane. To do this, you need the inverse of the rotation matrix.

Thankfully, it's pretty simple to do that with rotation matrices, since to inverse one, you just need to transpose it. There should be a method for it in your library of choice, but if there isn't one, it's simply swapping the values out in the following way:

$$\begin{bmatrix} a & b & c & d\\ e & f & g & h\\ i & j & k & l\\ m & n & o & p \end{bmatrix}\rightarrow \begin{bmatrix} a & e & i & m\\ b & f & j & n\\ c & g & k & o\\ d & h & l &p \end{bmatrix} $$

Now just multiply every point with this matrix and you'll transform them in the XY plane.


You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .