サイトトップ

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

Flash ActionScript 3.0 Reference

◎06 幾何

☆17 ★ベクトルの内積や外積で3次元空間における面の向きを知りたい

解説
Vector3Dクラスを使うと、3次元ベクトルの演算ができます。ベクトルの内積や外積は、ふたつのベクトルがなす角や面の向きを確かめるために使われます。まず、ベクトルAとBの内積はA・Bで表され、つぎの式で定義されます。なお、θはふたつのベクトルのなす角です。

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

ベクトルAの絶対値|A|は、ベクトルの長さを意味します。したがって、その値は必ず0以上です。ベクトルAとBの絶対値つまり長さがどちらも0でなければ、内積A・Bの値の正負はcosθによって決まります(図06-17-01)。よって、ベクトルの内積の値となす角との関係は、次表06-17-01のとおりです。

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

図06-17-01■ベクトルのなす角とcosθの値【FR090619_010.png】

つまり、3次元座標空間にある面について、視線と面の方向のふたつのベクトルの内積を計算すれば、視線に対して面が表向き(内積が負)か裏向き(内積が正)か確かめられます(内積が0なら面の向きは真横)。

つぎに、面の方向は、ベクトルの外積によって求められます。ベクトルAとBの外積はA×Bで表され、次表06-17-02のようなベクトルです。なお、θはふたつのベクトルのなす角を示します。

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

図06-17-02■Vector3Dインスタンスが表すベクトル【06_17_Vector3D_dotProduct_001.png/06_17_Vector3D_dotProduct_002.png】

したがって、向きを調べようとする面の平行でない2辺から外積を求めれば、その面に対して垂直つまり面の方向を示すベクトルが得られます。

ベクトルには、加減算もあります。ふたつのベクトルの足し算・引き算は、対応する各座標値を足し引きします。また、幾何学的には、つぎのように表されます。

図06-17-03■Vector3Dインスタンスが表すベクトル【FigMath05-005.png/FigMath05-006.png】

引くベクトルBは向きを反転

なお、Matrix3D.positionプロパティは、変換行列が適用された3次元座標のVector3Dインスタンスを示します。

Vector3Dクラス
パッケージ flash.geom
継承 Vector3D → Object
add()メソッド ASタイプ M
ランタイムバージョン AIR 1.5/Flash Player 10
文法 add(secondVector:Vector3D):Vector3D
意味 参照するVector3Dインスタンスに引数のVector3Dインスタンスがベクトル演算として加算された結果を、新たなVector3Dオブジェクトで返す。
引数 secondVector:Vector3D…加算するベクトルを示すVector3Dインスタンス。
戻り値 加算の結果となるベクトルを示す新たなVector3Dインスタンス。
subtract()メソッド ASタイプ M
ランタイムバージョン AIR 1.5/Flash Player 10
文法 subtract(secondVector:Vector3D):Vector3D
意味 参照するVector3Dインスタンスから引数のVector3Dインスタンスがベクトル演算として減算された結果を、新たなVector3Dオブジェクトで返す。
引数 secondVector:Vector3D…減算するベクトルを示すVector3Dインスタンス。
戻り値 減算の結果となるベクトルを示す新たなVector3Dインスタンス。
dotProduct()メソッド ASタイプ M
ランタイムバージョン AIR 1.5/Flash Player 10
文法 dotProduct(secondVector:Vector3D):Number
意味 参照するVector3Dインスタンスと引数のVector3Dインスタンスのベクトル演算としての内積を数値で返す。
引数 secondVector:Vector3D…内積を計算するためのもうひとつのベクトルとなるVector3Dインスタンス。
戻り値 内積として計算された数値。
crossProduct()メソッド ASタイプ M
ランタイムバージョン AIR 1.5/Flash Player 10
文法 crossProduct(secondVector:Vector3D):Vector3D
意味 参照するVector3Dインスタンスと引数のVector3Dインスタンスのベクトル演算としての外積を、新たなVector3Dオブジェクトで返す。
引数 secondVector:Vector3D…外積を計算するためのもうひとつのベクトルとなるVector3Dインスタンス。
戻り値 外積として計算されたベクトルを示す新たなVector3Dインスタンス。

