How to rotate, scale, and translate a matrix all at once in C#?

风流意气都作罢 提交于 2019-11-29 14:12:16

问题


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?


回答1:


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.




回答2:


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!




回答3:


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




回答4:


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.



来源:https://stackoverflow.com/questions/636081/how-to-rotate-scale-and-translate-a-matrix-all-at-once-in-c

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!