レイを使ったときの衝突判定について

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
A3

レイを使ったときの衝突判定について

#1

投稿記事 by A3 » 7年前


レイについて質問です
現在DirectXを用いてゲームを製作中なのですが、レイを使う衝突判定でつまづいてしまいました
基本的な部分はできたのですが、物体を回転させた場合の衝突判定がおかしく、
自分で調べたところ判定はメッシュで行うので物体を移動させたり回転させたりしても元々の座標や角度を参照するらしい、というところまではわかりました
他のコライダーで当たり判定を作り直すのは出来るだけ回避したいので、
レイを使って、オブジェクトの回転などをしてもその情報を衝突判定で参照出来る方法が知りたいです
よろしくお願いします

ISLe
記事: 2650
登録日時: 13年前
連絡を取る:

Re: レイを使ったときの衝突判定について

#2

投稿記事 by ISLe » 7年前

レイに対して、オブジェクトの変換行列の逆行列を掛けてから当たり判定をするとうまくいくと思います。

C6b14

Re: レイを使ったときの衝突判定について

#3

投稿記事 by C6b14 » 7年前

レイ(レーザー状の直線)とメッシュとの交差判定 については D3DXIntersect関数 とか 過去ログ 、Dxlib の レファレンス とか ホームページで 情報がたくさん あります。自分も知りたいので 過去ログのかたのように 具体的に コードで 示して いただければ と おもいますが。( マトリックス演算の問題で 解決したのならいいです よ)

Egg

Re: レイを使ったときの衝突判定について

#4

投稿記事 by Egg » 7年前

たしかDirectXTKの中の算術補助ライブラリに
解答のソースが存在していたと思われますので
それを参考にしてみてください

A3

Re: レイを使ったときの衝突判定について

#5

投稿記事 by A3 » 7年前

回答ありがとうございました。
逆行列を求めるとのことなのですが、一応求めて関数の中には入れてあります。
これだけでは不足ということなのでしょうか? 具体的にどの辺りを触ればいいか教えていただけたらと思います。

コード:

//レイとメッシュの当たり判定
bool clsMain::Intersect(
	clsDX9MESH* pThing,			//基準の物体
	clsDX9MESH* pTarget,		//対象の物体
	float* pfDistance,			//(out)距離
	D3DXVECTOR3* pvIntersect)	//(out)交差座標
{
	D3DXMATRIXA16	matRot;	//回転行列

	//回転行列を計算
	D3DXMatrixRotationY( &matRot, pThing->m_fYaw );

	//軸ベクトルを用意
	D3DXVECTOR3 vecAxisZ;
	//Z軸ベクトルそのものを現在の回転状態により変換する
	D3DXVec3TransformCoord( &vecAxisZ, &pThing->m_vAxis, &matRot );

	D3DXVECTOR3 vecStart, vecEnd, vecDistance;
	vecStart = vecEnd = pThing->m_vRay;//レイの位置を設定

	//自キャラの座標に回転座標を合成する
	vecEnd += vecAxisZ * 1.0f;

	//対象のworld行列の逆行列の作成準備
	D3DXMATRIX	matWorld;
	D3DXMatrixTranslation(
		&matWorld,
		pTarget->m_vPos.x,
		pTarget->m_vPos.y,
		pTarget->m_vPos.z );

	//逆行列を求める
	D3DXMatrixInverse( &matWorld, NULL, &matWorld );
	D3DXVec3TransformCoord( &vecStart, &vecStart, &matWorld );
	D3DXVec3TransformCoord( &vecEnd, &vecEnd, &matWorld );

	//距離を求める
	vecDistance = vecEnd - vecStart;

	BOOL bHit = false;	//命中フラグ
	DWORD dwIndex = 0;	//インデックス番号
	FLOAT U=0, V=0;		//(out)重心ヒット座標

	//メッシュとレイの交差を調べる
	D3DXIntersect(
		pTarget->m_pMeshForRay,	//対象メッシュ
		&vecStart,				//開始位置
		&vecDistance,			//レイの距離
		&bHit,					//(out)判定結果
		&dwIndex,	//(out)bHitがTrueの時、レイの始点に最も近くの面のインデックス値へのポインタ
		&U, &V,					//(out)重心ヒット座標
		pfDistance,				//ターゲットとの距離
		NULL, NULL );

	D3DXVECTOR3 vVertex[3];	//頂点座標
	if( bHit ){
		//命中したとき
		FindVerticesOnPoly( pTarget->m_pMeshForRay, dwIndex, vVertex );
		//重心座標から交点を算出
		//ローカル交点pは、v0 + U*(v1-v0) + V*(v2-v0)で求まる
		*pvIntersect
			= vVertex[0]
			+ U * ( vVertex[1] - vVertex[0] )
			+ V * ( vVertex[2] - vVertex[0] );

		*pvIntersect += pTarget->m_vPos;

		return true;//命中している
	}
	
	return false;//外れている
}

