Redpoll's 60
第3章 3D空間の基礎

$§$3-6 ベクトルの外積


3D空間内のベクトル $\boldsymbol{a} = (a_x, a_y, a_z)$、$\boldsymbol{b} = (b_x, b_y, b_z)$ に関して、次の成分で表されるベクトルを $\boldsymbol{a}$ と $\boldsymbol{b}$ の外積(Cross Product)といい、$\boldsymbol{a} \times \boldsymbol{b}$ で表す。

ベクトル $\boldsymbol{a} = (a_x, a_y, a_z)$、$\boldsymbol{b} = (b_x, b_y, b_z)$ の外積 $\boldsymbol{a} \times \boldsymbol{b}$
\[ \boldsymbol{a} \times \boldsymbol{b}\ =\ (a_yb_z - a_zb_y,\ a_zb_x - a_xb_z,\ a_xb_y - a_yb_x) \]
(計算例)
ベクトル $\boldsymbol{\mathsf{v_1}} = (1, 2, 3)$、$\boldsymbol{\mathsf{v_2}} = (4, 5, 6)$ の外積 $\boldsymbol{\mathsf{v_1}} \times \boldsymbol{\mathsf{v_2}}$
\begin{align*}\boldsymbol{\mathsf{v_1}} \times \boldsymbol{\mathsf{v_2}}\ &=\ (2\cdot6 - 3\cdot5,\ 3\cdot4 - 1\cdot6,\ 1\cdot5 - 2\cdot4) \\&= (12-15,\ 12-6,\ 5-8) = (-3,\ 6, -3)\end{align*}上の計算における $\boldsymbol{\mathsf{v_1}}$、$\boldsymbol{\mathsf{v_2}}$ の積の順序を入れ替えた場合
\begin{align*}\boldsymbol{\mathsf{v_2}} \times \boldsymbol{\mathsf{v_1}}\ &=\ (5\cdot3 - 6\cdot2,\ 6\cdot1 - 4\cdot3,\ 4\cdot2 - 5\cdot1) \\&= (15-12,\ 6-12,\ 8-5) = (3, -6,\ 3)\end{align*}
上の結果からわかるように、外積の積の順序は交換可能ではない。つまり、積の順序を入れ替えた場合、算出されるベクトルは異なる。より正確には、外積の積の順序については次の関係が成り立つ。($\boldsymbol{a}$、$\boldsymbol{b}$ を3次元ベクトルとすると)
\[ \boldsymbol{a} \times \boldsymbol{b} = -\boldsymbol{b} \times \boldsymbol{a} \]
ベクトルの内積が2つのベクトルから1つの実数値を算出する演算であったのに対し、ベクトルの外積は2つのベクトルから新たにもう1つのベクトルを算出する演算である。
具体的な例として、図1の2つのベクトル $\boldsymbol{a} = (0, 0, 2)$、$\boldsymbol{b} = (3, 0, 1)$ の外積 $\boldsymbol{a} \times \boldsymbol{b}$ を求めてみよう(以下では $\boldsymbol{a} \times \boldsymbol{b} = \boldsymbol{c}$ とおく ; 図中の緑色の数値はベクトルの成分を表している)。

図1 ベクトルa、b
図2 外積 a×b = c

\begin{align*}\boldsymbol{a} \times \boldsymbol{b}\ &=\ (0\cdot1 - 2\cdot0,\ 2\cdot3 - 0\cdot1,\ 0\cdot0 - 0\cdot3) \\&=(0,\ 6,\ 0) = \boldsymbol{c}\end{align*}
図2における赤いベクトルが、外積 $\boldsymbol{a} \times \boldsymbol{b}\ ( = \boldsymbol{c})$ である。
外積とは一体どのようなものなのであろうか。まず、外積の幾何的な意味から見ていこう。



A) 外積の大きさ

