Unity 坐标系与右手坐标系位姿(旋转和位移)转换
下图是 Unity 使用的坐标系和右手坐标系的示意图:
可以清楚地看到,Unity 中用的是左手坐标系,且是 z 轴向前,y 轴向上;而右手坐标系是 x 轴向前,z 轴向上(当然也可以自己规定怎么放)。
现需要把 Unity 的一个位姿转换为右手坐标系下的位姿。
位移转换
位移转换其实很简单,假设在 Unity 中的位移是
v
u
v_u
vu,右手坐标系的位移是
v
r
v_r
vr,那么把
v
r
v_r
vr 转换为
v
u
v_u
vu 则是:
v
u
x
=
−
v
r
y
v
u
y
=
v
r
z
v
u
z
=
v
r
x
v_{ux} = -v_{ry} \\ v_{uy} = v_{rz} \\ v_{uz} = v_{rx}
vux=−vryvuy=vrzvuz=vrx
其中
v
u
x
v_{ux}
vux 表示
v
u
v_u
vu 的 x 坐标,其它以此类推。
要把 v u v_u vu 转换为 v r v_r vr 的话,反过来就可以了。
旋转转换
为了能够消除旋转顺序和万向节的影响,这里不用欧拉角来表示旋转,而是使用四元数来表示一个唯一的旋转。
参考了这里 的文章,我才发现用四元数表示旋转的话,这两个坐标系的转换也很简单。
四元数的形式可以是
w
+
x
i
+
y
j
+
z
k
w+xi+yj+zk
w+xi+yj+zk ,其中
i
i
i,
j
j
j,
k
k
k 为四元数的虚部,
w
w
w 为四元数的实部。
四元数表达的是绕一个旋转轴
(
x
ω
,
y
ω
,
z
ω
)
(x_\omega,y_\omega,z_\omega)
(xω,yω,zω) 旋转了一个角度
ω
\omega
ω,所以,四元数中的实部和虚部为:
w
=
cos
(
ω
/
2
)
x
=
sin
(
ω
/
2
)
x
ω
y
=
sin
(
ω
/
2
)
y
ω
z
=
sin
(
ω
/
2
)
z
ω
w = \cos(\omega/2) \\ x = \sin(\omega/2) x_\omega \\ y = \sin(\omega/2) y_\omega \\ z = \sin(\omega/2) z_\omega
w=cos(ω/2)x=sin(ω/2)xωy=sin(ω/2)yωz=sin(ω/2)zω
因此,只要把旋转轴在两个坐标系下找对就行了。
位移和旋转轴的表示都是
(
x
,
y
,
z
)
(x,y,z)
(x,y,z),所以直接用位移的转换公式来转换旋转轴即可。
那么,把右手坐标系的四元数
q
r
q_r
qr 转换到 Unity 中的四元数
q
u
q_u
qu 的方式为:
w
u
=
w
r
x
u
=
−
y
r
y
u
=
z
r
z
u
=
x
r
w_u = w_r \\ x_u = -y_r \\ y_u = z_r \\ z_u = x_r
wu=wrxu=−yryu=zrzu=xr
但是还没完,因为左手 Unity 的旋转是左手旋转,跟右手坐标系的旋转刚好相反。有两种方法可以解决这个问题,要么是旋转的角度取反,要么是旋转轴的向量取反。根据上面的公式,其实两种方法的结果都一样,都是对虚部全部取反。
因此最后正确的转换应为:
w
u
=
w
r
x
u
=
y
r
y
u
=
−
z
r
z
u
=
−
x
r
w_u = w_r \\ x_u = y_r \\ y_u = -z_r \\ z_u = -x_r
wu=wrxu=yryu=−zrzu=−xr
得到的 q u = w r + y r i − z r j − x r k q_u = w_r + y_ri - z_rj - x_rk qu=wr+yri−zrj−xrk。
要把 q u q_u qu 转换为 q r q_r qr 的话,反过来就可以了。
扩展(其他坐标系形式的转换)
假如用到的左手和右手坐标系的对应关系跟前面说的不同,看到这里的话其实也能知道怎么自己推导了,就是换一下坐标轴而已。