Egg

Re: レイを使ったときの衝突判定について

#6

投稿記事 by Egg » 7年前

逆行列を作成するもとになるmatWorldですが、
平行移動しか考慮されてないのはなぜでしょうか?
正しく逆行列を作成できていないのでは?

A3

Re: レイを使ったときの衝突判定について

#7

投稿記事 by A3 » 7年前

返信ありがとうございます。
行列作成の部分が確かに回転や拡大縮小を考慮していないので書き直してみました。
ですが、回転前の当たり判定は正確でしたが回転した物体へ近づくと突然何もないところで浮き上がったり、やはり当たり判定がおかしいです。
以下の行列の求め方がおそらく間違っていると思うのですが、何か助言などよろしくお願いします。
(Scaleだけ行列を求めていないのは元々この項目だけ他と違いfloatで宣言しているため、Scale.x,y,zで行列作成ができないのです)

コード:

//対象のworld行列の逆行列の作成準備
	D3DXMATRIX	matWorld;
	D3DXMATRIX  matYPR, matMove;	//回転,移動行列;

   //回転行列
	D3DXMatrixRotationYawPitchRoll( &matYPR, pTarget->m_fYaw, pTarget->m_fPitch, pTarget->m_fRoll );

	//移動行列
	D3DXMatrixTranslation( &matMove, pTarget->m_vPos.x, pTarget->m_vPos.y, pTarget->m_vPos.z );
	//演算
	matWorld = matYPR * pTarget->m_fScale * matMove;

	//逆行列を求める
	D3DXMatrixInverse( &matWorld, NULL, &matWorld );
	D3DXVec3TransformCoord( &vecStart, &vecStart, &matWorld );
	D3DXVec3TransformCoord( &vecEnd, &vecEnd, &matWorld );

Egg

Re: レイを使ったときの衝突判定について

#8

投稿記事 by Egg » 7年前

コードの12行目でブレークし、行列の中身を覗いた場合
確かにワールド変換行列どおりになっていますでしょうか?

A3

Re: レイを使ったときの衝突判定について

#9

投稿記事 by A3 » 7年前

行列の中身なのですが、

こちらで幾らオブジェクトを回転させてRollの値を変更しても、pTarget->m_fRollの値が0でした
同様にどう回転させてもmatYPRの行列の中身は_11=1.0, _12=0.0, _13=0.0、
matMoveも同じ値です。
matWorldも、Scaleが1ですので1 * matYPR * matMove で中身は_11=1.0, _12=0.0, _13=0.0です

Inverseで求めたmatWorldは_11=0.999999940, _12=0.0, _13=0.0 でした

また、回転させたい物体はRollを使って90度ごとに回しているのですが、
0度と180度の時は当たり判定が正常です

A3

Re: レイを使ったときの衝突判定について

#10

投稿記事 by A3 » 7年前

記述漏れしました、
正確には90度ずつではなく約90度です
正確に90度回す方法がわからなかったので3.14159/2ずつ回転させています

A3

Re: レイを使ったときの衝突判定について

#11

投稿記事 by A3 » 7年前

失礼しました、
自分のデバッグ方法が悪く恐らく先ほど記述した内容が間違っているので、
正確に数値を記録してからまた報告させていただきます

A3

Re: レイを使ったときの衝突判定について

#12

投稿記事 by A3 » 7年前

お騒がせしてすみません

上記の数値はRollが0のときの結果で、このときは当たり判定が正常でした
Rollの中身はちゃんと変化します

約90度回転させたあとの数値がこちらです
mtYPR
{_11=5.96046448e-008 _12=-0.999999881 _13=-0.000000000 ...}
matMove
{_11=1.00000000 _12=0.000000000 _13=0.000000000 ...}
matWorld
{_11=5.96046448e-008 _12=-0.999999881 _13=0.000000000 ...}
Inverse matWorld
{_11=5.96046590e-008 _12=1.00000012 _13=0.000000000 ...}

Egg

Re: レイを使ったときの衝突判定について

#13

投稿記事 by Egg » 7年前

_11, _12, _13だけでは答えようがありません。

変換行列に対する知識があれば、
各行列の要素がある程度何を示しているか理解しているはずですので
このような貼り方をしないはずです。
変換行列の中身を正しく理解していますか?

A3

Re: レイを使ったときの衝突判定について

#14

投稿記事 by A3 » 7年前

変換行列の中身は正直理解できていません
何をどう書けばこうなる、と教えてもらった分をつぎはぎでコードを書いているような状態ですので、3Dに対しての理解度はかなり低いです

よければ仕組みや考え方などを教えていただけないでしょうか?

Egg

Re: レイを使ったときの衝突判定について

#15

投稿記事 by Egg » 7年前

もし学業や仕事に3Dをなされているなら今すぐ勉強してください。
そこを掴んでおかなければ、今後非常に苦労すると思います。