Matrix3Dクラス
パッケージ flash.geom
継承 Matrix3D → Object
positionプロパティ ASタイプ P
ランタイムバージョン AIR 1.5/Flash Player 10
文法 position:Vector3D
意味 インスタンスの3次元空間座標が保持されたVector3Dオブジェクトを示す。
プロパティ値 インスタンスの3次元座標値をもつVector3Dオブジェクト。

※内積と外積
3次元空間のベクトルAとBを、それぞれ(ax, ay, az)および(bx, by, bz)とすると、内積と外積はつぎの式で求められます。

A・B = axbx + ayby + azbz
A×B = (aybz - azby, azbx - axbz, axby - aybx)

内積は大きさのみの値(スカラー)であるのに対して、外積がベクトルであることにご注意ください。cosθは角度がπ/2(90度)のとき0となり、sinθは角度θが0のとき0になります。したがって、ベクトルAとBは互いに、内積の大きさが0のとき垂直、外積が0のときに平行となります。

記述例
以下のスクリプト06-17-01は、インスタンスのz座標を50ピクセル手前(-50)に移動し、z座標0(xy座標はインスタンスの基準点)のy軸で水平回転させます。そのうえで、視線のベクトル(0, 0, 1)と面の方向(回転の中心から面の基準点まで)のベクトルで内積を計算し、裏返った面はアルファを50%(0.5)にして結果を確かめています(図06-17-04)。

図06-17-04■水平回転するインスタンスのアルファを面の裏表で変化させる【FR090619_011.png】

z軸正方向の視線のベクトル(view)とインスタンスが回転する原点の位置ベクトル(origin)は、Vector3Dインスタンスとして初期化しました。

→関連項目
3次元変換行列でインスタンスに複数の変換を加えたい

DisplayObject.enterFrameイベント(定数Event.ENTER_FRAME)のリスナー関数xRotate()では、視線のベクトル(view)とインスタンスの面の方向のベクトル(vector)との内積(nDotProduct)をVector3D.dotProduct()メソッドにより求め、視線に対してインスタンスが表向きか裏向きかを確かめています。内積の値が正のときは、インスタンスの面は裏返っています(前掲表06-17-01)。

回転するインスタンスは基準点を真ん中に定めたので、その位置ベクトル(myPosition)から原点のベクトル(origin)を差引けば、インスタンスの面の方向がベクトル(vector)として得られます。ベクトルの引き算は、Vector3D.subtract()メソッドを使います。

なお、インスタンスのもつMatrix3Dオブジェクトからその基準点の位置ベクトルをVector3Dインスタンスとして得るには、Vector3D.positionプロパティを用います。

スクリプト06-17-01■

// フレームアクション
var nX:Number = my_mc.x;
var nY:Number = my_mc.y;
var nDeceleration:Number = 0.2;
var view:Vector3D = new Vector3D(0, 0, 1);   // 視線のベクトル
var origin:Vector3D = new Vector3D(nX, nY, 0);   // 原点のベクトル
my_mc.z = -50;
addEventListener(Event.ENTER_FRAME, xRotate);
function xRotate(eventObject:Event):void {
  var nRotationY:Number = (mouseX - nX) * nDeceleration;
  var nRotationX:Number = (mouseY - nY) * nDeceleration;
  my_mc.transform.matrix3D.appendTranslation(-nX, -nY, 0);
  my_mc.transform.matrix3D.appendRotation(nRotationY, Vector3D.Y_AXIS);
  my_mc.transform.matrix3D.appendTranslation(nX, nY, 0);
  var myPosition:Vector3D = my_mc.transform.matrix3D.position;
  var vector:Vector3D = myPosition.subtract(origin);   // 面の方向のベクトル
  var nDotProduct:Number = view.dotProduct(vector);
  if (nDotProduct > 0) {
    my_mc.alpha = 0.5;
  } else {
    my_mc.alpha = 1;
  }
}


作成者: 野中文雄
ドラフト作成: 2009年7月2日


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