3Dプログラミング応用 2-1A

~地形との当たり判定~

2-1-1.D3DXIntersect関数

3Dオブジェクトの衝突は D3DXIntersect 関数を用いて判定する。

この関数は、3D空間上で光線がメッシュに当たるかどうかを判定してくれる。

光線は出発点と進行方向で定義される。

レーザーポインターのようなものを想像していただくと、わかりやすいかもしれない。

※「光線、光源」と言っているが、実際の描画に影響が出てるわけではなく、あくまで概念的なものである。


D3DXIntersect関数の説明

[ LPD3DXBASEMESH pMesh ]

⇒ 判定対象のメッシュ


[ CONST D3DXVECTOR3 * pRayPos ]

⇒ 光源位置


[ CONST D3DXVECTOR3 * pRayDir,]

⇒ 光源方向


[ BOOL * pHit ]

⇒ 戻り値、光線がメッシュに当たったかどうか


[ DWORD * pFaceIndex, ]

⇒ 戻り値 光線がメッシュに当たった場合、メッシュのどの面に当たったか


[ FLOAT * pU ] [ FLOAT * pV, ]

⇒ 戻り値、光線がメッシュに当たった場合、面のどの位置に当たったか


[ FLOAT * pDist, ]

⇒ 戻り値 光線がメッシュに当たった場合、光源からの距離


[ LPD3DXBUFFER * ppAllHits ]

⇒ 戻り値 D3DXINTERSECTINFO 構造体が CountOfHits 個入った配列。ヒットしたすべての面の情報が入っている


[ DWORD * pCountOfHits ]

⇒ 戻り値 ヒットした回数



この関数の利用上で注意すべきは、すべての判定はメッシュのローカル座標上で行われるという点である。

pRayPos や pRayDir もメッシュローカル座標で指定しなくてはならない。


幸いにして、「ローカル座標からワールド座標に変換する行列」は、描画処理の時に作成してあるため、

これの逆行列を作成すれば「ワールド座標からローカル座標への変換行列」を得ることができる。


また、RayDir は方向ベクトルである点に注意してほしい。

「方向ベクトル」は始点と終点の差で定義されており、パラメータは原点を始点とした時の終点位置を表している。

ここで、終点のみをローカル座標に変換し、始点(原点)はワールド座標の値をそのまま使うと――当然、結果が狂ってくる。


原理的には、始点と終点の両方を座標変換し、その差を求めることで方向ベクトルを求めるわけだが、

通常、3次ベクトルの最後に1を付け足して4次ベクトル化し、行列演算するところ (x,y,z,1)

最後のパラメータを0として演算することで (x,y,z,0)

平行移動分が無視されて上記作業と同じ結果が得られることになる。


RayDirWorldの説明

それでは、この関数を使って地形との当たり判定を実装してみよう。

▲TOP

2-1-2.障害物との当たり判定

◆ CAnimateObject.h

CAnimateObject.h

◆ CAnimateObject.cpp(追記分のみ)


○ Update

CAnimateObject.cpp(追記分1)

○ GetBoneID ~ Intersect

CAnimateObject.cpp(追記分2)

◆ Scene.h

Scene.h

◆ Scene.cpp(一部)

○ IntersectList

Scene.cpp(一部)

◆ Doll.h

Doll.h

◆ Doll.cpp(一部)

Doll.cpp(一部)

○ Update

Update

前方の障害物判定は右図のように、3本の直線でチェックしている。

大雑把な障害物はこれで十分補足できるが、

この方法だと細い格子状の障害物はすり抜けてしまう。

すり抜け判定の絵

◆ Main.cpp

Main.cpp

  

▲TOP

2-1-3.動作確認

・障害物にぶつかると止まる

・床の端、何もない空間に向かって進もうとすると止まる

・坂を上る、下る

・箱の上、高い段差から踏みだそうとすると止まる


以上の動作がきちんとできていれば成功。


2-1-3 動作確認

↓参考動画


▲TOP

>「2-1B ジャンプアクションの実装」へ続く