さすがに1から説明するには時間が掛かりすぎるので以下を読んでみてください。
http://d.hatena.ne.jp/Zellij/20120523/p1

これは2Dのアフィン変換ですが。3Dはそれの拡張なので、まずこれを理解してください。
分からなければ質問してください。

ISLe
記事: 2650
登録日時: 13年前
連絡を取る:

Re: レイを使ったときの衝突判定について

#16

投稿記事 by ISLe » 7年前

基準の物体から、レイを求めている処理もおかしいのでは。
基準の物体に対する変換行列は既に計算済みであろうはずなので
それを使って計算すべきかと思います。

A3

Re: レイを使ったときの衝突判定について

#17

投稿記事 by A3 » 7年前

返信が遅れて申し訳ありません。
参考サイトのURLまで載せていただき、ありがとうございます。

アフィン変換を使って回転したオブジェクトに正しくレイを当てなければいけない、というのはわかりました。
そのためにワールド座標変換行列の中身をのぞく必要があるのですよね? どう照らし合わせればいいのでしょうか?

Egg

Re: レイを使ったときの衝突判定について

#18

投稿記事 by Egg » 7年前

clsDX9Meshの中にワールド変換行列は保持されていますか?
なければ、ワールド変換行列の管理の仕方から作らないとだめですね。
今回のように複数オブジェクトの時、この先困りますよ。

コード:

class clsDX9Mesh
{
private:
    D3DXMATRIX m_World; // 現在のすべてのワールド変換の合成が保存されている
public:
    D3DXMATIRX GetWorld(){
        return m_World;
    };
};
通常このようになっているはずなんですが。

A3

Re: レイを使ったときの衝突判定について

#19

投稿記事 by A3 » 7年前

clsDX9Meshの中でそういう形では宣言していないです
clsDX9Mesh.cppで作っているレンダリング関数の中で一時的にmWorldを宣言しています
clsDX9Mesh.hでコンスタントバッファの構造体の一つにmWがあり、mWorldの中身を渡しています

clsDX9Meshの中でmWorldを扱っているのはこの部分だけです

コード:

//コンスタントバッファのアプリ側の定義(Mesh.hlsl)
struct MESHSHADER_CONSTANT_BUFFER0
{
	D3DXMATRIX	mW;			//ワールド(位置)座標
	D3DXMATRIX	mWVP;		//ワールド,ビュー,射影の合成変換行列
	D3DXVECTOR4 vLightDir;	//ライト方向
	D3DXVECTOR4	vEye;		//カメラ位置(視点位置)
	D3DXVECTOR4 vAlpha;		//アルファ値(x)
};

コード:

//DX内のレンダリング関数
void clsDX9MESH::Render(
	D3DXMATRIX &mView, D3DXMATRIX &mProj,
	D3DXVECTOR3 &vLight, D3DXVECTOR3 &vEye)
{
	D3DXMATRIX mWorld;	//ワールド行列
	D3DXMATRIX mScale, mYaw, mPitch, mRoll, mTrans;

	//ワールド変換

   //mScaleなどの値の設定, 省略

	//合成(拡縮×回転×移動)
	mWorld = mScale * mYaw * mPitch * mRoll * mTrans;


	//シェーダのセット,  省略

	//シェーダのコンスタントバッファに各種データを渡す
	D3D11_MAPPED_SUBRESOURCE pData;
	//バッファ内のデータの書き換え開始時にMap
	if (SUCCEEDED(
		m_pDeviceContext11->Map(
		m_pConstantBuffer0, 0,
		D3D11_MAP_WRITE_DISCARD,
		0, &pData)))
	{
		//コンスタントバッファ
		MESHSHADER_CONSTANT_BUFFER0 cb;

		//ワールド行列を渡す
		cb.mW = mWorld;
		D3DXMatrixTranspose(&cb.mW, &cb.mW);

		//ワールド,ビュー,プロジェクション行列を渡す
		D3DXMATRIX m = mWorld * mView * mProj;
		D3DXMatrixTranspose(&m, &m);//行列を転置する
		//※行列の計算方法がDirectXとGPUで異なる為
		cb.mWVP = m;

     //以下省略

Egg

Re: レイを使ったときの衝突判定について

#20

投稿記事 by Egg » 7年前

実装がOOP的におかしいですね。
ゲームのオブジェクトを示すクラスがメンバ変数としてワールド変換行列を保持していないと個別にモノを動かせないはずですが。
他にそのオブジェクト固有のワールド変換行列を保存している部分はありませんか?

ISLe
記事: 2650
登録日時: 13年前
連絡を取る:

Re: レイを使ったときの衝突判定について

#21

投稿記事 by ISLe » 7年前

変換行列のキャッシュの有無は別として、考え方ですが

基準の物体のローカル座標系で表されたレイに対して
基準の物体のワールド変換を正方向
対象の物体のワールド変換を逆方向
と順に適用することで
対象の物体のローカル座標系に変換できます。

閉鎖

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