図3 外積 a×b の大きさは a、b の作る平行四辺形の面積に等しい
ベクトル $\boldsymbol{a}$、$\boldsymbol{b}$ を3次元ベクトルとし、$\boldsymbol{a}$、$\boldsymbol{b}$ のなす角を $T$ とすると、外積 $\boldsymbol{a} \times \boldsymbol{b}$ の大きさに関して以下の等式が成立する(角度$T$は、$0^\circ <= T <= 180^\circ$ の範囲にあるものとする)。
\[ |\boldsymbol{a} \times \boldsymbol{b}| = |\boldsymbol{a}||\boldsymbol{b}|\sin{T} \]この等式の意味を図3を用いて説明しよう。
ベクトル $\boldsymbol{b}$ の終点からベクトル $\boldsymbol{a}$ に垂線をおろしたとき、その垂線の足(ベクトル $\boldsymbol{a}$ と垂線の交点)とベクトル $\boldsymbol{b}$ の始点、及び終点は直角三角形を作る。$\boldsymbol{a}$ と $\boldsymbol{b}$ のなす角が $T$ であるから、垂線の長さ(図中の点線の長さ)は $|\boldsymbol{b}|\sin{T}$ である。したがって、$|\boldsymbol{a}||\boldsymbol{b}|\sin{T}$ はベクトル $\boldsymbol{a}$、$\boldsymbol{b}$ によって作られる平行四辺形の面積に等しい。
上の図1、図2の例でいえば、$\boldsymbol{a} = (0, 0, 2)$、$\boldsymbol{b} = (3, 0, 1)$ の外積は $\boldsymbol{a} \times \boldsymbol{b} = (0,\ 6,\ 0)\ (= \boldsymbol{c})$ であったが、外積の大きさは $|\boldsymbol{a} \times \boldsymbol{b}| = |\boldsymbol{c}| = 6$ である。これは、ベクトル $\boldsymbol{a}$ と $\boldsymbol{b}$ が作る平行四辺形の面積が $6$ であることを意味している。

下の図4、図5のように2つのベクトル $\boldsymbol{\mathsf{v_1}}$、$\boldsymbol{\mathsf{v_2}}$ が平行である場合の外積について見てみよう。

図4 平行なベクトル(なす角0°)
図5 平行なベクトル(なす角180°)

外積の大きさは $|\boldsymbol{\mathsf{v_1}} \times \boldsymbol{\mathsf{v_2}}|$ = $|\boldsymbol{\mathsf{v_1}}||\boldsymbol{\mathsf{v_2}}|\sin{T}$ で表されるが、この場合は $\boldsymbol{\mathsf{v_1}}$、$\boldsymbol{\mathsf{v_2}}$ のなす角が$0$°、$180$°となり、$\sin{T}$の値は$0$になってしまう。つまり、$|\boldsymbol{\mathsf{v_1}} \times \boldsymbol{\mathsf{v_2}}| = 0$ である。
これは、$\boldsymbol{\mathsf{v_1}}$と$\boldsymbol{\mathsf{v_2}}$ が平行であるときは、外積 $\boldsymbol{\mathsf{v_1}} \times \boldsymbol{\mathsf{v_2}}$ の大きさは$0$、すなわち外積 $\boldsymbol{\mathsf{v_1}} \times \boldsymbol{\mathsf{v_2}}$ が存在しないことを意味する。



B) 外積の向き

外積 $\boldsymbol{a} \times \boldsymbol{b}$ が示す向きは、3次元ベクトル $\boldsymbol{a}$、$\boldsymbol{b}$ が作る平行四辺形に対して垂直になる(より一般的ないいかたをすれば、外積 $\boldsymbol{a} \times \boldsymbol{b}$ は3次元ベクトル $\boldsymbol{a}$、$\boldsymbol{b}$ を含む平面に対して垂直になる)。すなわち、外積 $\boldsymbol{a} \times \boldsymbol{b}$ は、ベクトル $\boldsymbol{a}$ に対しても垂直であり、$\boldsymbol{b}$ に対しても垂直である。
法線の場合にもそうであったが、ある面に垂直な方向は2つあるが、左手系における外積の向きは以下のように定義される。

