飴屋

Flash3D/操作の道具

操作=計算

前回、操作の対象が2つや3つの数字の集まりであり、それが点や位置や運動や面積(体積)を表すというような話をしましたが、数字が集まっただけでは何のことやらさっぱりわかりませんので、その数字が何を意味するのかを定義したり、数字同士を計算して、Flash上で操作できるようにする必要があります。後者にはNumber2DやNumber3Dがあるorg.papervision3D.core.mathパッケージの中のクラスがいろいろ使えそうです。

例えば、3次元上の点を平行移動したい場合、(1,2,3)という三つの数字の組み合わせで点を表して、それぞれ、x軸方向、y軸方向、z軸方向にどれだけ移動させたいかをやはり3つの数字で表せます。例えば、全ての軸の方に1つずつ移動させたい場合、(1,1,1)という移動の向きと量で表します。平行移動する点にこの3つの数字を足し合わせると(1+1,2+1,3+1)=(2,3,4)という移動後の点を表す数字になります。すごく簡単ですし、Number3Dクラスのメソッドで計算してくれます。

また(1,2,3)という最初の点の位置を原点から3倍遠い位置に移動したい場合、それぞれの数字に3をかけることで(1*3,2*3,3*3)=(3,6,9)とあらわせます。これもNumber3Dクラスのメソッドで計算してくれます。

もう一つ点(1,2,3)をy軸に対して90度回転させるという操作もNumber3Dクラスのメソッドで計算してくれました。y軸を軸に回転するのでyの数値はそのままで、xとzの数値は三角関数を使って計算されます。(1*cos(90)+3*sin(90),2,3*cos(90)-1*sin(90))=(3,2,-1)。他の軸も同様に三角関数で計算できます。

行列(マトリックス)を使う

点に行う操作(計算)はNumber3Dでできることはわかりましたが、複雑な操作になるとメソッドをいくつも呼び出さないと結果が得られなくてとても煩雑になります。また、反復的に行う操作をその度にプログラムするのは正直しんどいです。なので、この移動操作を表すクラスがあったら便利だと思った人がいたのかどうかは知りませんが、行列を使って簡潔に拡大縮小、平行移動、回転移動を記述できるんだそうです。行列というのもNumber2DやNumber3Dと同じく実数が集まったものですね。ただ、(x,y)や(x,y,z)と違って、「行」と「列」という2系統の数字の集め方をしているのが行列なんだそうです。3系統以上あるやつもあるのかもしれませんが、使い道がわからないし、知りません。

3DCGでよく使う行列は3x4の12個の数字を持つ行列とか4x4の16個の数字を持つ行列です。あと、Number2DやNumber3Dも2x1、3x1とみなして考えることもできますね。行列同士は掛け算できまして、点の位置と3x4の行列の掛け算の結果が操作後の点の位置になっているのでびっくりですね。

しかし、12個の数字のどこにどの数字を入れたらどんな移動ができるのかよくわからない人も多いと思います。私もちゃんと覚えてません。そんなときには単位行列というやつを用意して順番に「(10,5,9)平行移動しろ!」とか「Z軸中心に30度回転しろ!」とかを意味するメソッドを呼び出してやればいいのだそうです。

Papervision3Dでは、org.papervision3d.core.math.Matrix3Dというクラスがこの行列を表しています。Matrix3D.IDENTITYというのが単位行列を表しているので、translationMatrix(a,b,c)というメソッドの返す平行移動を表す行列掛け算して合成すると平行移動を表す行列ができあがります。座標の行列にこの平行移動を表す行列をかける度に何度でも(a,b,c)方向に平行に移動し続けます。

行列を扱う時によく失敗するのは行列をかける順番を間違えて、予期せぬ移動が発生することですね。「右を向いて10歩進む」のと「10歩進んで右を向く」のでは操作が同じでも順番が違うので、移動先が変わってしまいます。

行列で操作を表すと、他にも嬉しい特典がありまして、座標Aから座標Zに移動するのに行列Xを用意すると、AからZまで移動する途中の座標Bへの移動行列を行列Xから逆算できるのです、確か。簡単に言うとアニメーションを行う際に中間フレームを表示するための行列の計算が簡単だってことです。

クォータニオンを使う

org.papervision3d.core.mathパッケージには、Quaternion.asというクラスもありました。これは4つの数字の集合でMatrix3Dクラスでは表現するのが大変な操作(任意の軸を中心に回転する操作)に役立つクラスのようです。

射影変換

行列を使った操作といえば大事なものがもう一つありました。立体物を平行移動させたり、回転移動させたりするのは、立体物を構成する全ての点に対して、上述の行列をかけて移動計算を行えばよかったのです。さて、3次元表現はそれでいいとして、実際にFlashのスクリーンではそれを2次元に落とし込まなければいけませんでした。3次元を2次元に変換するのも行列を使ってできます。これは射影という用語を使って説明されるそうです。

射影と関係するのは3Dシーンを切り取るカメラに関するパラメータです。カメラ自体の位置と、カメラの被写体の位置と、カメラを構える角度でスクリーンに何が映るかはほぼ決まりますので、それぞれの数値をセットした行列が必要になります。

また、人間の目のように一点から広がるような視野を持つと映像に遠近感が生まれます。CGでは別に人間の目にこだわる必要がないので、視野の広がり方の角度を指定することもできます。

あとは実際に表示する2Dスクリーンの縦横サイズが決定すれば、カメラに映ったものを適切なサイズで投影することができます。これらの一連の計算が行列を使ってされています。逆の操作で2次元座標を3次元の軸に変換することができます。マウスでクリックされた位置にある物体を取得するときなどに使えますね。

papervision3Dでは、org.papervision3d.camerasパッケージにカメラに関するクラスが用意されています。カメラに関するクラスは規定クラスにorg.papervision3d.core.proto.CameraObject3Dを持っていました。そこにはeyeという名前のMatrix3Dがありましたので、これでカメラの向きや位置の移動状態を表しているのだと思います。

org.papervision3d.viewには投影されるスクリーンに関する情報を定義できそうでした。どこまで実装されているかわかりませんが、投影された結果をさらに別の場所に投影するような仕組みもできているのかな・・・?

Flash3D