レイを使ったときの衝突判定について
レイを使ったときの衝突判定について
レイについて質問です
現在DirectXを用いてゲームを製作中なのですが、レイを使う衝突判定でつまづいてしまいました
基本的な部分はできたのですが、物体を回転させた場合の衝突判定がおかしく、
自分で調べたところ判定はメッシュで行うので物体を移動させたり回転させたりしても元々の座標や角度を参照するらしい、というところまではわかりました
他のコライダーで当たり判定を作り直すのは出来るだけ回避したいので、
レイを使って、オブジェクトの回転などをしてもその情報を衝突判定で参照出来る方法が知りたいです
よろしくお願いします
Re: レイを使ったときの衝突判定について
レイに対して、オブジェクトの変換行列の逆行列を掛けてから当たり判定をするとうまくいくと思います。
Re: レイを使ったときの衝突判定について
レイ(レーザー状の直線)とメッシュとの交差判定 については D3DXIntersect関数 とか 過去ログ 、Dxlib の レファレンス とか ホームページで 情報がたくさん あります。自分も知りたいので 過去ログのかたのように 具体的に コードで 示して いただければ と おもいますが。( マトリックス演算の問題で 解決したのならいいです よ)
Re: レイを使ったときの衝突判定について
回答ありがとうございました。
逆行列を求めるとのことなのですが、一応求めて関数の中には入れてあります。
これだけでは不足ということなのでしょうか? 具体的にどの辺りを触ればいいか教えていただけたらと思います。
逆行列を求めるとのことなのですが、一応求めて関数の中には入れてあります。
これだけでは不足ということなのでしょうか? 具体的にどの辺りを触ればいいか教えていただけたらと思います。
//レイとメッシュの当たり判定
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;//外れている
}
Re: レイを使ったときの衝突判定について
逆行列を作成するもとになるmatWorldですが、
平行移動しか考慮されてないのはなぜでしょうか?
正しく逆行列を作成できていないのでは?
平行移動しか考慮されてないのはなぜでしょうか?
正しく逆行列を作成できていないのでは?
Re: レイを使ったときの衝突判定について
返信ありがとうございます。
行列作成の部分が確かに回転や拡大縮小を考慮していないので書き直してみました。
ですが、回転前の当たり判定は正確でしたが回転した物体へ近づくと突然何もないところで浮き上がったり、やはり当たり判定がおかしいです。
以下の行列の求め方がおそらく間違っていると思うのですが、何か助言などよろしくお願いします。
(Scaleだけ行列を求めていないのは元々この項目だけ他と違いfloatで宣言しているため、Scale.x,y,zで行列作成ができないのです)
行列作成の部分が確かに回転や拡大縮小を考慮していないので書き直してみました。
ですが、回転前の当たり判定は正確でしたが回転した物体へ近づくと突然何もないところで浮き上がったり、やはり当たり判定がおかしいです。
以下の行列の求め方がおそらく間違っていると思うのですが、何か助言などよろしくお願いします。
(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 );
Re: レイを使ったときの衝突判定について
行列の中身なのですが、
こちらで幾らオブジェクトを回転させて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度の時は当たり判定が正常です
こちらで幾らオブジェクトを回転させて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度の時は当たり判定が正常です
Re: レイを使ったときの衝突判定について
記述漏れしました、
正確には90度ずつではなく約90度です
正確に90度回す方法がわからなかったので3.14159/2ずつ回転させています
正確には90度ずつではなく約90度です
正確に90度回す方法がわからなかったので3.14159/2ずつ回転させています
Re: レイを使ったときの衝突判定について
失礼しました、
自分のデバッグ方法が悪く恐らく先ほど記述した内容が間違っているので、
正確に数値を記録してからまた報告させていただきます
自分のデバッグ方法が悪く恐らく先ほど記述した内容が間違っているので、
正確に数値を記録してからまた報告させていただきます
Re: レイを使ったときの衝突判定について
お騒がせしてすみません
上記の数値は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 ...}
上記の数値は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 ...}
Re: レイを使ったときの衝突判定について
_11, _12, _13だけでは答えようがありません。
変換行列に対する知識があれば、
各行列の要素がある程度何を示しているか理解しているはずですので
このような貼り方をしないはずです。
変換行列の中身を正しく理解していますか?
変換行列に対する知識があれば、
各行列の要素がある程度何を示しているか理解しているはずですので
このような貼り方をしないはずです。
変換行列の中身を正しく理解していますか?
Re: レイを使ったときの衝突判定について
変換行列の中身は正直理解できていません
何をどう書けばこうなる、と教えてもらった分をつぎはぎでコードを書いているような状態ですので、3Dに対しての理解度はかなり低いです
よければ仕組みや考え方などを教えていただけないでしょうか?
何をどう書けばこうなる、と教えてもらった分をつぎはぎでコードを書いているような状態ですので、3Dに対しての理解度はかなり低いです
よければ仕組みや考え方などを教えていただけないでしょうか?
Re: レイを使ったときの衝突判定について
もし学業や仕事に3Dをなされているなら今すぐ勉強してください。
そこを掴んでおかなければ、今後非常に苦労すると思います。
さすがに1から説明するには時間が掛かりすぎるので以下を読んでみてください。
http://d.hatena.ne.jp/Zellij/20120523/p1
これは2Dのアフィン変換ですが。3Dはそれの拡張なので、まずこれを理解してください。
分からなければ質問してください。
そこを掴んでおかなければ、今後非常に苦労すると思います。
さすがに1から説明するには時間が掛かりすぎるので以下を読んでみてください。
http://d.hatena.ne.jp/Zellij/20120523/p1
これは2Dのアフィン変換ですが。3Dはそれの拡張なので、まずこれを理解してください。
分からなければ質問してください。
Re: レイを使ったときの衝突判定について
基準の物体から、レイを求めている処理もおかしいのでは。
基準の物体に対する変換行列は既に計算済みであろうはずなので
それを使って計算すべきかと思います。
基準の物体に対する変換行列は既に計算済みであろうはずなので
それを使って計算すべきかと思います。
Re: レイを使ったときの衝突判定について
返信が遅れて申し訳ありません。
参考サイトのURLまで載せていただき、ありがとうございます。
アフィン変換を使って回転したオブジェクトに正しくレイを当てなければいけない、というのはわかりました。
そのためにワールド座標変換行列の中身をのぞく必要があるのですよね? どう照らし合わせればいいのでしょうか?
参考サイトのURLまで載せていただき、ありがとうございます。
アフィン変換を使って回転したオブジェクトに正しくレイを当てなければいけない、というのはわかりました。
そのためにワールド座標変換行列の中身をのぞく必要があるのですよね? どう照らし合わせればいいのでしょうか?
Re: レイを使ったときの衝突判定について
clsDX9Meshの中でそういう形では宣言していないです
clsDX9Mesh.cppで作っているレンダリング関数の中で一時的にmWorldを宣言しています
clsDX9Mesh.hでコンスタントバッファの構造体の一つにmWがあり、mWorldの中身を渡しています
clsDX9Meshの中でmWorldを扱っているのはこの部分だけです
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;
//以下省略
Re: レイを使ったときの衝突判定について
実装がOOP的におかしいですね。
ゲームのオブジェクトを示すクラスがメンバ変数としてワールド変換行列を保持していないと個別にモノを動かせないはずですが。
他にそのオブジェクト固有のワールド変換行列を保存している部分はありませんか?
ゲームのオブジェクトを示すクラスがメンバ変数としてワールド変換行列を保持していないと個別にモノを動かせないはずですが。
他にそのオブジェクト固有のワールド変換行列を保存している部分はありませんか?
Re: レイを使ったときの衝突判定について
変換行列のキャッシュの有無は別として、考え方ですが
基準の物体のローカル座標系で表されたレイに対して
基準の物体のワールド変換を正方向
対象の物体のワールド変換を逆方向
と順に適用することで
対象の物体のローカル座標系に変換できます。
基準の物体のローカル座標系で表されたレイに対して
基準の物体のワールド変換を正方向
対象の物体のワールド変換を逆方向
と順に適用することで
対象の物体のローカル座標系に変換できます。