カメラの向いている方向にカメラを移動させたい

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

カメラの向いている方向にカメラを移動させたい

#1

投稿記事 by elle » 10年前

今3Dで簡単なプログラムを作っていて、つまづいています。
やりたいことはタイトルの通りなのですが、とりあえず最初に移動と周囲の見渡しができるように書いたコードが以下です。

コード:

#include "../dxlib_vc/DxLib.h"

const float PI = 3.1415926525897932f;
const float PI2 = 6.28318530718f;
const int DC_WIDTH = 800;
const int DC_HEIGHT = 600;
const int KEYMAX = 256;
const float ROTATE_AMOUNT = PI2 / 360;
const float MOVE_AMOUNT = 10.0f;

int WINAPI WinMain(HINSTANCE hThisInst, HINSTANCE hPrevInst, LPSTR lpszArgs, int nWinMode)
{
	ChangeWindowMode(TRUE);
	SetGraphMode(DC_WIDTH, DC_HEIGHT, 32);
	if (DxLib_Init()) return -1;
	SetDrawScreen(DX_SCREEN_BACK);

	char keystateBuf[KEYMAX];
	char keystate[KEYMAX] = { 0 };
	const float baseX = -500.0f;
	const float baseY = -500.0f;
	const float baseZ = -500.0f;
	const int LINE_MAX = 24;
	const float interval = 150.0f;
	const float endX = baseX + interval * LINE_MAX;
	const float endY = baseY + interval * LINE_MAX;
	const float endZ = baseZ + interval * LINE_MAX;

	VECTOR rotate = { 0 };
	VECTOR cameraPos = { DC_WIDTH / 2, DC_HEIGHT / 2, -1.0f };

	while (!ScreenFlip() && !ClearDrawScreen() && !ProcessMessage() && !CheckHitKey(KEY_INPUT_ESCAPE)){

		// keystate準備
		GetHitKeyStateAll(keystateBuf);
		for (int i = 0; i < KEYMAX; ++i){
			keystate[i] = keystateBuf[i] ? ++keystate[i] : 0;
		}

		// ☆
		if (keystate[KEY_INPUT_A])			cameraPos.x -= MOVE_AMOUNT;
		if (keystate[KEY_INPUT_D])			cameraPos.x += MOVE_AMOUNT;
		if (keystate[KEY_INPUT_W])			cameraPos.y += MOVE_AMOUNT;
		if (keystate[KEY_INPUT_S])			cameraPos.y -= MOVE_AMOUNT;
		if (keystate[KEY_INPUT_LSHIFT])		cameraPos.z += MOVE_AMOUNT;
		if (keystate[KEY_INPUT_LCONTROL])	cameraPos.z -= MOVE_AMOUNT;

		if (keystate[KEY_INPUT_LEFT])		rotate.x -= ROTATE_AMOUNT;
		if (keystate[KEY_INPUT_RIGHT])		rotate.x += ROTATE_AMOUNT;
		if (keystate[KEY_INPUT_UP])			rotate.y -= ROTATE_AMOUNT;
		if (keystate[KEY_INPUT_DOWN])		rotate.y += ROTATE_AMOUNT;
		if (keystate[KEY_INPUT_RSHIFT])		rotate.z += ROTATE_AMOUNT;
		if (keystate[KEY_INPUT_RCONTROL])	rotate.z -= ROTATE_AMOUNT;

		SetCameraPositionAndAngle(cameraPos, rotate.y, rotate.x, rotate.z);

		// 線
		for (int i = 0; i <= LINE_MAX; ++i){
			for (int j = 0; j <= LINE_MAX; ++j){
				DrawLine3D(VGet(baseX, baseY + i * interval, baseZ + j * interval), VGet(endX, baseY + i * interval, baseZ + j * interval), GetColor(255.f * i / LINE_MAX, 255.f * j / LINE_MAX, 255)); 
				DrawLine3D(VGet(baseX + i * interval, baseY, baseZ + j * interval), VGet(baseX + i * interval, endY, baseZ + j * interval), GetColor(255.f * i / LINE_MAX, 255.f * j / LINE_MAX, 255)); 
				DrawLine3D(VGet(baseX + i * interval, baseY + j * interval, baseZ), VGet(baseX + i * interval, baseY + j * interval, endZ), GetColor(255.f * i / LINE_MAX, 255.f * j / LINE_MAX, 255));
			}
		}

		// debug output
		DrawFormatString(0, 0, GetColor(255, 255, 255), "Rotate Y:% .2f,X:% .2f,Z:% .2f,", rotate.y, rotate.x, rotate.z);
	}

	DxLib_End();
	return 0;
}
このままだとどの方向を向いていてもキーに割り当てられた方向に移動してしまうので、
最終的には、LSHIFTキー(初期状態では前進の意)を押し続けると(絶対座標が)右上を向いていれば右上に、左下手前を向いていれば左下手前にcameraPosが移動するようにしたく、
//☆の部分を色々いじってみたのですが、自分が行列が苦手なこともあり、
rotateを回転行列としてMMultしたりしましたが、富士急ハイランドのような動きになってしまったり、思った通りの動きになりません。
また、

