『 drawTrianglesで球面マッピング 』
2009 年 12 月 20 日既視感ありまくりのエントリで恐縮なのですが、今までGraphics.drawTrianglesを使ったことなかったのと、仕事で必要になったので勉強しました。
外部から読み込んだ画像をテクスチャとして球面上にマッピングしています。
パースはつけていません。
一応最適化ということで、頂点をなるべく重複点させないようにしています。ただし画像の端に対応する頂点が反対側の端と(極に関しては隣とも)うまくマージできずにほったらかしなので、頑張ればもうちょっと減らせると思います。
迷ったのが、多数の3次元座標を Matrix3D を使って一括投影するのに、
Utils3D.projectVectorsとMatrix3D.transformVectorsがあるということ。
前者は2次元座標に、後者は3次元座標に投影してくれる。投影後にzバッファしようと思ったら、projectVectorsは第3引数で渡したuvtのうちtに奥行きが入っているのでそれでソートしてやる。transformVectorsなら3次元座標のzを使えばよろし。
今回は球体ということで、z バッファは必要なかったので(視点と逆向きの法線ベクトルを持つポリゴンのみを描画すればよい)、drawTrianglesの第4引数であるcullingの値を適切に設定することでこっち側向いてるポリゴンだけ描画しました。
具体的にはポリゴンを形成する頂点を時計回りで指定して、球体の内側から外側に向かって面の法線ベクトルを伸ばしてます。このときcullingにTriangleCulling.NEGATIVEを設定すれば、あっち側(視点ベクトルと同じ方向)を向いてるポリゴンは描画されないのでいい感じ。球体を内側から見る場合にはTriangleCulling.POSITIVEにする。
話を戻すと、projectVectorsでもtransformVectorsでもどっちでも良かったので、両方やって速い方を使うことにしたのですけど、両者ほとんど差がない。一瞬transformVectorsのが速い気がしたんだけど多分気のせい。
やってる途中でハマったのが、projectVectorsで投影後のuvt値のうち、t値がどうしても全部1になってしまう問題。これはpsyarkさんに教えてもらって理解。多謝。
@alumican_net 全部1になるのは、第一引数のMatrix3DがProjection行ってないからではないかなー [link]
PerspectiveProjection#toMatrix3D使うと計算楽だよ [link]
Projection行ってるかどうかは、Vector3Dを変換してwが大きくなるかで分かります。もしくはMatrix3Dの4列目に0以外があるかどうか(これはあまり自信なし) [link]
普通はrawData[11]が1とかになる。z→wにするために。 [link]
Matrix3DにPerspectiveProjectionを設定しないとダメらしい。並行投影なのでその辺を端折ったのがいけなかったのか。
最後に、drawTrianglesは意外と重い、期待値が高かっただけに拍子抜け。
限定的な使い方に絞って最適化頑張って、やっとPapervision3Dに勝てるくらい。
描画する頂点を全部まとめて毎フレーム1回のdrawTrianglesに押さえてはいますが、それでも結構くる。しかも残念なことに描画頂点数というよりは、むしろ描画領域が速度に大きく影響している。見えてないポリゴンをdrawTrianglesに渡さないとか色々試してみたけど結果はほとんど変わらず(むしろVectorを作り直すのに時間が余計かかったくらい)。結局画質を落とすのが一番パフォーマンスを上げるという結果になって萎え~。
とはいえdrawTrianglesを使えば簡単にかなりトリッキーなことができるので、使いどころを考えればおもしろい表現ができるはず。まだ完全には理解してないので、もっといい最適化手法がありそう。