例えば、図6のベクトル $\boldsymbol{a}$、$\boldsymbol{b}$ の外積 $\boldsymbol{a} \times \boldsymbol{b}$ の向きは、図7に示されるように左手の親指を $\boldsymbol{a}$、人差し指を $\boldsymbol{b}$ としたときに中指が指している方向が、外積 $\boldsymbol{a} \times \boldsymbol{b}$ の向きである (図7の赤いベクトル)。この $\boldsymbol{a} \times \boldsymbol{b}$ は $\boldsymbol{a}$ に対しても $\boldsymbol{b}$ に対しても垂直、すなわち $\boldsymbol{a}$、$\boldsymbol{b}$ を含む平面に対して垂直なベクトルである。

図6 ベクトルa, b
図7 ベクトルa, bの外積a×b(左手系における外積)

先ほども少し触れたが、外積の積の順序を入れ替えると、算出されるベクトルが反転する。すなわち、\[ \boldsymbol{a} \times \boldsymbol{b} = -\boldsymbol{b} \times \boldsymbol{a} \]である。これは、$\boldsymbol{b} \times \boldsymbol{a}$ の方向は $\boldsymbol{a} \times \boldsymbol{b}$ とは反対の方向になることを意味している。上の例において、左手の親指を $\boldsymbol{b}$ にあて、人差し指を $\boldsymbol{a}$ にあてたときの中指の指している方向が外積 $\boldsymbol{b} \times \boldsymbol{a}$ の方向である。

実際に外積 $\boldsymbol{a} \times \boldsymbol{b}$ が $\boldsymbol{a}$、$\boldsymbol{b}$ のそれぞれと直交していることを調べるには、内積を計算すればよい。つまり、上で示した \[ \boldsymbol{a} \times \boldsymbol{b}\ =\ (a_yb_z - a_zb_y,\ a_zb_x - a_xb_z,\ a_xb_y - a_yb_x) \]と $\boldsymbol{a}$ 及び $\boldsymbol{b}$ との内積を計算すれば、いずれも $0$ になることが簡単に確かめられる。
外積の直交性を示すのはこのように簡単なことであるが、外積が定義通りの向き、すなわち左手の親指を $\boldsymbol{a}$ に合わせ、人差し指を $\boldsymbol{b}$ に合わせたときに、上記の成分で表されるベクトル $\boldsymbol{a} \times \boldsymbol{b}$ が左手の中指の指す方向になるかを示すには、多少の準備を必要とする。詳しくは 3-11節参照。

(なお、右手系では右手の親指を $\boldsymbol{a}$、人差し指を $\boldsymbol{b}$ としたときに中指が指している方向が、右手系の外積 $\boldsymbol{a} \times \boldsymbol{b}$ の向きである。右手系の外積は左手系とは反対の方向を指すことに注意)



C) 法線の計算

外積の使用例として、3D空間内にある面の法線ベクトルを外積を使って求めてみよう。

図9 面PQRS
図10 面PQRSの法線n(単位ベクトル)

3D空間内に四角形の面$PQRS$が置かれている(図9)。この面の法線は次のようにして求めることができる。
まず、$P$を始点、$Q$を終点とするベクトルを $\boldsymbol{a}$ とし、$P$を始点、$S$を終点とするベクトルを $\boldsymbol{b}$ とする(図10)。
\[Q - P = \boldsymbol{a} \qquad\qquad\qquad S - P = \boldsymbol{b}\]このベクトル $\boldsymbol{a}$、$\boldsymbol{b}$ の外積$\boldsymbol{a} \times \boldsymbol{b}$は、ベクトル $\boldsymbol{a}$、$\boldsymbol{b}$ の両方に対して垂直、すなわち $\boldsymbol{a}$、 $\boldsymbol{b}$ を含む平面に対して垂直なベクトルである(もちろん面$PQRS$に対しても垂直である)。したがって、外積$\boldsymbol{a} \times \boldsymbol{b}$は面$PQRS$の法線ベクトルになるが、方向を表すベクトルは正規化して単位ベクトルの形にしておく方が望ましいので、ここでも$\boldsymbol{a} \times \boldsymbol{b}$を正規化した単位ベクトル $\boldsymbol{n}$ を面$PQRS$の法線ベクトルとする。
\[\frac{\boldsymbol{a} \times \boldsymbol{b}}{|\boldsymbol{a} \times \boldsymbol{b}|} = \boldsymbol{n}\](図10におけるベクトル $\boldsymbol{a}$ に左手の親指を合わせ、ベクトル $\boldsymbol{b}$ に左手の人差し指を合わせたとき、法線ベクトル $\boldsymbol{n}$ の方向は左手の中指の方向になる。)

