Search code examples
c#matrixrotationxnamonogame

Jittering when rotating and then translating a matrix in XNA/Monogame


I'm having a problem in Monogame/XNA where I am storing the position/rotation/scale in a matrix for easier manipulation of these values with parenting. It all seems to be going well, except for when I rotate the matrix, which is when the object seems to jitter around and shake. Here is the relevant code:

        // Executes every frame
        internal void Draw()
        {
            float RadRot = MathHelper.ToRadians(Rotation);

            // Sets world matrix for things that draw
            if (Parent != null) {
                WorldMatrix = Matrix.CreateScale(Size.X, Size.Y, 1) * -Matrix.CreateTranslation(Pivot.X, Pivot.Y, 0) * Matrix.CreateRotationZ(RadRot);
                WorldMatrix.Translation = Vector3.Zero; // Rotating seems to create a strange positioning issue, this fixes it
                WorldMatrix *= Matrix.CreateTranslation(RelativePosition.X, RelativePosition.Y, 0) * Matrix.CreateRotationZ(MathHelper.ToRadians(Parent.Rotation)) * <FIX JITTER> * Matrix.CreateTranslation(Parent.DecomposedPosition.X, Parent.DecomposedPosition.Y, 0);
            } else
            {
                // For objects without parents
                WorldMatrix = Matrix.CreateScale(RelativeSize.X, RelativeSize.Y, 1) * -Matrix.CreateTranslation(Pivot.X, Pivot.Y, 0) * Matrix.CreateRotationZ(RadRot);
                WorldMatrix.Translation = Vector3.Zero; // This fixes the jitter issue, but in the code above (in the if statement), I can't do this when translating the child around the parent
                WorldMatrix *= Matrix.CreateTranslation(RelativePosition.X, RelativePosition.Y, 0);
            }

            Vector3 TempPos = Vector3.Zero;
            Quaternion TempRot = Quaternion.Identity;
            Vector3 TempSize = Vector3.Zero;
            WorldMatrix.Decompose(out TempSize, out TempRot, out TempPos);

            DecomposedPosition = new Vector2(-TempPos.X, -TempPos.Y);
            DecomposedRotation = MathHelper.ToRadians(Rotation); // Can't convert quaternions, but this works
            DecomposedSize = new Vector2(MathF.Round(TempSize.X), MathF.Round(TempSize.Y));

            foreach (Component2D comp in Components)
            {
                comp.Draw();
            }
        }

This is what comp.Draw calls:

MyGame.SpriteDrawing.Draw(Image, new Rectangle(LinkedObject.DecomposedPosition.ToPoint(), LinkedObject.DecomposedSize.ToPoint()), RenderRegion, Color, LinkedObject.DecomposedRotation, LinkedObject.Pivot, SpriteEffects.None, LinkedObject.Layer + (SubLayer / 10000));

Here is what it looks like in action: Jitter

EXTRA NOTE: This jittering does occur no matter the scale of the objects


Solution

  • It seems that I was simply using the wrong SpriteBatch.Draw(). I was using the Rectangle version, whereas all I needed was to use the Vector2 version to prevent rounding errors.

    MyGame.SpriteDrawing.Draw(Image, LinkedObject.DecomposedPosition, RenderRegion, Color, LinkedObject.DecomposedRotation, LinkedObject.Pivot * RenderRegion.Size.ToVector2(), LinkedObject.DecomposedSize / RenderRegion.Size.ToVector2(), SpriteEffects.None, LinkedObject.Layer + (SubLayer / 10000));