如何在不使用外部库的情况下用 C# 在 2D 画布上绘制旋转立方体?

问题描述 投票:0回答:1

我需要在 C# 中的 2D 画布上绘制一个类似 3D 的立方体(使用 Windows 窗体中的图形),并使其绕其轴旋转。但是,我不允许使用任何外部库(例如 OpenGL 或 DirectX)来为我处理此问题。如何手动实现 3D 旋转并投影到 2D 画布上?任何有关在 C# 中使用旋转矩阵和透视投影的资源或指南将不胜感激!

在这个阶段,我只能使用基元绘制一个立方体。

graphics.DrawLine(Pens.Black, width / 2 - x, height / 2 - x, width / 2 + x, height / 2 - x);
            graphics.DrawLine(Pens.Black, width / 2 - x, height / 2 - x, width / 2 - x, height / 2 + x);
            graphics.DrawLine(Pens.Red, width / 2 + x, height / 2 - x, width / 2 + x, height / 2 + x);
            graphics.DrawLine(Pens.Black, width / 2 - x, height / 2 + x, width / 2 + x, height / 2 + x);

            graphics.DrawLine(Pens.Black, width / 2 + x, height / 2 - x, width / 2 + x + 3 / 2 * x, height / 2 - x - 3 / 2 * x);
            graphics.DrawLine(Pens.Black, width / 2 - x, height / 2 - x, width / 2 - x + 3 / 2 * x, height / 2 - x - 3 / 2 * x);

            graphics.DrawLine(Pens.Black, width / 2 - x + 3 / 2 * x, height / 2 - x - 3 / 2 * x, width / 2 + 2 * x, height / 2 - x - 3 / 2 * x);

            graphics.DrawLine(Pens.Blue, width / 2 + x, height / 2 + x, width / 2 + 2 * x, height / 2 + x - 3 / 2 * x);

            graphics.DrawLine(Pens.Brown, width / 2 + 2 * x, height / 2 + x - 3 / 2 * x, width / 2 + 2 * x, height / 2 + x - 3 / 2 * x - 2 * x);
c# 3d rotation
1个回答
0
投票

首先,我们需要获得立方体的 8 个点并能够旋转它们。四元数数学确实很复杂,但是一旦掌握了它的窍门,它们的 API 就非常简单了。

这是我如何做到这一点的基本要点(可能有更好的方法,我对图形不太精通)。不管怎样,你在 3D 空间中得到了立方体的 4 个非相对的角。在 3D 空间中旋转它们,然后将它们转换为 2D 表示。找出 2D 空间中哪个角最接近中心并将其删除。复制剩余点的负值,最终得到 6 个点,您可以将它们画成立方体。

这可能会破坏立方体面向前方的边缘情况,在这种情况下,您只需要 4 个点来绘制立方体。但这留给读者作为练习。

public class RotatingCube
{
    public Vector3[] points = new Vector3[4]
    {
        // This combination of points is important here!
        new( 1,  1, 1),
        new( 1, -1, 1),
        new(-1, -1, 1),
        new(-1,  1, 1),

        // new(-1, -1, -1),
        // new(-1,  1, -1),
        // new( 1,  1, -1),
        // new( 1, -1, -1),
    };

    public Vector2[] GetPoints2D(Quaternion rotation)
    {
        Vector2 points2D = new Vector2[6];
        
        // Rotate the 3D point and make it 2D.
        // Whilst we are doing that, figure out which point is closest to the center.
        double lowestLength = double.MaxValue;
        int lowestIndex;
        for (int i = 0; i < 4; i++)
        {
            var point = Vector3.Transform(point[i], rotation);
            points2D[i] = new Vector2(point.X, point.Y);
            var length = points2D[i].LengthSquared();
            if (length < lowestLength)
            {
                lowestLength = length;
                lowestIndex = i;
            }
        }

        // Remove the point closest to the center and copy the reverse of the other points.
        points2D[lowestIndex] = points2D[3];
        points2D[3] = -points2D[0];
        points2D[4] = -points2D[1];
        points2D[5] = -points2D[2];
    }

    public void Draw(Quaternion rotation)
    {
        // This won't work because the graphics API expects an array of Point[]
        // but you get the idea, just times it by 100 or sumethin'
        // Also you're lucky I was bored and have worked with 2D representation
        // of 3D objects before :)
        var points2D = GetPoints2D(rotation);
        graphics.FillPolygon(myBrush, points2D);
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.