ホーム < ゲームつくろー! < DirectX技術編 < あべこべにしちゃいけないカメラと座標系とDirect3D


その15 あべこべにしちゃいけないカメラと座標系とDirect3D



 3D空間は直交座標であればXYZ座標系が用いられます。今ご覧になっている画面の横方向(左→右)をX軸、上方向(下→上)をY軸と考えてみてください。するとZ軸は画面を突き抜ける軸となります。この時、皆さんから画面に向かって突き抜けるZ軸と、画面の奥からみなさんの方向に迫ってくるZ軸があります。奥に行ってしまう場合を『左手系』、向かってくる場合を『右手系』座標と言います。これは、親指をX軸方向、人差し指をY軸方向としたときの中指の向きを見て判断できます。

 DirectXは左手系座標で考えられています。もちろん右手系も扱うことは出来ますが、ちょっとした座標変換が必要になったりします。頂点を繊細に扱っていくときに、この座標系をあべこべに考えているととんでもなくやっかいになっていきます(←自分への反省(-_-))。そうならないためにも、この章では座標系、カメラとDirect3Dについてまとめてみます。



@ どうして左手系なのか?

 そもそも、左手系と右手系の2つある中でDirectXが左手系を選んだのはなぜなのでしょうか?私たちは小さい時から右方向がX軸、上方向がY軸の2Dのグラフを見てきました。そしてごく普通にアニメや漫画のキャラクタは上方向であるY軸に頭を向けて立ちます。さてこの状態で3Dになった時、キャラクタの目線は画面の奥に向かうのが自然でしょう。そうすれば、キャラクタの目線方向とプレーヤーの目線方向も合います。「前へ進め!」とボタンを押したとき、画面の奥に向かっていくのが自然なのです。Z軸が画面の奥へ進む座標系は『左手系』です。この自然な成り行きでDirectXなどの3Dゲームは左手系座標を採用しています。



A Direct3DのカメラがZ軸方向固定の理由

 3Dになった時、ワールドの上方向は@の理由からY軸となります。皆さんが見ている画面の上方向に空がある状態です。ここで皆さんがカメラで画面を撮影する事を考えてみてください。画面にカメラを向けますね。Direct3Dのカメラは正にこれと同様の事をしています。つまり、Direct3DのカメラはZ軸正方向を向き、Y軸方向を上とする固定カメラとするのが自然なのです。

 実はこうする事で2D画面との整合性も取れます。Direct3Dで2D画面を作成する時は、これまでと同様にXY平面で物を考えられます。カメラはZ軸方向のマイナス位置に引いた位置にいるわけです。3Dの空間として2Dゲームを捕らえてしまうと、ついつい「地面に2D画面がある状態」を想像してしまいます。しかし、3D空間での地面はXZ平面です。これを間違うと、オブジェクトを思うように操作できなくなります(私はこれにしっかりはまりました(^^;)。


B 座標系はポリゴンの作り方も変える

 左手座標系をしっかり意識するようになると、ポリゴンの作り方も自ずと決まってきます。作ったキャラクタの上方向はY軸です。そして、キャラクタが見つめる方向はZ軸となります。こうすると、キャラクタの右方向がX軸となり、自然な考えと一致するようになります。ローカル座標でこれをしっかり守っていれば、余計な角度調整などは必要なくなります。

 何より重要なのが法線の決定です。Direct3Dでは『各頂点が時計回りの順に定義された面を前面として描画する』ときっちり定義してあります(マニュアル:Direct3Dの基礎知識→3D座標系とジオメトリ→面法線ベクトルと頂点法線ベクトル)。これは左手系座標ならば正しくなりますが、右手系座標だと法線が真逆になってしまいます。頂点を読み込んで描画してみたら、何だかポリゴンの前後関係が変に見えた、こういう時は座標系と頂点の順序(そしてカリングをちゃんと設定しているか)を再検討してみるべきでしょう。

 上の図は3頂点で定義される三角形ポリゴンの左手系座標における法線の向きを表しています。頂点は1、2、3の順に定義されたとします。上の法線がちゃんと左手系であるかを確認するには、まず頂点1から頂点2に向かって左手の親指を伸ばします。次に、頂点2から頂点3に向かって人差し指を差します。そうすると、自ずと中指が上のずにある方向を向くのが分かると思います。このチェック方法は原始的かもしれませんが、座標系の感覚を間違えないようにする最も直感的な方法です。



C 回転方向は反時計回りきりもみ飛行

 座標系で頭を悩ます更なる要因は回転方向です。Direct3Dでは「原点の方向を見て時計回りが正の回転」と決められています。私個人的なイメージは「反時計回りにきりもみ飛行」なんです。飛行機が進む方向を軸方向とした時に、飛行機が反時計回りにきりもみ飛行をする時が正なんだと、いつもイメージしています。これは好き好きですが、やはりあべこべにしてはいけない約束事です。独自の回転行列や回転クォータニオンを定義する時には特に注意する必要があります。



D テクスチャ座標は要注意

 ここまで左手系座標を見てきて、非常に整合性の取れた自然の考えである事を示してきましたが、テクスチャ座標だけはちょっと違います。テクスチャ座標は「スクリーン座標」で考えられています。スクリーン座標とは、画面の左上を原点として、右方向をX軸、下方向をY軸とするコンピュータ独特の座標系です。これは、射影変換されて2Dとなったオブジェクトに貼り付ける仕様になっているからです。複雑な形状のポリゴンのテクスチャ座標を手打ちする事は普通ありませんが、ビルボードのテクスチャ座標を設定するときなどは頂点のローカル座標とテクスチャ座標のマッピングを間違えないように注意します。ローカル座標は横方向をX座標、上方向をY座標とするので、テクスチャ座標と上下が逆さまになります(筆者はまりその2でした)。



E ビュー変換行列と射影変換行列作成に注意

 筆者はまりその3です。レンダリングパイプラインに渡すビュー変換行列と射影変換行列は、座標系にあわせなければなりません。ビュー変換行列および射影変換行列を作成するヘルパー関数は、右手系左手系両方が用意されています。これを1つでも間違うと、レンダリングがまったくおかしくなってしまいます。私は射影変換行列をうっかり右手系のままにしてしまって、画面にオブジェクトがまったく表示されなくなり、泣きながらバグチェックをしました。皆さんはそうならなにように気をつけて下さいね。



F 意外な盲点「カリング」

 レンダリングステートには「カリングの設定」があります。カリングはカメラから見て後ろを向いているポリゴンを描画しない手法で、設定すればDirect3Dが自動的に行ってくれます。このカリングにも左手系と右手系があります。左手系を設定するにはレンダリングステートに以下のフラグを設定します。

カリングを左手系に設定
dev9->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW);

 右手系の場合はD3DCULL_CWを設定します。これを間違ってしまうと、裏側にあるポリゴンのみが描画されると言う摩訶不思議な事になってしまいます。



 以上のように、座標系は実は最初に決めなければならない重要な事項なのですが、筆者はおろそかにしてえらい苦労しました。しかし、一度決めてしっかりと設計すると、まるでパズルが合わさるようにすべての座標計算がきっちり整合を保つようになってきますので、皆さんもチェックしてみてください。