過去の独りごち/独りごとはこちら
過去のJavaアプレットは
こちら

 

9/9 これから

 えーと、あっという間に9月に入り、そろそろ上旬も終わりという頃ですが、先月中ごろからやってるブツのサンプルがまだですねぇ。


OctTest.zip
1.34M ソース+バイナリ

 というわけで、はいっ。

逆向きに走るお父さん
…衝突中は衝撃のため、透けて見えます

 サンプルのテクスチャはLemogにて公開されている物を使用させていただきました。ありがとう、メルシー。とかカタカナで書いてもなぁ… あと、お父さんは常に逆走しますが、お父さんのZ軸が逆転しているため、そういう事になってます。うわ、手抜き!

 それから、カリングのルーチンもちょっとまだ不満がありますね〜。時々めり込みもしますし。ただ、めり込みは起こるけど、突き抜けはなかなか起こらないと思います。 また、両面張りになっているポリゴンの間に挟まれて動けなくなるという仕様も持ってます、トホホ。

 そういえば、方針を少し変更しまして、結局Octet-treeで衝突検出を行うようにしました。一週間ほど取り組んだBSPではバグが取りきれなかったので、これは方向転換したほうが早いと判断したところ、三時間ほどでBSPでの実装に追いついてしまい…。 衝突検出よりも、使いまわしのかなり効く衝突応答の方が厄介なのと、一週間のうち半分は衝突応答に取り組んでたので、まあよしとしますか。

 ただ、このお蔭でBSPもOctet-treeも一長一短であると分かりました。いやホント。

 唐突に両者を比較してみると、BSPの場合の利点は

  1. 異なるノードに同じポリゴンが重複して含まれることは有り得ない、という事が保証される
  2. Quake3マップなどのローダーを作っておけば、自作のアプリでQuake3用のレベルエディタが使える
  3. ポータルシステムを導入すると特に屋内でのシーンではカリングについての強力なヒントになる

 案外大きなメリットだったりします。異なるノードで重複したポリゴンを持つ可能性が無い、というのは実は大きな利点です。2は…BSPというやり方自体には何の関係もないんですが、そういう発展の仕方もあるかな、という事で。ライセンスフリーなレベルエディタを探してくれば、色々面白い事出来そうです。ただ、そんなQuake3ツクールみたいなのでゲーム作っても面白く無さそうなので、僕個人としてはそんなに魅力的な要素じゃないんです。Metasequoiaで作ったモデルを読めれば必要にして充分と既に判断していますし。

 さて、話を戻してBSPの欠点を挙げて行くと

  1. 空間を分割していく過程で、元の地形がズタズタになり、ポリゴン数が爆発的に「増えたようにみえる」
  2. 凸な空間をそれ以上分割できないので、例えば正100面体だけ置いたシーンなどでは全く有効性が無い。
  3. 分割時の計算の過程で浮動小数演算の精度の問題が顕著になる
  4. どのポリゴンがどのノードに入るのか予測が出来ないため、デバッグが面倒
  5. 1ノードあたりのポリゴン数をコントロールできない。
  6. 1ノードがシーン全体に占める割合を予測できない
  7. ツリーを作った後から1ポリゴンだけシーンに追加、削除といった事に計算コストがかかる
  8. ポータルを作らないとカリングのための手がかりが得られない

  実はそんなに酷い欠点でもないんです。特に2とかは、「クイックソートでは逆順にソートされたデータは、極端に遅い」とか言ってるような物で、普通のケースでは問題になりえません。気になるとすれば、まぁ6や7くらいでしょうか? とりあえず、分割時の計算には工夫が要りそうです。理論どおり実装すると、必ず浮動小数演算の精度の問題が出てきます。

 それに対して、Octet-treeの利点は、

  1. 1ノードの占める大きさがはっきりしており、大きさ自体もコントロールできる(ノードごとに独立してコントロールというのは無理だが)
  2. どのノードに注目しているポリゴンが含まれるのか、予測が立てられるため、デバッグに役立つ
  3. カリングのための手がかりは、ツリー自体が持っている

 欠点を挙げると

  1. 異なるノードで同じポリゴンが重複して含まれることがある
  2. 狭い空間に密にポリゴンが並べられているような場所に弱い
  3. BSP同様、ツリーを作った後から1ポリゴンだけ追加、削除といった事に計算コストがかかる

 つまり、とっつきやすい、というのがOctet-treeの長所です。特に長所4が大きいと言えそうですが、実は僕の実装では、Octet-treeはカリングには一切利用してなかったりします。というのも、短所1にあるように、ノードごとに重複するポリゴンを弾くためには重複を検出して弾く手間と、IndexBufferを毎フレーム作り直す手間があるため、パフォーマンス的にかえって良くないのではないかという危惧があるためです。勿論、前のフレームとの差分を取るなどすればそうしたロスはかなり抑えられるかもしれませんが、僕の実装ではIndexBufferもVertexBufferも全く書き換えなくてもよいように、前もってマップを構成するメッシュを512ポリゴン以下、などのある程度の大きさで分割しておき(分割後のメッシュはフラグメント、とでも呼びます)フラグメント単位で可視判定と描画を行うようにしています。

 とりあえず、色々と自分なりに考えて実装してみたんですが、ゲームコンストラクターというよりゲームコンストリクターとでも言うべき、使う事によってゲームデザインの方向性まで変えてしまうような代物はあんまり作りたくないので、エンジンとかライブラリというより使いまわしの効くサンプルのような位置づけにしておきます。

 今後の予定としては、

  1. カスタム当たり判定ルーチンの実装ができるように…現状では壁ズリする楕球しか扱えないです
  2. 自分の作品に活かしつつ、バグ取り
  3. バンプマップやライトマップ、カスタムシェーダへの対応

 オクルージョンカリングとかも魅力的ですが、仕様を発散させていくより1と2を確実にこなしていくほうが良さそうな気がするので、まずはそこから、と。

Taku Hayase(SANDMAN)

戻る