サイトトップ

Director Flash 書籍 業務内容 プロフィール

ActionScript 3.0 for 3D

□Math02 ベクトル

ベクトルは座標を扱ったり、位置関係や方向を調べるために用いられます。ActionScriptで使ううえでは、基本的な計算のやり方とその意味がわかればよいでしょう。

[*筆者用参考] 物理のかぎしっぽ「ベクトル解析」。


Math02-01 ベクトルとは
ベクトル」は、大きさと向きをもった量です。これに対して、大きさだけの量は「スカラー」といいます。大きさというと、絶対値つまり正の値を想像してしまうかもしれません。しかし、スカラーは正負の値をもちます。つまり、ひとつの実数で表される量がスカラーです。たとえば、重さ(質量)とか温度などがスカラーにあたります。

ベクトルは、とくに物理で扱われる位置や速度・加速度、力などを表します。たとえば、スカラーである重さについては、1kgのみかんひと箱にもうひと箱加えると2kg(= 1 + 1)です。けれども、ベクトルとなる位置では、東に1km、北に1km進むと、北東√2km(= √(1 + 1))の位置になります。位置は、大きさ(距離)だけでなく、方向も併せ考えなければならないということです。

ベクトルを座標空間で幾何学的に扱うときには、始点と終点をもつ(有向)線分として矢印で表すことが多いです。

Word Math02-001■ベクトルとスカラー
「ベクトル」(vector)とは、大きさと向きをもつ量です。「スカラー」は、大きさだけの量です。

表Math02-001■ベクトルとスカラーの比較
性質
ベクトル 大きさと向きをもつ。座標空間において始点と終点をもった値として表される。
スカラー 大きさしかない。実数で示せる。

Maniac! Math02-001■抽象化されたベクトル
数学は理論を抽象化することによって、その適用範囲を拡げます。ベクトルについても、「方向」にこだわる必要はありません。複数のスカラーの組で表され、以降に説明する演算法則にしたがうものがベクトルだと定義されます。

「方向」という意味づけをなくせば、3次元を超えるベクトルも考えることができます。また、次章で説明する「行列」は、ベクトルのベクトルと捉えられます。

[*筆者用参考] Wikipedia「幾何ベクトル」、「ベクトル空間」。

ベクトルは大きさと向きをもちます。しかし、どこを始点とするかは問いません。つまり、始点が違っても、向きが等しく平行で、長さの等しいベクトルは、互いに等しいということです(図Math02-001左図)。もっとも、始点を原点に揃えると、ベクトルは終点の座標のみで表すことができて便利です。このように原点を始点とするベクトルは「位置ベクトル」と呼ばれます(図Math02-001右図)。位置ベクトルを示す終点の各座標値は、ベクトルの「成分」または「要素」といいます。

図Math02-001■等しいベクトルと位置ベクトル
ベクトルAとベクトルBは、互いに大きさと向きが同じなので等しい。始点の位置は問わない(左図)。位置ベクトルPは、原点Oを始点とする(右図)。

2次元平面の位置ベクトルPは、そのxy座標によってつぎのように表されます。

P = (x, y)

3次元空間の位置ベクトルには、これにz座標が加わります。

P = (x, y, z)

Word Math02-002■右手座標系
3次元空間は、2次元平面のxy軸に奥行きのz軸が加わったものです。そのとき、z軸の正の方向を決めなければなりません。Flashでは奥を正方向に定めました。これを右手座標系(右手系)といいます。

手の親指と人差し指それに中指をそれぞれxyz軸と見立てて、指を互いに直角になるように伸ばします。その指先を正の方向と考えたとき、Flashの座標空間はxyz軸が右手と同じ関係にあるからです。

逆にz軸が手前に正方向でしたら、左手座標系(左手系)になります。ただし、Flash(および一般にコンピュータディスプレイ)では、y軸が下に向かって正であることにご注意ください。数学では、普通y軸は上が正方向です。その場合、右手座標系のz軸は手前が正になります。

[*筆者用参考] Wikipedia「右手系」。


Maniac! Math02-002■[ヘルプ]の座標系の説明
[ヘルプ]の[ActionScript 3.0言語およびコンポーネントリファレンス]で[Vector3D]に、z軸についてのつぎのような説明があります。

右の3次元座標系のように、正のz軸は閲覧者から離れる方向を指し、オブジェクトが閲覧者の目から離れるにつれてzプロパティの値が増加します。

しかし、「右の3次元座標系」というのは意味がわかりません。原文は"right-handed three-dimensional coordinate system"ですので、つぎのように「3次元右手座標系」と訳すべきでしょう。

3次元右手座標系ですので、z軸の正は視線の方向で、z座標のプロパティ値はオブジェクトが視点から遠ざかるほど大きくなります。

Math02-02 ベクトルの絶対値
ベクトルの基本的な計算についてご説明する前に、ベクトルの絶対値を定義しておきます。ベクトルの扱いは、座標空間における矢印として考える幾何学的な見方と、位置ベクトルの成分を代数的に計算するふたつの捉え方があります。そのふたつの面をともに知ることが、ベクトルをより深く理解することになるでしょう。

ベクトルPの絶対値|P|は、幾何学的にはその長さ、つまりベクトルの始点と終点との距離です。2点間の距離は、代数では三平方の定理で求めます。したがって、2次元平面における位置ベクトルP(x, y)の絶対値は、つぎの式で定められます。

  _____
|P| = √ x2 + y2

