首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >四元数,旋转模型并与方向对齐

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

Stack Overflow用户
提问于 2012-11-07 03:56:53
回答 3查看 3.3K关注 0票数 1

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

我想做的是,给定一个对象(使用rotationQuaternion,侧向量...),我希望将其与目标点对齐。

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

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

代码语言:javascript
复制
        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处几乎为零

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

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2012-11-08 00:36:55

你的代码有点时髦。

代码语言:javascript
复制
if (_target._ray.Position != _obj._ray.Position)
{

这可能是正确的,也可能是错误的。显然,您已经覆盖了equals比较器。正确的做法是确保两条(单位长度)光线之间的点积接近于1。如果这两条光线具有相同的原点,则可能具有相同的“位置”,这意味着它们是相同的。

代码语言:javascript
复制
  Vector3 vec = Vector3.Normalize(_target._ray.Position - _obj._ray.Position);

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

下面是我推荐的伪代码:

代码语言:javascript
复制
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
EN

Stack Overflow用户

发布于 2012-11-07 19:55:04

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

代码语言:javascript
复制
Matrix rot = Matrix.CreateLookAt(_arrow.Position, _cube.Position, Vector3.Down);
_arrow.Rotation = Quaternion.CreateFromRotationMatrix(rot);

在这个例子中,我渲染了一个箭头和一个立方体,其中立方体在圆圈中移动,并且在上面的代码中,箭头始终指向立方体。(虽然我想象有一些边缘情况,当立方体恰好高于或低于立方体时)。

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

顺便说一句,你的旋转可能会减少到零,因为你在赋值的时候使用了*=

票数 3
EN

Stack Overflow用户

发布于 2012-11-08 04:36:50

天哪!成功了!

代码语言:javascript
复制
            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的想法;-)

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/13258413

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档