旋转然后平移 XNA/Monogame 中的矩阵时抖动

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

我在 Monogame/XNA 中遇到问题,我将 position/rotation/scale 存储在矩阵中以便通过育儿更轻松地操作这些值。一切似乎都进行得很顺利,除了当我旋转矩阵时,那是物体似乎在抖动和摇晃的时候。这是相关代码:

        // 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();
            }
        }

这就是comp.Draw所说的:

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

实际效果如下:

额外注意:无论对象的比例如何,这种抖动都会发生

尝试以不同的方式组织场景:

  • 让每个对象存储其比例 (Vector3)、旋转 (Quaternion) 和位置 (Vector3)
  • 每个对象都应该有一个 属性 结果矩阵(在本地 space),这将是这样的东西按以下顺序相乘:Matrix.CreateScale(scale) * Matrix.CreateRotationQuaterion(旋转)* Matrix.CreateTranslation(位置)
  • 现在,当你有了上面的局部space矩阵,用它来创建WorldMatrix,它是父世界矩阵和这个对象局部space矩阵的乘积,或者局部space 仅矩阵 - 当没有父级存在时。
  • 尽量只将每个元素的世界矩阵传递给你的绘图代码,避免分解
  • 如果层次结构较大,则可以在不更改的情况下缓存本地矩阵结果

看来我只是用错了SpriteBatch.Draw()。我使用的是 Rectangle 版本,而我所需要的只是使用 Vector2 版本来防止舍入错误。

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