コード:

		if (keystate[KEY_INPUT_A])			cameraPos = VTransform(cameraPos, MGetTranslate(VGet(+1.0f,0.0f,0.0f)));
		if (keystate[KEY_INPUT_D])			cameraPos = VTransform(cameraPos, MGetTranslate(VGet(-1.0f,0.0f,0.0f)));
		if (keystate[KEY_INPUT_W])			cameraPos = VTransform(cameraPos, MGetTranslate(VGet(0.0f,+1.0f,0.0f)));
		if (keystate[KEY_INPUT_S])			cameraPos = VTransform(cameraPos, MGetTranslate(VGet(0.0f,-1.0f,0.0f)));
		if (keystate[KEY_INPUT_LSHIFT])		cameraPos = VTransform(cameraPos, MGetTranslate(VGet(0.0f,0.0f,+1.0f)));
		if (keystate[KEY_INPUT_LCONTROL])	cameraPos = VTransform(cameraPos, MGetTranslate(VGet(0.0f,0.0f,-1.0f)));
こんなこともしてみましたが上のコードと同じことになってしまいました。

今向いている方向を基準にしてキー押下で移動するためには、どのようにすればいいのでしょうか。

アバター
みけCAT
記事: 6734
登録日時: 13年前
住所: 千葉県
連絡を取る:

Re: カメラの向いている方向にカメラを移動させたい

#2

投稿記事 by みけCAT » 10年前

試していないので間違っているかもしれないですが、
まずGetCameraViewMatrix関数でカメラのビュー行列を取得し、
それの逆行列をMInverse関数で取得すれば、
見た目の座標→実際の座標に変換する行列が取得できる気がします。

移動したい方向のベクトルをその行列で一次変換(掛け算)すれば、カメラの位置に加算するべきベクトルが得られると思います。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 13年前
住所: 東海地方
連絡を取る:

Re: カメラの向いている方向にカメラを移動させたい

#3

投稿記事 by softya(ソフト屋) » 10年前

みけCAT さんが書きました:試していないので間違っているかもしれないですが、
まずGetCameraViewMatrix関数でカメラのビュー行列を取得し、
それの逆行列をMInverse関数で取得すれば、
見た目の座標→実際の座標に変換する行列が取得できる気がします。

移動したい方向のベクトルをその行列で一次変換(掛け算)すれば、カメラの位置に加算するべきベクトルが得られると思います。
みけCATさんの言われる方法で大丈夫だと思います。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

elle
記事: 39
登録日時: 10年前

Re: カメラの向いている方向にカメラを移動させたい

#4

投稿記事 by elle » 10年前

みけCATさん、softyaさん、ありがとうございます。
その方法を参考に試行錯誤しているのですが、

