<p>四元数旋转的核心公式是 $ v' = q \otimes v \otimes q^{-1} $,其中 $ v $ 是实部为0的纯四元数,$ q $ 为单位四元数,且 $ q^{-1} = q^* $;若 $ q $ 未归一化,结果含缩放而非纯旋转。</p>

四元数旋转的核心公式是什么
直接用 q * v * q⁻¹,其中 v 是纯四元数(即实部为 0、虚部为向量坐标),q 是单位四元数。这不是近似或简化——它是严格等价于旋转矩阵的数学表示,前提是 q 归一化。没归一化?结果会缩放向量,不是纯旋转。
常见错误是把向量直接当四元数乘:q * v(漏掉右乘逆),或者误用 q⁻¹ = conjugate(q) 却忘了单位四元数下共轭等于逆——这点必须确认:若 q 非单位,q⁻¹ 要显式除以模长平方。
如何从欧拉角/轴角构造单位四元数
轴角最直观:给定单位轴 axis 和角度 theta(弧度),直接套公式:q = cos(theta/2) + sin(theta/2)*axis.x*i + sin(theta/2)*axis.y*j + sin(theta/2)*axis.z*k。C++ 中推荐用 std::sin/std::cos,别手写泰勒展开。
欧拉角(如 yaw-pitch-roll)容易出错,因为顺序敏感且存在万向节锁。建议只在输入明确是 ZYX 顺序时用标准转换,否则优先走轴角或直接用旋转矩阵转四元数(glm::quat_cast 或手动解)。
立即学习“C++免费学习笔记(深入)”;
务必检查构造后是否单位化:std::abs(q.w*q.w + q.x*q.x + q.y*q.y + q.z*q.z - 1.0) 。浮点误差累积后不归一,旋转会漂移。
实际代码中怎么安全地旋转一个 glm::vec3
用 GLM 库最省事,但得理解它封装了什么。GLM 的 glm::rotate 是作用于矩阵的,而四元数旋转向量应调用 glm::rotate 的四元数重载版本:
glm::vec3 v = {1.0f, 0.0f, 0.0f};
glm::quat q = glm::angleAxis(glm::radians(90.0f), glm::vec3(0.0f, 1.0f, 0.0f)); // 绕 Y 轴转 90°
glm::vec3 rotated = glm::rotate(q, v); // 内部自动做 q*v*q⁻¹注意三点:
-
glm::angleAxis输入角度是弧度,不是度 -
glm::rotate(q, v)要求q是单位四元数;GLM 不自动归一,得自己调glm::normalize(q) - 如果不用 GLM,手写乘法时虚部顺序必须一致(i/j/k 对应 x/y/z),否则旋转方向反了
为什么旋转后向量长度变了
几乎全是归一化问题。四元数非单位 → q⁻¹ ≠ conjugate(q) → 缩放残留。调试时先打日志:std::cout 。
另一个隐蔽坑:用 glm::quat 构造函数传四个 float 时,参数顺序是 (w,x,y,z),但有些教程或自定义类用 (x,y,z,w)。混用会导致 q 实部错位,旋转完全失真。
还有就是 C++ 浮点精度:多次累乘未归一的四元数(比如动画插值中间态),误差会指数级放大。每帧更新后建议强制 q = glm::normalize(q),别依赖“应该很接近 1”。


















