使模型面向目标


28

我有两个对象(目标和播放器),都具有位置(Vector3)和旋转(四元数)。我希望目标旋转并正对着玩家。目标射击时,应该向玩家射击。

我已经看到了很多关于播放器的示例,但是我不希望增量旋转,好吧,我想,只要我可以将播放器设置为100%,并且只要它确实起作用就可以。

仅供参考-我无法使用位置和旋转来做很多其他事情,而且除了我无法弄清楚的最后一件作品外,其他一切都很好。

代码示例在Target的类中运行,Position =目标位置,Avatar =玩家。

编辑

我现在正在使用他提供的Maik的C#代码,效果很好!


4
如果您要进行100%的slerp,则说明您没有使用slerp。您只是将旋转设置为0*(rotation A) + 1*(rotation B)-换句话说,您只是将旋转设置为旋转B很长一段时间。Slerp仅用于确定旋转方式应介于两者之间的方式(0%<x <100%)。
doppelgreener

好的,这是有道理的,但是目标仍然没有完全朝玩家旋转……使用该代码“很长一段时间”。
马克

Answers:


20

有多种方法可以做到这一点。您可以计算绝对方向或相对于化身的旋转,这意味着您的新方向= avatarOrientation * q。这是后者:

  1. 通过获取化身的单位前向矢量与从化身到目标的单位矢量(新的前向矢量)的叉积来计算旋转轴:

    vector newForwardUnit = vector::normalize(target - avatarPosition);
    vector rotAxis = vector::cross(avatarForwardUnit, newForwardUnit);
  2. 使用点积计算旋转角度

    float rotAngle = acos(vector::dot(avatarForwardUnit, newForwardUnit));
  3. 使用rotAxis和rotAngle创建四元数,并将其与头像的当前方向相乘

    quaternion q(rotAxis, rotAngle);
    quaternion newRot = avatarRot * q;

如果您需要帮助来查找化身的当前前向矢量,则输入1.即可:)

编辑:计算绝对方向实际上要容易一些,使用恒等矩阵的正向向量代替化身正向向量作为1)和2)的输入。并且不要将其乘以3),而是直接将其用作新方向:newRot = q


重要说明:该解决方案有2个由叉积的性质引起的异常:

  1. 如果前向向量相等。解决方案这里只是返回标识四元数

  2. 如果向量恰好指向相反的方向。解决方案是通过使用化身上轴作为旋转轴以及角度为180.0度来创建四元数。

这是在C ++中实现的那些边缘情况的实现。将其转换为C#应该很容易。

// returns a quaternion that rotates vector a to vector b
quaternion get_rotation(const vector &a, const vector &b, const vector &up)
{   
    ASSERT_VECTOR_NORMALIZED(a);
    ASSERT_VECTOR_NORMALIZED(b);

    float dot = vector::dot(a, b);    
    // test for dot -1
    if(nearly_equal_eps_f(dot, -1.0f, 0.000001f))
    {
        // vector a and b point exactly in the opposite direction, 
        // so it is a 180 degrees turn around the up-axis
        return quaternion(up, gdeg2rad(180.0f));
    }
    // test for dot 1
    else if(nearly_equal_eps_f(dot, 1.0f, 0.000001f))
    {
        // vector a and b point exactly in the same direction
        // so we return the identity quaternion
        return quaternion(0.0f, 0.0f, 0.0f, 1.0f);
    }

    float rotAngle = acos(dot);
    vector rotAxis = vector::cross(a, b);
    rotAxis = vector::normalize(rotAxis);
    return quaternion(rotAxis, rotAngle);
}

编辑:马克的XNA代码的更正的版本

// the new forward vector, so the avatar faces the target
Vector3 newForward = Vector3.Normalize(Position - GameState.Avatar.Position);
// calc the rotation so the avatar faces the target
Rotation = Helpers.GetRotation(Vector3.Forward, newForward, Vector3.Up);
Cannon.Shoot(Position, Rotation, this);


public static Quaternion GetRotation(Vector3 source, Vector3 dest, Vector3 up)
{
    float dot = Vector3.Dot(source, dest);

    if (Math.Abs(dot - (-1.0f)) < 0.000001f)
    {
        // vector a and b point exactly in the opposite direction, 
        // so it is a 180 degrees turn around the up-axis
        return new Quaternion(up, MathHelper.ToRadians(180.0f));
    }
    if (Math.Abs(dot - (1.0f)) < 0.000001f)
    {
        // vector a and b point exactly in the same direction
        // so we return the identity quaternion
        return Quaternion.Identity;
    }

    float rotAngle = (float)Math.Acos(dot);
    Vector3 rotAxis = Vector3.Cross(source, dest);
    rotAxis = Vector3.Normalize(rotAxis);
    return Quaternion.CreateFromAxisAngle(rotAxis, rotAngle);
}

好的,我通过对问题的编辑(提供的代码)看到了这张照片。不太清楚是什么问题。a和b输入是正向向量,或者至少是。
马克

@Marc在我的答案中看到我的XNA代码的更正版本。存在2个问题:1)新正向向量的计算错误,必须规范化AvatarPosition-TargetPosition 2)rotAxis必须在GetRotation中的叉积之后进行规范化
Maik Semder 2011年

@ Marc,2个较小的更改:3)源和dest已经标准化,无需在GetRotation中再次对其进行标准化4)不要在GetRotation中测试绝对值1 / -1,而是使用一些容差,我使用0.000001f
Maik Semder

嗯,多数民众赞成在仍然无法正常工作。模型也会发生相同的缩放问题,并且目标不会向虚拟角色旋转(我在您的注释中注意到您正在尝试将虚拟角色向虚拟对象旋转。...应该是相反的方向)...基本上,尝试让暴民面对玩家(第三人称相机中的头像)。GetRotation方法不应该了解有关目标和头像的当前旋转的信息,例如,您认为newForward是否已正确创建?
马克

如果对象已缩放,则意味着四元数没有单位长度,这意味着rotAxis没有被标准化。您是否使用rotAxis的规范化添加了我的最后一个代码更改?但是,请显示您当前的代码,并针对不起作用的示例情况,还请发布以下值:newForward rotAngle rotAxisreturned quaternion。暴民的代码将是相同的,一旦我们使它与化身一起工作,就很容易更改任何对象的标题。
Maik Semder 2011年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.