Away3Dに関するオレのオレによるオレのための覚え書き開始。
地味だけど座標変換のキモとなる Matrix3D と Number3Dから。それと、理解が追いつかない Quaternion もついでに。
Matrix3D
まずはMatrix3D。行列を扱うクラス。
コンストラクタ
import away3d.core.math.Matrix3D;
var matrix:Matrix3D = new Matrix3D();
PV3Dの
var matrix:Matrix3D = Matrix3D.IDENTITY;
と等価。
各成分へのアクセス
| sxx |
sxy |
sxz |
tx |
| syx |
syy |
syz |
ty |
| szx |
szy |
szz |
tz |
| 0 |
0 |
0 |
1 |
|
var matrix:Matrix3D = new Matrix3D();
matrix.sxx; //1行1列目
matrix.sxy; //1行2列目
matrix.sxz; //1行3列目
matrix.tx; //1行4列目
・
・
・
matrix.tz; //3行4列目
行列から位置を取得
var matrix:Matrix3D = new Matrix3D();
var pos:Number3D = matrix.position();
やってることは以下と同じ
var pos:Number3D = new Number3D();
pos.x = matrix.tx;
pos.y = matrix.ty;
pos.z = matrix.tz;
行列式の取得
var matrix:Matrix3D = new Matrix3D();
var determinant:Number = matrix.det();
※逆行列が存在するかどうかの判別以外に行列式の使い道知らないんだけど、何かあるのかな?
行列のかけ算
var multiplymatrix:Matrix3D();
multiplymatrix.multiply(matrix1, matrix2);
回転成分だけをかけ算
var multiply3x3matrix:Matrix3D();
multiply3x3matrix.multiply3x3(matrix1, matrix2);
行列をスカラー倍
matrix.scale(2, 1, 1);
行列の複製
var newMatrix:Matrix3D = matrix.clone();
回転成分だけをコピー
var newMatrix:Matrix3D = Matrix3D.copy3x3(matrix);
回転行列の取得
Matrix3D.rotationMatrix(u:Number, v:Number, w:Number, angle:Number)
//X軸で40度回転する行列の取得
var rotationmatrix:Matrix3D = new Matrix3D();
rotationmatrix.rotationMatrix(1, 0, 0, 30*Math.PI/180);
//Y軸で20度回転する行列の取得
var rotationmatrix:Matrix3D = new Matrix3D();
rotationmatrix.rotationMatrix(0, 1, 0, 20*Math.PI/180);
//Z軸で15度回転する行列の取得
var rotationmatrix:Matrix3D = new Matrix3D();
rotationmatrix.rotationMatrix(0, 0, 1, 15*Math.PI/180);
移動行列の取得
//X軸方向に20、Y軸方向に30、Z軸方向に40移動する
var translationmatrix:Matrix3D = new Matrix3D();
translationmatrix.translationMatrix(20, 30, 40);
拡大縮小行列の取得
//X軸方向に2倍、Y軸方向に3倍、Z軸方向に4倍
var scalematrix:Matrix3D = new Matrix3D();
scalematrix.translationMatrix(2, 3, 4);
逆行列の取得
var inverseMatrix:Matrix3D = new Matrix3D();
inverseMatrix.inverse(matrix);
配列から行列を生成
var matArray:Array =
[
1,0,0,0,
0,1,0,0,
0,0,1,0
];
//4行目は0,0,0,1固定なので、3行4列分を定義
matrix.array2matrix(matArray);
行列からオイラー角に変換
var angle:Number = matrix.matrix2euler();
//角度はDegreeに変換される
obj.rotationX = angle.x;
obj.rotationY = angle.y;
obj.rotationZ = angle.z;
クォータニオンから行列に変換
var q:Quaternion = new Quaternion();
q.axis2quaternion(1,0,0,45*Math.PI/180);
var mat:Matrix3D = new Matrix3D();
mat.quaternion2matrix(q);
よくある使いどころ
//Cubeを生成
var wcMat:WireColorMaterial = new WireColorMaterial(0x0099CC, {wirecolor:0x00CCFF});
vae cube:Cube = new Cube({width:200, height:200, depth:200, faces:{left:wcMat, right:wcMat, bottom:wcMat,top:wcMat,front:wcMat,back:wcMat} });
scene.addChild(sphere);
//Z軸で45度回転する行列を取得
var rotationmatrix:Matrix3D = new Matrix3D();
rotationmatrix.rotationMatrix(0, 0, 1, 45*Math.PI/180);
//行列をcube.transform(Cubeの同次座標)にかける
cube.transform.multiply(cube.transform, rotationmatrix);
※これだけだったらrotationZ使えって話;
Number3D
次はNumber3D。ベクトルを扱うクラス。
コンストラクタ
import away3d.core.math.Number3D;
var vec:Number3D = new Number3D(x:Number, y:Number, z:Number, n:Boolean);
//引数を定義しなければ方向性を持たないゼロベクトルになる
var vec:Number3D = new Number3D();
各成分へのアクセス
var vec:Number3D = new Number3D(1,0,1);
trace(vec.x, vec.y, vec.z);
static変数
Number3D.FORWARD … Number3D(0, 0, 1)と等価
Number3D.BACKWARD … Number3D(0, 0, -1)と等価
Number3D.LEFT … Number3D(-1, 0, 0)と等価
Number3D.RIGHT … Number3D(1, 0, 0)と等価
Number3D.UP … Number3D(0, 1, 0)と等価
Number3D.DOWN … Number3D(0, -1, 0)と等価
ベクトルの正規化
var vec:Number3D = new Number3D(5, 1, 3);
vec.normalize();
//コンストラクタの第4引数をtrueにすることで代用可
var vec:Number3D = new Number3D(5, 1, 3, ture);
ノルム(ベクトルの大きさ)を取得
var vec:Number3D = new Number3D(2, 1, 8);
var mod:Number = vec.modulo;
ノルムの大きさを大まかに判別(ざっくりだけど高速?)
var vec:Number3D = new Number3D(20, 20, 0);
var mod:Number = vec.modulo2;
var magnitude:Number = 5;
//(mod > magnitude*magnitude) が true ならvecのノルムはmagnitudeより大きい
//(mod < magnitude*magnitude) が true ならvecのノルムはmagnitudeより小さい
//(mod == magnitude*magnitude) が true ならvecのノルムはmagnitudeと等しい
※PV3DのNumber3DにあるmoduloSquaredと同じものだと思うけど自信ない。
ベクトルを複製
var vec:Number3D = new Number3D(20, 20, 0);
var newVec:Number3D = vec.clone();
加算と減算
//加算
var result:Number3D = new Number3D();
var vec1:Number3D = new Number3D();
var vec2:Number3D = new Number3D();
result.add(vec1, vec2);
//減算
var result:Number3D = new Number3D();
var vec1:Number3D = new Number3D();
var vec2:Number3D = new Number3D();
result.sub(vec1, vec2);
内積と外積
//内積
var vec1:Number3D = new Number3D();
var vec2:Number3D = new Number3D();
vec1.dot(vec2);
//外積(法線ベクトル取得)
var crossResult:Number3D = new Number3D();
var vec1:Number3D = new Number3D();
var vec2:Number3D = new Number3D();
crossResult.cross(vec1, vec2);
ベクトルをスカラー倍
var vec:Number3D = new Number3D();
var vec1:Number3D = new Number3D(1,0,0);
vec.scale(vec1,2);
2つのベクトルのなす角度(ラジアン)を取得
var vec:Number3D = new Number3D(1, 0, 0);
var vec2:Number3D = new Number3D(0, 1, 0);
var angle:Number = vec.getAngle(vec2);
2つのベクトルの距離を取得
var vec:Number3D = new Number3D(1, 0, 0);
var vec2:Number3D = new Number3D(0, 1, 0);
var dist:Number = vec.distance(vec2);
Matrix3Dでベクトルを変換
//Number3D.rotate(v:Number3D, m:Matrix3D)
//回転のみ
var vecResult:Number3D = new Number3D();
var vec:Number3D = new Number3D(1, 0, 0);
var rotationmatrix:Matrix3D = new Matrix3D();
rotationmatrix.rotationMatrix(0, 0, 1, 45*Math.PI/180);
vecResult.rotate(vec,rotationmatrix);
//Number3D.transform(v:Number3D, m:Matrix3D)
//4x4
var vecResult:Number3D = new Number3D();
var vec:Number3D = new Number3D(1, 0, 0);
var translationmatrix:Matrix3D = new Matrix3D();
translationmatrix.translationMatrix(0, 30, 0);
vecResult.transform(vec,rotationmatrix);
ベクトルが無限平面と交わる位置を取得?
var p:Number3D = new Number3D(5,5,2); //任意のベクトル
var k:Number3D = new Number3D(10, 10, 10); //平面上の一点
var n:Number3D = new Number3D(0, 0, 1); //平面の法線ベクトル
var vecResult:Number3D;
vecResult = p.closestPointOnPlane(p,k,n); //vecResultにベクトルpが平面と交わる座標が返るのか?
※これについてはウソ書いてる可能性多いにアリ。PV3Dにも core.math.Plane3D に同様のメソッドがある。
Quaternion
最後はQuaternion。文字通りクォータニオン(四元数)を扱うクラス。永遠に理解できそうもない。
PV3Dと比べると限定的な機能しかなさげ。ライブラリ内部でもほとんど使われてない。SLERP(球面線形補完)のメソッドも無いので、どーしても使いたきゃ自力で実装しろってことか。
import away3d.core.math.Quaternion;
var q:Quaternion = new Quaternion();
※コンストラクタが無いので、クォータニオンを生成するには後述のaxis2quaternionか、euler2quaternionを使うと。
回転クォータニオンを得る
//axis2quaternion(x:Number, y:Number, z:Number, angle:Number)
var q:Quaternion = new Quaternion();
q.axis2quaternion(1,0,0,45*Math.PI/180);
オイラー角から回転クォータニオンを得る?
//euler2quaternion(ax:Number, ay:Number, az:Number)
var q:Quaternion = new Quaternion();
q.euler2quaternion(0,0,45*Math.PI/180);
※これも自信ないなぁ思惑と違う結果になる。引き続き意識の片隅に。
クォータニオンの大きさを得る
var q:Quaternion = new Quaternion();
q.euler2quaternion(rotationZ,rotationY,rotationX);
var mag:Number = q.magnitude;
クォータニオンを正規化
var q:Quaternion = new Quaternion();
q.euler2quaternion(rotationZ,rotationY,rotationX);
q.normalize();
クォータニオンのかけ算
var q:Quaternion = new Quaternion();
var q2:Quaternion = new Quaternion();
var ans:Quaternion = new Quaternion();
q.euler2quaternion(rotationZ,rotationY,rotationX);
q2.axis2quaternion(1,0,0,45*Math.PI/180);
ans.multiply(q,q2);
あと、Number2D っていうNumber3Dの2D版っぽいクラスもあって、MovieMaterialとかで使われてるみたいだけど、とりあえず割愛。
core.mathパッケージのクラスは、コードの書き方をまとめたところで何の役にも立ちませんな;
「ベクトルの内積が0なら、2つのベクトルは直角」とか「3Dベクトルの外積=法線ベクトル」みたいな超基本的な事はもちろん、Number3DやMatrix3Dの各メソッドがどういう概念に基づいて実装されてるのかがわかってないと使いようがない。逆にそういった知識は3Dプログラミング全般で役に立つと思うので、もっと必死こいて勉強すれ!>オレ