在三維空間,給定兩個球體 A 和 B 的球心初始位置 \mathbf{c}_A 和 \mathbf{c}_B,半徑 r_A 和 r_B,勻速移動速度 \mathbf{v}_A 和 \mathbf{v}_B,如何判斷它們兩者會否碰撞,如會碰撞求碰撞時間。
錯誤思路:
求兩射線是否相交:在三維中兩射線相交幾乎是不可能發生的。
求兩圓柱體是否相交:即使相交,還不能判斷是否碰撞。
如果沒有頭緒,給第一個提示:
如果不考慮移動,怎樣判斷兩個靜態的球體是否相交?
這算是最基本的相交測試,通常都可以答出來。如果兩球心的距離小於等於兩半徑之和,即兩者相交:
\left \| \mathbf{c}_A - \mathbf{c}_B \right \| \le r_A+r_B
第二個提示:
那麼,可以把兩個勻速移動的球心位置表示為時間 t 的函式麼?
這是簡單的運動學,速度乘以時間等於位移,再加上初始位置:
\begin{align}
\mathbf{x}_A(t) &= \mathbf{c}_A + \mathbf{v}_At\\
\mathbf{x}_B(t) &= \mathbf{c}_B + \mathbf{v}_Bt
\end{align}
到這一步,多數同學能想到可以用這兩個函式代入上面的方程。由於只需要考慮兩個球剛觸碰的時間,不需考慮不等式,只需考慮方程:
\left \| \mathbf{x}_A(t) - \mathbf{x}_B(t) \right \| &= r_A+r_B\\
\left \| (\mathbf{c}_A + \mathbf{v}_At) - (\mathbf{c}_B + \mathbf{v}_Bt) \right \| &= r_A+r_B\\
\left \| (\mathbf{v}_A - \mathbf{v}_B)t +(\mathbf{c}_A - \mathbf{c}_B) \right \| &= r_A+r_B\\
為簡單起見,設 \mathbf{v} = \mathbf{v}_A - \mathbf{v}_B, \mathbf{c} = \mathbf{c}_A - \mathbf{c}_B, r = r_A + r_B:
\left \| \mathbf{v}t + \mathbf{c} \right \| = r
到這一步,有些同學會用 \left \| \mathbf{u} \right \| = \sqrt{u_x^2 + u_y^2 + u_z^2} 去展開,但理想地不需這樣以分量去計算,而是以點積表示 \left \| \mathbf{u} \right \|^2 = \mathbf{u} \cdot \mathbf{u},並且知道點積在加法上的分配律:
\left \| \mathbf{v}t + \mathbf{c} \right \|^2 &= r^2\\
(\mathbf{v}t + \mathbf{c}) \cdot (\mathbf{v}t + \mathbf{c}) &= r^2\\
(\mathbf{v} \cdot \mathbf{v})t^2 + 2(\mathbf{v} \cdot \mathbf{c})t + \mathbf{c} \cdot \mathbf{c} &= r^2\\
(\mathbf{v} \cdot \mathbf{v})t^2 + 2(\mathbf{v} \cdot \mathbf{c})t + \mathbf{c} \cdot \mathbf{c} - r^2 &= 0\\
同學應該看得出,這是關於 t 的一元二次方程 at^2 + bt + c = 0。
求解一元二次方程有多少種情況?每種情況表示什麼碰撞情況?
前半是初中的數學知識,按判別式 \Delta = b^2 - 4ac:
如果 \Delta > 0,方程有兩個根 t_1, t_2,設 t_1 < t_2;
如果 \Delta = 0,方程有重根 t_1;
如果 \Delta < 0,方程無實根。
後半的問題難倒了一些同學,主要是忘記了方程本來是表達什麼。這個方程的意義,是求出某個時間點,當時兩個球體剛好接觸。那麼三種情況對應的是:
兩個球體在時間 t_1 觸碰,然後互相進入穿過(物理上不可能數學上可以),在時間 t_2 分離;
兩個球體在時間 t_1 擦身而過;
兩個球體不碰撞。
但兩者是否碰撞還有一個約束 t \ge 0,不應考慮逆向時間碰撞。所以我們還是需要求根,才能判斷它們是否碰撞。
怎樣解一元二次方程?寫成程式有什麼地方要注意?
不就是背公式麼?
t = \frac{-b\pm\sqrt{\Delta}}{2a}
有同學看到除數都不敏感,除數是會出現 division by zero 錯誤的啊!
a 在什麼時候會為零?怎樣處理?
在 a=0 的時候,一元二次方程就退化成一元一次方程 bt + c = 0 \Leftrightarrow t=-c/b。不過在這個問題中,當 a=\mathbf{v}\cdot\mathbf{v}=0 的時候,也表示 \mathbf{v} = 0,所以 b = 2(\mathbf{v} \cdot \mathbf{c})=0。最後原來的一元二次方退化成:
c=0
這是什麼意思?若 c = 0 代表什麼?若 c \ne 0 又代表什麼?
從數學上說,若 c = 0 代表方程有無窮解,t 為任意值都滿足方程;若 c \ne 0,代表方程無解,無論 t 為任何值都不能滿足方程。
對於本問題來說,a=0 \Leftrightarrow \mathbf{v} = 0 \Leftrightarrow \mathbf{v}_A = \mathbf{v}_B 即兩個球體速度相同,那麼它們是平行地往同一個方向勻速移動。而 c=0 \Leftrightarrow \mathbf{c}\cdot\mathbf{c} - r^2 = 0\Leftrightarrow \left \| \mathbf{c}_A - \mathbf{c}_B \right \| =r_A + r_B 即兩球球心初始位置的距離等於兩球半徑之和。換句話說,如果兩球的速度相同,我們需要判斷它們初始位置是否剛好接觸,若是,它們永遠碰撞不分離,若否,它們永遠不碰撞。
前天,有一位同學想到,利用閔可夫斯基差的概念,這個問題可以轉變為射線與球體相交問題(A 球體縮小至一點,B球體膨脹成半徑 r_A + r_B;按相對速度,當 B 變為靜上,A 的速度變為 \mathbf{v}_A - \mathbf{v}_B)。其實這也會得到相同的一元二次方程。不過按這個思路,也可以用上 RTR 中提到射線和球體相交測試的一些最佳化方法。
相對速度、變換參考系等
我們可以不考慮兩球分別的速度,而僅考慮它們的相對速度。例如,假設球 B 是觀察者,那麼球 A 相對於球 B 的速度為:
\mathbf{v}_{A|B} = \mathbf{v}_A - \mathbf{v}_B
我們也知道,兩球的絕對位置是不重要的,我們只需要考慮它們的相對位移。以球 B 為原點的話,球 A 相對於球 B 的初始位置為:
\mathbf{c}_{A|B}=\mathbf{c}_A - \mathbf{c}_B
然後,我們可以發現,這樣和之前列出的方程是一模一樣的:
\left \| \mathbf{c}_{A|B} + \mathbf{v}_{A|B}t \right\| = r^2
此外,有人提出
在一個球靜止的情況下,可用直線與原點的距離是否小於半徑之和,來判定兩者是否碰撞。
我們來試一下。首先,設直線為引數式 \mathbf{r}(t) = \mathbf{c} + \mathbf{v}t。設直線上最近原點的點為 \mathbf{r}(t_0),原點過 \mathbf{r}(t_0) 的直線與 \mathbf{v} 垂直,因此它們的點積為零:
(\mathbf{c} + \mathbf{v}t_0)\cdot\mathbf{v} &= 0\\
\mathbf{c}\cdot \mathbf{v} + \mathbf{v} \cdot \mathbf{v} t_0 &= 0\\
t_0 &= -\frac{\mathbf{c}\cdot \mathbf{v}}{\mathbf{v} \cdot \mathbf{v}}
得出 t_0 後,\mathbf{r}(t_0) 與原點的距離就是它的模,我們計算其模的平方:
\left\|\mathbf{r}(t_0)\right\|^2 &= \mathbf{r}(t_0) \cdot \mathbf{r}(t_0)\\
&= (\mathbf{c}+\mathbf{v}t_0) \cdot (\mathbf{c}+\mathbf{v}t_0)\\
&= \mathbf{v}\cdot\mathbf{v}t_0^2+2\mathbf{c}\cdot\mathbf{v}t_0+\mathbf{c}\cdot\mathbf{c}\\
&= \mathbf{v}\cdot\mathbf{v} \left(-\frac{\mathbf{c}\cdot\mathbf{v}}{\mathbf{v}\cdot\mathbf{v}} \right )^2+2\mathbf{c}\cdot\mathbf{v}\left(-\frac{\mathbf{c}\cdot\mathbf{v}}{\mathbf{v}\cdot\mathbf{v}} \right )+\mathbf{c}\cdot\mathbf{c}\\
&= \frac{(\mathbf{c}\cdot\mathbf{v})^2}{\mathbf{v}\cdot\mathbf{v}} - 2 \frac{(\mathbf{c}\cdot\mathbf{v})^2}{\mathbf{v}\cdot\mathbf{v}} + \mathbf{c} \cdot \mathbf{c}\\
&= \mathbf{c}\cdot\mathbf{c}- \frac{(\mathbf{c}\cdot\mathbf{v})^2}{\mathbf{v}\cdot\mathbf{v}}
然後我們檢查它是否小於半徑和的平方:
\mathbf{c}\cdot\mathbf{c}-\frac{(\mathbf{c}\cdot\mathbf{v})^2}{\mathbf{v}\cdot\mathbf{v}} &\le r^2\\
-\frac{(\mathbf{c}\cdot\mathbf{v})^2}{\mathbf{v}\cdot\mathbf{v}} &\le r^2 -\mathbf{c}\cdot\mathbf{c} \\
\frac{(\mathbf{c}\cdot\mathbf{v})^2}{\mathbf{v}\cdot\mathbf{v}} &\ge \mathbf{c}\cdot\mathbf{c} - r^2 \\
(\mathbf{c}\cdot\mathbf{v})^2 &\ge (\mathbf{v}\cdot\mathbf{v})(\mathbf{c}\cdot\mathbf{c} - r^2) \\
(\mathbf{c}\cdot\mathbf{v})^2 - (\mathbf{v}\cdot\mathbf{v})(\mathbf{c}\cdot\mathbf{c} - r^2) &\ge 0 \\
這個不等式是不是有點眼熟?我們之前沒展開判別式\Delta:
\Delta &= b^2 - 4ac\\
&= (2 \mathbf{v}\cdot\mathbf{c})^2 - 4 (\mathbf{v}\cdot\mathbf{v})(\mathbf{c}\cdot\mathbf{c} - r^2)\\
&= 4 (\mathbf{v}\cdot\mathbf{c})^2 - 4 (\mathbf{v}\cdot\mathbf{v})(\mathbf{c}\cdot\mathbf{c} - r^2)
我們發現,剛才計算直線\mathbf{r}(t)與原點的距離是否小於半徑和的不等式,等價於檢測 \Delta \ge 0 。這不是巧合,事實上這兩個問題是等價的。如果有同學想到直線距離的判斷,也是正確的,不過之後也是要求直線和原點距離剛好等於半徑和時候的 t,結果也要做相同的計算。
在三維空間,給定兩個球體 A 和 B 的球心初始位置 \mathbf{c}_A 和 \mathbf{c}_B,半徑 r_A 和 r_B,勻速移動速度 \mathbf{v}_A 和 \mathbf{v}_B,如何判斷它們兩者會否碰撞,如會碰撞求碰撞時間。
錯誤思路:
求兩射線是否相交:在三維中兩射線相交幾乎是不可能發生的。
求兩圓柱體是否相交:即使相交,還不能判斷是否碰撞。
如果沒有頭緒,給第一個提示:
如果不考慮移動,怎樣判斷兩個靜態的球體是否相交?
這算是最基本的相交測試,通常都可以答出來。如果兩球心的距離小於等於兩半徑之和,即兩者相交:
\left \| \mathbf{c}_A - \mathbf{c}_B \right \| \le r_A+r_B
第二個提示:
那麼,可以把兩個勻速移動的球心位置表示為時間 t 的函式麼?
這是簡單的運動學,速度乘以時間等於位移,再加上初始位置:
\begin{align}
\mathbf{x}_A(t) &= \mathbf{c}_A + \mathbf{v}_At\\
\mathbf{x}_B(t) &= \mathbf{c}_B + \mathbf{v}_Bt
\end{align}
到這一步,多數同學能想到可以用這兩個函式代入上面的方程。由於只需要考慮兩個球剛觸碰的時間,不需考慮不等式,只需考慮方程:
\begin{align}
\left \| \mathbf{x}_A(t) - \mathbf{x}_B(t) \right \| &= r_A+r_B\\
\left \| (\mathbf{c}_A + \mathbf{v}_At) - (\mathbf{c}_B + \mathbf{v}_Bt) \right \| &= r_A+r_B\\
\left \| (\mathbf{v}_A - \mathbf{v}_B)t +(\mathbf{c}_A - \mathbf{c}_B) \right \| &= r_A+r_B\\
\end{align}
為簡單起見,設 \mathbf{v} = \mathbf{v}_A - \mathbf{v}_B, \mathbf{c} = \mathbf{c}_A - \mathbf{c}_B, r = r_A + r_B:
\left \| \mathbf{v}t + \mathbf{c} \right \| = r
到這一步,有些同學會用 \left \| \mathbf{u} \right \| = \sqrt{u_x^2 + u_y^2 + u_z^2} 去展開,但理想地不需這樣以分量去計算,而是以點積表示 \left \| \mathbf{u} \right \|^2 = \mathbf{u} \cdot \mathbf{u},並且知道點積在加法上的分配律:
\begin{align}
\left \| \mathbf{v}t + \mathbf{c} \right \|^2 &= r^2\\
(\mathbf{v}t + \mathbf{c}) \cdot (\mathbf{v}t + \mathbf{c}) &= r^2\\
(\mathbf{v} \cdot \mathbf{v})t^2 + 2(\mathbf{v} \cdot \mathbf{c})t + \mathbf{c} \cdot \mathbf{c} &= r^2\\
(\mathbf{v} \cdot \mathbf{v})t^2 + 2(\mathbf{v} \cdot \mathbf{c})t + \mathbf{c} \cdot \mathbf{c} - r^2 &= 0\\
\end{align}
同學應該看得出,這是關於 t 的一元二次方程 at^2 + bt + c = 0。
求解一元二次方程有多少種情況?每種情況表示什麼碰撞情況?
前半是初中的數學知識,按判別式 \Delta = b^2 - 4ac:
如果 \Delta > 0,方程有兩個根 t_1, t_2,設 t_1 < t_2;
如果 \Delta = 0,方程有重根 t_1;
如果 \Delta < 0,方程無實根。
後半的問題難倒了一些同學,主要是忘記了方程本來是表達什麼。這個方程的意義,是求出某個時間點,當時兩個球體剛好接觸。那麼三種情況對應的是:
兩個球體在時間 t_1 觸碰,然後互相進入穿過(物理上不可能數學上可以),在時間 t_2 分離;
兩個球體在時間 t_1 擦身而過;
兩個球體不碰撞。
但兩者是否碰撞還有一個約束 t \ge 0,不應考慮逆向時間碰撞。所以我們還是需要求根,才能判斷它們是否碰撞。
怎樣解一元二次方程?寫成程式有什麼地方要注意?
不就是背公式麼?
t = \frac{-b\pm\sqrt{\Delta}}{2a}
有同學看到除數都不敏感,除數是會出現 division by zero 錯誤的啊!
a 在什麼時候會為零?怎樣處理?
在 a=0 的時候,一元二次方程就退化成一元一次方程 bt + c = 0 \Leftrightarrow t=-c/b。不過在這個問題中,當 a=\mathbf{v}\cdot\mathbf{v}=0 的時候,也表示 \mathbf{v} = 0,所以 b = 2(\mathbf{v} \cdot \mathbf{c})=0。最後原來的一元二次方退化成:
c=0
這是什麼意思?若 c = 0 代表什麼?若 c \ne 0 又代表什麼?
從數學上說,若 c = 0 代表方程有無窮解,t 為任意值都滿足方程;若 c \ne 0,代表方程無解,無論 t 為任何值都不能滿足方程。
對於本問題來說,a=0 \Leftrightarrow \mathbf{v} = 0 \Leftrightarrow \mathbf{v}_A = \mathbf{v}_B 即兩個球體速度相同,那麼它們是平行地往同一個方向勻速移動。而 c=0 \Leftrightarrow \mathbf{c}\cdot\mathbf{c} - r^2 = 0\Leftrightarrow \left \| \mathbf{c}_A - \mathbf{c}_B \right \| =r_A + r_B 即兩球球心初始位置的距離等於兩球半徑之和。換句話說,如果兩球的速度相同,我們需要判斷它們初始位置是否剛好接觸,若是,它們永遠碰撞不分離,若否,它們永遠不碰撞。
前天,有一位同學想到,利用閔可夫斯基差的概念,這個問題可以轉變為射線與球體相交問題(A 球體縮小至一點,B球體膨脹成半徑 r_A + r_B;按相對速度,當 B 變為靜上,A 的速度變為 \mathbf{v}_A - \mathbf{v}_B)。其實這也會得到相同的一元二次方程。不過按這個思路,也可以用上 RTR 中提到射線和球體相交測試的一些最佳化方法。
相對速度、變換參考系等
我們可以不考慮兩球分別的速度,而僅考慮它們的相對速度。例如,假設球 B 是觀察者,那麼球 A 相對於球 B 的速度為:
\mathbf{v}_{A|B} = \mathbf{v}_A - \mathbf{v}_B
我們也知道,兩球的絕對位置是不重要的,我們只需要考慮它們的相對位移。以球 B 為原點的話,球 A 相對於球 B 的初始位置為:
\mathbf{c}_{A|B}=\mathbf{c}_A - \mathbf{c}_B
然後,我們可以發現,這樣和之前列出的方程是一模一樣的:
\left \| \mathbf{c}_{A|B} + \mathbf{v}_{A|B}t \right\| = r^2
此外,有人提出
在一個球靜止的情況下,可用直線與原點的距離是否小於半徑之和,來判定兩者是否碰撞。
我們來試一下。首先,設直線為引數式 \mathbf{r}(t) = \mathbf{c} + \mathbf{v}t。設直線上最近原點的點為 \mathbf{r}(t_0),原點過 \mathbf{r}(t_0) 的直線與 \mathbf{v} 垂直,因此它們的點積為零:
\begin{align}
(\mathbf{c} + \mathbf{v}t_0)\cdot\mathbf{v} &= 0\\
\mathbf{c}\cdot \mathbf{v} + \mathbf{v} \cdot \mathbf{v} t_0 &= 0\\
t_0 &= -\frac{\mathbf{c}\cdot \mathbf{v}}{\mathbf{v} \cdot \mathbf{v}}
\end{align}
得出 t_0 後,\mathbf{r}(t_0) 與原點的距離就是它的模,我們計算其模的平方:
\begin{align}
\left\|\mathbf{r}(t_0)\right\|^2 &= \mathbf{r}(t_0) \cdot \mathbf{r}(t_0)\\
&= (\mathbf{c}+\mathbf{v}t_0) \cdot (\mathbf{c}+\mathbf{v}t_0)\\
&= \mathbf{v}\cdot\mathbf{v}t_0^2+2\mathbf{c}\cdot\mathbf{v}t_0+\mathbf{c}\cdot\mathbf{c}\\
&= \mathbf{v}\cdot\mathbf{v} \left(-\frac{\mathbf{c}\cdot\mathbf{v}}{\mathbf{v}\cdot\mathbf{v}} \right )^2+2\mathbf{c}\cdot\mathbf{v}\left(-\frac{\mathbf{c}\cdot\mathbf{v}}{\mathbf{v}\cdot\mathbf{v}} \right )+\mathbf{c}\cdot\mathbf{c}\\
&= \frac{(\mathbf{c}\cdot\mathbf{v})^2}{\mathbf{v}\cdot\mathbf{v}} - 2 \frac{(\mathbf{c}\cdot\mathbf{v})^2}{\mathbf{v}\cdot\mathbf{v}} + \mathbf{c} \cdot \mathbf{c}\\
&= \mathbf{c}\cdot\mathbf{c}- \frac{(\mathbf{c}\cdot\mathbf{v})^2}{\mathbf{v}\cdot\mathbf{v}}
\end{align}
然後我們檢查它是否小於半徑和的平方:
\begin{align}
\mathbf{c}\cdot\mathbf{c}-\frac{(\mathbf{c}\cdot\mathbf{v})^2}{\mathbf{v}\cdot\mathbf{v}} &\le r^2\\
-\frac{(\mathbf{c}\cdot\mathbf{v})^2}{\mathbf{v}\cdot\mathbf{v}} &\le r^2 -\mathbf{c}\cdot\mathbf{c} \\
\frac{(\mathbf{c}\cdot\mathbf{v})^2}{\mathbf{v}\cdot\mathbf{v}} &\ge \mathbf{c}\cdot\mathbf{c} - r^2 \\
(\mathbf{c}\cdot\mathbf{v})^2 &\ge (\mathbf{v}\cdot\mathbf{v})(\mathbf{c}\cdot\mathbf{c} - r^2) \\
(\mathbf{c}\cdot\mathbf{v})^2 - (\mathbf{v}\cdot\mathbf{v})(\mathbf{c}\cdot\mathbf{c} - r^2) &\ge 0 \\
\end{align}
這個不等式是不是有點眼熟?我們之前沒展開判別式\Delta:
\begin{align}
\Delta &= b^2 - 4ac\\
&= (2 \mathbf{v}\cdot\mathbf{c})^2 - 4 (\mathbf{v}\cdot\mathbf{v})(\mathbf{c}\cdot\mathbf{c} - r^2)\\
&= 4 (\mathbf{v}\cdot\mathbf{c})^2 - 4 (\mathbf{v}\cdot\mathbf{v})(\mathbf{c}\cdot\mathbf{c} - r^2)
\end{align}
我們發現,剛才計算直線\mathbf{r}(t)與原點的距離是否小於半徑和的不等式,等價於檢測 \Delta \ge 0 。這不是巧合,事實上這兩個問題是等價的。如果有同學想到直線距離的判斷,也是正確的,不過之後也是要求直線和原點距離剛好等於半徑和時候的 t,結果也要做相同的計算。