解决了



我正在引擎中制作3D门户系统(例如Portal游戏)。每个门户网站都有其自己的方向,保存在四元数中。要在其中一个门户中渲染虚拟场景,我需要计算两个四元数之间的差异,并将结果用于旋转虚拟场景。

当在左侧墙上创建第一个门户时,在右侧墙上创建第二个门户时,从一个方向到另一个方向的旋转将仅在一个轴上进行,例如,当在地板上创建第一个门户时,第二个门户将被创建在右墙上,从一个到另一个的旋转可能是在两个轴上,这就是问题所在,因为旋转出错了。

我认为存在问题是因为例如X轴和Z轴的方向存储在一个四元数中,因此我需要分别手动将X * Z(或Z * X)相乘,但如何仅使用一个四元数(差异四元数)来实现呢?还是有其他方法可以正确旋转场景?

编辑:

在此图片上,有两个入口P1和P2,箭头显示了它们如何旋转。当我查看P1时,我将看到P2。为了找到需要旋转主场景以使其类似于该图片中的虚拟场景的旋转,我正在执行以下操作:


从四元数P2到四元数P1的差异
将结果沿Y轴旋转180度(门户的UP)
使用结果旋转虚拟场景


上述方法仅在仅在一个轴上发生差异时有效。当一个门户位于地板上或天花板上时,这将不起作用,因为四元差四元轴构建在多个轴上。正如建议的那样,我尝试将P1的四元数乘以P2的四元数,反之,但这是行不通的。



编辑2:

为了找到P2和P1的区别,我在做以下工作:

Quat q1 = P1->getOrientation();
Quat q2 = P2->getOrientation();

Quat diff = Quat::diff(q2, q1);  // q2 * diff = q1 //


这是Quat :: diff函数:

GE::Quat GE::Quat::diff(const Quat &a, const Quat &b)
{
    Quat inv = a;
    inv.inverse();
    return inv * b;
}


逆:

void GE::Quat::inverse()
{
    Quat q = (*this);
    q.conjugate();
    (*this) = q / Quat::dot((*this), (*this));
}


共轭:

void GE::Quat::conjugate()
{
    Quat q;
    q.x = -this->x;
    q.y = -this->y;
    q.z = -this->z;
    q.w = this->w;

    (*this) = q;
}


点积:

float GE::Quat::dot(const Quat &q1, const Quat &q2)
{
    return q1.x*q2.x + q1.y*q2.y + q1.z*q2.z + q1.w*q2.w;
}


运营商*:

const GE::Quat GE::Quat::operator* ( const Quat &q) const
{
    Quat qu;
    qu.x = this->w*q.x + this->x*q.w + this->y*q.z - this->z*q.y;
    qu.y = this->w*q.y + this->y*q.w + this->z*q.x - this->x*q.z;
    qu.z = this->w*q.z + this->z*q.w + this->x*q.y - this->y*q.x;
    qu.w = this->w*q.w - this->x*q.x - this->y*q.y - this->z*q.z;
    return qu;
}


操作员/:

const GE::Quat GE::Quat::operator/ (float s) const
{
    Quat q = (*this);
    return Quat(q.x / s, q.y / s, q.z / s, q.w / s);
}


所有这些东西都有效,因为我已经使用GLM库对其进行了测试

最佳答案

如果要查找诸如diff的四元数diff * q1 == q2,则需要使用乘法逆:

diff * q1 = q2  --->  diff = q2 * inverse(q1)

where:  inverse(q1) = conjugate(q1) / abs(q1)

and:  conjugate( quaternion(re, i, j, k) ) = quaternion(re, -i, -j, -k)


如果四元数是旋转四元数,则它们都应该是单位四元数。这使得查找反函数变得容易:由于abs(q1) = 1,只需对inverse(q1) = conjugate(q1)ij分量取反就可以找到您的k



但是,对于您描述的那种基于场景的几何配置,您实际上可能不想执行上述操作,因为您还需要正确计算平移。

正确执行所有操作的最直接方法是将四元数转换为4x4旋转矩阵,并按适当的顺序将其与4x4转换矩阵相乘,如大多数入门计算机图形学文本中所述。

当然,可以手动进行欧几里得变换,将旋转保持四元数形式,同时将四元数递增地应用于单独的平移向量。但是,这种方法在技术上趋于模糊,并且容易出现编码错误:4x4矩阵形式是常规格式有充分的理由,其中一个重要原因是,以这种方式正确设置似乎更容易。

07-28 14:25