3次元空間のベクトルP(x, y, z)でも、考え方は同じです。まずxy平面に映したxy座標のみの長さ(√x2 + y2)を求め、つぎにz座標が加わった距離を計算します(図Math02-002)。その式は2次元と同じく、各成分を2乗した和の平方根です。

  _____
|P|2 = (√ x2 + y2)2 + z2 = x2 + y2 + z2
  __________
|P| = √ x2 + y2 + z2
図Math02-002■3次元位置ベクトルの絶対値

3次元のベクトルでも、その絶対値は三平方の定理より、xyz各成分の2乗の和の平方根になる。

[*筆者用参考] 物理のかぎしっぽ「もう一度ベクトル1」「右手座標系と位置ベクトル」、「ベクトル其の弐」。


シンタックスMath02-001■2次元と3次元ベクトルの絶対値
ベクトルの絶対値

2次元平面のベクトルP(x, y)の絶対値|P|は、三平方の定理よりつぎのとおり。

  _____
|P| = √ x2 + y2

3次元空間のベクトルP(x, y, z)の絶対値|P|も、三平方の定理で求まる(前掲図Math02-002参照)。

  __________
|P| = √ x2 + y2 + z2

なお、n次元のベクトルの絶対値については、Maniac! Math02-003「n次元ベクトルの絶対値」参照。


Tips Math02-001■ActionScriptのクラスにおけるベクトルの絶対値
ActionScriptにおけるベクトルは、2次元平面をPointクラス、3次元空間はVector3Dクラスが扱います。ベクトルの絶対値つまり長さを表すプロパティは、ともに同じ名前のPoint.length(シンタックス01-004)およびVector3D.length(シンタックス06-005)です。


Maniac! Math02-003■n次元ベクトルの絶対値
任意の次元つまりn次元ベクトルについても、その絶対値はN個の各成分を2乗した和の平方根で定義されます。


Math02-03 ベクトルの和と差
次元の等しいベクトルは、互いに足したり引いたりすることができます。図Math02-003のベクトルAとBについて、足し算と引き算を考えましょう。

図Math02-003■ふたつのベクトルAとB
ベクトルAとBについて、足し算と引き算を考える。

ベクトルの和
ベクトルの足し算A + Bは、足されるベクトルAの終点に足すベクトルBの始点をつなげ、Aの始点とBの終点を結びます(図Math02-004左図)。あるいは、互いの終点を結ぶふたつのベクトルAとBについて、それらが2辺となる平行四辺形を描いて、その対角までのベクトルと捉えることもできます(図Math02-004右図)。すると、ベクトルの足し算は足す順序を問わない、つまり交換法則が成立つこともわかります。

図Math02-004■ベクトルの足し算
 
足されるベクトルAの終点に足すベクトルBの始点をつなげ、Aの始点とBの終点を結ぶ(左図)。あるいは、終点が結ばれたふたつのベクトルAとBを2辺とする平行四辺形の対角までのベクトル(右図)。

ベクトルの成分を使って計算するときは、各成分同士を足します。ベクトルAを(ax, ay)、ベクトルBを(bx, by)とすると、A + Bはつぎのとおりです。

A + B = (ax + bx, ay + by)

ベクトルの差
ベクトルの引き算は、足し算に直して考えます。A - B = Cとすると、C + B = Aです。つまり、Bと足してAになるベクトルCを求めればよいということになります。それは、Bの終点からAの終点を結ぶベクトルになります(図Math02-005左図)。

あるいは、次節でベクトルに-1を掛けると、方向が逆転することを習います。A - B = A + (-B)ですので、引くベクトルBの方向を逆にした-BとAとを足し算しても、同じベクトルが導かれます(図Math02-005右図)。

図Math02-005■ベクトルの引き算
 
Bと足してAになるベクトルCを求める(左図)。あるいは、引くベクトルBの方向を逆にしたベクトル-BとAを足し算(右図)。

ベクトルの成分を使った引き算は、引かれるベクトルの各成分から引くベクトルの各成分を、それぞれ引き算します。ベクトルAを(ax, ay)、ベクトルBを(bx, by)とすれば、A - Bはつぎのとおりです。

A - B = (ax - bx, ay - by)

成分の計算によるベクトルの和と差
ベクトルの成分による足し算と引き算を、シンタックスMath02-003にまとめます。

シンタックスMath02-002■成分の計算によるベクトルの足し算と引き算
ベクトルの足し算と引き算

ふたつのベクトルA(ax, ay)とB(bx, by)があるとき、その和A + Bと差A - Bはそれぞれつぎのように求められる。

A + B = (ax + bx, ay + by)
A - B = (ax - bx, ay - by)

3次元空間のベクトルA(ax, ay, az)とB(bx, by, bz)についても、同じように計算される。

A + B = (ax + bx, ay + by, az + bz)
A - B = (ax - bx, ay - by, az - bz)

なお、幾何学的な捉え方については、前掲図Math02-004および図Math02-005を参照。

[*筆者用参考] 物理のかぎしっぽ「もう一度ベクトル2(ベクトルの読み書きそろばん)」。


Math02-04 ベクトルのスカラー倍と単位ベクトル
ベクトルには、次章で解説する行列とは異なり、掛け算は定義されていません(その逆演算である割り算も当然ありません)。しかし、実数つまりスカラーを乗じることはできます。また、絶対値が1の「単位ベクトル」が定義されます。


ベクトルのスカラー倍
スカラーaとベクトルPとの積は、つぎのように表します。

aP

ベクトルにスカラーを乗じる場合、ベクトルの向きは変えずに、絶対値つまり長さをスカラー倍します(図Math02-006)。ただし、負の数を掛けたときは、向きを逆すなわち始点と終点を入替えます。