コード:

		const float moveAmount = 0.1f;
		const VECTOR VecPositiveX = VGet(+moveAmount, .0f, .0f);
		const VECTOR VecNegativeX = VGet(-moveAmount, .0f, .0f);
		const VECTOR VecPositiveY = VGet(.0f, +moveAmount, .0f);
		const VECTOR VecNegativeY = VGet(.0f, -moveAmount, .0f);
		const VECTOR VecPositiveZ = VGet(.0f, .0f, +moveAmount);
		const VECTOR VecNegativeZ = VGet(.0f, .0f, -moveAmount);

		const MATRIX convMat = MInverse(GetCameraViewMatrix());

		if (keystate[KEY_INPUT_A])			cameraPos = VAdd(cameraPos, VTransform(VecNegativeX, convMat));
		if (keystate[KEY_INPUT_D])			cameraPos = VAdd(cameraPos, VTransform(VecPositiveX, convMat));
		if (keystate[KEY_INPUT_W])			cameraPos = VAdd(cameraPos, VTransform(VecPositiveY, convMat));
		if (keystate[KEY_INPUT_S])			cameraPos = VAdd(cameraPos, VTransform(VecNegativeY, convMat));
		if (keystate[KEY_INPUT_LSHIFT])		cameraPos = VAdd(cameraPos, VTransform(VecPositiveZ, convMat));
		if (keystate[KEY_INPUT_LCONTROL])	cameraPos = VAdd(cameraPos, VTransform(VecNegativeZ, convMat));
このコードだとどのキーを押しても右上に加速度的に飛んで行ってしまいます…。
cameraPosを表示させてみると X:6400 Y:4800 Z:-16などとなっていたので、原点→カメラの座標のベクトルに乗って離れて行っているように思いました。
どこかで使い方を間違えてしまったでしょうか…?

実行コード:
► スポイラーを表示

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 13年前
住所: 東海地方
連絡を取る:

Re: カメラの向いている方向にカメラを移動させたい

#5

投稿記事 by softya(ソフト屋) » 10年前

convMatに移動したい方向の回転行列を掛けあわせて、その行列でcameraPos をVTransformしたらうまく行きませんか?
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

elle
記事: 39
登録日時: 10年前

Re: カメラの向いている方向にカメラを移動させたい

#6

投稿記事 by elle » 10年前

こうでしょうか?

コード:

		const MATRIX convMat = MInverse(GetCameraViewMatrix());

		if (keystate[KEY_INPUT_A])			cameraPos = VTransform(cameraPos, MMult(convMat, MGetRotX(-PI2 / 360)));
		if (keystate[KEY_INPUT_D])			cameraPos = VTransform(cameraPos, MMult(convMat, MGetRotX(+PI2 / 360)));
		if (keystate[KEY_INPUT_W])			cameraPos = VTransform(cameraPos, MMult(convMat, MGetRotY(+PI2 / 360)));
		if (keystate[KEY_INPUT_S])			cameraPos = VTransform(cameraPos, MMult(convMat, MGetRotY(-PI2 / 360)));
		if (keystate[KEY_INPUT_LSHIFT])		cameraPos = VTransform(cameraPos, MMult(convMat, MGetRotZ(+PI2 / 360)));
		if (keystate[KEY_INPUT_LCONTROL])	cameraPos = VTransform(cameraPos, MMult(convMat, MGetRotZ(-PI2 / 360)));
結果は前と同じになってしまいました…。

実行コード:
► スポイラーを表示

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 13年前
住所: 東海地方
連絡を取る:

Re: カメラの向いている方向にカメラを移動させたい

#7

投稿記事 by softya(ソフト屋) » 10年前

あっ直接VTransformではなく、真正面の移動ベクトルをVTransformしてcameraPos にVAddしてください。すいません。ボケてました。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

elle
記事: 39
登録日時: 10年前

Re: カメラの向いている方向にカメラを移動させたい

#8

投稿記事 by elle » 10年前

ありがとうございます。そうしますと、こうでしょうか?