3-5節でも述べたが、Unityでは面の表側のみが描画され、面の裏側は何も描画されない。そして、面の表側とは法線の出ている側である。図9や図10で面$PQRS$が描画されているのは見えている部分が面の表側、つまり法線$\boldsymbol{n}$の出ている側だからである。もし、法線$\boldsymbol{n}$が逆向きであった場合は、面$PQRS$の(図中において)見えていない側が表側となり、(Unityでは)描画されなくなってしまう。
例えば、3Dオブジェクトを作成する際、ある面の法線を上で述べた外積経由で定める場合などでは、法線の方向が$\boldsymbol{a} \times \boldsymbol{b}$の方向なのか、$\boldsymbol{b} \times \boldsymbol{a}$の方向なのかに気を付ける必要がある。



D) 三角形の内外判定

ある点が三角形に含まれるかどうかを外積を用いて調べることができるが、以下この点について説明する。
3D空間内の適当な位置に平面が置かれており、下図11に示されるようにこの平面は黒い線分によって分断されている。図中の点 $A$、$B$ は黒い線分上の点であり、点 $P$ はこの平面上において線分の右側に置かれている。
このとき、ベクトル $\overrightarrow{AP}$ と ベクトル $\overrightarrow{AB}$ の外積 $\overrightarrow{AP} \times \overrightarrow{AB}$ の向きは、左手の親指を $\overrightarrow{AP}$ に、人差し指を $\overrightarrow{AB}$ に合わせたときの左手の中指の指す方向であるから、図12における $\boldsymbol{\mathsf{v}}$ の方向になる。もし点 $P$ が黒い線分の右側ではなく左側に置かれている場合には、外積 $\overrightarrow{AP} \times \overrightarrow{AB}$ の向きは図13における $\boldsymbol{\mathsf{w}}$ の方向になる (左手の親指を $\overrightarrow{AP}$ に、人差し指を $\overrightarrow{AB}$ に合わせれば中指は $\boldsymbol{\mathsf{w}}$ の方向を向く ; 下図における $\boldsymbol{\mathsf{v}}$、$\boldsymbol{\mathsf{w}}$ はいずれもこの平面に直交する方向)。

  • 図11 黒い線分によって平面が分断されている。A、Bは線分上にあり、P は平面上において線分より右側にある
  • 図12 外積 AP x AB は v の方向を向く
  • 図13 外積 AP x AB は w の方向を向く

より詳しくは、上の状況では平面上の点 $P$ が黒い線分よりも右側にある場合には外積 $\overrightarrow{AP} \times \overrightarrow{AB}$ の方向は $\boldsymbol{\mathsf{v}}$ の方向になり、点 $P$ が線分よりも左側にある場合には $\boldsymbol{\mathsf{w}}$ の方向になるのである。

状況を簡単にするために考える平面をXY平面とし、XY平面の y軸上にベクトル $\overrightarrow{AB}$ が置かれているものとしよう (図14)。この場合には図に示されるように点 $P$ が y軸より右側にあるとき、外積 $\overrightarrow{AP} \times \overrightarrow{AB}$ の方向はここでも同様に左手の親指を $\overrightarrow{AP}$ に、人差し指を $\overrightarrow{AB}$ に合わせたときの中指の指す方向であるから、この場合には z軸プラス方向となる。点 $P$ が y軸よりも左側にある場合には $\overrightarrow{AP} \times \overrightarrow{AB}$ の方向は z軸マイナス方向になる(図15)。