図Math02-006■ベクトルにスカラーを乗じる

ベクトルの向きは変えずに、長さをスカラー倍する。

成分による計算は、スカラーをベクトルの各成分値に乗じます。つまり、ベクトルP(x, y)にスカラーaを掛けると、つぎのようになります。

aP = (ax, ay)

単位ベクトル
絶対値つまり長さが1のベクトルを、「単位ベクトル」と呼びます。Pの単位ベクトルEを求めるには、ベクトルPをその絶対値|P|で割ります。絶対値|P|による割り算は、逆数1/|P|でスカラー倍するのと同じです。ただし、ベクトルの絶対値は0ではないもの(|P|≠0)とします。なお、単位ベクトルを求める計算は、ベクトルの「正規化」と呼ばれます(Word Math02-003「単位ベクトル・基本ベクトルと正規化」参照)。

E = P/|P|

x軸とy軸に平行な単位ベクトル、(1, 0)と(0, 1)をそれぞれi、jで表すと、任意の成分(x, y)をもつベクトルPは以下の式で示されます。このiとjを「基本ベクトル」といいます。

P = (x, y) = x(1, 0) + y(0, 1) = xi + yj

つまり、平面上の任意の位置ベクトルは、スカラー倍した基本ベクトルの和で表せます。

[*筆者用参考]「基本ベクトル」、Wikipedia「空間ベクトル」。

Word Math02-003■単位ベクトル・基本ベクトルと正規化
絶対値が1のベクトルを「単位ベクトル」といいます。また、あるベクトルと向きが等しい単位ベクトルを求めることは「正規化」(normalize)と呼ばれます。

なお、直交座標の各軸の正に向いた単位ベクトルを、「基本ベクトル」といいます。


Tips Math02-002■ActionScriptのベクトルを正規化するメソッド
Vector3Dクラスには、ベクトルの正規化のメソッドとしてVector3D.normalize()があります。このメソッドは、参照するVector3Dインスタンスの方向は変えずに単位ベクトルにします(シンタックス06-005)。

Pointクラスにも、同じ名前のPoint.normalize()メソッドがあります。しかし、このメソッドは、ベクトルの長さを引数で渡された値に変えます(シンタックス01-005)。したがって、単位ベクトルにしたいときには、引数に1を指定しなければなりません。


ベクトルの長さを変える計算
ベクトルのスカラー倍と単位ベクトルを求める正規化は、ともにベクトルの絶対値つまり長さを変える計算です。また、その計算には、実数の場合と似た法則が成立ちます。これらを、シンタックスMath02-003としてまとめます。

シンタックスMath02-003■ベクトルの長さを変える計算と法則
ベクトルのスカラー倍

ベクトルP(x, y)にスカラーaを掛ける計算はつぎのとおり。

aP = (ax, ay)

3次元空間のベクトルP(x, y, z)についても、同じように求められる。

aP = (ax, ay, az)
単位ベクトル

ベクトルPと向きの同じ単位ベクトルEは、つぎのように定められる。

E = P/|P|

2次元平面のベクトルP(x, y)と向きの同じ単位ベクトルEは、つぎのように導ける。

E = P/√x2 + y2
= (x/√x2 + y2, y/√x2 + y2)
  _____
[*編集者用注釈] √x2 + y2は、√ x2 + y2を示します。

3次元空間のベクトルP(x, y, z)と向きの同じ単位ベクトルEも、同じように計算される。

E = = P/√x2 + y2 + z2
= (x/√x2 + y2 + z2, y/√x2 + y2 + z2, z/√x2 + y2 + z2)
  _________
[*編集者用注釈] √x2 + y2 + z2は、√ x2 + y2 + z2を示します。
基本ベクトル

2次元平面のx軸とy軸に平行な基本ベクトルをそれぞれi(1, 0)とj(0, 1)とすると、任意のベクトルP(x, y)はスカラー倍した基本ベクトルの和で表せる。

P = (x, y) = x(1, 0) + y(0, 1) = xi + yj

3次元空間については、xyzの各軸に平行な基本ベクトルをそれぞれi(1, 0, 0)とj(0, 1, 0)およびk(0, 0, 1)として、任意のベクトルP(x, y, z)が同じように示せる

P = xi + yj + zk
ベクトルとスカラーの計算法則

任意のベクトルをAとB、同じく任意のスカラーをaならびにbとすると、つぎの計算法則が成立つ。

(a + b)A = aA + bA
(ab)A = a(bA)
A + B = B + A
a(A + B) = aA + aB

Math02-05 ベクトルの内積
前述のとおり、ベクトル同士の乗算は定義されていません。しかし、掛け算に似た計算に「内積」があります。


内積の幾何学的な定義とその役割
ベクトルAとBの内積はA・Bで表され、AとBとのなす角をθとすると、以下の式で定義されます(図Math02-007)。ベクトルでは演算記号「・」は内積を示し、掛け算を意味しません。また、内積の値は実数つまりスカラーであって、ベクトルではないことにご注意ください。

A・B = |A||B|cosθ
図Math02-007■ベクトルAとBの内積を表す

|A|cosθは、ベクトルAをBに射影した長さ。

ベクトルAとBの始点を結んだとき、ベクトルAの終点からBに下ろした垂線との交点までの長さをAの射影といい、|A|cosθになります。この長さとベクトルBの長さ|B|の積が内積A・Bです。なお、ふたつのベクトルのなす角θは、小さい方の角度つまり0以上π(180度)以下の範囲で定められます。また、ベクトルAとBのどちらかひとつでも絶対値が0(すべての成分が0)のとき、角度θは決められませんが、内積A・B = 0とします。

