【问题标题】:View Matrix from Quaternion从四元数查看矩阵
【发布时间】:2012-10-08 08:12:31
【问题描述】:

我目前正在构建自己的四元数相机。据我所知,您只需要一个四元数即可完全指定相机的方向(如果我错了,请纠正我)。那么,我将如何创建视图矩阵?顺便说一句,我使用 C++ 作为编程语言。

任何帮助将不胜感激。

【问题讨论】:

    标签: c++ math camera directx quaternions


    【解决方案1】:

    首先有一些注意事项。你会在网上和关于这个主题的文献中看到很多明显相互矛盾的公式。大多数冲突只是显而易见的。有一些是真正的冲突,但那是因为有人弄错了数学。问题是没有单一的正确方法可以做到这一点。您需要知道如何使用四元数和矩阵,源如何使用它们,以及如何纠正这些明显的差异。

    旋转与变换
    你的相机有一个与之关联的参考框架,底层空间也是如此。您的矩阵是表示相机从基础空间到相机方向的物理旋转,还是表示将基础空间中表示的向量转换为相机框架的矩阵? (或者别的什么;这里有四个选择。)这些选择是相关的;变换矩阵是旋转矩阵的转置。变换和旋转是共轭运算。同样的概念也适用于四元数。您使用的是转换四元数还是旋转四元数?这些又是相关的概念;一个是另一个的共轭。

    左四元数与右四元数
    给定一个单位四元数 q 来变换或旋转向量 v,有些人使用 qvq* 来变换/旋转向量向量,其他人使用 q*vq。哪种形式是正确的?两者都是。这两种形式的区别仅在于非共轭四元数是在左边 (qvq*) 还是在右边 (q*vq) 要转换/旋转的向量。

    列向量与行向量
    大多数人使用列向量,但有些人使用行向量。在这里,您遇到了矩阵的左右问题。列向量通过 Mv 进行变换/旋转,矩阵位于向量的左侧;行向量通过vM,右边是矩阵。

    影响
    你必须小心阅读文学作品。关于从四元数形成矩阵,您需要注意构造矩阵的非对角元素时的符号变化。一种配方的加减法可能会变成另一种配方的减法/加法。

    左变换四元数到行向量变换矩阵
    我使用左变换四元数和变换矩阵,并将向量表示为行向量。我还将四元数 q 表示为包含实数标量部分 qs 和矢量虚数部分 qv子>。给定这些表示,从四元数生成矩阵的计算是(伪代码):

    // Compute the cosine of the rotation angle.
    cost = 2.0*qs*qs - 1.0;
    
    // Construct the diagonal of the matrix:
    // T_ii = cost + 2qv_i^2
    for (i = 0; i < 3; ++i) {
       T[i][i] = cost + 2.0*qv[i]*qv[i];
    }
    
    // Construct off-diagonal transformation matrix elements:
    //   T_ij = 2 (qv_i qv_j - eps_ijk qs qv_k), where eps is the Levi-Civita symbol
    for (k = 0; k < 3; ++k) {
       i = (k+1)%3;
       j = (i+1)%3;
       T[i][j] = 2.0*(qv[i]*qv[j] - qs*qv[k]);
       T[j][i] = 2.0*(qv[i]*qv[j] + qs*qv[k]);
    }
    

    您可能想要扩展这些循环。第一个循环扩展为三个语句,后者为六个。后一个循环的展开不需要计算ij;循环的扩展使它们成为固定数量。

    替代表示
    上面的这些警告并不像看起来那么糟糕。你需要确保我的陈述与你的一致。赔率是 50-50,它不是。如果不是,只需将分配交换到非对角线元素。将T[i][j] 的计算用于T[j][i],反之亦然。如何分辨:

    • s=1 开始。
    • 如果您使用旋转四元数而不是变换四元数,则将 s 乘以 -1。
    • 如果您使用右四元数而不是左四元数,则将 s 乘以 -1。
    • 如果您使用旋转矩阵而不是变换矩阵,则将 s 乘以 -1。
    • 如果您使用行向量而不是列向量,请将 s 乘以 -1。

    如果 s 的最终值为 1,请使用我的公式。如果为 -1,只需将分配交换为 T[i][j]T[j][i]。或者你可以把加法改成减法,减法改成加法。

    最后一个问题
    当标量部分不接近于零时,上述计算适用。如果我们有无限精度的算术,它将在任何地方都有效。您可能希望对非常接近零或 180 度的旋转使用单独的计算。

    【讨论】:

    • 上述大多数观点的共同主题是:您需要知道您的系统遵循哪些约定。听起来您正在构建自己的数学库,因此某些约定(例如左四元数与右四元数)是您自己的选择-但我猜其他约定(例如结果视图矩阵的确切使用方式)将由无论您使用什么图形库。所以,你的首要任务是查找并理解后者……
    • @comingstorm - 是的。了解约定很重要,特别是当您需要与其他人交换四元数时,或者当您阅读一些以某种创造性方式使用四元数并尝试将其数学合并到您的包中的期刊文章时。我不得不调解太多“你做错了!”当双方都“正确”地做事时争论不休,但双方都不知道有不止一种方法可以正确地做事。
    • 嗯...让我们看看...我会一一介绍您的观点。我正在使用 DirectX,所以我认为底层框架是左撇子。此外,我倾向于翻译我世界中的所有内容以适合我的相机,因此它将成为一个转换四元数。最后,我使用列主矩阵布局。所以这意味着我只需要切换矩阵索引!非常感谢你的回答,大卫,我真的很感谢你花时间写它。它清除了我所有的问题,以及我要问的更多问题!再次感谢,我真的很感激。 +1 并被接受为答案!
    • 顺便说一句,我只是感兴趣。你们都是在哪里学的四元数微积分?我错过了太多高中数学课吗?
    • 左手坐标系?你可能想重新考虑一下。它会给你带来麻烦。四元数明确地基于右手系统。我们的叉积相当于两个纯虚四元数的四元数积——但前提是您使用右手坐标。请注意,当我说左四元数和右四元数时,我离开了“分发”。他们不是左撇子/右撇子。他们是左右运算符。
    【解决方案2】:

    维基百科知道:Quaternions and spatial rotation

    【讨论】:

    • Erm... 但这并不能帮助我获得视图矩阵。我需要面向向量、向上向量等。
    • 维基百科知道,但不在那里。链接的文章是关于四元数的矩阵表示。它与手头的问题无关。
    • 其实很抱歉发错了链接,现在更正了。
    • 好多了。请注意,该链接使用左四元数 (qvq*)。
    【解决方案3】:

    我建议使用Eigen C++ 库来表示您的四元数和矩阵。当你有一个四元数对象时,你可以简单地在它上面调用.toRotationMatrix()来得到一个3x3的矩阵。

    另一个可能会工作的库是glm

    【讨论】:

    • 感谢大家对数学库的推荐。我当然会研究他们如何实施这些操作。但是,我正在尝试编写自己的数学库,因为我相信它会帮助我了解幕后的真实情况。而且,我认为为自己的游戏编写自己的数学库比坐在教室里听关于矩阵和四元数的讲座更令人兴奋! :)
    【解决方案4】:

    可配置数学库 (http://cmldev.net/) 是一个非常轻量级的库,可以为您进行计算。它是一个头文件库,因此集成到您的代码中应该不成问题。此功能 (http://cmldev.net/?p=196) 也可能对您有所帮助。

    【讨论】:

    • 这个包和 David Grayson 引用的 Eigen 包很好地说明了我的观点。 CML 显然使用右四元数,而 eigen 使用左四元数;它们对非对角线元素的加法和减法颠倒了。两个包都没有说明“四元数”的含义。完全呆在一个包中,你可能没问题(假设他们的数学是正确的)。但是与其他人交换数据(他们不可避免地使用不同的约定;这里的可能性非常有利于墨菲定律),或者尝试混合和匹配包,你就有麻烦了。
    • 感谢大家对数学库的建议。我当然会研究他们如何实施这些操作。但是,我正在尝试编写自己的数学库,因为我相信它会帮助我了解幕后的真实情况。而且,我认为为自己的游戏编写自己的数学库比坐在教室里听关于矩阵和四元数的讲座更令人兴奋! :)
    • @DavidHammen AFAIK CML 是可配置的,这意味着你可以选择你想要的四元数
    • 只有一个matrix_rotation_quaternion;在这里:cmldev.sourceforge.net/cml1-doc/dd/d60/…。算法是固定的。没有配置。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多