如何在 C# 中同时旋转、缩放和平移矩阵?

发布于 2024-07-15 08:07:51 字数 1005 浏览 10 评论 0 原文

好吧,这应该是一个简单的矩阵问题,但我对矩阵的理解有些有限。 场景如下:我有一个 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 中。 我究竟做错了什么?

Okay, this is something that should be a simple matrix question, but my understanding of matrices is somewhat limited. Here's the scenario: I have a 1px by 1px sprite that I want to scale by some amount x and y (different amounts on each side), and then I want to rotate that sprite by some angle, and then I want to be able to precisely position the whole thing (from the top left or the center, makes no difference to me).

So far my code is vaguely close, but it tends to be off by some random amount depending on the angle I pass in.

I would think that this would do it:

        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 );

But it tends to shrink the scale of the rotated line way down, even though I think it's positioning it sort of right.

I've also tried this:

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

The line looks exactly right, with the exact right size and shape, but I can't position it correctly at all. If I use the translation vector at the end of the call above, or if I set a position using Sprite.Draw, neither works right.

This is all in SlimDX. What am I doing wrong?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

天荒地未老 2024-07-22 08:07:51

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

我找到了这些 文章 是< /a> 非常有助于理解发生的情况。 XNA 中的方法调用非常相似,其背后的理论都应该适用于您,即使使用 SlimDX 也是如此。

从浏览你的代码来看,我认为你应该从一开始就翻译到原点,然后在最后再次翻译到最终位置,尽管我在这方面仍然有点新手。

我执行此操作的顺序是:

  • 平移到原点
  • 缩放
  • 旋转
  • 平移到所需位置

首先平移到原点的原因是旋转是基于原点的。 因此,要围绕某个点旋转某物,请在旋转之前将该点放置在原点上。

I just went through the pain of learning matrix transformation, but using XNA.

I found these articles to be very helpful in understanding what happens. The method calls are very similar in XNA and the theory behind it all should apply to you, even with SlimDX.

From glancing at your code, I think you should be translating at the start, to the origin, and then translating again at the end, to the final position, though I'm still a little bit of a newbie at this as well.

The order I would do it in is:

  • Translate to origin
  • Scale
  • Rotate
  • Translate to desired location

The reason for translating to the origin first is that rotations are based from the origin. Therefore to rotate something about a certain point, place that point on the origin before rotating.

只涨不跌 2024-07-22 08:07:51

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

    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 开始,增加 0.1 之类的值,直到达到 2PI,然后重置为 0,您将得到一条像时钟指针或雷达扫描一样围绕中心旋转的线。 这就是我一直在寻找的东西——感谢所有贡献者!

Okay, this is now working. Here's my working code for this, in case someone else needs it:

    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 );

This will draw an angled line of your chosen length, with a thickness equal to your chosen thickness (presuming your texture is a 1x1 pixel white image). The source location is where the line will emit from, with whatever angle you specify (in radians). So if you start at zero and increment by something like 0.1 until you hit 2PI, and then reset to 0, you'll have a line that rotates around a center like a clock hand or radar sweep. This is what I was looking for -- thanks to all who contributed!

遇到 2024-07-22 08:07:51

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

Are you rotating around the correct axis? I'm a newbie at matrix stuff, but it seems to me that since the sprite exists in the x, y space, the rotation axis should be the Z-Axis - i.e. (0,0,1).

腹黑女流氓 2024-07-22 08:07:51

您需要做的是一次一步地进行每个转换。 首先进行缩放绘制。 是不是你所期待的地方。 然后放入旋转,然后进行平移。 这将有助于发现错误的假设。

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

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

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

回复评论

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

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

What you need to do is do each transformation one step at a time. Do the scaling first draw it. Is it where you expect it. Then throw in the the rotate, and then the translate. This will help uncover incorrect assumptions.

You can also draw in temporary lines to help figure where the coordinates are. For example if you do your stretching and rotation and expect your end point to be at 0,0. Drawing a another line with one endpoint at 0,0 will serve as a double check to see if that really the case.

For your specific problem the problem may be with the rotation. After you have scaled and rotate the line is now off center causing you problems when you are translating.

The general solution is to move the line back to the origin do any operations that involve changing it shape or orientation. Afterward because you are at a known good location you can translate to your final destination.

RESPONSE TO COMMENTS

If translation is an issue and you are transforming the coordinate system then you will need to write a conversion function to convert between the old system and the new.

For example if you are rotating 45 degrees. Before the rotation you could translate by 0,1 to move up 1 inch. After rotation you will have to translate by roughly -.70707, .070707 to move up 1 inch relative to the original coordinate system.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文