
attitude Control(要:FlashPlayer9)
haramakotoさんのエントリー「方向ベクトルからMatrix回転への変換」を読んで。
ある方向に形状の任意軸ベクトルを揃えることで、姿勢を制御するというお題。
haramakotoさんはクォータニオンで挑戦されているようなので、オレは行列でやってみた。正直言ってオレもよくわかってないんだけど、なんとなく上手くいったので書いておく。
例えば、ある形状のY軸を適当な方向に向けたい場合の手順は
- 姿勢をコントロールしたいオブジェクトのY軸ベクトルをゲット — [1]元の姿勢
- ゲットしたY軸のベクトルに目標座標のベクトルを加算して新しいベクトルをゲット — [2]変形後の姿勢
- [1]と[2]の外積をとって、法線ベクトル(回転軸)をゲット — [3]
- 二つのベクトルの角度をゲット — [4]
- [3]のベクトルと、[4]の角度でもって回転行列を作る
- 姿勢をコントロールしたいオブジェクトのtransformと合成
って感じで上手くいった。
姿勢をコントロールしたいオブジェクトのY軸ベクトルは、DisplayObject3Dのtransformプロパティを参照すれば、調べることができる。
| n11 |
n12 |
n13 |
n14 |
| n21 |
n22 |
n23 |
n24 |
| n31 |
n32 |
n33 |
n34 |
| n41 |
n42 |
n43 |
n44 |
|
transformプロパティ(Matrix3D)の各列、
|n11,n21,n31|、|n12,n22,n32|、|n13,n23,n33|は、形状のX,Y,Z軸の単位ベクトルを示してる。なので、ある形状Obj(DisplayObject3D)の各軸のベクトルは、
X軸:Xvec:Number3D = new Number3D(Obj.transform.n11, Obj.transform.n21, Obj.transform.n31);
Y軸:Yvec:Number3D = new Number3D(Obj.transform.n12, Obj.transform.n22, Obj.transform.n32);
Z軸:Zvec:Number3D = new Number3D(Obj.transform.n13, Obj.transform.n23, Obj.transform.n33);
として取り出すことができる。これで、ある時点での形状の姿勢がわかる。ここまではyamasvさんの「回転行列の列ベクトル」の解説が詳しい。
「ゲットしたY軸のベクトルに目標座標のベクトルを加算」ってのは、自分も理解できてない。感覚的にこうじゃねーの?とかいうドンブリ勘定実装したら上手くいっちゃったので説明できない。わっはっは。…申し訳ございません。最初は目標座標のベクトルを加算せず、目標座標のベクトルをそのまま使ったんだけど、それだとリボン状にPlaneが並ばなかった。
残りの手順は、[Papervision3D2.0] Quaternionと同じ要領で、最終的に姿勢をコントロールするコードは以下のような感じになった。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| //ある方向に向けたい軸
var StartVec:Number3D = new Number3D( obj.transform.n12, obj.transform.n22, obj.transform.n32 );
//目標になる座標
var TargetPoint:Number3D = new Number3D( 目標のX座標, 目標のY座標, 目標のZ座標 );
//元のベクトルを揃わせたい最終的なベクトル
var EndVec:Number3D = Number3D.add( StartVec, TargetPoint );
StartVec.normalize();
EndVec.normalize();
//2つのベクトルの法線ベクトル(回転軸)
var vcross:Number3D = Number3D.cross( EndVec, StartVec );
vcross.normalize();
//2つのベクトルから回転角度(ラジアン)算出
var rot:Number = Math.acos(Number3D.dot( StartVec, EndVec));
//ベクトルを合わせるための回転軸と角度から回転行列作成
var mat:Matrix3D = Matrix3D.rotationMatrix(vcross.x, vcross.y, vcross.z, rot);
//行列を適用
obj.transform = Matrix3D.multiply3x3(mat, obj.transform); |
あと、wonderflに上がってたharamakotoさんのコードをforkして、行列での姿勢制御版を作ってみた。
ここらへん、ちゃんと理解したいなぁ。