DXライブラリ3D 角ポリゴンとの押し出し処理

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
アバター
ptolemy
記事: 258
登録日時: 12年前

DXライブラリ3D 角ポリゴンとの押し出し処理

#1

投稿記事 by ptolemy » 10年前

今回は、角を作るポリゴンとカプセルとの押し出し処理で自分ではもう解決に至らなかったため質問いたします。

まず、角に外から衝突したときに押し出す場合では、
画像
このように角を直接メタセコイアで丸める処理をすることで、そもそも角として判定させず、すり抜けを回避できました。

押し出し方法は、
・当たった壁のポリゴンの法線ベクトル方向に押し出す処理
・当たっている壁ポリゴンに垂直な方向にスライドする処理
をすることで押し出しています。

コード:

void	StageWallCollision(	stage	*stage/*ステージの構造体*/, person *thing/*判定するものの構造体*/, MV1_COLL_RESULT_POLY_DIM	*wall/*壁のポリゴン構造体*/ ) {

	//ポリゴンと衝突していたら
	if( wall->HitNum != 0 ) {

		//ヒットしてるかどうかのフラグを初期化
		stage->Hitflag = 0 ;
		
		//進行フラグが立っていたら
		if( thing->move_flag == 1 ) {
		
			//ヒットしてるかどうかのフラグを立てる
			stage->Hitflag = 1 ;
			
			//ポリゴンの法線ベクトルを取得してスライド
			for( int	i = 0 ; i < wall->HitNum ; i ++ ) {

				//衝突しているポリゴンの法線ベクトルを取得
				stage->polyNormal = wall->Dim[ i ].Normal ;

				//y方向の変数は初期化
				stage->polyNormal.y = 0.0f ;
				thing->move_vector.y = 0.0f ;
				
				//横にスライドするベクトルを取得
				stage->NorPmove_vector = CrossVector( thing->temp_move_vector , stage->polyNormal ) ;
				stage->slide_vector = CrossVector( stage->polyNormal, stage->NorPmove_vector ) ;
	
				//スライド処理
				thing->x += stage->slide_vector.x  ;
				thing->z += stage->slide_vector.z  ;
			}
		}
		
	}else{

		//衝突してない時は衝突フラグを回収
		stage->Hitflag = 0 ;

		//ポリゴンと衝突していないときは後始末を行う
		MV1CollResultPolyDimTerminate( *wall ) ;
	}
	
	//衝突フラグが立っていたら
	if( stage->Hitflag == 1 ) {

		//法線ベクトル方向に移動量分押し出し
		thing->x += stage->polyNormal.x * thing->move_speed ;
		thing->z += stage->polyNormal.z * thing->move_speed ;
	}

}
CrossVector関数はDXライブラリのVCrossと同じく外積を求める関数です。

ポリゴン構造体はこちらです。MV1_COLL_RESULT_POLY_DIM 構造体

次にこのように内側からの押し出し処理をしようと思いました。
画像
しかし、押し出し処理が多方向に複数発生し、通り抜けが発生します。
内側から角に当たった場合は違う処理をして押し出せば通り抜けは回避できる気がしますが、内側から衝突しているかどうかを区別するやり方が分かりません。
角との衝突処理の考え方が知りたいです。

DXライブラリのサンプルを参考にしようと思いましたが、注意書きに鋭角はダメとあるので参考にすることができませんでした。

説明が伝わりずらいかもしれませんがご回答してくだされば幸いです。
また、プログラムの書き方や他にも見落としている点などでダメな点がありましたらご指摘お願いします。

よろしくお願いします。

アバター
usao
記事: 1892
登録日時: 12年前
連絡を取る:

Re: DXライブラリ3D 角ポリゴンとの押し出し処理

#2

投稿記事 by usao » 10年前

オフトピック
話がよくわからないので的外れかもしれませんが…

・カプセル(って何だ?)と辺(添付図参照)とで判定すれば,「外から」すり抜けるということはないのでは…?

・「内側から」については,単純に
  少なくとも面Aと衝突しているから解決したい→面Aの法線の方向に押し出す
  →押し出した場所を調べたら面Bと衝突している→面Bの方向に押し出す
  →そしたらまたAと衝突する場所になったんですが→Aの法線方向に押し出す
  →…
  →良い位置に持ってこれた.解決
 とか…(だとダメなのかな?)
添付ファイル
クリップボード01.jpg
クリップボード01.jpg (11.87 KiB) 閲覧数: 4241 回

ISLe()

Re: DXライブラリ3D 角ポリゴンとの押し出し処理

#3

投稿記事 by ISLe() » 10年前

スレイヴ さんが書きました:内側から衝突しているかどうかを区別するやり方が分かりません。
判定したい物体の移動ベクトルと壁の法線ベクトルの内積を求めて符号を見る方法で判断できないでしょうか。

物体から見て、壁の内側から外側に抜けるところかどうか判定できます。

その手の一般的な方法が使えない状況だったらすみません。

アバター
ptolemy
記事: 258
登録日時: 12年前

Re: DXライブラリ3D 角ポリゴンとの押し出し処理

#4

投稿記事 by ptolemy » 10年前

