飴屋

Flash3D/レンダリングフロー

レンダリング

表現の対象である立体(点の集合)を移動操作した上で、平面に投影するところまで何となくわかったので、3Dエンジンが最低限やるべきことは知ったかぶることにします。それではPapervision3Dでは、その一連の処理がどんな風に行われているのでしょうか。この一連の処理をレンダリングといいます。

org.papervision3d.renderパッケージの中にレンダリングエンジンを表すクラスがありましたので、そのうち基本的なレンダリング処理を行うであろうBasicRenderEngineクラスが理解するのによさそうなので中身を眺めてみることにしました。このクラスはorg.papervision3d.core.render.AbstractRenderEngineを既定クラスにもっていて、org.papervision3d.core.render.IRenderEngineのインターフェイスを持っているそうです。

インターフェイスをみれば、なんとなく最低限やるべきことがみえてきそうです。IRenderEngineの中には、renderScene、addToRenderList、removeFromRenderListという3つのメソッドがありました。
renderSceneメソッドは引数のSceneObject3DをCameraObject3Dで撮影してViewport3Dに投影するメソッドのようですね。
addToRenderList描画対象を追加するメソッドで、removeFromRenderListは描画対象を削除する処理のようです。ここでいう描画対象はIRenderListItemクラスで表現されています。どうもorg.papervision3d.core.render.commandパッケージの中に具体的な描画対象が定義されていました。名前から察するに「Fog(霧)」「Line(線分)」「Particle(パーティクル)」「Pixels(点)」「Triangle(三角形)」「VectorShape(ベクトルイメージ)」を描きこむクラスがそれぞれあるようです。

何となくレンダリングを実行するメソッドと、レンダリングの対象を増減させるメソッドを持っていることがわかったので、BasicRenderEngineクラスに戻ってみます。このクラスの持つ変数にIRenderSorter、IRenderFilterという変わったクラスのインスタンスがありました。どうもこれはそれぞれ、レンダリング対象物のレンダリング順を変えたり、不要な物体の計算を省くようにレンダリング対象から一時的に外す(フィルタリング)するもののような気がします。
前者は描画の順番を入れ替えないと前面にあるポリゴンが背面にあるはずのポリゴンに隠れてしまうというのを防ぐために必要な処理です。確か、Papervision3Dでは標準的にZソートという方法を使ってレンダリングの順番を決定していた気がします。この方法は万能ではなくて、ポリゴンの形状によっては、部分的にポリゴンがかけてしまうおそれがあり、結構調整に苦労させられた記憶があります。これを補うためにポリゴンを複数に分割して描画の矛盾を軽減してくれる方法も提供されているのですが、計算量が増えるのでむやみやたらに使うわけにはいきません。
後者はFlash上で3D空間を投影するViewportの外側にあるポリゴンや、カメラに近すぎたり遠すぎたりするポリゴンをフィルタリングして計算コストを削減する仕組みだと思います。って思ってBasicRenderFilterの中身をみたら{return 0;}なだけでロクにフィルタリングしてませんでした。理由はわからないですが、とりあえずみなかったことにしましょう。

他にStopWatchなんていう面白そうなクラスを使っているのをみつけました。アニメーションとかに利用する時間を計測するクラスなんでしょうかね。私はPapervision3D標準のアニメーション機能を使ったことがないのでよくわからないのでした。

では、次にrenderSceneメソッドの中身をみてみましょう。これは引数にSceneObject3D、CameraObject3D、Viewport3Dをとるメソッドで、呼び出されるごとにViewport3Dにレンダリング結果が反映される内容になっています。その詳細はRenderSessionDataクラスのインスタンスを用意して、必要な情報をまとめて、ProjectionPipelineに投げています。BasicProjectionPipelineでは、受け取ったそれらの情報を元に3Dオブジェクト(DisplayObject3D)のprojectメソッドを呼び出しています。このメソッドによって

  1. DisplayObject3Dの位置行列に所属するDisplayObjectContainer3Dの位置行列を順番にかける
  2. シーンの位置行列までかけ終わったら、カメラの位置行列をかける
  3. ビューポート変換をかけて、立体オブジェクト(DisplayObject3D)をムービークリップやらスプライト(DisplayObject)などに変換(射影)して描画対象リストに挿入する
  4. 変換の際得られた奥行き(Z値)を返す

ということをやります。その後、処理はdoRenderメソッドに移ります。

ここでさっきのストップウォッチをリセットして再スタートさせ、マテリアルの準備を始めます。マテリアルについてはいまは無視します。
そして、BasicRenderFilterで要るのか要らないのかわからないフィルタリング処理をして、さっき計算したZ値を元にオブジェクトの描画順を並び変えます。あとは並び変えた描画対象リストを順番に一つずつビューポートに並べていきます。

これで立体物が平面に描画されるレンダリング処理は完了です。次の処理が呼び出されると、現在描画されている平面オブジェクトは一度クリアされます。

ビュー

レンダリングの中身はわかりましたが、誰がレンダラにrenderSceneさせているのでしょうか?それはビューというものだそうです。org.papervision3d.viewパッケージにBasicViewという基本的なビュークラスが用意されています。ビューは初期処理でビューポート作ってくれたり、カメラを用意してくれたり、シーンを準備してくれたりしました。この三つをさっきのレンダラに渡して、Event.ENTER_FRAMEの度にレンダラのrenderSceneメソッドを呼びだしてくれるところまでやってくれます。

早足でしたが、やっとPapervision3dが立体表現をどうやって平面に落とし込んでいるのかの全容がみえてきた気がします。

Flash3D