|
ActionScript 3.0 for 3D
○Column Math01 Vector3D.wプロパティ
Vector3Dインスタンスは、3次元のベクトルを表します。プロパティにはそれぞれxyzの各座標値をもつVector3D.x/Vector3D.y/Vector3D.zのほかに、第4の成分値としてVector3D.wプロパティがあります。しかし、Vector3D.wプロパティは位置ベクトルの座標値ではありませんので、メソッドなどによる演算でその値がどう扱われるかわかりにくいところがあります。
●Vector3D.wプロパティはオプションの値
3次元のベクトルは3つの成分から成立ちます。アフィン変換で4次元のベクトルとして扱うときも、成分値は定数1です。[ヘルプ]の[Vector3D]クラスには、インスタンスの表す列べクトルがつぎのように示されています(再掲図06-001)。けれども、この4次元ベクトルがそのまま数学のベクトル演算や行列を使った座標変換に用いられる訳ではありません。
図06-001■Vector3Dインスタンスが表す4次元ベクトル(再掲)
xyz座標値に加えて、w値を成分にもつ4次元ベクトルで表される。
|
3次元空間の位置ベクトルであれば、成分はxyz座標値の計3つです。アフィン変換で4次元ベクトルとして扱われるときも、第4成分は定数1になります。したがって、Vector3D.wプロパティに設定された値は、ベクトル演算や行列による座標変換には基本的には使われません。[ヘルプ]の[Vector3D]クラスの「Vector3D()コンストラクタ」の項にも、Vector3D.wプロパティの値である第4引数は「追加データのオプションエレメント(回転角度など)」と説明されています。
Vector3D.wプロパティの具体的な使い途のひとつは、前述06「3次元空間の座標を扱う − Vector3Dクラス」の06-02「遠近法が投影されたワイヤーフレームの立方体を回す」で解説したVector3D.project()メソッドによる透視投影です。Vector3D.project()メソッドは、Vector3D.x/y/zの各座標値をVector3D.wプロパティの値で割り算します(シンタックス06-004)。
もうひとつ、[ヘルプ]で[Vector3D]クラスの「Vector3D.wプロパティ」の項を見ると、「四元数」(しげんすう)による「回転角度」の指定という説明があります(シンタックス06-001参照)。この四元数については、つぎにコラムを改めて簡単にご紹介します。
さらに、このプロパティは「オプション」ですので、ユーザーがその目的に合わせて使うことも認められます。そこで、Vector3Dクラスのおもなメソッドによる演算で、Vector3D.wプロパティがどのように扱われるのか簡単に確かめてみましょう(なお、Tips MathC1-001「Vector3Dクラスの使い途」参照)。
Tips MathC1-001■Vector3Dクラスの使い途
Vector3Dクラスそのものも、位置ベクトルを示すためにのみ使われる訳ではありません。[ヘルプ]の[Vector3D]クラスの説明にも、つぎのように書かれています。
Vector3Dクラスは方向、つまり(0,0,0)などの座標の起点からエンドポイントまでの矢印、またはRGB(赤、緑、青)カラーモデルの浮動小数点成分を表すこともできます。
つまり、広く3次元ベクトルで表せ、計算できるものであれば、Vector3Dクラスを利用することができます。その場合にも、Vector3D.wプロパティの扱いを知っておくことは役に立つでしょう。
|
●加減算とスカラー倍
まず、3次元空間のベクトルの足し算と引き算です。Vector3D.add()およびVector3D.subtract()メソッドは、参照するVector3Dインスタンスに引数のインスタンスを3次元ベクトルとして足し引きし、その演算結果を新たなVector3Dインスタンスとして返します(シンタックス06-005)。その戻り値のVector3Dインスタンスは、Vector3D.wプロパティがつねに0になります。
var my0Vector3D:Vector3D = new Vector3D(1, 2, 3, 4);
var my1Vector3D:Vector3D = new Vector3D(5, 6, 7, 8);
var resultVector3D:Vector3D = my0Vector3D.add(my1Vector3D);
trace(resultVector3D, resultVector3D.w); // 出力: Vector3D(6, 8, 10) 0
|
つぎに、Vector3Dインスタンスのスカラー倍は、Vector3D.scaleBy()メソッドを使います。ただし、加減算のメソッドとは異なり、参照するVector3Dインスタンスのベクトルの成分そのものを書替えます(シンタックス06-007)。そのとき参照したインスタンスのVector3D.wプロパティは、そのまま保たれます。つまり、0にリセットされることはなく、またスカラー倍もされません。
var myVector3D:Vector3D = new Vector3D(1, 2, 3, 4);
myVector3D.scaleBy(2);
trace(myVector3D, myVector3D.w); // 出力: Vector3D(2, 4, 6) 4
|
ほかには、位置ベクトルの大きさであるVector3D.lengthプロパティ、およびふたつのベクトルの内積および外積を求めるVector3D.dotProduct()やVector3D.crossProduct()メソッドの計算は、3次元空間ではxyz座標により定められています(シンタックス06-005)。つまり、ベクトルの第4成分が関わる余地はありません。
とくに、Vector3D.lengthプロパティとVector3D.dotProduct()メソッドは戻り値が数値(スカラー)ですから、Vector3D.wプロパティは無視されます。ただ、Vector3D.crossProduct()メソッドから返されるVector3Dインスタンスは、参照したもとのインスタンスのプロパティに拘らず、Vector3D.wプロパティの値が1になるようです。
var myVector3D:Vector3D = new Vector3D();
trace(myVector3D, myVector3D.w); // 出力: Vector3D(0, 0, 0) 0
var resultVector3D:Vector3D = myVector3D.crossProduct(new Vector3D());
trace(resultVector3D, resultVector3D.w); // 出力: Vector3D(0, 0, 0) 1
|
●行列との乗算
Matrix3D.transformVector()メソッドを使うと、Matrix3Dインスタンスの正方行列にVector3Dインスタンスのベクトルが乗じられます。戻り値は、積を示す新たなVector3Dインスタンスです(シンタックス06-003)。試しに単位行列となるデフォルトのMatrix3DインスタンスをVector3Dインスタンスに掛合わせると、Vector3D.wプロパティは一見1にリセットされているように思えます。
var myVector3D:Vector3D = new Vector3D(1, 2, 3, 4);
var myMatrix3D:Matrix3D = new Matrix3D();
trace(myVector3D, myVector3D.w); // 出力: Vector3D(1, 2, 3) 4
var resultVector3D:Vector3D = myMatrix3D.transformVector(myVector3D);
trace(resultVector3D, resultVector3D.w); // 出力: Vector3D(1, 2, 3) 1
|
しかし、厳密には単純にVector3D.wプロパティ値が1にリセットされている訳ではありません。演算の処理をもう少し正確に知るため、掛合わせる4次正方行列の第4行目に成分値を設定してみます。
もっともアフィン変換では、4次正方行列の第4行目の成分は、単位行列と同じ[0 0 0 1]に定められています。これらの成分値を変えるには、シンタックスMathC1-001のMatrix3D.rawDataプロパティを使います。
シンタックスMathC1-001■Matrix3D.rawDataプロパティ
Matrix3D.rawDataプロパティ
|
文法
|
rawData:Vector.<Number>
|
プロパティ値
|
Matrix3Dインスタンスが表す4次正方行列の16成分値をもつ数値(Number)ベース型のVectorオブジェクト。16の成分値は、正方行列の第1列から第4列まで、列順に納められる。
|
Matrix3D.rawDataプロパティは、Matrix3Dインスタンスの表す4次正方行列の16成分値を、数値ベース型のVectorオブジェクトでもちます。ただし、数値エレメントの順序に注意しなければなりません。たとえば、Matrix3Dインスタンスがつぎのような4次正方行列を表すとします。
|
a11 |
a12 |
a13 |
a14 |
|
a21 |
a22 |
a23 |
a24 |
a31 |
a32 |
a33 |
a34 |
a41 |
a42 |
a43 |
a44 |
すると、Matrix3D.rawDataプロパティのVectorオブジェクトには、数値エレメントがつぎのような列ごとの順序で納められるのです。
a11, a21, a31, a41, a12, a22, a32, a42, a13, a23, a33, a43, a14, a24, a34, a44
試してみましょう。単位行列となるデフォルトのMatrix3DインスタンスにMatrix3D.appendTranslation()で移動の変換を行い、4次正方行列の第3列目に成分を変えます。Matrix3D.rawDataプロパティのVectorオブジェクトを[出力]すると、第3列の成分値が並んで表示されます。
var myMatrix3D:Matrix3D = new Matrix3D();
myMatrix3D.appendTranslation(1, 2, 3);
trace(myMatrix3D.rawData); // 出力: 1,0,0,0,0,1,0,0,0,0,1,0,1,2,3,1
|
Tips MathC1-002■Matrix3Dインスタンスの4次正方行列の成分を行の順に[出力]する
Matrix3Dインスタンスが表す4次正方行列の成分を列でなく行の順で示したいときは、Matrix3D.transpose()メソッドで転置すればよいでしょう。もとのMatrix3Dインスタンスをそのまま残すには、Matrix3D.clone()メソッドで複製をとっておきます(シンタックス04-011)。
var myMatrix3D:Matrix3D = new Matrix3D();
myMatrix3D.appendTranslation(1, 2, 3);
var outputMatrix3D:Matrix3D = myMatrix3D.clone();
outputMatrix3D.transpose();
trace(outputMatrix3D.rawData); // 出力: 1,0,0,1,0,1,0,2,0,0,1,3,0,0,0,1
|
シンタックスMathC1-002■Matrix3D.transpose()メソッド
|
したがって、Matrix3Dインスタンスが表す4次正方行列の第4行目の成分は、Matrix3D.rawDataプロパティのVectorオブジェクトのインデックス3、7、11、15の4つだということです。そこで、Matrix3D.rawDataプロパティにこれら4成分の値が設定されたVectorオブジェクトを代入したうえで、Matrix3D.transformVector()メソッドを試します。
var myVector3D:Vector3D = new Vector3D(1, 2, 3, 4);
var myMatrix3D:Matrix3D = new Matrix3D();
var myVector:Vector.<Number> = myMatrix3D.rawData;
myVector[3] = 5;
myVector[7] = 6;
myVector[11] = 7;
myVector[15] = 8;
myMatrix3D.rawData = myVector;
trace(myMatrix3D.rawData); // 出力: 1,0,0,5,0,1,0,6,0,0,1,7,0,0,0,8
var resultVector3D:Vector3D = myMatrix3D.transformVector(myVector3D);
trace(resultVector3D, resultVector3D.w); // 出力: Vector3D(1, 2, 3) 46
|
Tips MathC1-003■Matrix3D.rawDataプロパティの設定にはVectorインスタンスを代入する
Matrix3D.rawDataプロパティによりMatrix3Dの表す4次正方行列の成分値を変えるには、プロパティに数値ベース型のVectorインスタンスを設定しなければなりません。Matrix3D.rawDataプロパティに対して値を直接配列アクセス演算子[]で与えようとしても、成分値は変わりません。
var myMatrix3D:Matrix3D = new Matrix3D();
var myVector:Vector.>Number< = myMatrix3D.rawData;
myMatrix3D.rawData[0] = 10; // プロパティに配列アクセス演算子で直接値を設定
trace(myMatrix3D.rawData[0]); // 出力: 1
myVector[0] = 10;
myMatrix3D.rawData = myVector; // プロパティにVectorインスタンスを設定
trace(myMatrix3D.rawData[0]); // 出力: 10
|
|
Matrix3Dインスタンスの4次正方行列は、第1から第3行目まではデフォルトつまり単位行列のままですから、戻り値のVector3Dインスタンスのxyz座標値は変わりません。注目するのはベクトルの第4成分であるVector3D.wプロパティ値です。この値は、4次正方行列の第4行目とMatrix3D.transformVector()メソッドの引数に渡したVector3Dインスタンスが表す位置ベクトルとの内積になるはずです(前述Math03-03「行列の積および単位行列と逆行列」の「行列の積」参照)。
しかし、4次正方行列の第4行目(5, 6, 7, 8)とVector3Dインスタンスのxyz座標値にVector3D.wプロパティ値を加えた(1, 2, 3, 4)との内積はつぎのように70と計算され、上記スクリプトの[出力]である46とは一致しません。
(5, 6, 7, 8)・(1, 2, 3, 4) = 5×1 + 6×2 + 7×3 + 8×4 = 5 + 12 + 21 + 32 = 70
ところで、Matrix3D.transformVector()メソッドを試したとき、戻り値のVector3D.wプロパティの値が1になってしまったことを思い出しましょう。今回は1にならず、何らかの計算はされているようです。ということは、Matrix3D.transformVector()メソッドの戻り値ではなく、引数の方のVector3Dインスタンスを表すベクトルの第4成分が1として扱われているのです。実際、ベクトルの第4成分を1とすれば、内積の計算が上記スクリプトで[出力]されたVector3D.wプロパティの値と合います。
(5, 6, 7, 8)・(1, 2, 3, 1) = 5×1 + 6×2 + 7×3 + 8×1 = 5 + 12 + 21 + 8 = 46
初めに述べたとおり、Vector3D.wプロパティは位置ベクトルの座標値ではないため、アフィン変換で4次元のベクトルとして扱うときの定数1が用いられているものと考えられます。他方で、4次正方行列の第4行目にあえて成分値を設定して使う場合に備えて、計算結果を戻り値のVector3D.wプロパティに設定しているのでしょう。
●演算後のVector3D.wプロパティ値
Vector3Dオブジェクトのベクトルに対して演算を行うとVector3D.wプロパティの値がどう変わるかを、下表MathC1-001にまとめました。
表MathC1-001■演算をした後のVector3D.wプロパティ値
演算 |
メソッド |
Vector3D.wプロパティの値 |
ベクトルの加減算 |
Vector3D.add()
Vector3D.subtract()
|
0に設定
|
ベクトルのスカラー倍 |
Vector3D.scaleBy()
|
もとの値のまま
|
行列との乗算 |
Matrix3D.transformVector()
|
乗じるプロパティ値を1にして計算
|
[Prev/Next]
作成者: 野中文雄
作成日: 2010年4月1日
Copyright ©
2001-2010 Fumio Nonaka. All rights reserved.
|