図14 外積 AP x AB は z軸プラス方向
図15 外積 AP x AB は z軸マイナス方向

このことを実際に外積を計算して確認してみよう。この例では $\overrightarrow{AB}$、$\overrightarrow{AP}$ はいずれもXY平面上のベクトルであり、いずれも z成分は $0$ である。したがって、$\overrightarrow{AP} = (a_x, a_y, 0)$、$\overrightarrow{AB} = (b_x, b_y, 0)$ とすれば、$\overrightarrow{AP} \times \overrightarrow{AB}$ は
\[\overrightarrow{AP} \times \overrightarrow{AB}\ =\ (a_y\!\cdot\!0 - 0\!\cdot\!b_y,\ 0\!\cdot\!b_x - a_x\!\cdot\!0,\ a_xb_y - a_yb_x)\ =\ (0,\ 0,\ a_xb_y - a_yb_x)\]
となり、その方向は z軸プラス方向、マイナス方向のいずれかである (点 $P$ の位置による)。
つまり、上記のようにXY平面がある直線によって分断されているとき、XY平面上の点 $P$ がその直線のどちら側にあるかを調べるには直線上のベクトル $\overrightarrow{AB}$ と $\overrightarrow{AP}$ との外積を計算し、その z成分を調べればよいのである。そして、(XY平面上の)三角形の内外判定ではこの z成分の計算 $a_xb_y - a_yb_x$ を特別に Edge Function と呼ぶ。

XY平面上において、ある点が三角形に含まれるかどうかは、この Edge Function を用いて以下のように行われる。
点 $P$ が三角形 $ABC$ に含まれていたとしよう (図16)。このとき、図17のようにベクトル $\overrightarrow{AP}$ と $\overrightarrow{AB}$ の外積 $\overrightarrow{AP} \times \overrightarrow{AB}$ を考えれば、左手の親指を $\overrightarrow{AP}$ に、人差し指を $\overrightarrow{AB}$ に合わせると中指は z軸プラス方向を指す。すなわち、$\overrightarrow{AP} \times \overrightarrow{AB}$ は z軸プラス方向を指す。同様に、残りの2つの辺との外積 $\overrightarrow{BP} \times \overrightarrow{BC}$、$\overrightarrow{CP} \times \overrightarrow{CA}$ の場合も左手の中指は z軸プラス方向を指す。
つまり、点 $P$ が三角形 $ABC$ に含まれる場合には、三角形の各辺との外積 $\overrightarrow{AP} \times \overrightarrow{AB}$、$\overrightarrow{BP} \times \overrightarrow{BC}$、$\overrightarrow{CP} \times \overrightarrow{CA}$ はいずれも z軸プラス方向を指すのである。これは言い換えれば、点 $P$ が三角形 $ABC$ に含まれる場合にはこれらの Edge Function がいずれもプラスの値になるということである。

  • 図16 XY平面上の三角形ABCと点P
  • 図17 左手の親指をAPに、人差し指をABに合わせたとき、中指は z軸プラス方向を指す
  • 図18 左手の親指をBPに、人差し指をBCに合わせたとき、中指は z軸マイナス方向を指す

逆に、点 $P$ が三角形の外側にある場合には少なくとも1つの辺との Edge Function がマイナスになる。例えば、図18の場合 $\overrightarrow{BP} \times \overrightarrow{BC}$ がマイナスになる。
したがって、ある点が三角形に含まれるかどうかを調べるには3つの辺との Edge Function の正負を調べればよいのである (Edge Function が $0$ である場合には三角形のいずれかの辺上に点があることを意味する)。

