質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.37%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

1回答

2887閲覧

マウス座標をワールド座標に変換

nonnon7

総合スコア2

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2021/08/27 07:22

C++でクライアント座標をワールド座標に変換してマウスカーソルのワールド座標を取得しようとしています。
(X,Y座標のみとれれば問題ないのですが)
DirectXMathを使用して
http://www.marupeke296.com/DXG_No48_PointGroundInScreen.html
↑のサイトを参考に作成してみましたがなかなかうまくいきません。
どのように間違っているのかが分からず途方に暮れてしまっています。
どこが間違っているのかアドバイスをお願いしたいです。

実行して数値を見てみると
x,y,zともに [-nan(ind)]と出ます。

// 関数呼び出し
POINT *mousePos = CInput::GetMousePosition();
XMFLOAT2 mouse = XMFLOAT2(mousePos->x, mousePos->y);
XMFLOAT3 worldPos;
XMMATRIX view, proj;
view = XMLoadFloat4x4(&CSceneManager::GetScene()->GetCamera()->GetViewMatrix());
proj = XMLoadFloat4x4(&CSceneManager::GetScene()->GetCamera()->GetProjMatrix());
CalcScreenToXY(
&worldPos,// ワールド座標
mouse.x,// クライアント座標X
mouse.y,// クライアント座標Y
SCREEN_WIDTH,// スクリーンサイズW
SCREEN_HEIGHT,// スクリーンサイズH
&view,// ビュー行列
&proj// プロジェクション行列
);

XMFLOAT3* CalcScreenToWorld(
XMFLOAT3* pout,
int Sx,
int Sy,
float fZ,
int ScreenW,
int ScreenH,
XMMATRIX* view,
XMMATRIX* prj
)
{
XMMATRIX InvView, InvPrj, VP, InvViewport;
InvView = XMMatrixInverse(nullptr, *view);
InvPrj = XMMatrixInverse(nullptr, *prj);
VP = XMMatrixIdentity();
XMFLOAT4X4 mtx;
XMStoreFloat4x4(&mtx, VP);
mtx._11 = ScreenW / 2.0f;
mtx._22 = -ScreenH / 2.0f;
mtx._41 = ScreenW / 2.0f;
mtx._42 = ScreenH / 2.0f;
VP = XMLoadFloat4x4(&mtx);
InvViewport = XMMatrixInverse(nullptr, VP);
// 逆行列
XMMATRIX tmp = InvViewport * InvPrj * InvView;
XMVECTOR mat = XMLoadFloat3(pout);
XMVECTOR vec = XMVector3TransformCoord(mat, tmp);
XMStoreFloat3(pout, vec);
return pout;
}

XMFLOAT3* CalcScreenToXY(
XMFLOAT3* pout,
int Sx,
int Sy,
int ScreenW,
int ScreenH,
XMMATRIX* pView,
XMMATRIX* pPrj
)
{
XMFLOAT3 nearpos = XMFLOAT3(0.0f, 0.0f, 0.0f);
XMFLOAT3 farpos = XMFLOAT3(0.0f, 0.0f, 0.0f);
XMFLOAT3 ray = XMFLOAT3(0.0f, 0.0f, 0.0f);
CalcScreenToWorld(&nearpos, Sx, Sy, 0.0f, ScreenW, ScreenH, pView, pPrj);
CalcScreenToWorld(&farpos, Sx, Sy, 1.0f, ScreenW, ScreenH, pView, pPrj);
ray = XMFLOAT3(farpos.x - nearpos.x, farpos.y - nearpos.y, farpos.z - nearpos.z);
XMStoreFloat3(&ray, XMVector3Normalize(XMLoadFloat3(&ray)));

if (ray.y <= 0)
{
// 平面交点
XMFLOAT3 v = XMFLOAT3(0.0f, 1.0f, 0.0f);
XMVECTOR Lray = XMVector3Dot(XMLoadFloat3(&ray), XMLoadFloat3(&v));
XMFLOAT3 v2 = XMFLOAT3(0.0f, 1.0f, 0.0f);
nearpos.x *= -1.0f;
nearpos.y *= -1.0f;
nearpos.z *= -1.0f;
XMVECTOR LP0 = XMVector3Dot(XMLoadFloat3(&nearpos), XMLoadFloat3(&v2));
//*pout = nearpos + (LP0 / Lray)*ray;
XMFLOAT3 lp0;
XMStoreFloat3(&lp0, LP0);
XMFLOAT3 lray;
XMStoreFloat3(&lray, LP0);

*pout = XMFLOAT3
(nearpos.x + (lp0.x / lray.x)*ray.x,nearpos.y + (lp0.y / lray.y)*ray.y,nearpos.z + (lp0.z / lray.z)*ray.z);
}
else *pout = farpos;
return pout;
}

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

CalcScreenToWorld(&nearpos, Sx, Sy, 0.0f, ScreenW, ScreenH, pView, pPrj);
CalcScreenToWorld(&farpos, Sx, Sy, 1.0f, ScreenW, ScreenH, pView, pPrj);
ray = XMFLOAT3(farpos.x - nearpos.x, farpos.y - nearpos.y, farpos.z - nearpos.z);

ここ,
1行目と2行目の違いは,「第四引数値が 0.0f か 1.0f か」しかないように見える.

で,CalcScrrenToWorld は第四引数 fZ を一切使ってないように見える.

なので,nearpos と farpos は全く同じ値となり,結果として ray の要素は全て0となるだろう.

以降の処理は詳細見てないけど,この状態は

if (ray.y <= 0)

の条件を満たすから,ここでやってる処理でまずいこと(例えば0割りとかそんな)がおきるのではなかろうか.

投稿2021/08/27 09:05

fana

総合スコア11954

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

nonnon7

2021/08/27 10:28

アドバイスありがとうございます。 指摘していただいたところを以下のように修正したところ数値が表示されるようになりましたが数値がいきなり大きく変わったりと安定しません。 XMFLOAT3 pV = XMFLOAT3(Sx, Sy, fZ); XMVECTOR v = XMLoadFloat3(&pV); XMVECTOR vec = XMVector3TransformCoord(v, tmp); XMStoreFloat3(pout, vec); たびたび申し訳ないですが、ワールド座標でZ0.0の平面上のX,Yの値を取得することは可能でしょうか?
fana

2021/08/27 10:47 編集

素人でも示されたコードを見て「これはいかんのでは」とわかる事柄を述べただけで 私自身はDirectXの経験があるわけじゃないので…(軸の方向とかすらもわからんです) --- ただ,可能であれば検算してみればどこで値が異常になるのか(:実装のどこがまちがっているのか)を突き止められるのではないのか? と思います. すなわち, ワールド座標でのある位置Wが最終的にクライアント座標のある位置pに投影される ということが既知であるとき, その投影経路の各時点での値もまた既知とできるでしょう. (:各種マトリクスを乗じて変換していったときにどんな値になっていくのかを求めることは可能であろう,と) で,それらの値と,今回の処理を p から出発させた場合の各時点での値とを照らし合わせれば,「どの時点までは計算結果があっていてどの時点で合わなくなるのか?」を突き止めることができるのではないのでしょうか?
fana

2021/08/27 10:48

(要は,処理の各時点での正当な値がわかっている入力値を用いてデバッグしましょうよ,っていう)
nonnon7

2021/08/27 11:49

順を追ってひとつずつ、もっとしっかり見ていきたいと思います。 対応していただきありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.37%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問