コード:

		const float moveAmount = 0.1f;
		const VECTOR VecPositiveX = VGet(+moveAmount, .0f, .0f);
		const VECTOR VecNegativeX = VGet(-moveAmount, .0f, .0f);
		const VECTOR VecPositiveY = VGet(.0f, +moveAmount, .0f);
		const VECTOR VecNegativeY = VGet(.0f, -moveAmount, .0f);
		const VECTOR VecPositiveZ = VGet(.0f, .0f, +moveAmount);
		const VECTOR VecNegativeZ = VGet(.0f, .0f, -moveAmount);

		const MATRIX convMat = MInverse(GetCameraViewMatrix());

		if (keystate[KEY_INPUT_A])			cameraPos = VAdd(cameraPos, VTransform(VecNegativeX, MMult(convMat, MGetRotX(-PI2 / 360))));
		if (keystate[KEY_INPUT_D])			cameraPos = VAdd(cameraPos, VTransform(VecPositiveX, MMult(convMat, MGetRotX(+PI2 / 360))));
		if (keystate[KEY_INPUT_W])			cameraPos = VAdd(cameraPos, VTransform(VecPositiveY, MMult(convMat, MGetRotY(+PI2 / 360))));
		if (keystate[KEY_INPUT_S])			cameraPos = VAdd(cameraPos, VTransform(VecNegativeY, MMult(convMat, MGetRotY(-PI2 / 360))));
		if (keystate[KEY_INPUT_LSHIFT])		cameraPos = VAdd(cameraPos, VTransform(VecPositiveZ, MMult(convMat, MGetRotZ(+PI2 / 360))));
		if (keystate[KEY_INPUT_LCONTROL])	cameraPos = VAdd(cameraPos, VTransform(VecNegativeZ, MMult(convMat, MGetRotZ(-PI2 / 360))));
これでもやはり、右上に高速移動してしまいます…。

実行コード:
► スポイラーを表示

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 13年前
住所: 東海地方
連絡を取る:

Re: カメラの向いている方向にカメラを移動させたい

#9

投稿記事 by softya(ソフト屋) » 10年前

原因が別にあるかも知れないので、足しているベクトル値をprintfDXなどで表示してみてください。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

elle
記事: 39
登録日時: 10年前

Re: カメラの向いている方向にカメラを移動させたい

#10

投稿記事 by elle » 10年前

以下のようなコードにしてみました。
► スポイラーを表示
足しているベクトル値が大きく、初期値でカメラの座標の値が移動量として扱われていますね…。
キーを押すと倍倍にベクトル値も増加しているようです。
また、カメラのrotateを動かすと、その回転方向のベクトル値にmoveAmountの量を最大値として影響があるようですが、
足すベクトルの値は本来は0を基準にしてmoveAmountの中で変化するべきところが、カメラの座標を基準に変化しているということでしょうか。

コード:

		if (keystate[KEY_INPUT_D])			cameraPos = VAdd(VecPositiveX, addedPositiveX);
		if (keystate[KEY_INPUT_A])			cameraPos = VAdd(VecPositiveX, addedNegativeX);
		if (keystate[KEY_INPUT_W])			cameraPos = VAdd(VecPositiveY, addedPositiveY);
		if (keystate[KEY_INPUT_S])			cameraPos = VAdd(VecPositiveY, addedNegativeY);
		if (keystate[KEY_INPUT_LSHIFT])		cameraPos = VAdd(VecPositiveZ, addedPositiveZ);
		if (keystate[KEY_INPUT_LCONTROL])	cameraPos = VAdd(VecPositiveZ, addedNegativeZ);
こうもしてみましたが、やはり直線的になりません。なぜ…

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 13年前
住所: 東海地方
連絡を取る:

Re: カメラの向いている方向にカメラを移動させたい

#11

投稿記事 by softya(ソフト屋) » 10年前

ちょっと忙しいので、夜にでも確認してみます。
他の方で調べられる方がいたらお願いします。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 13年前
住所: 東海地方
連絡を取る:

Re: カメラの向いている方向にカメラを移動させたい

#12

投稿記事 by softya(ソフト屋) » 10年前

こんな感じですかね。
カメラビューマトリクスの逆行列convMat から平行移動成分だけを取り除いて、それぞれの方向ベクトルをconvMat で回転させて移動ベクトルを作成しています。

コード:

#include "DxLib.h"
 
const float PI = 3.1415926525897932f;
const float PI2 = 6.28318530718f;
const int DC_WIDTH = 800;
const int DC_HEIGHT = 600;
const int KEYMAX = 256;
const float ROTATE_AMOUNT = PI2 / 360;
const float MOVE_AMOUNT = 10.0f;
 