返信遅れました。
usao さんが書きました:・「内側から」については,単純に  少なくとも面Aと衝突しているから解決したい→面Aの法線の方向に押し出す  →押し出した場所を調べたら面Bと衝突している→面Bの方向に押し出す  →そしたらまたAと衝突する場所になったんですが→Aの法線方向に押し出す  →…  →良い位置に持ってこれた.解決 とか…(だとダメなのかな?)
ご返信ありがとうございます。

押し出し処理をループさせるという方法を参考にプログラムを組んでみたら、8割すり抜けがなくなりました。

コード:


//二つのベクトルの外積を求める関数
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 ;

}

//壁とのコリジョン情報の更新
void	StageWallPolyUpdate( stage	*stage/*ステージ構造体*/, person	*thing/*判定するものの構造体*/, float	Capsule_r/*カプセルの半径*/ ) {
	
	thing->capsule_up = VGet( thing->x, thing->y + 2.0f, thing->z ) ;
	thing->capsule_down = VGet( thing->x, thing->y - 7.0f, thing->z ) ;

	stage->wall_dim = MV1CollCheck_Capsule( stage->model_CL, -1, thing->capsule_up, thing->capsule_down, Capsule_r ) ;

}

//壁とのコリジョン
void	StageWallCollision(	stage	*stage/*ステージの構造体*/, person *thing/*判定するものの構造体*/, float	Capsule_r/*衝突判定用のカプセルの半径*/ ) {

	//初期判定
	StageWallPolyUpdate( stage, thing, Capsule_r ) ;

	//ポリゴンとの衝突数
	if( stage->wall_dim.HitNum != 0 ) {
		
		//衝突フラグを立てる
		stage->Hitflag = 1 ;

		//進行状態
		if( thing->move_flag == 1 ) {
		
			//衝突している壁ポリゴンの数だけ繰り返し
			for( int	i = 0 ; i < stage->wall_dim.HitNum ; i ++ ) {

				//衝突しているポリゴンの法線ベクトルを取得
				stage->polyNormal = stage->wall_dim.Dim[ i ].Normal ;

				//y方向の変数は初期化
				stage->polyNormal.y = 0.0f ;
				thing->move_vector.y = 0.0f ;

				//横にスライドするベクトルを取得
				stage->NorPmove_vector = CrossVector( thing->move_vector , stage->polyNormal ) ;
				stage->slide_vector = CrossVector( stage->polyNormal, stage->NorPmove_vector ) ;
	
				//スライド処理
				thing->x += stage->slide_vector.x  ;
				thing->z += stage->slide_vector.z  ;

			}
		}


		//衝突していたら押し出す
		if( stage->Hitflag  == 1 ) {

			//衝突している壁ポリゴンの数だけ繰り返し
			for( int h = 0 ; h < stage->wall_dim.HitNum ; h ++ ) {

				//ポリゴンのコリジョン情報をスライド処理後のものに更新
				StageWallPolyUpdate( stage, thing, Capsule_r ) ;

				//衝突しているポリゴンの法線ベクトルを取得
				stage->polyNormal = stage->wall_dim.Dim[ h ].Normal ;

				//押し出し
				thing->x += stage->polyNormal.x * thing->move_speed ;
				thing->z += stage->polyNormal.z * thing->move_speed ;
				
				//ポリゴンのコリジョン情報を押し出し処理後のものに更新
				StageWallPolyUpdate( stage, thing, Capsule_r ) ;

				//衝突していなかったら抜け出す
				if( stage->wall_dim.HitNum == 0 ) {
					break ;
				}

			}
		}


	}else{

		//ポリゴンに触れていない時は衝突フラグを回収
		stage->Hitflag = 0 ;

		//ポリゴンと衝突していないときは後始末を行う
		MV1CollResultPolyDimTerminate( stage->wall_dim ) ;
	}
	
}

大きな原因は更新を行っていなかったことでした。
また、大まかな変更点として、押し出し処理後に再度判定をし、当たっていなかったらループを抜け出し、当たっていたら再度押し出し処理をするようにしました。
ISLe() さんが書きました:判定したい物体の移動ベクトルと壁の法線ベクトルの内積を求めて符号を見る方法で判断できないでしょうか。物体から見て、壁の内側から外側に抜けるところかどうか判定できます。その手の一般的な方法が使えない状況だったらすみません。
ご回答ありがとうございます。
まだ、スライドベクトルとポリゴンの法線ベクトルが逆向きに働いた場合ができていないので、内積を使用してみます。

アバター
ptolemy
記事: 258
登録日時: 12年前

Re: DXライブラリ3D 角ポリゴンとの押し出し処理

#5

投稿記事 by ptolemy » 10年前

解決しました。

最後の問題だったスライド処理によって壁に衝突した場合の押し出し処理ですが、
単純に「スライド時の移動量 > 法線ベクトル方向への押し出しの移動量」というようなものが成り立っていました。

よって、スライド時の移動量のほうが大きく、薄い壁だとすり抜けが発生していたようです。

よって、前レスでのプログラムは正常に動作していました。

閉鎖

“C言語何でも質問掲示板” へ戻る