3D立方体X轴旋转不符合预期问题排查咨询
3D立方体局部轴旋转问题修复
现有代码的核心问题
- Y轴旋转写法存在隐患:Y轴旋转步骤中引用了未做任何旋转的原始顶点
originalP*.z参与计算,没有使用上一步旋转后的当前顶点Z坐标。该写法在你原有Z→Y的旋转顺序下因为Z轴旋转不改变顶点Z值暂时没有触发错误,但只要调整旋转顺序或新增其他变换,就会出现计算结果失真。 - 旋转顺序不符合局部轴旋转要求:当前代码按Z轴→Y轴→X轴的顺序分步直接修改顶点坐标,这种写法下后执行的旋转永远绕全局固定坐标轴生效,而非物体自身的局部坐标轴。你观察到的Z、Y轴旋转“正常”只是初始状态下物体局部轴与全局轴完全重合的巧合,当物体已经绕其他轴产生旋转偏移后,后续旋转就会出现和预期不符的全局轴旋转效果。
- 存在冗余无效代码:函数第一行的
position;是无任何作用的废语句,可以直接删除。
问题原理
3D旋转不满足交换律,分步对顶点做绕全局轴的旋转时,旋转顺序直接决定最终效果:
- 按Z→Y→X顺序逐次旋转顶点,所有旋转都绕全局固定轴生效
- 若要实现绕物体自身局部轴的旋转,需要将旋转顺序反转,按X→Y→Z的顺序逐次基于上一步旋转后的顶点坐标计算,即可让三个轴的旋转都对应物体自身的局部坐标轴。
另外原代码重复写了大量角度转弧度的计算,既冗余也容易写错,建议提前把三个轴的弧度值计算好存为局部变量复用。
修复后完整代码示例
void Triangle::update() { // 提前计算三个轴的旋转弧度值,0.0174533是角度转弧度的系数 const float deg2rad = 0.0174533f; float xRad = (*rotation).x * deg2rad; float yRad = (*rotation).y * deg2rad; float zRad = (*rotation).z * deg2rad; // 从原始顶点开始计算 p0 = originalP0; p1 = originalP1; p2 = originalP2; sf::Vector3f rotatedP0, rotatedP1, rotatedP2; // 第一步:绕局部X轴旋转 rotatedP0.x = p0.x; rotatedP0.y = p0.y * cos(xRad) - p0.z * sin(xRad); rotatedP0.z = p0.y * sin(xRad) + p0.z * cos(xRad); rotatedP1.x = p1.x; rotatedP1.y = p1.y * cos(xRad) - p1.z * sin(xRad); rotatedP1.z = p1.y * sin(xRad) + p1.z * cos(xRad); rotatedP2.x = p2.x; rotatedP2.y = p2.y * cos(xRad) - p2.z * sin(xRad); rotatedP2.z = p2.y * sin(xRad) + p2.z * cos(xRad); p0 = rotatedP0; p1 = rotatedP1; p2 = rotatedP2; // 第二步:绕局部Y轴旋转,使用上一步旋转后的顶点坐标计算 rotatedP0.x = p0.x * cos(yRad) + p0.z * sin(yRad); rotatedP0.y = p0.y; rotatedP0.z = -p0.x * sin(yRad) + p0.z * cos(yRad); rotatedP1.x = p1.x * cos(yRad) + p1.z * sin(yRad); rotatedP1.y = p1.y; rotatedP1.z = -p1.x * sin(yRad) + p1.z * cos(yRad); rotatedP2.x = p2.x * cos(yRad) + p2.z * sin(yRad); rotatedP2.y = p2.y; rotatedP2.z = -p2.x * sin(yRad) + p2.z * cos(yRad); p0 = rotatedP0; p1 = rotatedP1; p2 = rotatedP2; // 第三步:绕局部Z轴旋转 rotatedP0.x = p0.x * cos(zRad) - p0.y * sin(zRad); rotatedP0.y = p0.x * sin(zRad) + p0.y * cos(zRad); rotatedP0.z = p0.z; rotatedP1.x = p1.x * cos(zRad) - p1.y * sin(zRad); rotatedP1.y = p1.x * sin(zRad) + p1.y * cos(zRad); rotatedP1.z = p1.z; rotatedP2.x = p2.x * cos(zRad) - p2.y * sin(zRad); rotatedP2.y = p2.x * sin(zRad) + p2.y * cos(zRad); rotatedP2.z = p2.z; // 最后应用位置偏移 p0 = rotatedP0 + *position; p1 = rotatedP1 + *position; p2 = rotatedP2 + *position; }
优化建议
如果后续要加缩放、层级联动变换,不建议手动分步计算每个轴的旋转,改用4x4齐次变换矩阵合并所有缩放、旋转、平移操作,一次性对顶点做矩阵乘法变换,既可以避免分步计算时引用错坐标的问题,也能更灵活地控制局部/全局变换、父子节点层级变换,代码可维护性更高。
内容的提问来源于stack exchange,提问作者OwenPT
相关产品推荐
相关产品推荐