int WINAPI WinMain(HINSTANCE hThisInst, HINSTANCE hPrevInst, LPSTR lpszArgs, int nWinMode)
{
    ChangeWindowMode(TRUE);
    SetGraphMode(DC_WIDTH, DC_HEIGHT, 32);
    if (DxLib_Init()) return -1;
    SetDrawScreen(DX_SCREEN_BACK);
 
    char keystateBuf[KEYMAX];
    char keystate[KEYMAX] = { 0 };
    const float baseX = -500.0f;
    const float baseY = -500.0f;
    const float baseZ = -500.0f;
    const int LINE_MAX = 24;
    const float interval = 150.0f;
    const float endX = baseX + interval * LINE_MAX;
    const float endY = baseY + interval * LINE_MAX;
    const float endZ = baseZ + interval * LINE_MAX;
 
    VECTOR rotate = { 0 };
    VECTOR cameraPos = { DC_WIDTH / 2, DC_HEIGHT / 2, -1.0f };
 
    while (!ScreenFlip() && !ClearDrawScreen() && !ProcessMessage() && !CheckHitKey(KEY_INPUT_ESCAPE)){
 
        // keystate準備
        GetHitKeyStateAll(keystateBuf);
        for (int i = 0; i < KEYMAX; ++i){
            keystate[i] = keystateBuf[i] ? ++keystate[i] : 0;
        }
 
        // ☆
        const float moveAmount = 0.1f;
        const VECTOR VecPositiveX = VGet(+moveAmount, .0f, .0f);
        const VECTOR VecNegativeX = VGet(-moveAmount, .0f, .0f);
        const VECTOR VecPositiveY = VGet(.0f, +moveAmount, .0f);
        const VECTOR VecNegativeY = VGet(.0f, -moveAmount, .0f);
        const VECTOR VecPositiveZ = VGet(.0f, .0f, +moveAmount);
        const VECTOR VecNegativeZ = VGet(.0f, .0f, -moveAmount);
 
 		//	回転だけにする。
        MATRIX convMat = MInverse(GetCameraViewMatrix());
        convMat.m[3][0] = 0;
        convMat.m[3][1] = 0;
        convMat.m[3][2] = 0;
        convMat.m[3][3] = 0;
 
        VECTOR addedPositiveX = VTransform(VecPositiveX, convMat );
        VECTOR addedNegativeX = VTransform(VecNegativeX, convMat );
        VECTOR addedPositiveY = VTransform(VecPositiveY, convMat );
        VECTOR addedNegativeY = VTransform(VecNegativeY, convMat );
        VECTOR addedPositiveZ = VTransform(VecPositiveZ, convMat );
        VECTOR addedNegativeZ = VTransform(VecNegativeZ, convMat );
 
        if (keystate[KEY_INPUT_D])          cameraPos = VAdd(cameraPos, addedPositiveX);
        if (keystate[KEY_INPUT_A])          cameraPos = VAdd(cameraPos, addedNegativeX);
        if (keystate[KEY_INPUT_W])          cameraPos = VAdd(cameraPos, addedPositiveY);
        if (keystate[KEY_INPUT_S])          cameraPos = VAdd(cameraPos, addedNegativeY);
        if (keystate[KEY_INPUT_LSHIFT])     cameraPos = VAdd(cameraPos, addedPositiveZ);
        if (keystate[KEY_INPUT_LCONTROL])   cameraPos = VAdd(cameraPos, addedNegativeZ);
 
        if (keystate[KEY_INPUT_LEFT])       rotate.x -= ROTATE_AMOUNT;
        if (keystate[KEY_INPUT_RIGHT])      rotate.x += ROTATE_AMOUNT;
        if (keystate[KEY_INPUT_UP])         rotate.y -= ROTATE_AMOUNT;
        if (keystate[KEY_INPUT_DOWN])       rotate.y += ROTATE_AMOUNT;
        if (keystate[KEY_INPUT_RSHIFT])     rotate.z += ROTATE_AMOUNT;
        if (keystate[KEY_INPUT_RCONTROL])   rotate.z -= ROTATE_AMOUNT;
 
        SetCameraPositionAndAngle(cameraPos, rotate.y, rotate.x, rotate.z);
 
        // 線
        for (int i = 0; i <= LINE_MAX; ++i){
            for (int j = 0; j <= LINE_MAX; ++j){
                DrawLine3D(VGet(baseX, baseY + i * interval, baseZ + j * interval), VGet(endX, baseY + i * interval, baseZ + j * interval), GetColor(255.f * i / LINE_MAX, 255.f * j / LINE_MAX, 255));
                DrawLine3D(VGet(baseX + i * interval, baseY, baseZ + j * interval), VGet(baseX + i * interval, endY, baseZ + j * interval), GetColor(255.f * i / LINE_MAX, 255.f * j / LINE_MAX, 255));
                DrawLine3D(VGet(baseX + i * interval, baseY + j * interval, baseZ), VGet(baseX + i * interval, baseY + j * interval, endZ), GetColor(255.f * i / LINE_MAX, 255.f * j / LINE_MAX, 255));
            }
        }
 
        // debug output
        DrawFormatString(0, 500, GetColor(255, 255, 255), "Rotate Y:% .2f,X:% .2f,Z:% .2f,", rotate.y, rotate.x, rotate.z);
        DrawFormatString(0, 530, GetColor(255, 255, 255), "cameraPos X:% .2f,Y:% .2f,Z:% .2f,", cameraPos.x, cameraPos.y, cameraPos.z);
        clsDx();
        printfDx(
            "+X.x:% .2f, +X.y:% .2f, +X.z:% .2f, \n-X.x:% .2f, -X.y:% .2f, -X.z:% .2f, \n"
            "+Y.x:% .2f, +Y.y:% .2f, +Y.z:% .2f, \n-Y.x:% .2f, -Y.y:% .2f, -Y.z:% .2f, \n"
            "+Z.x:% .2f, +Z.y:% .2f, +Z.z:% .2f, \n-Z.x:% .2f, -Z.y:% .2f, -Z.z:% .2f, \n"
            ,
            addedPositiveX.x, addedPositiveX.y, addedPositiveX.z, addedNegativeX.x, addedNegativeX.y, addedNegativeX.z,
            addedPositiveY.x, addedPositiveY.y, addedPositiveY.z, addedNegativeY.x, addedNegativeY.y, addedNegativeY.z,
            addedPositiveZ.x, addedPositiveZ.y, addedPositiveZ.z, addedNegativeZ.x, addedNegativeZ.y, addedNegativeZ.z
            );
    }
 
    DxLib_End();
    return 0;
}
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

