7 月 21 2008

Papervision3Dでレースゲーム制作 05 - 遠くのモデルを非表示

Posted by tanjo at 4:26 PM

今回は実はかなり大事な処理です。
ゲーム好きの方ならピンとくると思いますが、PlayStationのレースゲームなんかでよく見られる「走っていくと少しずつ遠くのオブジェクトから表示されてくる」という処理を実装してみます。
といってもありがたいことに、Papervision3D 2.0 Alpha にはこの機能が実装されているんですね。FrustumCamera3D です。でも今までの FreeCamera3D から FrustumCamera3D に切り替えるにあたって、実は結構つまずきました。。。そのときの備忘録です。

まず、「遠方モデルを表示しない」機能のメリットは、「とてつもなく広大なフィールドが実現できるようになる」こと。
カメラからの距離に応じてレンダリングするポリゴンを制限できるため、フィールドがどんなに広くなっても描画処理自体の負荷はほとんど変わりません。レースゲームには必須ですね。(逆に箱庭式の3Dには不向き。)
しかも私の作っているゲームは、遠方のスケール感をごまかすために疑似3Dの地平線の位置を下げて描画しているので、遠くの3Dモデルは宙に浮いて見えるんです。(→前回サンプル
なんとしても実装しなければ!

FrustumCamera3Dについて

ざっくり Papervision3D 2.0 Alpha のカメラについておさらいしておきますと、次の3つがあります。
説明正確じゃなかったらすいません~。

Camera3D
常に3D空間の原点のほうを向こうとするカメラ。
よって Camera3D.rotationX とかで向きを変えたりはできない。またこのカメラを原点座標(0,0,0)に設置するとマズイらしい。視野角とかプロジェクションは、focus, zoom プロパティで制御する。
FreeCamera3D
座標や向きを自由に動かせるカメラ。
x, y, z, rotationX, rotationY, rotationZ プロパティが使える。要はフツーのカメラってことですね。プロジェクション方法は Camera3D と同じっぽい。
FrustumCamera3D
2.0 Alpha で実装された、視錐台を利用するカメラ。
ポリゴンを描画する台形錐?領域を空間上に設定して、その範囲を投影する。カメラの座標と向きは自由に動かせるが、rotation系のプロパティに不備あり。

FrustumCamera3D についてもう少し詳しく。

  • 定義はほかと全然違います。

    FrustumCamera3D(
    	viewport3D:Viewport3D,
    	fov:Number = 90,
    	near:Number = 10,
    	far:Number = 1000
    )
    
  • fov でカメラの視野角を設定します。単位は「度」。40~60度くらいが自然でしょうか。ほかのカメラとは違って、zoom, focus プロパティは使わないようです。
  • near, far でカメラからどのくらいの距離にあるオブジェクトを表示するか、を決めます。(正確にはクリッピング平面までの直線距離。) near が 0 以下だと動作がおかしくなります。
  • rotation系のプロパティは、取得はできるが代入しても描画に反映されないという現状です。しょうがないので pitch(), yaw(), roll() メソッドを使ってカメラを動かしました。それぞれ X, Y, Z 軸に対しての回転角度(←カメラの向きではない)を引数に与えます。
  • かなりピンポイントな現象かもしれませんが、読み込んだのモデルデータのスケールによって、クリッピングの判定がうまくいかないことがあります。「明らかに画面に収まる位置のポリゴンなのに、カメラの座標によっては全く表示されない」という現象です。
    解決策は、「とにかく大きくモデリングをすること」!3Dソフトの時点でかなり大きめにモデルを作っておいて、Collada.scale で縮小しつつサイズ調整する方法にしたところ、正常に判定されるようになりました。

実装してみる

さて、ここまで把握できれば、後はモデルを作って配置して微調整するだけです。

まずはカメラ作成。
床よりも3Dモデルのほうが遠くまで見えるようにしています。

camera = new FrustumCamera3D(viewport, 55, 10, 16000);
camera.y = 250;
camera.z = -400;

camera2 = new FrustumCamera3D(viewport2, 55, 10, 30000);
camera2.y = 250;
camera2.z = -400;

COLLADAモデルの配置。
なかなか中途半端な微調整をしています。3Dモデルの四隅に適当なモデルを作っておいて、それが床テクスチャの端っこにフィットするように、スケールや座標を調整していきました。

courseObjects = new Collada("courseModel01a.dae");

courseObjects.x = 35100;
courseObjects.z = 46200;
courseObjects.rotationY = -90;
courseObjects.scale = 1/3;

カメラの移動。
(ひどい式。自機の座標と向きから求めればよかった。。。)

camera2.z += (12000 / 360) * 6 * (myCurrentSpeed / myMaxSpeed) * Math.cos(myDirection);
camera2.x += (12000 / 360) * 6 * (myCurrentSpeed / myMaxSpeed) * Math.sin(myDirection);
camera2.yaw(deltaDirection * 180 / Math.PI);

これでようやくゲーム描画の基本部分はできあがってきました。

レースゲーム・サンプル画面

*ソースファイル Main.as の全文はこちらから参照できます。
(試行錯誤中のソースなんで怪しい行がいっぱいです。)

Leave a Reply