C++自定义四元数实现Y/Z轴旋转正常 加入X轴后模型异常拉伸
四元数旋转拉伸问题修复方案
核心问题点
- 旋转轴未归一化:生成旋转四元数的前提是输入的旋转轴为单位向量,你传入的
(1,1,0)、(1,0,1)这类组合轴的模长为√2≠1,生成的四元数模长不等于1,不是单位四元数,最终转换得到的矩阵不是正交矩阵,会引入非预期的缩放效果,也就是你看到的拉伸。你之前测试的单轴、(0,1,1)组合轴能正常工作只是巧合,要么是测试角度过小误差不明显,要么是测试时无意中传入了归一化后的轴参数。 - 四元数更新后未主动归一化:你仅在四元数模长偏离1超过阈值时才做归一化,且乘法运算后没有主动触发归一化,浮点误差加上非单位四元数的初始偏差会持续累积,加重拉伸问题。
- 额外优化提示:你
rotate函数的第一个参数名用w容易和四元数的实部w混淆,建议改名为angle提升代码可读性。
修复代码
1. 修正rotate函数,增加轴归一化逻辑
Quaternion rotate(float angle, float x, float y, float z) { Quaternion n; // 先对旋转轴做归一化 float axis_len = sqrtf(x*x + y*y + z*z); // 避免轴长度为0导致的除零异常 if (axis_len < 1e-6f) { n.w = 1.0f; n.x = n.y = n.z = 0.0f; return n; } x /= axis_len; y /= axis_len; z /= axis_len; float half_angle = angle / 2.0f; float sin_half = sinf(half_angle); n.w = cosf(half_angle); n.x = x * sin_half; n.y = y * sin_half; n.z = z * sin_half; return n; }
2. 优化归一化函数,每次更新主动调用
Quaternion normalize(Quaternion n) { double total = (double)n.w*n.w + (double)n.x*n.x + (double)n.y*n.y + (double)n.z*n.z; // 模长接近0时返回单位四元数避免异常 if (total < 1e-12) { Quaternion unit = {1.0f, 0, 0, 0}; return unit; } float inv_len = (float)(1.0 / sqrt(total)); n.w *= inv_len; n.x *= inv_len; n.y *= inv_len; n.z *= inv_len; return n; }
3. 修正旋转更新逻辑
obj.rotation = normalize(rotate(angle, x_axis, y_axis, z_axis) * obj.rotation);
你现有的四元数乘法、四元数转矩阵的公式逻辑是正确的,无需修改。
内容的提问来源于stack exchange,提问作者patrickbies
相关产品推荐
相关产品推荐

