关于三维空间中的旋转,我们以前提到过基于欧拉角的旋转表达矩阵,它们分别描述了围绕 x 轴、y 轴、z 轴旋转后坐标应当如何变化。事实上,我们可以更进一步,推导出一个通用的、围绕过原点的任意轴旋转的公式。
这一节我们来描述我们已知的条件和待求的目标:
给定一个方向向量 u ⃗ \vec{u} u作为旋转轴, v ⃗ \vec{v} v为待旋转的向量,我们希望得到 v ⃗ \vec{v} v围绕着 u ⃗ \vec{u} u逆时针旋转 θ \theta θ角度之后的向量 v ′ ⃗ \vec{v'} v′。注意, v ′ ⃗ \vec{v'} v′的表达式必须用已知条件 u ⃗ \vec{u} u、 v ⃗ \vec{v} v和 θ \theta θ来表达。
旋转前后向量的长度不会变化,反而是如何计算旋转后向量的方向成为了一个难题。我们采用分解向量的思路来解决向量旋转的问题——把 v ⃗ \vec{v} v分解为平行于 u ⃗ \vec{u} u的向量 v / / ⃗ \vec{v_{//}} v//和垂直于 u ⃗ \vec{u} u的向量 v ⊥ ⃗ \vec{v_\bot} v⊥,分解的示意图如下:
这样定义向量的分解方式是有好处的,我们可以发现,旋转前后 v / / ⃗ \vec{v_{//}} v//没有变化,而旋转前的 v ⊥ ⃗ \vec{v_\bot} v⊥、旋转后的 v ⊥ ′ ⃗ \vec{v'_\bot} v⊥′都在一个平面内,同一个平面内的旋转比起三维旋转要好解决的多。
v / / ⃗ \vec{v_{//}} v//实际上是 v ⃗ \vec{v} v在 u ⃗ \vec{u} u上的正交投影,因此我们可以得出:
KaTeX parse error: Expected 'EOF', got '&' at position 14: \vec{v_{//}}&̲=|\vec{v}|\frac…
然后,我们运用向量减法给出 v ⊥ ⃗ \vec{v_{\bot}} v⊥的表达式:
v ⊥ ⃗ = v ⃗ − v / / ⃗ \vec{v_{\bot}}=\vec{v}-\vec{v_{//}} v⊥=v−v//
接下来,我们需要给出 v ⊥ ′ ⃗ \vec{v'_\bot} v⊥′的表达式。给出一个直观的旋转俯视图:
先定义 w ⃗ \vec{w} w。引入这个向量是为了正交分解 v ⊥ ′ ⃗ \vec{v'_\bot} v⊥′,因此它必须垂直于 v ⊥ ⃗ \vec{v_{\bot}} v⊥。如果你对叉乘很熟悉的话,很快就能想到我们可以用 u ⃗ × v ⃗ \vec{u}\times\vec{v} u×v来得到具有这样的性质的向量。注意叉乘的顺序,根据旋转示意图和右手定则, u ⃗ × v ⊥ ⃗ \vec{u}\times\vec{v_{\bot}} u×v⊥的向量方向才是俯视图中的 w ⃗ \vec{w} w方向。
然后,我们把 v ⊥ ′ ⃗ \vec{v'_\bot} v⊥′正交分解成平行于 v ⊥ ⃗ \vec{v_{\bot}} v⊥的 v v ′ ⃗ \vec{v'_{v}} vv′和平行于 w ⃗ \vec{w} w的 v w ′ ⃗ \vec{v'_w} vw′,并给出 v ⊥ ′ ⃗ \vec{v'_\bot} v⊥′的表达式。
v ⊥ ′ ⃗ = v v ′ ⃗ + v w ′ ⃗ v v ′ ⃗ = ∣ v ⊥ ⃗ ∣ cos θ ⋅ v ⊥ ⃗ ∣ v ⊥ ⃗ ∣ = v ⊥ ⃗ cos θ v w ′ ⃗ = ∣ v ⊥ ⃗ ∣ sin θ ⋅ u ⃗ × v ⊥ ⃗ ∣ u ⃗ × v ⊥ ⃗ ∣ ∣ u ⃗ × v ⊥ ⃗ ∣ = ∣ u ⃗ ∣ ∣ v ⊥ ⃗ ∣ sin ( π / 2 ) = ∣ v ⊥ ⃗ ∣ v w ′ ⃗ = ( u ⃗ × v ⊥ ⃗ ) sin θ v ⊥ ′ ⃗ = v ⊥ ⃗ cos θ + ( u ⃗ × v ⊥ ⃗ ) sin θ \vec{v'_\bot}=\vec{v'_{v}}+\vec{v'_w}\\ \vec{v'_{v}}=|\vec{v_\bot}|\cos\theta\cdot\frac{\vec{v_\bot}}{|\vec{v_\bot}|}=\vec{v_\bot}\cos\theta\\ \vec{v'_w}=|\vec{v_\bot}|\sin\theta\cdot\frac{\vec{u}\times\vec{v_{\bot}}}{|\vec{u}\times\vec{v_{\bot}}|}\\ |\vec{u}\times\vec{v_{\bot}}|=|\vec{u}||\vec{v_{\bot}}|\sin(\pi/2)=|\vec{v_{\bot}}|\\ \vec{v'_w}=(\vec{u}\times\vec{v_{\bot}})\sin\theta\\ \vec{v'_\bot}=\vec{v_\bot}\cos\theta+(\vec{u}\times\vec{v_{\bot}})\sin\theta v⊥′=vv′+vw′vv′=∣v⊥∣cosθ⋅∣v⊥∣v⊥=v⊥cosθvw′=∣v⊥∣sinθ⋅∣u×v⊥∣u×v⊥∣u×v⊥∣=∣u∣∣v⊥∣sin(π/2)=∣v⊥∣vw′=(u×v⊥)sinθv⊥′=v⊥cosθ+(u×v⊥)sinθ
上面的式子可以进一步被化简,我们代入 v ⊥ ⃗ \vec{v_{\bot}} v⊥的表达式,并运用叉乘的分配律:
v ⊥ ′ ⃗ = ( v ⃗ − v / / ⃗ ) cos θ + ( u ⃗ × ( v ⃗ − v / / ⃗ ) ) sin θ 使用分配律, ( u ⃗ × ( v ⃗ − v / / ⃗ ) ) = u ⃗ × v ⃗ − u ⃗ × v / / ⃗ 因为共线, u ⃗ × v / / ⃗ = 0 v ⊥ ′ ⃗ = v ⃗ cos θ − v / / ⃗ cos θ + ( u ⃗ × v ⃗ ) sin θ \vec{v'_\bot}=(\vec{v}-\vec{v_{//}})\cos\theta+(\vec{u}\times(\vec{v}-\vec{v_{//}}))\sin\theta\\ 使用分配律,(\vec{u}\times(\vec{v}-\vec{v_{//}}))=\vec{u}\times\vec{v}-\vec{u}\times\vec{v_{//}}\\ 因为共线,\vec{u}\times\vec{v_{//}}=0\\ \vec{v'_\bot}=\vec{v}\cos\theta-\vec{v_{//}}\cos\theta+(\vec{u}\times\vec{v})\sin\theta v⊥′=(v−v//)cosθ+(u×(v−v//))sinθ使用分配律,(u×(v−v//))=u×v−u×v//因为共线,u×v//=0v⊥′=vcosθ−v//cosθ+(u×v)sinθ
最后,我们终于可以给出 v ′ ⃗ \vec{v'} v′的表达式:
v ′ ⃗ = v / / ⃗ + v ⊥ ′ ⃗ v ′ ⃗ = v / / ⃗ + v ⃗ cos θ − v / / ⃗ cos θ + ( u ⃗ × v ⃗ ) sin θ = v ⃗ cos θ + ( 1 − cos θ ) v / / ⃗ + ( u ⃗ × v ⃗ ) sin θ v ′ ⃗ = v ⃗ cos θ + ( 1 − cos θ ) ( u ⃗ ⋅ v ⃗ ) u ⃗ + ( u ⃗ × v ⃗ ) sin θ \vec{v'}=\vec{v_{//}}+\vec{v'_{\bot}}\\ \vec{v'}=\vec{v_{//}}+\vec{v}\cos\theta-\vec{v_{//}}\cos\theta+(\vec{u}\times\vec{v})\sin\theta=\vec{v}\cos\theta+(1-\cos\theta)\vec{v_{//}}+(\vec{u}\times\vec{v})\sin\theta\\ \vec{v'}=\vec{v}\cos\theta+(1-\cos\theta)(\vec{u}\cdot{\vec{v}})\vec{u}+(\vec{u}\times\vec{v})\sin\theta v′=v//+v⊥′v′=v//+vcosθ−v//cosθ+(u×v)sinθ=vcosθ+(1−cosθ)v//+(u×v)sinθv′=vcosθ+(1−cosθ)(u⋅v)u+(u×v)sinθ
上式的结果即是作为标题而提及的 Rodrigues’ Rotation Formula。
我们需要进一步化简公式,得到其等价的矩阵表达形式,才方便代码的实现。
首先,我们需要知道向量三重积公式:
a ⃗ × ( b ⃗ × c ⃗ ) = ( a ⃗ ⋅ c ⃗ ) ⋅ b ⃗ − ( a ⃗ ⋅ b ⃗ ) ⋅ c ⃗ \vec{a}\times(\vec{b}\times\vec{c})=(\vec{a}\cdot\vec{c})\cdot\vec{b}-(\vec{a}\cdot\vec{b})\cdot\vec{c} a×(b×c)=(a⋅c)⋅b−(a⋅b)⋅c
然后,我们还需要知道,向量的叉乘与矩阵之间的联系:
a ⃗ × b ⃗ = ( y a z b − z a y b z a x b − x a z b x a y b − y a x b ) = A ⋅ b = ( 0 − z a y a z a 0 − x a − y a x a 0 ) ( x b y b z b ) \vec{a}\times\vec{b}=\begin{pmatrix}y_az_b-z_ay_b\\z_ax_b-x_az_b\\x_ay_b-y_ax_b\end{pmatrix}=A\cdot b= \begin{pmatrix} 0 & -z_a & y_a\\ z_a& 0 & -x_a\\ -y_a& x_a & 0 \end{pmatrix}\begin{pmatrix}x_b\\y_b\\z_b\end{pmatrix} a×b= yazb−zaybzaxb−xazbxayb−yaxb =A⋅b= 0za−ya−za0xaya−xa0 xbybzb
向量的叉乘可以化为矩阵与向量的乘积,而且需要注意的是,矩阵只与左边的向量有关。
我们化简的目标是得到下述形式的表达式,其中M是矩阵。
v ′ ⃗ = M ⋅ v ⃗ \vec{v'}=M\cdot\vec{v} v′=M⋅v
再次观察公式:
v ′ ⃗ = v ⃗ cos θ + ( 1 − cos θ ) ( u ⃗ ⋅ v ⃗ ) u ⃗ + ( u ⃗ × v ⃗ ) sin θ \vec{v'}=\vec{v}\cos\theta+(1-\cos\theta)(\vec{u}\cdot{\vec{v}})\vec{u}+(\vec{u}\times\vec{v})\sin\theta v′=vcosθ+(1−cosθ)(u⋅v)u+(u×v)sinθ
第一项和第三项都可以快速给出等价的矩阵形式,其中, v ⃗ cos θ \vec{v}\cos\theta vcosθ可以化为:
v ⃗ cos θ = ( cos θ 0 0 0 cos θ 0 0 0 cos θ ) ⋅ v ⃗ \vec{v}\cos\theta=\begin{pmatrix} \cos\theta & 0 & 0\\ 0 & \cos\theta & 0\\ 0 & 0 & \cos\theta \end{pmatrix}\cdot\vec{v} vcosθ= cosθ000cosθ000cosθ ⋅v
正如前文所说, ( u ⃗ × v ⃗ ) sin θ (\vec{u}\times\vec{v})\sin\theta (u×v)sinθ也可以化成矩阵乘向量的形式,这里记向量 u ⃗ \vec{u} u形成的矩阵为 R u R_u Ru,可以得到 ( u ⃗ × v ⃗ ) sin θ = R u sin θ ⋅ v ⃗ (\vec{u}\times\vec{v})\sin\theta=R_u\sin\theta\cdot\vec{v} (u×v)sinθ=Rusinθ⋅v
比较难以化简的是第二项,处于外部的是向量 u ⃗ \vec{u} u而不是 v ⃗ \vec{v} v,这给我们带来了一些麻烦。观察 ( u ⃗ ⋅ v ⃗ ) u ⃗ (\vec{u}\cdot{\vec{v}})\vec{u} (u⋅v)u这一项和已知的三重积公式,或许可以想办法配凑另外一项,从而把点乘变为叉乘,再运用叉乘的性质化作矩阵。有好几种可能的叉乘式,最终我们选择配凑出这样的叉乘: u ⃗ × ( u ⃗ × v ⃗ ) \vec{u}\times(\vec{u}\times\vec{v}) u×(u×v)。其中一个理由是 u ⃗ \vec{u} u都在左边,我们可以复用前面提到的矩阵 R u R_u Ru;另一个理由是缺失的那一项很好配凑:
u ⃗ × ( u ⃗ × v ⃗ ) = ( u ⃗ ⋅ v ⃗ ) u ⃗ − ( u ⃗ ⋅ u ⃗ ) v ⃗ = ( u ⃗ ⋅ v ⃗ ) u ⃗ − v ⃗ \vec{u}\times(\vec{u}\times\vec{v})=(\vec{u}\cdot\vec{v})\vec{u}-(\vec{u}\cdot\vec{u})\vec{v}=(\vec{u}\cdot\vec{v})\vec{u}-\vec{v} u×(u×v)=(u⋅v)u−(u⋅u)v=(u⋅v)u−v
明确了目标之后,开始化简:
v ⃗ cos θ + ( 1 − cos θ ) ( u ⃗ ⋅ v ⃗ ) u ⃗ = v ⃗ cos θ + v ⃗ − v ⃗ = v ⃗ − ( 1 − cos θ ) v ⃗ + ( 1 − cos θ ) ( u ⃗ ⋅ v ⃗ ) u ⃗ = v ⃗ + ( 1 − cos θ ) ( ( u ⃗ ⋅ v ⃗ ) u ⃗ − v ⃗ ) = v ⃗ + ( 1 − cos θ ) ( u ⃗ × ( u ⃗ × v ⃗ ) ) \vec{v}\cos\theta+(1-\cos\theta)(\vec{u}\cdot{\vec{v}})\vec{u}=\vec{v}\cos\theta+\vec{v}-\vec{v}=\vec{v}-(1-\cos\theta)\vec{v}+(1-\cos\theta)(\vec{u}\cdot{\vec{v}})\vec{u}\\ =\vec{v}+(1-\cos\theta)((\vec{u}\cdot{\vec{v}})\vec{u}-\vec{v})\\ =\vec{v}+(1-\cos\theta)(\vec{u}\times(\vec{u}\times\vec{v})) vcosθ+(1−cosθ)(u⋅v)u=vcosθ+v−v=v−(1−cosθ)v+(1−cosθ)(u⋅v)u=v+(1−cosθ)((u⋅v)u−v)=v+(1−cosθ)(u×(u×v))
我们再次利用叉乘转换为矩阵的性质,可以得到:
u ⃗ × ( u ⃗ × v ⃗ ) = u ⃗ × ( R u ⋅ v ⃗ ) = R u 2 ⋅ v ⃗ \vec{u}\times(\vec{u}\times\vec{v})=\vec{u}\times(R_u\cdot\vec{v})=R_u^2\cdot\vec{v} u×(u×v)=u×(Ru⋅v)=Ru2⋅v
最后我们得到了一个比较复杂的矩阵:
v ′ ⃗ = v ⃗ + ( 1 − cos θ ) ⋅ R u 2 ⋅ v ⃗ + R u sin θ ⋅ v ⃗ 记 I 为单位矩阵 v ′ ⃗ = ( I + ( 1 − cos θ ) ⋅ R u 2 + R u sin θ ) ⋅ v ⃗ M = I + ( 1 − cos θ ) ⋅ R u 2 + R u sin θ \vec{v'}=\vec{v}+(1-\cos\theta)\cdot R_u^2\cdot\vec{v}+R_u\sin\theta\cdot\vec{v}\\ 记I为单位矩阵\\ \vec{v'}=(I+(1-\cos\theta)\cdot R_u^2+R_u\sin\theta)\cdot\vec{v}\\ M=I+(1-\cos\theta)\cdot R_u^2+R_u\sin\theta v′=v+(1−cosθ)⋅Ru2⋅v+Rusinθ⋅v记I为单位矩阵v′=(I+(1−cosθ)⋅Ru2+Rusinθ)⋅vM=I+(1−cosθ)⋅Ru2+Rusinθ
M即为我们所求的矩阵。
罗德里格旋转公式(Rodrigues’ rotation formula)
四元数与三维旋转