以下のメソッド CollisionTest_Point_Triangle(..) はXY平面上において、点 $P$ が三角形 $ABC$ に含まれるかを調べるものであり、上で述べてきたことを実装したものである (引数には各点の座標をセットする)。
bool CollisionTest_Point_Triangle(Vector2 P, Vector2 A, Vector2 B, Vector2 C)
{
    // AP x AB
    Vector2 a = (P - A);
    Vector2 b = (B - A);
    if (a.x * b.y - a.y * b.x < 0.0f) { return false; }

    // BP x BC
    a = (P - B);
    b = (C - B);
    if (a.x * b.y - a.y * b.x < 0.0f) { return false; }

    // CP x CA
    a = (P - C);
    b = (A - C);
    if (a.x * b.y - a.y * b.x < 0.0f) { return false; }

    return true;
}

3つの辺との Edge Function が行われるが、3つともプラスである場合のみ点 $P$ が三角形 $ABC$ に含まれると判定される。1つでもマイナスである場合には三角形に含まれていないと判定され、その場で false が返される。





では、本節に関連したプログラムを作成する。

# Code1
Unityで外積を求める場合には次のメソッドが用意されている。

Vecotr3.Cross(Vector3 v1, Vector3 v2)
  :  引数に指定される2つのベクトルの外積 $\boldsymbol{\mathsf{v_1}}\times\boldsymbol{\mathsf{v_2}}$ を計算する Vector3構造体のstaticメソッドで、戻り値は Vector3型 (引数の2つのベクトルの双方と直交するベクトルが返される ; 引数の順序に注意)。

[Code1]  (実行結果 図11)
Vector3 a = new Vector3(0, 0, 2);
Vector3 b = new Vector3(3, 0, 1);
Vector3 c = Vector3.Cross(a, b);  // a x b
Debug.Log(c);

c = Vector3.Cross(b, a);          // b x a
Debug.Log(c);

図19 Code1 実行結果
このプログラムは本節の始めに示した外積の計算例である。1行目、2行目の ab は2つのベクトルを表し、この2つのベクトルの外積を求めている。最初の計算が $\boldsymbol{a} \times \boldsymbol{b}$ であり、次の計算が $\boldsymbol{b} \times \boldsymbol{a}$ である。
実行結果(図19)に示されるように、外積の順序を入れ替えると算出されるベクトルの向きが逆になる。


# Code2
次に、図20に示される$\triangle ABC$の法線ベクトルを求めてみよう。
各点の座標は $A = (3.92,\ 4.35, -4.31)$、$B = (0.52,\ 4.0, -7.95)$、$C = (0,\ 4, -5)$ である。

図20 △ABC
図21 ベクトルa、bと法線ベクトルn

[Code2]  (実行結果 22)
Vector3 A = new Vector3(3.92f, 4.35f, -4.31f);
Vector3 B = new Vector3(0.52f, 4.0f, -7.95f);
Vector3 C = new Vector3(0.0f, 4.0f, -5.0f);

Vector3 a = A - C;
Vector3 b = B - C;
Vector3 n = Vector3.Cross(a, b).normalized;

Debug.Log("(" + n.x + ", " + n.y + ", " + n.z + ")");

図22 Code2 実行結果
1行目から3行目の ABC は$\triangle ABC$の各点を表している。5行目の a は始点を$C$、終点を$A$とするベクトルであり、6行目の b は始点を$C$、終点を$B$とするベクトルである (図21)。7行目において、この2つのベクトルの外積を計算している。図21の $\boldsymbol{a}$ を左手の親指とし、$\boldsymbol{b}$ を左手の人差し指としたときの中指の向いている方向が外積$\boldsymbol{a} \times \boldsymbol{b}$の向きであり、図中では $\boldsymbol{n}$ で表されているベクトルである。
実行結果(図22)は、外積nの正規化された値である (ほぼy軸に平行である)。





(参考資料)
https://www.scratchapixel.com/lessons/3d-basic-rendering/rasterization-practical-implementation/rasterization-stage.html

















© 2020-2024 Redpoll's 60 (All rights reserved)