Gimbal Lock
Gimbal Lock
环架锁定
三维物体旋转有很多种方式,其中有一种叫做欧拉角的方式,其特点就是将一次旋转分为3次旋转,
这三次旋可以是XYZ、XZY、ZYX……等等顺序,这个不重要,
但是第一次旋转的那个轴总是世界坐标轴,也就是不变的,旋转角度称为静态欧拉角
其余的两次旋转则是相对物体自身的坐标轴,旋转角度称为动态欧拉角
区别就是:
动态欧拉角坐标系旋转时,其余两个坐标系都会随物体转动而转动,
而静态欧拉角转动时则不会。
假设三个轴旋转的顺序是ABC,
A轴作为第一个旋转轴,其使用静态欧拉角旋转,旋转时BC坐标轴不变,
B轴旋转时,为了保证A轴刚才的旋转不丢失,A轴也会随物体一起旋转,但C轴不变
C旋转时,为了保证AB旋转角度不丢失,AB都会随物体一起旋转,
但是C轴本身是静止的,能够旋转的只有AB轴而已,
万向锁问题出现在第二步:B轴带动A轴转动上,
这时如果B轴转动的角度是±90°,会导致BC轴重叠,
造成维度丢失的问题。
万向锁的解决方式
四元组
通过四元组旋转物体,可以解决万向锁。
1 | // XYZ模式下 沿Y、Z轴的旋转 |
四元组的其他用法
同时四元组还可以用来实现物体沿任意(而非坐标轴)轴线旋转的功能:
如果将旋转效果应用到position而不是rotation上,
能够实现围绕世界坐标系旋转的效果:
1 | const quaternionO = new THREE.Quaternion() |
相机的旋转也是同样的道理:
1 | function rotateCamera(){ |
rotateTowards && slerp
setFromAxisAngle可以通过指定坐标轴和旋转角来配置四元组,
rotateTowards需要两个参数:
- q Quaternion类型
- step Float类型
可以将当前的quaternion按照step逐步移动接近最终的q数值:
1 | cube.quaternion.rotateTowards(cube2.quaternion, 0.01) |
使用slerp也是相同的方式:
1 | cube.quaternion.slerp(cube2.quaternion, 0.1) |
slerp的第二个参数控制单次旋转量,能实现更加丝滑的旋转效果