ホームゲームつくろー!衝突判定編< 床ポリゴンの高さを得るには?

3D衝突編
その8 床ポリゴンの高さを得るには?


 そろそろ実用的な衝突を見ていくことにします。この章では、3DのアクションゲームやRPGなどでは必須である「床ポリゴン」との衝突について考えてみることにします。ただ、ポリゴン同士の衝突を考えるととてつもなく面倒になってしまうでしょうから、ここではポリゴンと点や線の衝突で話を進めます。



@ 床ポリゴンの高さは立ち位置を決める

 床ポリゴンは平らかもしれませんし、ぼこぼこと起伏があるかもしれません。いずれにせよ、床はポリゴンで出来ているとします。「床」というのは、その背後に「重力」を暗黙に仮定しています。だって、壁を見て「床だ」と言う人はいませんよね(笑)。ですから前提として、床ポリゴンの空はY軸方向だとしましょう。重力は-Y軸方向ということです。床は通常XZ平面に極近い部分に広がっていますが、一概にそうと言い切れるものでもありません。坂を下り続ければ、XZ平面がどんどん遠く(多分空の方へ)離れてしまうでしょう。しかし、地図を見るのと一緒で、空のかなたからXZ平面を見れば、大体の地形がわかる。床はそういうものだとしておきます。

 さて、ゲームの主人公は大地を駆け回ります。この時、主人公の位置をXZ平面で記述すると簡単です。つまり、真上から眺めれば、主人公の奇跡をXZ平面の地図として残せるということです。これは、3Dのゲームを2Dのゲーム(真上から見たRPGなど)にしたのと一緒です。しかし2Dと異なるのは、重力のある3Dには「高さ」の概念があることです。真上から見て同じ地点にいるとしても、それは0cmの高さ(Y成分)かもしれませんし、1000mの高さかもしれません。主人公の立ち位置を3次元で決めるには、高さを固定する必要が出てくるわけです。

 主人公が床の上に立つ時、それは、主人公が「床の高さにいる」という事になります。つまり、「あるXZ座標にいる主人公の立つべき高さは、その地点での床の高さである」と言えるでしょう。これは、「あるXZ座標における任意の床ポリゴンの高さ」とも言えるでしょう。さて、床ポリゴンの高さを得るにはどうしたら良いのでしょうか?



A 三点測量法が大活躍!

 実は、床ポリゴンの高さを測るのは簡単なんです!というのも、世の中にはそういう事を必要とする場面がちゃんとあるからでして、その方法論も確立されています…と思い三点測量をネットで検索したのですが、驚くほど少ない…そういうものなのでしょうか。兎にも角にも、三点測量の技術は、床ポリゴンの高さを得るのに直接利用できます。

 床ポリゴンとは、Direct3Dで言えば1つの三角ポリゴンです。三角ポリゴンは3つの頂点で構成されます。これら頂点は空間内で座標として表されます。このあたりは問題ないですね。さて、これを重力のある空間で捕らえるならば、各頂点のXZ座標がその頂点の地図上の位置、そしてY座標が高さという意味になります。この条件は、三角測量の条件そのものです。

 3点で決まるもの。それは「平面」です。平面は必ず「法線」を持ちます。今、3点A、B、Cが与えら得ている時に、その法線ベクトルは次の式で表されます。

この法線、点の取り方によって逆さまになってしまうことがあります。床は重力と反対を向いているでしょうから、この法線も空方向を向くようにしなければいけません。これは、まず法線のy成分の符号を調べます。もしy成分がマイナスだったら、地面方向を向いていると言うことなので、これは逆向きを示してしまっています。ですから法線の各成分の符号を反転させて、空方向を向くようにします。

 さて、このように空方向を向く法線が取れれば、後はとっても簡単です。床ポリゴンを真上から見た時に、そこに含まれる点Oがあるとしましょう。「含まれる」というのは、真上から見た投射ポリゴンに含まれているという意味です。それが本当にポリゴンに含まれているかどうかはわかりません(それがわかっているなら、高さを求める必要はないわけでして(^-^;;;)。点Oはx成分とz成分はもうわかっているものとします。ただ、y成分だけがわからない。そういう状態です。

 ある適切なy成分を選ぶと、床ポリゴンに点Oを完全に含めることが出来ます。その時、ある重要な関係が成り立ちます。点Aから点Oに向かうベクトルをAOとしましょう。点Aも点Oもポリゴンに含まれているのですから、当然、線分AOもポリゴンに含まれます。一方、先程求めた法線は、ポリゴンに対して鉛直です。ということは、ベクトルAOと法線は垂直関係にあるということになります。もう、ピンと来ているかもしれませんが、2つのベクトルが直行する時、その内積は0になります。つまり、次式が成り立ちます。

 上の式で、法線の各成分、点Aの各成分はすでに分かっています。そして地図上の位置であるOxとOzも今は分かっているという前提です。ということは、分からないのはOyだけでして、上の式からOyだけを抽出できることになります。展開した式は以下のようになります。

 見た目もわりとすっきりですね。ポリゴンの法線がすでに分かっている場合、上の式を用いれば、特定の位置xzにおける床ポリゴンの高さを求めることが出来ます。



B 法線を用いない方法

 法線を用いずにOyを得る方法もあります。これは「重み付け平均法」の理屈を利用します。式は以下のようなものです。

Sは三角形ABCの面積を表します。この三角形は3Dではなくて、上から見た時の三角形ですから注意してください。SBCとは三角形OBCの面積で、以下同様にSACは三角形OAC、SABは三角形OABの面積を表します。つまり、点Oで分けられる三角形の面積を求めれば、たちどころにOyが分かる仕組みになっています。重み付けというのは、分母にある全三角形の面積に対する分子にある3つの三角形の割合の部分を指しています。三角形の面積の求め方は世の中に沢山ありますが、2Dであれば外積を使うのが手っ取り早いでしょう。つまり、

 という公式です。これを上の式に代入すれば、各点の座標情報だけから床ポリゴンの高さを計算することができます。
 法線を用いた方法にするか、点情報だけにするかは好きずきでしょうね。どちらも計算量は大して変わりません。実装しやすい方を選択してください。