根据您的评论,您似乎将对象的方向存储为一组欧拉角,并在玩家旋转对象时增加/减少了角度。也就是说,您有类似以下的伪代码:
// in player input handling:
if (axis == AXIS_X) object.angleX += dir;
else if (axis == AXIS_Y) object.angleY += dir;
else if (axis == AXIS_Z) object.angleZ += dir;
// in physics update and/or draw code:
matrix = eulerAnglesToMatrix(object.angleX, object.angleY, object.angleZ);
正如查尔斯·比蒂(Charles Beattie)所指出的那样,因为旋转不会进行换向,所以除非玩家按照应用旋转的相同顺序旋转对象,否则旋转将无法按预期进行eulerAnglesToMatrix()
。
特别是,请考虑以下旋转顺序:
- 围绕X轴将对象旋转x度;
- 围绕Y轴将对象旋转y度;
- 围绕X轴将对象旋转− x度;
- 将对象绕Y轴旋转-y度。
在上面的伪代码中实现的朴素欧拉角表示中,这些旋转将抵消,并且对象将返回其原始方向。在现实世界中,这不会发生–如果您不相信我,抓住一个六边形的模具或魔方,让x = y = 90°,然后自己尝试!
如您在自己的答案中所述,解决方案是将对象的方向存储为旋转矩阵(或四元数),并根据用户输入更新该矩阵。也就是说,您可以执行以下操作来代替上面的伪代码:
// in player input handling:
if (axis == AXIS_X) object.orientation *= eulerAnglesToMatrix(dir, 0, 0);
else if (axis == AXIS_Y) object.orientation *= eulerAnglesToMatrix(0, dir, 0);
else if (axis == AXIS_Z) object.orientation *= eulerAnglesToMatrix(0, 0, dir);
// in physics update and/or draw code:
matrix = object.orientation; // already in matrix form!
(在技术上,因为任何旋转矩阵或四元数可以被表示为一组欧拉角,它是能够使用它们来存储该对象的方向。但是,用于组合两个相继的旋转的物理上正确的规则,作为欧拉角的每个表示旋转成单个旋转相当复杂,从本质上讲等于将旋转转换为矩阵/四元数,将它们相乘,然后将结果转换回欧拉角。)