トップ 差分 一覧 ソース 検索 ヘルプ PDF RSS ログイン

3D計算で使えるVector3DとMatrix3D_Flex

3D計算で使えるVector3DとMatrix3D

3DCGでは、ベクトルと行列の扱いが必須になります。Flex3で追加されたVector3DとMatrix3Dを使うことで、そのベクトルと行列計算を行うことができます。

Vector3D

「Vector3D」型は、(x, y, z, w)の要素を持ちます。

var v:Vector3D;
v = new Vector3D();

とすると、(v.x, v.y, v.z, v.w)にそれぞれアクセスできます。

w要素は使わないのでしたらメモリの無駄になりますので、Vectorを使って

var v:Vector.<Number>;
v = new Vector.<Number>(3 * 頂点数, true);
v[0] = 1.0;    // X要素に相当
v[1] = 2.2;    // Y要素に相当
v[2] = 3.1;    // Z要素に相当

として扱うほうが節約できそうです(特に何千という頂点を一括管理するような場合)。

このVector3Dは後述するMatrix3Dや3DCGを意識した描画処理にて使われます。Vector3D型では、以下のような関数が用意されています。

XYZ要素の加算

var v1:Vector3D, v2:Vector3D;
v1 = new Vector3D(1, 2, 3);
v2 = new Vector3D(3, 6, 2);
		
v1 = v1.add(v2);

Vector3Dの加算は「add」にて行います。この場合は、「v1 = v1 + v2」の計算を行います。上記結果は「v1 = (4, 8, 5)」です。

XYZ要素の減算

var v1:Vector3D, v2:Vector3D;
v1 = new Vector3D(1, 2, 3);
v2 = new Vector3D(3, 6, 2);

v1 = v1.subtract(v2);

Vector3Dの減算は「subtract」にて行います。この場合は、「v1 = v1 - v2」の計算を行います。上記結果は「v1 = (-2, -4, 1)」です。

内積計算

var v1:Vector3D, v2:Vector3D;
v1 = new Vector3D(1, 2, 3);
v2 = new Vector3D(3, 6, 2);
		
var dVal:Number = v1.dotProduct(v2);

内積計算は

dVal = v1.x * v2.x + v1.y * v2.y + v1.z * v2.z;

同等のものを「dotProduct」にて内積計算を行います。この場合のdValの値は21になります。

外積計算

var v1:Vector3D, v2:Vector3D;
v1 = new Vector3D(1, 2, 3);
v2 = new Vector3D(3, 6, 2);

var v3:Vector3D = v1.crossProduct(v2);

「crossProduct」関数にて、v1とv2に垂直なベクトルを計算します。以下の計算と同じになります。

v3.x = v1.y * v2.z - v1.z * v2.y;
v3.y = v1.z * v2.x - v1.x * v2.z;
v3.z = v1.x * v2.y - v1.y * v2.x;

この場合の結果は「v3 = (-14, 7, 0)」となります。

ベクトルの長さを求める

var v1:Vector3D;
v1 = new Vector3D(1, 2, 3);

var len:Number = v1.length;

ベクトルの長さは「length」にて取得します。

len = Math.sqrt(v1.x * v1.x + v1.y * v1.y + v1.z * v1.z);

と結果は同じです。この場合の結果は「len = 3.7416573867739413」となります。

ベクトルを正規化(単位ベクトル化)

var v1:Vector3D;
v1 = new Vector3D(1, 2, 3);

v1.normalize();

ベクトルの長さを1.0にする正規化は「normalize」にて行います。指定のベクトル自身が正規化されます。

 len = Math.sqrt(v1.x * v1.x + v1.y * v1.y + v1.z * v1.z);
 v1.x /= len;
 v1.y /= len;
 v1.z /= len;

と同じ結果になります。この場合の結果は「v1 = (0.2672612419124244, 0.5345224838248488, 0.8017837257372732)」となります。

Matrix3D

4x4行列を扱う型として「Matrix3D」があります。

var m:Matrix3D;
m = new Matrix3D();

行列の各要素を取り出し

配列の要素は「Matrix3D.rawData」にて16個の要素を持つNumberの配列(Vector)として格納されています。

var m:Matrix3D;
m = new Matrix3D();
var val:Number = m.rawData[2 * 4 + 1];

とした場合は、mの2行目1列でのデータがvalに入ることになります。行列の並びは以下のようになります。

m = \begin{bmatrix} 0&1&2&3\\ 4&5&6&7\\ 8&9&10&11\\ 12&13&14&15\\ \end{bmatrix}

newした初期段階では単位行列が入ることになります。

行列の各要素を変更

var m:Matrix3D;
m = new Matrix3D();
m.rawData[2] = 5.0;

として要素を変えることができる、と一瞬思ってしまいますが、実はこれがダメです。

var m:Matrix3D;
m = new Matrix3D();

// 16個のNumberを持つ配列を作成
var dat:Vector.<Number>;
dat = new Vector.<Number>(16, true);

// 行列 m の内容を配列datに複製		
dat = m.rawData;

// 配列datでの値を変更
dat[2] = 5.0;

// 配列datの内容を行列 m のrawDataに複製
m.rawData = dat;

のように、一度Numberの配列(Vector)を作成し、配列に行列の内容(rawData)をコピーします。コピーした配列上で変更して配列ごとMatrix3DのrawDataにコピーすると反映されます。ちと面倒ですね。

単位行列を入れる

var m:Matrix3D;
m = new Matrix3D();

m.indentity();

「Matrix3D.indentity();にて単位行列を入れます。

行列を複製する

var m:Matrix3D, m2:Matrix3D;
m  = new Matrix3D();

として行列 m にデータを格納したとします。これを複製するには

m2 = m.clone();

と「clone」関数を使用することで戻り値のm2に複製された値が格納されることになります。

行列同士の乗算(ちょっと納得できない点があるので後で追記予定)

m = m * m2

の行列計算は、

var m:Matrix3D, m2:Matrix3D;
m  = new Matrix3D();
m2 = new Matrix3D();
...
m.append(m2);

のように「append」関数にて行います。この場合は、行列 m の値が変更されます。mの値を変更したくない場合は、一度cloneしてからそれに対してappendするようにします。

http://livedocs.adobe.com/flex/3_jp/langref/index.html
では、
thisMatrix = lhs * thisMatrix;
となっているのですが、
thisMatrix = thisMatrix * lhs;
の結果になってるようだけど、、、。

回転行列を求める

var m:Matrix3D;
m = new Matrix3D();
m.appendRotation(10, Vector3D.Y_AXIS);

行列に対して、回転行列を乗算します。第一引数は回転角度(度数指定)、第二引数は「Vector3D.X_AXIS」「Vector3D.Y_AXIS」「Vector3D.Z_AXIS」でそれぞれXYZ軸中心回転を表します。

m = m * 回転行列

の計算になります(逆かもしれん)。この順番が逆になって「回転行列 * m」となったものが「prependRotation」になります。

ベクトルと行列の乗算

var v:Vector3D = new Vector3D();
var m:Matrix3D = new Matrix3D();

という行列があった場合、

var v2:Vector3D = m.transformVector(v);

の「transformVector」関数にて、ベクトルvと行列mでの乗算が行われます。透視変換行列などで計算して、Vector3Dでのw値が必要な場合はそのままwに対して値が入ります(普段は1.0)。

Future's Laboratory 技術格納庫 2004-2013 Yutaka Yoshisaka.