ページ 11

DirectXで視点の回転がうまくいかない

Posted: 2013年2月06日(水) 15:12
by あうあう
以前質問したものです。
http://dixq.net/forum/viewtopic.php?t=1 ... ndKey.cppの
WM_MOUSEMOVEを以下のように改良し、GetMoveX(),GetMoveY()を累積するようにしました。

コード:

	case WM_MOUSEMOVE:
		GetCursorPos(&CursorPos);
		CltToScr.x=0;
		CltToScr.y=0;
		ClientToScreen(hWnd,&CltToScr);
		ClientToScreen(hWnd,&CursorPos);
		mouseposX+=(CltToScr.x+WINDOW_WIDTH/2)-CursorPos.x;
		mouseposY+=(CltToScr.y+WINDOW_HEIGHT/2)-CursorPos.y;
		SetCursorPos(WINDOW_WIDTH/2,WINDOW_HEIGHT/2);
		return 0;
ですが、当初の問題(真上や真下を向けない)は解決できず、未だ悩んでいます。
どうすれば解決できるのでしょうか?

Re: DirectXで視点の回転がうまくいかない

Posted: 2013年2月06日(水) 17:29
by ISLe
前の質問のコードを見てなくてあてずっぽうですが。

マウスのX方向→横回転
マウスのY方向→縦回転
にそのまま当てはめて計算してませんか?
それだと極に近付くにつれて僅かな動きで大きく回転してしまいます。

>真下/真上を見れずぐるっとなってしまいます。
とおっしゃっているので当たっていると思いますけど。

どの方向でもマウスの動きと視線の動きを一定に対応させるには
1. マウスの移動を球面上の移動にマッピングする
2. 球面上の現在位置からsin,cosを求める
という手順を踏む必要があります。

Re: DirectXで視点の回転がうまくいかない

Posted: 2013年2月06日(水) 17:50
by あうあう
返信ありがとうございます。
>マウスの移動を球面上の移動にマッピングする
ということでしたが、勉強不足なものでどのように実現すればよいかわかりませんでした・・
ヒントなど頂けないでしょうか?

Re: DirectXで視点の回転がうまくいかない

Posted: 2013年2月06日(水) 18:19
by ISLe
メルカトル図法の世界地図上を座標(X,Y)で表すのではなく、地球儀上をベクトル(X,Y)で移動するイメージ、と言ったら分かりますか?

メルカトル図法の世界地図では、どの場所においても、X座標は経度、Y座標は緯度に相当します。

地球儀上でX座標を経度とした場合、Y座標の意味がまったく異なります。
Y座標は赤道上では緯度ですが、北上あるいは南下するにしたがい傾いていきます。
北極あるいは南極ではY座標は経度に重なってしまい、すべてのX座標は一点を表すのみとなります。

なので、移動距離を重視するのであれば、常に現在位置を中心とした移動(というか球面なので回転)として処理する必要があります。

Re: DirectXで視点の回転がうまくいかない

Posted: 2013年2月06日(水) 21:48
by あうあう
うーん・・・
MSDNを探してみたりしたのですが、
それを実現できるような関数などが見つかりませんでした。
D3DXRotationYとかを使うのだろうと考えたのですが・・

Re: DirectXで視点の回転がうまくいかない

Posted: 2013年2月06日(水) 23:56
by ISLe
特殊なライブラリは使いません。
三角関数を使って計算できます。

行列用の関数を使えば一括で計算できて便利だとは思いますけど。

Re: DirectXで視点の回転がうまくいかない

Posted: 2013年2月09日(土) 13:10
by あうあう
三角関数を一度使ってからまた三角関数を使うのですか・・
なんだか不思議です。

Re: DirectXで視点の回転がうまくいかない

Posted: 2013年2月09日(土) 17:27
by ISLe
3Dで物理的な挙動の処理には、三角関数をまとめた回転行列を使い、ある回転行列の逆行列を掛けて、変換して、再び行列を掛ける、ということが頻繁にあります。
今回はカメラに立体的な挙動をさせるわけなので。

連休中にDXライブラリ使用のサンプルコードを用意するつもりです。
たまたま今週は用事があるので来週にずれ込むかもしれません。

Re: DirectXで視点の回転がうまくいかない

Posted: 2013年2月10日(日) 16:38
by ISLe
サンプルコード書いてる途中で気付いたんですが、あうあうさんはFPSゲームを作りたいのですよね。
真上や真下を見たい→宙返りできるようにしたい、というふうに勘違いしてました。