elle
記事: 39
登録日時: 10年前

Re: カメラの向いている方向にカメラを移動させたい

#13

投稿記事 by elle » 10年前

…!!!す、すごいです…!
まさにやりたかった動きそのものです。
行列の平行移動の部分を無効化する必要があったんですね。
綺麗に動いた瞬間感動しました…
お忙しい中お答えいただき本当にありがとうございます!!

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 13年前
住所: 東海地方
連絡を取る:

Re: カメラの向いている方向にカメラを移動させたい

#14

投稿記事 by softya(ソフト屋) » 10年前

やってから思いましたが、rotate.y, rotate.x, rotate.zで回転マトリクスを作っても結果は同じ気がします。
※ rotate.y ⇔  rotate.x 入れ替わってませんか?
MATRIX rotateMatrix = MMult( MMult( MGetRotZ( RotZ ), MGetRotX( RotX ) ), MGetRotY( RotY ) );//回転マトリクス
X,Y,Zの順番があるので、間違えないようにしてください。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

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

Re: カメラの向いている方向にカメラを移動させたい

#15

投稿記事 by ISLe » 10年前

平行移動成分を使わないのは、MATRIXを弄るより、VTransformの代わりにVTransformSRを使ったほうが計算量が減るような気がします。

roteteを使った場合のコード書いてみました。
せっかくなので式をまとめて計算量を減らしました。

コード:

        // ☆
        float vx = 0.0f;
        float vy = 0.0f;
        float vz = 0.0f;
        if (keystate[KEY_INPUT_A])          vx = -MOVE_AMOUNT;
        if (keystate[KEY_INPUT_D])          vx =  MOVE_AMOUNT;
        if (keystate[KEY_INPUT_W])          vy =  MOVE_AMOUNT;
        if (keystate[KEY_INPUT_S])          vy = -MOVE_AMOUNT;
        if (keystate[KEY_INPUT_LSHIFT])     vz =  MOVE_AMOUNT;
        if (keystate[KEY_INPUT_LCONTROL])   vz = -MOVE_AMOUNT;
        VECTOR v = VGet(vx, vy, vz);
        MATRIX m = MMult(MMult(MGetRotZ(rotate.z), MGetRotY(rotate.x)), MGetRotX(rotate.y));
        //MATRIX m = MGetIdent();
        //m= MMult(m, MGetRotX(rotate.y));
        //m= MMult(m, MGetRotY(rotate.x));
        //m= MMult(m, MGetRotZ(rotate.z));
        v = VTransformSR(v, m);
        cameraPos = VAdd(cameraPos, v);

