在Unity中利用刚体RigidBody使物体运动是非常容易的事,但是有时有时不希望物体倒下,这就要复杂一些,因为Unity使用四元数Quaternion来表示旋转。

但其实四元数也不算难

先上代码,将这段代码放在Update()函数中

1
2
3
4
5
6
7
8
9
10
11
12
var dst_quaternion = transform.rotation;
var angle = Mathf.Acos(dst_quaternion.w);//arccos
if(dst_quaternion.y < 0)
{
angle = -angle;
}
var sin_value = Mathf.Sin(angle);
dst_quaternion.z = 0;
dst_quaternion.y = sin_value;
dst_quaternion.x = 0;

transform.rotation=dst_quaternion;//apply the transform

解释

四元数的一种几何解释是如果物体围绕一个轴 (ax,ay,az)(a_x,a_y,a_z) 旋转 θ\theta ,那么四元数为

{x,y,z,w}={axsin(θ2),aysin(θ2),aysin(θ2),cos(θ2)}\{x,y,z,w\}=\{a_x\cdot \sin (\frac{\theta}{2}),a_y\cdot \sin (\frac{\theta}{2}),a_y\cdot \sin (\frac{\theta}{2}),\cos (\frac{\theta}{2})\}

θ2\frac{\theta}{2} 看做一个整体为 angleangle ,又因为一开始物体是正的,相应旋转轴为 (0,1,0)(0,1,0) 且Unity中的角度 [π2,π2]\in [-\frac{\pi}{2},\frac{\pi}{2}] ,而 {yy=arccos(x),x[11]}=[0,π]\{y|y=arccos(x),x \in [-1,1]\} = [0,\pi]

angle={arccos(w)θ0 Also y0arccos(w)θ0 Also y0angle=\left\{ \begin{array}{l} \arccos(w)& {\theta \geq 0\ Also\ y \geq 0}\\ - \arccos(w)& {\theta \leq 0\ Also\ y \leq 0} \end{array} \right.

为使旋转轴始终为yy轴,那么

(ax,ay,az)=(0,1,0)(a_x,a_y,a_z)=(0,1,0)

相应的四元数为

{0,sin(θ2),0,w}={0,sin(angle),0,w}\{0,\sin (\frac{\theta}{2}),0,w\}=\{0,\sin (angle),0,w\}

进一步,设置一个插值可以让物体运动得更自然

1
transform.rotation = Quaternion.Lerp(transform.rotation,dst_quaternion,Time.deltaTime*4);

注:其实初始时四元数为{0,0,0,1}\{0,0,0,1\},这时这种几何解释是有问题的,但经过这个变换后答案仍然正确

参考资料

四元数与三维旋转

Microsoft Docs