宙返りしないのであれば、
マウスのX方向→横回転
マウスのY方向→縦回転
で問題ないです。

何が問題かというとD3DXMatrixLookAtLHの上向きを示すパラメータです。
真上や真下を向くときは視線と重なってしまうため、どっちが上か定まらずくるりと回ってしまうわけです。

視線を回転させるのといっしょに上向きを示すパラメータも回転してやれば問題はなくなりますが、真上や真下を見れないよう仰俯角に制限をかけるだけで済ますのがしばしば使われる手です。

Re: DirectXで視点の回転がうまくいかない

Posted: 2013年2月10日(日) 18:09
by ISLe
DXライブラリで真上や真下を見れるサンプルコード書いてみました。
FPSゲームふうのものです。
こちらの勘違いで惑わしてしまってすみません。

コード:

#include "DxLib.h"

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
	ChangeWindowMode(TRUE);
	if (DxLib_Init() != 0) return 0;
	SetDrawScreen(DX_SCREEN_BACK);

	VECTOR cameraPosision = VGet(0.0f, 0.0f, 0.0f);
	VECTOR cameraTarget = VGet(0.0f, 0.0f, 100.0f);
	VECTOR cameraUp = VGet(0.0f, 1.0f, 0.0f);

	SetupCamera_Perspective(DX_PI_F * 2 / 4);

	int xDist = 0;
	int yDist = 0;
	int xPosOld = 640/2;
	int yPosOld = 480/2;
	SetMousePoint(xPosOld, yPosOld);

	while (ProcessMessage() == 0 && ScreenFlip() == 0 && ClearDrawScreen() == 0) {
		{
			int xPos, yPos;
			GetMousePoint(&xPos, &yPos);
			SetMousePoint(xPosOld, yPosOld);

			xDist += xPos - xPosOld;
			yDist += yPos - yPosOld;

			// 真上や真下より後ろには回さない ※1000ピクセルで1周換算
			if (yDist < -250) yDist = -250;
			if (yDist >  250) yDist =  250;

			// 回転行列を作る
			MATRIX mat = MGetIdent();
			mat = MMult(mat, MGetRotX(yDist * DX_PI_F * 2 / 1000)); // ※1000ピクセルで1周換算
			mat = MMult(mat, MGetRotY(xDist * DX_PI_F * 2 / 1000)); // ※1000ピクセルで1周換算

			// カメラの向きを回転
			VECTOR target = VTransform(cameraTarget, mat);
			VECTOR up = VTransform(cameraUp, mat); // ※真上や真下で破綻させないために必要
			// ※カメラ位置も原点以外なら要変換
			SetCameraPositionAndTargetAndUpVec(cameraPosision, target, up);
		}
		{
			VECTOR v[] = {
				VGet(-100.0f,  100.0f,  100.0f),
				VGet( 100.0f,  100.0f,  100.0f),
				VGet(-100.0f, -100.0f,  100.0f),
				VGet( 100.0f, -100.0f,  100.0f),
				VGet( 100.0f,  100.0f, -100.0f),
				VGet( 100.0f, -100.0f, -100.0f),
				VGet(-100.0f,  100.0f, -100.0f),
				VGet(-100.0f, -100.0f, -100.0f),
			};
			int idxs[] = {
				0,6,1,4,1,6,0,1,2,3,2,1,1,4,3,5,3,4,4,6,5,7,5,6,6,0,7,2,7,0,2,3,7,5,7,3,
			};
			int color[] = {
				GetColor(  0,  0,255),
				GetColor(255,255,255),
				GetColor(255,192,  0),
				GetColor(255,255,  0),
				GetColor(255,  0,  0),
				GetColor(  0,255,  0),
			};
			for (int i=0; i<6*2; i++) {
				DrawTriangle3D(v[idxs[i*3+0]], v[idxs[i*3+1]], v[idxs[i*3+2]], color[i/2], TRUE);
			}
		}
		DrawString(0, 0, "終了 : Alt + F4", GetColor(0,0,0));
	}

	DxLib_End();
	return 0;
}

Re: DirectXで視点の回転がうまくいかない

Posted: 2013年2月11日(月) 22:53
by あうあう
うおお、サンプルコードまで書いていただきありがとうございます。
そちらのコードを参考にすることで、なんとか1歩進みました。
本当にありがとうございます!