1

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

我想要做的是,给定一个对象(带有rotationQuaternion,侧向量......),我想将它与目标点对齐。

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

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

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

一段时间后,旋转四元数在 X、Y、Z 和 W 处几乎为零

有什么帮助吗?谢谢 ;-)

4

3 回答 3

3

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

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

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

在此处输入图像描述

一旦你得到这个四元数(从宇宙飞船到目标),你可以Quaternion.Lerp()用来在当前的飞船旋转和对齐的旋转之间进行插值。这将使您的旋转平滑过渡(不仅仅是捕捉到目标)。


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

于 2012-11-07T11:55:04.493 回答
2

你的代码有点时髦。

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

这可能正确也可能不正确。显然,您已经覆盖了 equals 比较器。正确的做法是确保两条(单位长度)射线之间的点积接近 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. 在乘法之后定期标准化你的四元数很重要。否则小错误会累积,它们会偏离单位长度,导致各种悲伤。
于 2012-11-07T16:36:55.133 回答
0

我的天啊!有效!!!

            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 的想法 ;-)

于 2012-11-07T20:36:50.337 回答