elle
記事: 39
登録日時: 10年前

Re: カメラの向いている方向にカメラを移動させたい

#16

投稿記事 by elle » 10年前

softyaさん
ありがとうございます、仰るとおりでした。

コード:

		const MATRIX rotateMatrix = MMult(MMult(MGetRotZ(rotate.z), MGetRotX(rotate.x)), MGetRotY(rotate.y));

		if (keystate[KEY_INPUT_D])			cameraPos = VAdd(cameraPos, VTransform(VecPositiveX, rotateMatrix));
		if (keystate[KEY_INPUT_A])			cameraPos = VAdd(cameraPos, VTransform(VecNegativeX, rotateMatrix));
		if (keystate[KEY_INPUT_W])			cameraPos = VAdd(cameraPos, VTransform(VecPositiveY, rotateMatrix));
		if (keystate[KEY_INPUT_S])			cameraPos = VAdd(cameraPos, VTransform(VecNegativeY, rotateMatrix));
		if (keystate[KEY_INPUT_LSHIFT])		cameraPos = VAdd(cameraPos, VTransform(VecPositiveZ, rotateMatrix));
		if (keystate[KEY_INPUT_LCONTROL])	cameraPos = VAdd(cameraPos, VTransform(VecNegativeZ, rotateMatrix));
これでも同じように動作しました。

回転の方も、

コード:

		if (keystate[KEY_INPUT_RIGHT])		rotate.y += ROTATE_AMOUNT;
		if (keystate[KEY_INPUT_LEFT])		rotate.y -= ROTATE_AMOUNT;
		if (keystate[KEY_INPUT_DOWN])		rotate.x += ROTATE_AMOUNT;
		if (keystate[KEY_INPUT_UP])			rotate.x -= ROTATE_AMOUNT;
		if (keystate[KEY_INPUT_RSHIFT])		rotate.z += ROTATE_AMOUNT;
		if (keystate[KEY_INPUT_RCONTROL])	rotate.z -= ROTATE_AMOUNT;

		SetCameraPositionAndAngle(cameraPos, rotate.x, rotate.y, rotate.z);
正しくはこうですね。
Vertical RotateとHorizontal Rotateを逆に考えてました。

カメラが天地逆転したときの左右の回転が逆になるのはまた別の問題ですよね。
もう少し調べてみます…。

ISLeさん
ありがとうございます。
VTransform と違い InV を行列として見立てた際の第4要素が 0.0f (DXライブラリ置き場 - VTransformSR関数
というのはこういう時のための機能だったのですね…。
平行移動を実現している効果が反映されません(同上)
とあったので何か苦肉の策として使用するマイナー関数かと思っていました。

コード:

		MATRIX convMat = MInverse(GetCameraViewMatrix());

		if (keystate[KEY_INPUT_D])			cameraPos = VAdd(cameraPos, VTransformSR(VecPositiveX, convMat));
		if (keystate[KEY_INPUT_A])			cameraPos = VAdd(cameraPos, VTransformSR(VecNegativeX, convMat));
		if (keystate[KEY_INPUT_W])			cameraPos = VAdd(cameraPos, VTransformSR(VecPositiveY, convMat));
		if (keystate[KEY_INPUT_S])			cameraPos = VAdd(cameraPos, VTransformSR(VecNegativeY, convMat));
		if (keystate[KEY_INPUT_LSHIFT])		cameraPos = VAdd(cameraPos, VTransformSR(VecPositiveZ, convMat));
		if (keystate[KEY_INPUT_LCONTROL])	cameraPos = VAdd(cameraPos, VTransformSR(VecNegativeZ, convMat));
これで確かに同じ動作です。


最終的にこのようなコードになりました。
皆さんのアドバイスに感謝します!
(よく考えたら動きのベクトルに掛ける変換行列はrotateを元にしているので、rotateを先にしてmoveを後にしました)
► スポイラーを表示

閉鎖

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