ふたつのベクトルAとBの絶対値がいずれも0でなければ、それらの絶対値の積|A||B|はつねに正になります。

|A||B| > 0   (|A|≠0、|B|≠0のとき)

したがって、内積A・Bの値の正負は、cosθによって決まります。cosθは角θが0からπ(180度)までの範囲で、鋭角のとき正、直角であれば0、そして鈍角では負の値になります(表06-003)。つまり、内積からふたつのベクトルの互いの向きがわかります。

表06-003■ベクトルの内積となす角(再掲)
内積の値 なす角(θ) cosθ
90度より小さい(鋭角)
0 90度(直角) 0
90度より大きい(鈍角)

たとえば、ひとつのベクトルを視線、もうひとつは面の向きとすると、ふたつの内積が負なら互いに向合って(鈍角)いるので、面は表が見えているということです(図06-014左図)。逆に内積が正であれば、視線と面は同じ向き(鋭角)で、面は裏返っています(図06-014右図)。内積が0のときは、互いに垂直ですので、面は真横を向いています。

図06-014■視線と面のふたつの方向のベクトルから面の裏表を決める(再掲)
面と視線のベクトルのふたつが向合って(鈍角)いれば表、同じ方向(鋭角)であれば裏。

[イラスト] 内積でベクトル同士の向きがわかる。

内積の代数的な定義とその導出
ベクトルAとBの各成分がそれぞれ(ax, ay)と(bx, by)である場合、ふたつのベクトルの内積A・BはシンタックスMath02-004のように求められます。なお、シンタックスMath02-004には、ふたつのベクトルが直交する条件とおもな性質も併せて掲げました。

シンタックスMath02-004■ベクトルの内積とその性質
ベクトルの内積

ベクトルAとBのなす角をθとするとき、ふたつのベクトルの内積A・Bはつぎのように定められる。

A・B = |A||B|cosθ

ベクトルAとBの各成分がそれぞれ(ax, ay)および(bx, by)である場合、内積A・Bはつぎの式で導かれる。

A・B = axbx + ayby

3次元空間のベクトルA(ax, ay, az)と(bx, by, bz)についても、同じように各成分ごとに掛合わせて和をとる。

A・B = axbx + ayby + azbz
ベクトルの直交条件

ベクトルAとBが直交するとき、ふたつのベクトルのなす角θはπ/2(90度)で、cosθ = 0となる。したがって、ふたつのベクトルAとBが直交する場合の内積A・Bは0である。

A・B = |A||B|cosθ = 0   (cosθ = 0より)
内積の性質

内積はその定義より、交換法則が成立つ。また、同じベクトルの内積は、なす角が0なので絶対値の2乗に等しい。

A・B = B・A
A・A = |A||A|cosθ = |A|2   (cosθ = 1より)

シンタックスMath02-004に示したベクトルの成分による内積の計算式は、三角関数の余弦定理を用いて導きます。まず、下図Math02-008のベクトルAとBの内積は、そのなす角をθとしてつぎのように定められました。

A・B = |A||B|cosθ
図Math02-008■内積と余弦定理

内積
A・B = |A||B|cosθ

余弦定理
c2 = a2 + b2 - 2ab cosθ

|A| = a、|B| = b、|A - B| = cとする。

つぎに、|A| = a、|B| = b、|A - B| = cとすると、余弦定理はつぎの等式で表されました(シンタックスMath01-010)。

c2 = a2 + b2 - 2ab cosθ

この式を上記のベクトルAとBで表したうえで、cosθを求めます。

|A - B|2 = |A|2 + |B|2 - 2|A||B|cosθ
2|A||B|cosθ = |A|2 + |B|2 - |A - B|2
cosθ = (|A|2 + |B|2 - |A - B|2)/2|A||B|

このcosθを、前記の内積A・Bの式に代入します。

A・B = |A||B|cosθ
= |A||B|(|A|2 + |B|2 - |A - B|2)/2|A||B|
= (|A|2 + |B|2 - |A - B|2)/2

ここで、ベクトルAとBの成分をそれぞれ(ax, ay)および(bx, by)とすると、A - B = (ax - bx, ay - by)です。また、シンタックスMath02-001の絶対値の定義から、任意のベクトルP(x, y)について|P|2 = x2 + y2です。したがって、上記の内積A・Bの式は、ベクトルの成分を使ってつぎのように書替えられます。

