四元数,旋转模型并与方向对齐

时间:2012-11-06 19:56:53

标签: xna rotation alignment point quaternions

假设您有四元数描述3D模型的旋转。

我想要做的是,给定一个Object(使用rotationQuaternion,side vector ...),我想将它与目标点对齐。

对于宇宙飞船,我希望驾驶舱指向目标。

这是我的一些代码......它不是我想要的,我不知道为什么......

        if (_target._ray.Position != _obj._ray.Position)
        {
            Vector3 vec = Vector3.Normalize(_target._ray.Position - _obj._ray.Position);
            float angle = (float)Math.Acos(Vector3.Dot(vec, _obj._ray.Direction));
            Vector3 cross = Vector3.Cross(vec, _obj._ray.Direction);

            if (cross == Vector3.Zero)
                cross = _obj._side;

            _obj._rotationQuaternion *= Quaternion.CreateFromAxisAngle(cross,angle);
        }
        // Updates direction, up, side vectors and model Matrix
        _obj.UpdateMatrix();

一段时间后,rotationQuaternion在X,Y,Z和W

处几乎为零

有任何帮助吗? 谢谢; - )

3 个答案:

答案 0 :(得分:2)

这是我用来获取锁定目标旋转的四元数的快捷方式:

Matrix rot = Matrix.CreateLookAt(_arrow.Position, _cube.Position, Vector3.Down);
_arrow.Rotation = Quaternion.CreateFromRotationMatrix(rot);

对于这个例子,我正在渲染一个箭头和一个立方体,其中立方体在一个圆圈中移动,并且使用上面的代码,箭头总是指向立方体。 (虽然我认为当立方体恰好在上方或下方时有一些边缘情况)。

enter image description here

一旦获得此四元数(从太空飞船到目标),您可以使用Quaternion.Lerp()在当前船舶旋转和对齐的轮船之间进行插值。这将使您的旋转平滑过渡(而不仅仅是对齐目标)。


顺便说一句,可能是因为你在分配时使用*=,你的轮换会减少到零。

答案 1 :(得分:2)

你的代码有点时髦。

if (_target._ray.Position != _obj._ray.Position)
{

这可能是也可能不正确。显然,你已经覆盖了等于比较器。在这里做的正确的事情是确保两条(单位长度)光线之间的点积接近1.如果光线具有相同的原点,那么可能具有相同的“位置”意味着它们是相同。

  Vector3 vec = Vector3.Normalize(_target._ray.Position - _obj._ray.Position);

这似乎特别错误。除非以奇怪的方式覆盖了减号运算符,否则减去这种方式是没有意义的。

这是我推荐的伪代码:

normalize3(targetRay);
normalize3(objectRay);
angleDif = acos(dotProduct(targetRay,objectRay));
if (angleDif!=0) {
  orthoRay = crossProduct(objectRay,targetRay);
  normalize3(orthoRay);
  deltaQ = quaternionFromAxisAngle(orthoRay,angleDif);
  rotationQuaternion = deltaQ*rotationQuaternion;
  normalize4(rotationQuaternion);
}

这里有两点需要注意:

  1. 四元数不是可交换的。我假设你的四元数是旋转列向量;所以我把deltaQ放在左边。目前还不清楚你的* =运营商在做什么。
  2. 在乘法后定期规范化四元数非常重要。否则会出现小错误,并且会逐渐偏离单位长度,造成各种各样的悲伤。

答案 2 :(得分:0)

OMG!有效!!!

            Vector3 targetRay = Vector3.Normalize(_target._ray.Position - _obj._ray.Position);
        Vector3 objectRay = Vector3.Normalize(_obj._ray.Direction);
        float angle = (float)Math.Acos(Vector3.Dot(targetRay, objectRay));

        if (angle!=0)
        {
            Vector3 ortho = Vector3.Normalize(Vector3.Cross(objectRay, targetRay));
            _obj._rotationQuaternion = Quaternion.CreateFromAxisAngle(ortho, angle) * _obj._rotationQuaternion;
            _obj._rotationQuaternion.Normalize();
        }
        _obj.UpdateMatrix();

非常感谢JCooper !!!

niko我喜欢Lerp的想法; - )