0
\$\begingroup\$

In my 2d XNA game, because SpriteBatch treats world space as client space and has positive Y axis down and negative up, I've built my game's world space with that coordinate system too. However, I've hit a snag when I try to rotate a position around the origin using a matrix.

var p1 = new Vector2(95f, 40f);

var m = Matrix.CreateRotationZ(MathHelper.ToRadians(90));

var p2 = Vector2.TransformNormal(p1, m);

This results in p2.X == -40 and p2.Y == 95. If there's an object that is positioned relative to another object and that other object rotates, the child object gets swung around the parent object in the opposite direction because the matrix works in the positive Y axis up and negative down coordinate system.

What's the best way to account for this? Negate the Y value before and after transforming?

EDIT: To get more detailed I am trying to do a transformation like this, where child rotates with parent:

enter image description here

I though I would be able to multiply the matrices from the child object up through each of its parents' transform matrices in order to get its final world position, scale, and rotation that can be passed to SpriteBatch.Draw. Unfortunately the combined translations and rotations don't work out properly with the inverted Y axis.

\$\endgroup\$
1
\$\begingroup\$

Because the y-axis is flipped, you need to negate the angle.

The x-axis is in the same place, so angles of 0 and pi are the same (the x-axis and the negative x-axis). Negating the angle has the effect of negating the y-axis, because y=sin(a), and sin(-a)=-sin(a). Thus just negating the angle (right before making the Z matrix) has the effect you desire. Be very careful with multiple coordinate systems: I would advise sticking to one for as much as possible, even if that means adding a bunch of negations to get the angles to do what you expect.

\$\endgroup\$
  • \$\begingroup\$ Doing this caused the final rotation of the child object to be 180 degrees off. I guess somehow the parent relative rotation of the child is being negated as well? Please see edit. \$\endgroup\$ – Mars Jan 28 '14 at 7:49
  • \$\begingroup\$ Add an extra matrix at the top of the stack that transforms from the world you want (where +Y is up) to the world SpriteBatch or whatever wants. It should be easy to construct this matrix: it is almost the identity, but with a -1 on the diagonal in the y column. Be careful which order you are multiplying matrices in. Is the child fixed relative to the parent, just backwards, or does the relative position vary as they move? \$\endgroup\$ – user41442 Jan 28 '14 at 19:37
  • \$\begingroup\$ It's fixed relative to the parent. \$\endgroup\$ – Mars Jan 29 '14 at 8:07
0
\$\begingroup\$

What ended up being the solution was to transform the individual position, rotation, and scale of each object with the combined matrices of each parent going up when rendering in world space. Previously I was multiplying the matrix representing the position, rotation, and scale of the object with the parent matrices and then decomposing the final matrix. Now everything works as expected even with the positive Y axis going down and rotation is always clockwise.

\$\endgroup\$
0
\$\begingroup\$

It can be also done with pure math, take a look:

b.rotation = a.rotation;
b.Position.X = a.Position.X+(Math.Cos((b.rotation+offset)/180*Math.PI)*distanceOffset);
b.Position.Y = a.Position.Y+(Math.Sin((b.rotation+offset)/180*Math.PI)*distanceOffset);

Where:

  • "b" is the small cirlce around the big one
  • "a" is the big circle
  • "offset" is the offset around the circle in degrees
  • "distanceOffset" is the small circle's distance from the big circle (big circle radius+small circle radius)

Code in work. (link works, but the host is slow)

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.