【问题标题】:How to rotate, scale, and translate a matrix all at once in C#?如何在 C# 中一次旋转、缩放和平移矩阵?
【发布时间】:2009-03-11 19:52:37
【问题描述】:

好的,这应该是一个简单的矩阵问题,但我对矩阵的理解有些有限。这是场景:我有一个 1px x 1px 的精灵,我想按一定量 x 和 y 缩放(每边不同的量),然后我想将该精灵旋转某个角度,然后我希望能够精确定位整个东西(从左上角或中心,对我来说没有区别)。

到目前为止,我的代码有点接近,但根据我通过的角度,它往往会偏离一些随机量。

我认为这样做可以:

        Point center = new Point( 50, 50 );
        float width = 60;
        float height = 100;
        float angle = 0.5;
        Vector3 axis = new Vector3( center.X, center.Y, 0 );
        axis.Normalize();
        Matrix m = Matrix.Scaling( width, height, 0 ) *
            Matrix.RotationAxis( axis, angle ) *
            Matrix.Translation( center.X, center.Y, 0 );

但它往往会缩小旋转线的比例,即使我认为它的定位有点正确。

我也试过这个:

  Matrix m = Matrix.Transformation2D( new Vector2( center.X, center.Y ), 0f,
      new Vector2( width, height ), new Vector2( center.X, center.Y ),
      angle, Vector2.Zero );

这条线看起来完全正确,大小和形状都完全正确,但我根本无法正确定位它。如果我在上述调用结束时使用平移向量,或者如果我使用 Sprite.Draw 设置位置,则两者都无法正常工作。

这一切都在 SlimDX 中。我做错了什么?

【问题讨论】:

    标签: c# matrix translation slimdx


    【解决方案1】:

    我刚刚经历了学习矩阵变换的痛苦,但是使用了 XNA。

    我发现 these articles to be very 有助于理解发生的事情。 XNA 中的方法调用非常相似,其背后的理论都应该适用于您,即使使用 SlimDX。

    看一眼您的代码,我认为您应该在开始时翻译到原点,然后在结尾处再次翻译到最终位置,尽管我在这方面还是有点新手好吧。

    我会这样做的顺序是:

    • 翻译到原点
    • 规模
    • 旋转
    • 翻译到所需位置

    首先翻译到原点的原因是旋转是基于原点的。因此,要围绕某个点旋转某些东西,请在旋转之前将该点放在原点上。

    【讨论】:

    • 嗯...这似乎非常接近。平移到原点、缩放和旋转步骤效果很好,但是当我尝试平移到所需位置时,它的行为真的很奇怪——我改变了 x 坐标,它在 x 和 y 中移动。我在想它是在旋转的空间中平移...
    • 我还不清楚的另一件事是如何翻译到原点。我有两个点,加上第三个在它们的中心。我一直在将中心翻译成原点,但我应该以不同的方式翻译吗?
    • 与其翻译回你想要的位置,你能改变你画的位置吗?
    • 改变我画的位置...你的意思是调整世界坐标,然后再调整回来?我对此犹豫不决,特别是因为我已经在为模拟 2d 缩放等处理世界坐标。我想我已经接近完成这项工作了。
    【解决方案2】:

    好的,现在可以了。这是我的工作代码,以防其他人需要它:

        Point sourceLoc = new Point ( 50, 50 );
        float length = 60;
        float thickness = 2;
        float angle = 0.5;
        Matrix m = Matrix.Scaling( length, thickness, 0 ) *
                Matrix.RotationZ( angle ) *
                Matrix.Translation( sourceLoc.X, sourceLoc.Y, 0 );
        sprite.Transform = m;
    
        sprite.Draw( this.tx, Vector3.Zero, Vector3.Zero, Color.Red );
    

    这将绘制一条您选择的长度的斜线,其厚度等于您选择的厚度(假设您的纹理是 1x1 像素的白色图像)。源位置是发射线的位置,无论您指定什么角度(以弧度为单位)。因此,如果您从零开始并递增 0.1 直到达到 2PI,然后重置为 0,您将拥有一条围绕中心旋转的线,如时钟指针或雷达扫描。这就是我一直在寻找的——感谢所有做出贡献的人!

    【讨论】:

      【解决方案3】:

      您是否围绕正确的轴旋转?我是矩阵方面的新手,但在我看来,由于精灵存在于 x、y 空间中,因此旋转轴应该是 Z 轴 - 即 (0,0,1)。

      【讨论】:

      • 嗯,这是一个很好的观点,但是当我进行缩放时我的旋转似乎工作正常 - 当我尝试定位它时问题就来了。我可以将这三个中的任何两个都工作,但是当把它们放在一起时我做错了!
      • 嘿,Z 轴很好——在我上面的第一个例子中,这是非常相关的。
      【解决方案4】:

      您需要做的是一次一步地进行每个转换。做缩放先画它。是不是你期望的地方。然后加入旋转,然后平移。这将有助于发现不正确的假设。

      您还可以绘制临时线以帮助确定坐标的位置。例如,如果您进行拉伸和旋转,并期望您的终点位于 0,0。在 0,0 处画一条端点作为另一条线的双重检查,看看是否真的如此。

      对于您的具体问题,问题可能与轮换有关。缩放和旋转后,线现在偏离中心,导致您在翻译时出现问题。

      一般的解决方案是将线移回原点,执行任何涉及更改其形状或方向的操作。之后,因为您在一个已知的好位置,您可以翻译到您的最终目的地。

      对评论的回应

      如果平移是一个问题并且您正在转换坐标系,那么您将需要编写一个转换函数来在旧系统和新系统之间进行转换。

      例如,如果您旋转 45 度。在旋转之前,您可以平移 0,1 以向上移动 1 英寸。旋转后,您必须平移大约 -.70707、.070707 才能相对于原始坐标系向上移动 1 英寸。

      【讨论】:

      • 我已经尝试过单独做每个部分——我应该提到这一点。缩放和翻译完美地工作。但是正如您所说,当我添加旋转时,它会消失。是的,我确实必须在参考点使用图标,这样我才能看到我有多接近。我现在要试试抵消。
      • 旋转混乱,因为它围绕原点旋转。
      • 我现在尝试回到原点,然后翻译回我想要的位置。这似乎很接近,但平移已关闭,因为它似乎在旋转的坐标空间内平移。
      • 转换绘图对象的坐标空间而不是对象本身会导致您看到的许多奇怪行为。
      猜你喜欢
      • 2017-02-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-02-14
      • 1970-01-01
      相关资源
      最近更新 更多