ページ 11

[DXライブラリ]コリジョン関数について

Posted: 2015年3月29日(日) 19:45
by ptolemy
今回は、DXライブラリのコリジョン関数である、MV1_COLL_RESULT_POLY_DIM MV1CollCheck_Capsule関数について質問があります。

私は3D内でポリゴンとカプセルの衝突判定をするために、
(カプセルと壁のようなモデルとの衝突判定です。)
①衝突地点とカプセルの中心との距離を取得
②カプセルの半径と①によって取得した距離の差が押し出し量
③当たったポリゴンの法線ベクトルの方向にカプセル押し出す

というような形で行っています。
しかし、カプセルの場合は衝突した地点が求められないため、
「カプセルの半径と同じ大きさで移動ベクトル方向に向くカプセルの中心とを結ぶ線分」を利用して
MV1_COLL_RESULT_POLY MV1CollCheck_Line関数で衝突地点を取得しております。

そこで問題が発生しました。
角などに当たると、線分のためちょうど壁同士が交わった点に当たり、モデルの形によってはすり抜けが発生してしまいます。また、角に限らずモデルの形状によって時々発生します。
それ以外は特に問題がありませんでした。

よって、線分を使わずに衝突地点を求める方法としてほかに方法がないでしょうか?
そして、なぜカプセルの場合は地点が取得できないのでしょうか?複数出るためでしょうか?

分かりずらいと思いますがご回答してくだされば幸いです。
よろしくお願いします。

イメージとしてはこのような感じです。
上から見た図です。

Re: [DXライブラリ]コリジョン関数について

Posted: 2015年4月01日(水) 14:36
by softya(ソフト屋)
衝突した面は分かるはずなので、その面の中央を通る線分から押出量は計算できませんか?
やった事ないので保証は出来かねますけど。

あとは、DXライブラリ御本家のサンプルを参考にされると良いかもしれません。
新しく出た本の3Dゲームのサンプルもありますし。

Re: [DXライブラリ]コリジョン関数について

Posted: 2015年4月01日(水) 14:51
by ptolemy
ご回答ありがとうございます。
softya(ソフト屋) さんが書きました:衝突した面は分かるはずなので、その面の中央を通る線分から押出量は計算できませんか?
やった事ないので保証は出来かねますけど。
なるほど。ポリゴンの中心座標ということですね。
ポリゴンの三点座標は取得出来るので、試したいと思います。
softya(ソフト屋) さんが書きました:衝突した面は分かるはずなので、その面の中央を通る線分から押出量は計算できませんか?
やった事ないので保証は出来かねますけど。

あとは、DXライブラリ御本家のサンプルを参考にされると良いかもしれません。
新しく出た本の3Dゲームのサンプルもありますし。
上記の方法で出来なかったらサンプルを参考にしたいと思います。

Re: [DXライブラリ]コリジョン関数について

Posted: 2015年4月02日(木) 00:17
by ptolemy
できました。
ポリゴンの中心座標ではありませんが、ポリゴンの数分押し出すという処理が必要だったようです。

コード:

/*変数一部抜粋*/

	MV1_COLL_RESULT_POLY_DIM	wall ; //壁のコリジョン構造体
	VECTOR	slide_vector ; //スライドベクトル
	VECTOR	capsule ; //カプセルの座標
	VECTOR	capsule_move_vector ; //カプセルの進行ベクトル
	int	capsule_move_flag ; //カプセルの移動フラグ

/*DXライブラリにもありますが...*/

	//二つのベクトルの外積を求める関数
	VECTOR	CrossVector( VECTOR	Avector, VECTOR	Bvector ) {

		VECTOR	Cross ;

		Cross.x = Avector.y * Bvector.z - Avector.z * Bvector.y ;
		Cross.y = Avector.z * Bvector.x - Avector.x * Bvector.z ;
		Cross.z = Avector.x * Bvector.y - Avector.y * Bvector.x ;

		return	Cross ;

	}

/*ここから別に抜粋*/

	//壁のポリゴンと衝突したら
	if( wall.HitNum != 0 ) {

		//衝突したポリゴン分法線ベクトルの方向へ押し出す
		for( int i = 0 ; i < wall.HitNum ; i ++ ) {

			capsule.x += wall.Dim->Normal.x ;
			capsule.z += wall.Dim->Normal.z ;

		}

		//カプセルが移動したら
		if( capsule_move_flag != 0 ) {

			//横にスライドするベクトルを取得
			//当たったポリゴンの法線ベクトルと進行ベクトルの外積とポリゴンの法線ベクトルの外積
			slide_vector = CrossVector( wall.Dim->Normal, CrossVector( capsule_move_vector, wall.Dim->Normal ) ) ;

			//横にスライド
			capsule.x += slide_vector.x ;
			capsule.z += slide_vector.z ;

		}

	}else{

		//衝突していない時は後始末を行う
		MV1CollResultPolyDimTerminate( wall ) ;

	}
あくまで一部抜粋して少し改変したものです。

今考えてみるとそこまで難しいことではなかった気がしますが、当たった地点というものにとらわれていました。

今回は本当にありがとうございました。