在3D中随时间旋转

时间:2013-02-19 20:45:25

标签: c# xna rotation

我正在与Xna 4合作,做一个游戏,我有一个游戏对象(宇宙飞船)在Y轴= 0平面的3D世界中移动.. Aka 2.5D ..

到目前为止,我使用非常复杂的角度计算来创建2个向量之间的旋转,但该算法缺乏考虑对象已经旋转的能力。所以结果变得有趣.. 因此,我希望有人能够向我展示一种智能且易于实现的使用矩阵和矢量数学的方法,以便随着时间推移进行这样的旋转。

我在之前的搜索中注意到,人们在对象类中有以下变量: - 位置矢量3 - 右矢量3 - 向上vector3 - 旋转矩阵 - transformMatrix矩阵 - 速度矢量3 - 等..

我经常问自己为什么需要为一个简单的当前位置拥有那么多变量..或者我可能不理解..反正..

我目前有位置,旋转和变换矩阵,并且想知道我还需要什么以及如何计算它,然后如何实现JUST随时间的旋转。

我的右键单击移动命令trig调用的方法在点击发生的Y = 0平面上发送一个vector3位置。

public void MoveCommand(Vector3 pos){ }

我测试过这个,给出的“pos”是准确的。任何帮助都会被贬低..

3 个答案:

答案 0 :(得分:0)

您应根据所需的旋转检查Matrix.CreateRotationX Y或Z. X,Y或Z是旋转轴, 如果选择Y,您将看到“2D”旋转(偏航),因为这是您用作深度的轴。 如果选择X轴或Z轴,您将看到“3D”旋转(俯仰和滚动)

代码应如下所示:

WorldMatrix = Rotations * Translation

,其中     Rotations = Matrix.CreateRotationX(angleRadians)  和     Translation = Matrix.CreateTranslation(Position);

世界矩阵是影响模型的矩阵,视图和投影取决于相机

现在,如果你想知道矢量之间的角度,你应该检查点积或atan2函数,因为你在2D中

答案 1 :(得分:0)

Vector3 Position;
float Rotation;

Matrix World
{
    get
    {
        return Matrix.CreateRotationZ(Rotation) * Matrix.CreateTranslation(Position);
    }
}

public void RotateInstantly(Vector3 position)
{
    Rotation = Math.Atan2(Position.Y - position.Y, Position.x - position.x);
}

public void RotateIncremently(Vector3 position, float maxStep)
{
    float targetRotation = Math.Atan2(Position.Y - position.Y, Position.x - position.x);
    float diff = targetRotation - Rotation;

    if (Math.Abs(diff) > maxStep)
    {
        if (targetRotation > Rotation)
            Rotation += maxStep;
        else
            Rotation -= maxStep;
    }
    else
        Rotation = targetRotation;
}

您可以像这样使用RotateIncremently:* float dt =(float)gameTime.ElapsedGameTime.TotalSeconds;

float maxRotationVelocity = Math.TwoPi; // 2 * Pi是一场革命。

RotateIncremently(target.Position,maxRotationVelocity * dt);

答案 2 :(得分:0)

感谢Stig-RuneSkansgård的回复(如果你的丹麦 hi5 ),我修复了我的旧角度计算,并在每种情况下都能使用它。所以我想我会回答我自己的问题适用于我的解决方案,以便将来的访问者可以从中受益..这是一个非常大的Ship类的片段+一个帮助计算角度的方法:

public static float CalculateAngleFromVectors(Vector3 v1, Vector3 v2) {
        float x = 0;
        float X = v2.X - v1.X,
              Z = v2.Z - v1.Z;
        if (Z == 0) {
            x = (X < 0 ? 90 : 270);
        } else if (X == 0) {
            x = (Z < 0 ? 180 : -180);
        } else {
            float temp = MathHelper.ToDegrees((float)Math.Atan(X / Z));
            if (X < 0) {
                x = (Z < 0 ? Math.Abs(temp) : 180 - Math.Abs(temp));
            } else {
                x = (Z < 0 ? 360 - Math.Abs(temp) : Math.Abs(temp) + 180);
            }
        }
        return x;
    }

此方法可以获得旋转船只的浮动角度(以度为单位)(从标准的0度起点)。

要使用它,只需在你的类中创建一些类似这样的更新/动画方法:

float desiredRotation = 0, currentRotation = 0, totalElapsed = 0, timePerFrame = 0.05f;
        if (desiredRotation != 0) {
            totalElapsed += elapsed;
            if (totalElapsed > timePerFrame) {
                if (isRotationComplete()) {
                    rotX += MathHelper.ToRadians(desiredRotation);
                    currentRotation = desiredRotation = 0;
                } else if (desiredRotation > currentRotation) {
                    currentRotation += shipTurnSpeed;
                } else if (desiredRotation < currentRotation) {
                    currentRotation -= shipTurnSpeed;
                }
                totalElapsed -= timePerFrame;
            }
        }

编辑:和完成检查:

private bool isRotationComplete() {
        bool b = false;
        if (desiredRotation > currentRotation && currentRotation + shipTurnSpeed > desiredRotation) {
            b = true;
        } else if (desiredRotation < currentRotation && currentRotation - shipTurnSpeed < desiredRotation) {
            b = true;
        }
        return b;
    }

基本上这样做是为了总是检查是否DesherRotation大于0 ..如果是,那么这意味着玩家已经给出旋转命令(或AI)..我的例子中的CurrentRotation是如何自从最后一次给出旋转命令以来已经旋转了很多,并且在旋转完成后设置为0。你应该有一个旋转矩阵,它使用不同的变量来显示旋转..我的是:

public float rotX { get; set; }
    public float rotY { get; set; }
    public Vector3 position { get; set; }
    public Matrix Transform {
        get {
            return (Matrix.Identity *
                    Matrix.CreateScale(scale) *
                    Matrix.CreateRotationY(MathHelper.Pi) *
                    Rotation *
                    Matrix.CreateTranslation(position));
        }
    }
    public float ShipCurRotation { get { return (rotX + MathHelper.ToRadians(currentRotation)); } }
    public Matrix Rotation { get { return (Matrix.CreateRotationY(ShipCurRotation) * Matrix.CreateRotationX(rotY)); } }

当旋转完成时,我的动画中设置了rotX变量,并且在初始化时也是如此。以下是我使用第一个代码片段为我生成的旋转角度的方法:

public void MoveToPosition(Vector3 pos) {
        desiredRotation = (CalculateAngleFromVectors(position, pos) - MathHelper.ToDegrees(rotX));
        isMoving = true;
    }

..这使得平滑的可自定义旋转,变换和移动设置..在XZ平面ofc .. Y轴是UP并始终为0 ..

如果您有任何建议或更改或想法可以让事情变得更好,请随意发表评论。我总是乐于改进。感谢您的回复,并希望这有助于很多新的开发人员,带我永远从网上收集这些东西..

PS。旋转可以直接应用到rotX进行即时旋转,绕过动画并转动。

WithRegards MatriXz