在XNA中旋转3D模型

10

我是XNA的新手,正在创建一个简单的游戏。很抱歉这可能非常简单,但我找不到任何帮助。游戏中有一艘我用Blender制作的飞船,我想通过旋转飞船的X、Y和Z轴来控制它。以下是我的代码:

protected override void Draw(GameTime gameTime)
    {
        GraphicsDevice.Clear(Color.CornflowerBlue);
  RotationMatrix = Matrix.CreateRotationY(MathHelper.PiOver2) * Matrix.CreateRotationY    (rotationY) * Matrix.CreateRotationX(rotationX) * Matrix.CreateRotationZ(rotationZ);

        Matrix shipTransformMatrix = RotationMatrix * Matrix.CreateTranslation(ship.Position);

                        DrawModel(ship.Model, shipTransformMatrix, ship.Transforms);
        // TODO: Add your drawing code here


        base.Draw(gameTime);
    }

    public  void DrawModel(Model model, Matrix modelTransform, Matrix[] absoluteBoneTransforms)
    {
        //Draw the model, a model can have multiple meshes, so loop
        foreach (ModelMesh mesh in model.Meshes)
        {
            //This is where the mesh orientation is set
            foreach (BasicEffect effect in mesh.Effects)
            {

                effect.World = absoluteBoneTransforms[mesh.ParentBone.Index] * modelTransform;
                effect.Projection = projectionMatrix;
                effect.View = viewMatrix;

            }

            //Draw the mesh, will use the effects set above.
            mesh.Draw();
        }
    }

这将旋转船只,但不是沿着船的轴心旋转。 如果我旋转Y轴(通过更改rotationY的值),那么船将沿其Y轴旋转。 但是,如果我旋转X或Z轴,则船会根据世界的X和Z轴旋转,而不是自己的轴心。 我如何使船沿着自己的轴心旋转? 我需要以不同方式处理矩阵吗? 谢谢

3个回答

6
使用CreateRotationX,CreateRotationY和CreateRotationZ都是围绕世界或全局轴应用旋转。这意味着它只导致您的对象围绕世界/全局轴旋转,而不是您的对象本地轴。
使用CreateFromAxisAngle允许您输入任何旋转轴,包括船舶自己的本地轴。
然而,需要进行整体旋转范例的转换,因为围绕船的上方等任意轴旋转,可能会同时更改任何3个角度值。跟踪所有这些变化非常困难。有一种更简单的方法:
只需将旋转以矩阵(或四元数)形式存储即可,而不是三个角度值。

谢谢。在CreateFromAxisAngle中,我如何定义我的飞船旋转轴?我尝试过了,但它只是改变了我的飞船形状。我该如何将旋转存储在矩阵中?这就是我一直在尝试做的事情。 - davidsbro
碰巧我写了一篇关于这个问题的博客文章。http://stevehazen.wordpress.com/2010/02/15/matrix-basics-how-to-step-away-from-storing-an-orientation-as-3-angles/ - Steve H
谢谢。在你发布链接之前,我已经找到了它。哈哈。我阅读了它并成功解决了问题。非常感谢!它非常清晰且非常有帮助。 - davidsbro

2

编辑:在此给Steve一些功劳(非常好的答案,我已经很久没有做过这么多3D数学了)。

本教程将向您展示如何设置Steve建议的内容!

http://www.riemers.net/eng/Tutorials/XNA/Csharp/Series1/Rotation_-_translation.php

原帖:

我相信你必须在你的BasicEffect循环中创建一个effect.Rotation。

我相信所有这些都在MSDN的基本教程中涵盖了。你的代码甚至看起来像是从那里来的。

http://msdn.microsoft.com/en-us/library/bb203897(v=xnagamestudio.31)

如果没有,请查看这个链接,Reimer覆盖所有值得了解的3D内容:

http://www.riemers.net/eng/Tutorials/XNA/Csharp/series1.php


谢谢。我尝试在我的BasicEffect循环中创建一个effect.Rotation效果,但是该效果没有旋转属性。我的问题不是旋转模型,我可以做到,而是让模型的轴与模型一起旋转。当我执行RotationMatrix = Matrix.CreateRotationY(MathHelper.PiOver2) * Matrix.CreateRotationY(rotationY) * Matrix.CreateRotationX(rotationX) * Matrix.CreateRotationZ(rotationZ);时,无论我首先为哪个轴创建旋转,都会随船一起旋转,但后面两个则不会。我必须按照某种特定的顺序乘以矩阵才能让它们与模型一起旋转吗? - davidsbro
顺序并不重要(就我所知)。但我确实看到你的问题了。请执行以下操作:RotationMatrix = Matrix.CreateRotationY(rotationY) * Matrix.CreateRotationX(rotationX) * Matrix.CreateRotationZ(rotationZ); - Nick Funk
我猜MathHelper.PiOver2是为了将你的船预先对齐到某个角度。相反,当你开始时,预设你的rotationY、X、Z为你想要的初始值。这样应该创建你所寻找的旋转。它围绕其中心轴旋转。 - Nick Funk
我非常确定顺序很重要,因为矩阵相乘的方式不同。矩阵A乘以矩阵B与B乘以A是不同的。我尝试了你说的那段代码,但结果却一样。如果我这样做RotationMatrix = Matrix.CreateRotationY (rotationY) * Matrix.CreateRotationX(rotationX) * Matrix.CreateRotationZ(rotationZ); 模型的Y轴会随之旋转,但如果我这样做 RotationMatrix = Matrix.CreateRotationX (rotationX) * Matrix.CreateRotationY(rotationY) * Matrix.CreateRotationZ(rotationZ); X轴会随着飞船旋转而Y轴不会。如何让所有轴都旋转? - davidsbro
你是正确的,davidsbro,顺序确实很重要。你所经历的是由于绕着三个轴旋转时出现的“万向锁”而导致自由度丧失。你可以通过使用四元数操作组合来产生你所需要的旋转来解决这个问题。(来源:https://en.wikipedia.org/wiki/Gimbal_lock) (来源:https://en.wikipedia.org/wiki/Quaternion) - Nick Funk

1

以下是我最终采取的措施,以防其他人像我一样被卡住:

Matrix RotationMatrix;
//every time I wanted to rotate around an axis, I would do something like this:
protected void rotateY()
    {
        RotationMatrix *= Matrix.CreateFromAxisAngle(RotationMatrix.Up, MathHelper.ToRadians(1.0f));
        //For the X axis I used RotationMatrix.Right, and for the Z RotationMatrix.Forward
    }
protected override void Draw(GameTime gameTime)
    {
        GraphicsDevice.Clear(Color.CornflowerBlue);


    Matrix shipTransformMatrix = RotationMatrix * Matrix.CreateTranslation(ship.Position);

                    DrawModel(ship.Model, shipTransformMatrix, ship.Transforms);
    // TODO: Add your drawing code here


    base.Draw(gameTime);
}

public  void DrawModel(Model model, Matrix modelTransform, Matrix[] absoluteBoneTransforms)
{
    //Draw the model, a model can have multiple meshes, so loop
    foreach (ModelMesh mesh in model.Meshes)
    {
        //This is where the mesh orientation is set
        foreach (BasicEffect effect in mesh.Effects)
        {

            effect.World = absoluteBoneTransforms[mesh.ParentBone.Index] * modelTransform;
            effect.Projection = projectionMatrix;
            effect.View = viewMatrix;

        }

        //Draw the mesh, will use the effects set above.
        mesh.Draw();
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接