Google Chrome または Safari を使用される事を強くお薦めしますw
他のブラウザでは Javascript の処理が重いです(汗)


2010/10/13

リアルタイムで3D迷路を表示する

リアルタイムで3D迷路を表示するためにはなんとかして計算の回数を減らす必要があるのですが、ここではそのテクニック(?)を紹介します。

まず、div の border を使って台形を表示する、てのがこの3D迷路の大元になってます。これについては過去ログ参照ということでまた解説することはしませんが、 div を使うことでブラウザでも高速にポリゴンらしきものを表示することができます。

とはいえ、それを表示するためにいっぱい計算していたのでは遅いので、いろいろとごまかしながら計算をガンガンはしょります。

以下はゲームのメインスクリーンですが、画面中央に赤で水平線を引きました。これに注目。


この線を境に図形は上下で対称になっています。
つまり、上半分で計算したものはそのまま反転して下半分の表示に使っているわけです。
本来四角形を3D→2D投影する場合には4頂点すべてを計算しなければなりませんが、このように表示することで2頂点だけの計算で済ませています。

さらに壁の高さはすべて同じ、すなわちY座標は一定です。これはY座標を0(ゼロ)にして計算していることと同じで、実際に計算するのは横方向(X)と奥行き方向(Z)だけになります。つまり3Dの計算ではなく2Dの計算で済んでしまうということです。
軸が1本無いことで削減できる計算量は相当なものになります。
(表示する際のY座標の値は奥行きZの値の比例で表されます。要するに奥にあるものはZの値に応じて値を小さくするだけです。)

次にクリッピングです。これは見えない部分をカットするということです。プログラムは馬鹿正直ですから実際には見えていないものでも0で割るとかいう事態が起こらない限りまじめに計算します。
その結果本来視角の外にあるものでも表示しようとしてワケのわからない図形がお目見えすることになります(たとえば本来真後ろにある図形をまじめに計算すると虚像が出現します)。
もちろん見えるべきでないものを計算する時間がもったいないですから、見えるものだけを計算すべきです。

下は他所からちょいと拝借してきた3Dクリッピングの図です。


原点が視点、Z方向が視線の向きです。角θ(シータ)は画角です。これが小さいと望遠、大きいと広角になります。面aはフロントクリッピングプレーンと言い、これより手前のものは表示されません。面bはバッククリッピングプレーンと言い、これより向こうにあるものは表示されません。
通常面aは画面の表示領域と一致しています。つまりこの面に投影された図形がそのまま画面に表示される図形となります。
全体としてグレーの四角錘台(視錘台といいます)の内側にあるものだけが面aに投影されるように、視錘台の外にあるものを排除する作業を行うことになります。

ここで、ただ単に排除するだけなら良いのですが、図形をこの視錘台の6面で切ることになる場合もあります。たとえば直線の2端点P1とP2のうち片方が視錘台の内側、もう片方が外側だと、この直線を切らないといけません。また、P1P2の両方が視錘台の外だけれども線の中央部分は視錘台の中ということもありますので、線を2箇所で切るなんてことも必要になります。

このように図形をちょん切ることをクリッピングと呼ぶわけですが、 線ならまだしも面を切ると切り方によって三角形になったり五角形になったりして div では表現できませんし、そもそも切るロジックが面倒くさすぎてクラクラしますw 当然処理時間は無茶苦茶に長くなります。

そこで今回のゲームではこのちょん切るという作業は一切行っていません。
単に視錘台の外なら表示しない。少しでも視錘台の中に入っているなら全部表示、ということをしています。

当然視錘台の外にあるものを表示すると変なものが表示されたりしますので、いくつか手を打っています。

手その1:面aの外周より外側に描画しないよう、面aに相当する div に対して overflow:hidden を設定する。
→実際にはゲームのメインスクリーンの外側にも描画してしまっているのですが、HTMLの機能でそれを表示しないようにしています。

手その2:視点よりも後ろにあるものを表示しないよう、視点と面aの距離を十分に取る。
→視点よりも後ろにあるものを描画すると虚像が現れます。図形の頂点全てが視錘台の外にあれば表示しないロジックなので、面aにある頂点を置いたときに、そこからもっとも視点側にある頂点がそれでも視点よりも奥に(Zの正方向に)あれば虚像になりません(それよりもポリゴンが手前に来ると全頂点が視錘台の外になるので表示されない)
このゲームでは表示する図形は全て同じ大きさの直方体なので、その対角線よりも長い距離が視点と面aの間にあれば良いことになります。

字でずらずら書いても分かりにくいので図示します。上(Y軸の正方向)から見下ろしたと思ってください。

 上の方で3次元ではなく2次元で計算していると書きましたが、 実際この図のような平面で考えた計算を行っています。

ゲームメインスクリーンの overflow : hidden をはずすとこんな風になりますw


では、どうやって視錘台の内外を判定するのかですが、長くなったので、それは次回に。

0 件のコメント:

コメントを投稿