A・B = ((ax2 + ay2) + (bx2 + by2) - ((ax - bx)2 + (ay - by)2)/2
= ((ax2 + ay2 + bx2 + by2) - ((ax2 - 2axbx + bx2) + (ay2 - 2ayby + by2))/2
= (2axbx + 2ayby)/2
= axbx + ayby

Tips Math02-003■ふたつのベクトルのなす角
ベクトルAとBの内積A・Bから、ふたつのベクトルのなす角を求めることができます。

A・B = |A||B|cosθ
cosθ = (A・B)/(|A||B|)

ベクトルAとBの成分をそれぞれ(ax, ay)および(bx, by)とすると、右辺の値は簡単に計算できます。そこで、逆三角関数cos-1を使えば、角度θが導けます。

θ = cos-1((A・B)/(|A||B|))

もっとも、Vector3Dクラスには、静的メソッドVector3D.angleBetween()が備わっています。引数にふたつのVector3Dインスタンスを渡すと、それらのベクトルのなす角がラジアン値で返されます。


Maniac! Math02-004■n次元ベクトルの内積
任意の次元つまりn次元ベクトルについても、その絶対値はN個の各成分を乗じた和で定義されます。つまり、ベクトルA(a1, a2, …, an)とB(b1, b2, …, bn)との内積A・Bは、つぎの式で導かれます。

A・B = a1b1 + a2b2 + … + anbn

[*筆者用参考]「内積空間」(PDF)、Wikipedia「内積」。


内積の性質
シンタックスMath02-004には、ベクトルの内積のおもな性質を掲げています。まず、前述のとおり、内積の正負はcosθの値で決まります。とくに、ふたつのベクトルAとBのなす角θがπ/2(90度)つまり互いに直交するとき内積A・Bは0です。

つぎに、内積の定義A・B = |A||B|cosθから明らかなように、ベクトルAとBの計算の順序を入替えても、その値は変わりません。つまり、内積は交換法則が成立ちます。

A・B = B・A

さらに、同じベクトルA同士の内積A・Aは、なす角が0です。したがって、cos0が1となり、内積A・Aは絶対値の2乗|A|2に等しくなります。

A・A = |A|2

[*筆者用参考] 物理のかぎしっぽ「もう一度ベクトル2(ベクトルの読み書きそろばん)」、「ベクトルの内積」、Wikipedia「ドット積」、「内積空間」、「内積」、ジュケンブログ数学「内積を理解する」。


Math02-06 ベクトルの外積
ベクトル同士の掛け算に似た計算には、もうひとつ「外積」があります。「外積」は、ふたつのベクトルのどちらにも垂直なベクトルを求める演算です。ふたつのベクトルによりひとつの面が定まります。つまり、「外積」を用いると面の向きが決められるのです。


ベクトルの外積の定義と性質
3次元空間のベクトルAとBの外積はA×Bで表され、AとBとのなす角をθとすると、シンタックスMath02-005のように定義されます。ベクトルでは演算記号「×」は外積を示し、掛け算を意味しません。また、内積がスカラーであったのに対して、外積はベクトルであることにご注意ください。

シンタックスMath02-005■ベクトルの外積とその性質
ベクトルの外積

3次元空間のベクトルAとBのなす角をθとするとき、ふたつのベクトルの外積はA×Bで表され、ふたつのベクトルにともに垂直で、ベクトルAからBへの回転の右ネジの進む向きのベクトルになる。そして、その絶対値(大きさ)|A×B|はつぎの式で定められる(表06-002)。

|A×B| = |A||B|sinθ
表06-002■外積で求められるベクトル(再掲)
外積の要素 求められた外積のベクトルとふたつのベクトルの関係
角度 ふたつのベクトルAとBを含む平面に垂直。
方向 ベクトルAからBに向かう回転を考えたとき、右手座標系(Word Math02-002)ではその回し方で右ネジの進む方向。
大きさ ベクトルAからBを平行四辺形の隣り合う2辺としたとき、ベクトルの外積の大きさ(絶対値)|A×B|はこの平行四辺形の面積|A||B|sinθと等しい。

3次元空間のベクトルAとBの各成分がそれぞれ(ax, ay, az)および(bx, by, bz)である場合、外積A×Bはつぎの式で導かれる。

A×B = (aybz - azby, azbx - axbz, axby - aybx)
ベクトルの平行条件

ベクトルAとBが平行のとき、ふたつのベクトルのなす角は0またはπ(180度)で、いずれもsinθ = 0となる。したがって、ふたつのベクトルAとBが平行の場合の外積A×Bは、すべての成分が0のべクトル0(0, 0, 0)である。

A×B = |A||B|sinθ = 0   (sinθ = 0より)
外積の性質

外積はその定義より、計算の順所を逆にすると方向が逆になる。つまり、交換法則は成立たない。また、同じベクトルの外積は、なす角が0なので、絶対値が0つまりすべての成分が0のべクトルになる。

A×B = -B×A
A×A = |A||A|sinθ = 0   (sinθ = 0より)

なお、ベクトル0はすべての成分が0のベクトルを表す。

ふたつのベクトルAとBの外積A×Bは、第1にふたつのベクトルに互いに垂直なベクトルを導きます。したがって、当然3次元空間が前提となります(なお、Maniac! Math02-005「外積とドット積」参照)。

もっとも、ある面に垂直なベクトルといっても、表と裏のふたつの向きがありえます。そこで第2に、外積A×Bのベクトルの向きは、ふたつのベクトルAとBの互いの位置によって決めます。互いの始点を結んだベクトルAからBへの回転を考えたとき、同じように回した右ネジの進む先が外積A×Bのベクトルの方向です。

第3に、外積A×Bのベクトルの大きさつまり絶対値|A×B|を定めます。ふたつのベクトルAとBのなす角をθとすると、絶対値|A×B|はつぎの式のとおりです。

|A×B| = |A||B|sinθ

この絶対値|A×B|の大きさは、ふたつのベクトルAとBを2辺とする平行四辺形の面積に等しくなります。|A|を平行四辺形の底辺とすると、|B|sinθはその高さになるからです。

なお、ベクトルAとBの成分による外積A×Bの計算は、前掲シンタックスMath02-005に示した式のとおりです。

[イラスト] ベクトルAとB内積は|A||B|cosθで、外積の大きさが|A||B|sinθ。内積はスカラーで、外積はベクトルであることに注意。

Maniac! Math02-005■外積とクロス積
本来の「外積」(exterior product)は、数学の「テンソル」という分野で定義され、その次元はとくに限定されません。たとえば、2次元の外積は、つぎのようにスカラーになります。

A×B = |A||B|sinθ   (ただし、AとBは2次元のベクトル)

3次元にかぎる場合には、用いられる演算記号「×」に由来する「クロス積」(cross product)と呼ぶ方が精確なようです(なお、Maniac! 06-004「外積と内積の別名」参照)。けれども、日本では3次元のクロス積の議論も「外積」と表記されることが多いので、本書もこの語法にしたがいます。より進んだ学習をする際や、英語の文献を参照するときには注意が必要です。


外積の性質
まず前述のとおり、ベクトルAとBの内積A・Bは、|A||B|cosθで定義されるので、ふたつのベクトルが直交するとき(cos(π/2) = 0なので)0になりました。外積の絶対値|A×B|は、|A||B|sinθと定められましたので、ふたつのベクトルが平行つまり角θが0またはπ(180度)のときに(sinθ = 0なので)0となり、すべての成分が0のべクトル0(0, 0, 0)になります。ただし、ふたつのベクトルの向きは、角θが0のときは同じで、π(180度)では互いに逆向きです。

つぎに、ベクトルAとBの外積A×Bは、その向きがAからBへの回転の右ネジの方向に決められました。したがって、ベクトルAとBとの計算の順序を逆にすると、絶対値は変わらず、向きが反対になります。つまり、外積に交換法則は成立ちません。

A×B = -B×A

そして、同じベクトルA同士の外積A×Aは、なす角が0つまり平行ですので、つねに0ベクトルになります。

A×A = 0

[*筆者用参考] 物理のかぎしっぽ「もう一度ベクトル2(ベクトルの読み書きそろばん)」、Wikipedia「クロス積」、「外積」、「外積の成分表示」、「外積」、「2次元ベクトルの外積の効用」、「内積と外積の使い方」、「外積の使い方」、「外積について」、「内積と外積」、「外積か。。」、「幾何学・CG のアルゴリズム集」、高校の数学「ベクトル」。


Math02-07 ベクトルの内積や外積の使い途
3次元空間の扱いでベクトルの内積や外積を用いるのは、何といっても面の表裏を調べる場合でしょう。まず、面の向きは、面の頂点を結ぶふたつのベクトルから外積により定めます。もちろん、ふたつのベクトルが右ネジの位置になるように、頂点を選ばなければなりません。そして、つぎに視線のベクトルを決めて、面の向きのベクトルとの内積を求めれば、Math02-06「ベクトルの外積」に述べたとおり、その値の正負により面の視線に対する裏表がわかるのです。

面の頂点と視線のベクトルから面の視線に対する裏表を調べるスクリプトは、06「3次元空間の座標を扱う − Vector3Dクラス」の06-03「面が表向きか裏向きかを調べる − ベクトルの外積と内積」ですでにご紹介しました(再掲スクリプト06-004)。そこに定めた関数xIsFront()は、面が視線に対して表向きかどうかをブール(論理)値で返します。第1引数は面の頂点座標をVector3Dインスタンスで納めたVectorオブジェクト、第2引数は視線を示すVector3Dインスタンスです。なお、面の頂点の順序は時計回りに決めています(再掲図06-013)。スクリプトの詳しい説明については、06章をお読みください。

図06-013■平面の頂点番号を時計回りに定める(再掲)
頂点0から2のベクトルと頂点0から1のベクトルとの外積を求めることにより、平面の向きとなる垂直ベクトルが決まる。

スクリプト06-004■平面の頂点座標から視線に対する裏表の向きを返す関数(再掲)
    // フレームアクション
  1. function xIsFront(myVertices:Vector.<Vector3D>, myView:Vector3D):Boolean {
  2.   var vector3D_0:Vector3D = myVertices[0];
  3.   var vector3D_1:Vector3D = myVertices[1];
  4.   var vector3D_2:Vector3D = myVertices[2];
  5.   var vector3D_0_1:Vector3D = vector3D_1.subtract(vector3D_0);
  6.   var vector3D_0_2:Vector3D = vector3D_2.subtract(vector3D_0);
  7.   var direction3D:Vector3D = vector3D_0_2.crossProduct(vector3D_0_1);
  8.   direction3D.normalize();
  9.   var bFront:Boolean = (direction3D.dotProduct(myView) < 0);
  10.   return bFront;
  11. }

ほかの使い方としては、ふたつのベクトルが直交するかあるいは互いに平行かを、内積もしくは外積が0かどうかで調べられました(シンタックスMath02-004およびMath02-005)。

【ベクトルAとBの直交条件】
A・B = 0

【ベクトルAとBの平行条件】
A×B = 0

また、三角形の2辺のベクトルAとBから、外積の絶対値|A×B|を求めれば、三角形の面積はその半分になります。外積の絶対値|A×B|は、ふたつのベクトルを2辺とする平行四辺形の面積に等しいからです(シンタックスMath02-005)。

ベクトルAとBを2辺とする三角形の面積 = |A×B|/2

最後にもうひとつ、外積を使うと、2次元平面で、ある座標が三角形の内側にあるかどうかを調べることができます(図Math02-009上図)。ふたつのベクトルAとBの外積A×Bを求めると、そのベクトルはAからBへ右ネジを回す向きに定められました。すると、逆に外積A×Bのベクトルの向きから、ベクトルAの右にBがあるかどうかわかるということです。

三角形の3辺のベクトルそれぞれについて、その始点と調べる座標を結んだベクトルとの外積により、座標が辺のベクトルの右側にあるかどうかを確かめます。時計回りに向けた3辺のベクトルいずれに対しても座標のベクトルが右側にあるなら、その座標は三角形の内側になります(図Math02-009下図)。2次元平面ですので、すべてのベクトルのz座標値を0としておけば、外積のベクトルのz座標値が正のとき、ふたつのベクトルは右ネジの位置にあります(Tips Math02-004「凸な多角形に対して座標が内側にあるかどうか調べる」参照)。

図Math02-009■外積で2次元平面上の座標が三角形の内側にあるかどうかを調べる


3辺のベクトルのいずれに対しても座標のベクトルが右ネジの位置にあれば、その座標は三角形の内側になる。

Tips Math02-004■凸な多角形に対して座標が内側にあるかどうか調べる
本文に述べた辺のベクトルと座標の位置により内側かどうかを調べる方法は、三角形にかぎらず、一般に凸な多角形に対して用いることができます。凸な多角形というのは、すべての頂点の角度がπ(180度)未満である多角形をいいます(図Math02-010)。もっとも、三角形は必ず凸な多角形です。したがって、その数がきわめて多いといった場合を除けば、三角形に分けて調べた方が扱いやすいでしょう。

図Math02-010■凸でない四角形
凸でない頂点があると、辺のベクトルと座標の位置で内側かどうかが決められない。

[*筆者用参考] 「点と直線との位置関係を調べる」、「多角形の交差判定編」。

試しに、Graphics.drawTriangles()メソッドで塗ったインスタンスをクリックしたときに、それがどの三角形(の内側)なのかを調べてみましょう。塗りに使う矩形のビットマップはふたつの対角線で分けて、4つの三角形を描くことにします(図Math02-011)。

図Math02-011■矩形を対角線で4つの三角形に分けてテクスチャマッピング
塗りの矩形のビットマップはふたつの対角線で分けて、4つの三角形を描く。

フレームアクションは、スクリプトMath02-001として後に掲げます。外積を使ってふたつのベクトルが右ネジの位置にあるかを調べるのが、関数xIsRight()です(スクリプト第65〜71行目)。引数には、2次元平面の位置ベクトルA(ax, ay)とB(bx, by)それぞれのxy座標を4つの数値で渡します。ベクトルAの右(もしくはその上)にBがあればtrue、そうでなければfalseを返します(なお、後掲Tips Math02-005「z座標が0のベクトルの外積」およびManiac! Math02-006「2次元べクトルの外積」参照)。

  1. function xIsRight(ax:Number, ay:Number, bx:Number, by:Number):Boolean {
  2.   var a:Vector3D = new Vector3D(ax, ay, 0);
  3.   var b:Vector3D = new Vector3D(bx, by, 0);
  4.   var crossProduct:Vector3D = a.crossProduct(b);
  5.   var bIsRight:Boolean = (crossProduct.z >= 0);
  6.   return bIsRight;
  7. }

スクリプト第66〜67行目は、前述のとおりz座標を0にしたふたつxy座標のVector3Dインスタンスを生成します。そして第68〜70行目で、まずふたつの位置ベクトルの外積を求め、その外積のベクトルのz座標値が0以上であるかどうかをブール値の変数に納めたうえで、その変数値を関数から返しています。

以下のスクリプトMath02-001の第1〜34行目は、矩形を対角線で分けた4つの三角形にテクスチャマッピングしています。Graphics.drawTriangles()メソッドを使った基本的な処理です(07「三角形分割によるテクスチャマッピング − Graphics.drawTriangles()メソッド」07-02「Graphics.drawTriangles()メソッド」参照)。

ビットマップを塗ったSprite(変数mySprite)には、スクリプト第17行目でInteractiveObject.clickイベント(定数MouseEvent.CLICK)にリスナー関数xSelectTriangle()を登録しています。この関数xSelectTriangle()が、クリックしたインスタンスの座標からその場所にある三角形を調べます(第35〜64行目)。

スクリプトMath02-001■クリックされた三角形を調べる
    // フレームアクション
    // [ライブラリ]のビットマップに[クラス]としてImageを設定
  1. var mySprite:Sprite = new Sprite();
  2. var mySprite2:Sprite = new Sprite();
  3. var myGraphics:Graphics = mySprite.graphics;
  4. var myGraphics2:Graphics = mySprite2.graphics;
  5. var myTexture:BitmapData = new Image(0, 0);
  6. var vertices:Vector.<Number> = new Vector.<Number>();
  7. var indices:Vector.<int> = new Vector.<int>();
  8. var uvtData:Vector.<Number> = new Vector.<Number>();
  9. var nX:Number = stage.stageWidth / 2;
  10. var nY:Number = stage.stageHeight / 2;
  11. addChild(mySprite);
  12. addChild(mySprite2);
  13. mySprite.x = nX;
  14. mySprite.y = nY;
  15. mySprite2.x = nX;
  16. mySprite2.y = nY;
  17. mySprite.addEventListener(MouseEvent.CLICK, xSelectTriangle);
  18. vertices.push(0, 0);
  19. vertices.push(-50, -50);
  20. vertices.push(50, -50);
  21. vertices.push(50, 50);
  22. vertices.push(-50, 50);
  23. indices.push(0, 1, 2);
  24. indices.push(0, 2, 3);
  25. indices.push(0, 3, 4);
  26. indices.push(0, 4, 1);
  27. uvtData.push(0.5, 0.5);
  28. uvtData.push(0, 0);
  29. uvtData.push(1, 0);
  30. uvtData.push(1, 1);
  31. uvtData.push(0, 1);
  32. myGraphics.beginBitmapFill(myTexture);
  33. myGraphics.drawTriangles(vertices, indices, uvtData);
  34. myGraphics.endFill();
  35. function xSelectTriangle(eventObject:MouseEvent):void {
  36.   var nMouseX:Number = eventObject.localX;
  37.   var nMouseY:Number = eventObject.localY;
  38.   var triangle:Vector.<Number> = new Vector.<Number>();
  39.   var nLength:uint = indices.length;
  40.   for (var i:uint = 0; i < nLength; i += 3) {
  41.     var nIndex:uint = indices[i + 2] * 2;
  42.     for (var j:uint = 0; j < 3; j++) {
  43.       var nBeginX:Number = vertices[nIndex];
  44.       var nBeginY:Number = vertices[nIndex + 1];
  45.       nIndex = indices[i + j] * 2;
  46.       var nEndX:Number = vertices[nIndex];
  47.       var nEndY:Number = vertices[nIndex + 1];
  48.       var bIsRight:Boolean = xIsRight(nEndX - nBeginX, nEndY - nBeginY, nMouseX - nBeginX, nMouseY - nBeginY);
  49.       if (!bIsRight) {
  50.         break;
  51.       }
  52.     }
  53.     if (j == 3) {
  54.       for (var n:uint = 0; n < 3; n++) {
  55.         nIndex=indices[i+n]*2;
  56.         triangle.push(vertices[nIndex], vertices[nIndex + 1]);
  57.       }
  58.       myGraphics2.clear();
  59.       myGraphics2.lineStyle(2, 0x0000FF);
  60.       myGraphics2.drawTriangles(triangle);
  61.       break;
  62.     }
  63.   }
  64. }
  65. function xIsRight(ax:Number, ay:Number, bx:Number, by:Number):Boolean {
  66.   var a:Vector3D = new Vector3D(ax, ay, 0);
  67.   var b:Vector3D = new Vector3D(bx, by, 0);
  68.   var crossProduct:Vector3D = a.crossProduct(b);
  69.   var bIsRight:Boolean = (crossProduct.z >= 0);
  70.   return bIsRight;
  71. }

スクリプト第36〜37行目は、MouseEventオブジェクトからインスタンスのクリック位置のxy座標を取出して、変数に納めます。第40行目から始まるforループは、まず頂点番号のVectorオブジェクト(変数indices)から三角形の3つの頂点番号を順に取出します。つぎに、第42行目からの入れ子のforループで、座標のVectorオブジェクト(変数vertices)からそれぞれの頂点番号のxy座標値を得ます。

スクリプト第48行目は、三角形の頂点座標とクリックした位置座標を関数xIsRight()に渡して、三角形の辺の右側にクリックした座標があるかどうかを調べます。第49〜51行目により、クリック位置が辺の右にない(関数xIsRight()の戻り値がfalseの)ときは、直ちにつぎの三角形の処理に移ります。

スクリプト第53〜62行目は、クリック位置が3辺の右にあったとき、その三角形の3頂点のxy座標をVectorオブジェクト(vertices)から取出して、第38行目で初期化したVectorインスタンスに加えています。そして、第58〜61行目で、Graphics.drawTriangles()メソッドによりその三角形を線描します。この描画は、テクスチャマッピングしたインスタンス(変数mySprite)とは別のSpriteインスタンス(mySprite2)を用意して行っています。

[ムービープレビュー]で描画されたインスタンスをクリックすると、Graphics.drawTriangles()メソッドに渡したその場所の三角形の頂点座標を調べて、三角形が線描されます(図Math02-012)。

図Math02-012■インスタンスをクリックするとその場所の三角形が線描される
インスタンスをクリックすると、Graphics.drawTriangles()メソッドに渡したその場所の三角形の頂点座標を調べて、三角形が描かれる。

Tips Math02-005■z座標が0のベクトルの外積
ふたつのVector3DインスタンスaとbのVector3D.zプロパティをともに0に設定していると、Vector3D.crossProduct()メソッドの戻り値である外積のVector3Dインスタンスは、Vector3D.xおよびVector3D.yプロパティがどちらも0になります。

ふたつのベクトルがxy平面上にあれば、その外積のベクトルはz軸と平行になるからです。ふたつのベクトルA(ax, ay, az)とB(bx, by, bz)の成分による計算でも、それが確かめられます(シンタックスMath02-005)。

A×B = (aybz - azby, azbx - axbz, axby - aybx)

ここでaz = bz = 0より、つぎの結果になります。

A×B = (0, 0, axby - aybx)

Maniac! Math02-006■2次元べクトルの外積
Maniac! Math02-005「外積とクロス積」で触れたとおり、2次元ベクトルAとBの外積A×Bはつぎの式で表されるスカラーになります。

A×B = |A||B|sinθ

そして、ベクトルの成分をそれぞれA(ax, ay)および(bx, by)とすると、外積A×Bはつぎの式で求められます。

A×B = axby - aybx

この値は、3次元べクトルの外積におけるz座標の成分と同じです(シンタックスMath02-005参照)。前掲スクリプトMath02-001に定めた関数xIsRight()は、この2次元べクトルの外積の式を用いれば、Vector3Dインスタンスを生成することなく簡単な計算で済みます。

function xIsRight(ax:Number, ay:Number, bx:Number, by:Number):Boolean {
  var bIsRight:Boolean = (ax * by - ay * bx >= 0);
  return bIsRight;
}


[Prev/Next]


作成者: 野中文雄
更新日: 2010年3月13日 Maniac! Math02-004を追加。
更新日: 2010年2月26日 Tips Math02-005を追加。
作成日: 2010年2月23日


Copyright © 2001-2010 Fumio Nonaka.  All rights reserved.