行列を用いた注視カメラの円周回転行列の求め方

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

行列を用いた注視カメラの円周回転行列の求め方

#1

投稿記事 by KRNKRS » 7年前

私は現在、DXライブラリ(C++)を用いて「対象とする座標を見つつ、その周りを"角度指定で"回る」という処理を行列を用いて実装しようとしています。
こちら(http://i-libro.net/wpmu/blog/archives/618)のページや、こちら(http://dixq.net/forum/viewtopic.php?f=3&t=10136)のトピックを参考にすることで、「回転x移動」「移動x回転」の行列の計算結果の違いについて理解したつもりで以下のコードを書いたのですが期待したとおりの動きにはならず、こちらで質問させていただきました。
以下、回転処理のコードになります。

コード:

//回転(Z Up)
m_rotation.x += inputAxisL.y * ROTATE_SPEED; // 縦回転角度
m_rotation.y += inputAxisL.x * ROTATE_SPEED; // 横回転角度
//角度制限
m_rotation.x = ClampF(m_rotation.x, ANGLE_MIN, ANGLE_MAX);

//回転原点
MATRIX center = MGetTranslate(m_lookTargetPos);

//centerからずれる位置指定(m_toTargetLength:半径)
MATRIX moveMatX = MGetTranslate(VScale(VECTOR_X_AXIS, m_toTargetLength));
MATRIX moveMatZ = MGetTranslate(VScale(VECTOR_Z_AXIS, m_toTargetLength));

//カメラ右方向軸とワールドZ軸で回転指定
//cameraWorldMat = MInverse(GetCameraViewMatrix());
MATRIX rotMatX = MGetRotAxis(VTransformSR(VECTOR_X_AXIS, cameraWorldMat), -DegToRad(m_rotation.x));
MATRIX rotMatZ = MGetRotZ(DegToRad(m_rotation.y));

//以下
//http://i-libro.net/wpmu/blog/archives/618
//参考箇所
MATRIX posMat = MATRIX_IDENTITY;
//移動行列をかける
posMat = MMult(posMat, moveMatX);
posMat = MMult(posMat, moveMatZ);
//回転行列をかける
posMat = MMult(posMat, rotMatX);
posMat = MMult(posMat, rotMatZ);
//回転原点からずらす
posMat = MMult(posMat, center);

//行列からX,Y,Z座標を抜き出す関数から移動先となる座標を取得
m_position = GetPositionFromMatrix(posMat);
SetCameraPositionAndTargetAndUpVec(m_position, m_lookTargetPos, VECTOR_Z_AXIS);

コード:

//行列からX,Y,Z座標を抜き出す関数
VECTOR Camera::GetPositionFromMatrix(MATRIX mat)
{
    return VGet(mat.m[3][0], mat.m[3][1], mat.m[3][2]);
}
具体的には、
「左右で横方向回転」「上下で縦方向回転(角度制限あり)」「角度指定で回転」
というのが期待した挙動だったのですが、
このプログラムを実行すると、ほんの少し縦横に波打ちつつ回転した直後、怒涛の勢いでカメラがあらぶります。

また角度制限も、360度(180~360間での最大角度)と指定がされているのに中途半端な位置で止まってしまいます。
この件については、

コード:

//centerからずれる位置指定(半径)
MATRIX moveMatX = MGetTranslate(VScale(VECTOR_X_AXIS, m_toTargetLength));
MATRIX moveMatZ = MGetTranslate(VScale(VECTOR_Z_AXIS, m_toTargetLength));
で「二つのベクトルを使用しているから斜め方向にベクトルが向いてしまっているからだ」と推測します。
が、VECTOR_Z_AXIS(0, 0, 1)のみですと、横方向回転はしますが縦方向回転が行われなくなってしまいます。

期待する通りの挙動を行わせるには、どういった修正を行うべきか、また修正に当たって参考になるサイトなどの情報を頂ければと思います。
よろしくお願いいたします。

Idra

Re: 行列を用いた注視カメラの円周回転行列の求め方

#2

投稿記事 by Idra » 7年前

こんな感じでいいと思うけど

コード:

MATRIX localTransform = MGetTranslate(VGet(0,0,-m_toTargetLength));
MATRIX rotation = MMult(MGetRotX(m_rotation.x), MGetRotY(m_rotation.y)); //m_rotationはラジアンで
MATRIX translation = MGetTranslate(m_lookTargetPos);

MATRIX transform = MMult(MMult(localTransform, rotation), translation);
MATRIX view = MInverse(transform); //カメラの変換行列の逆行列がビュー行列になるという手抜きテク
SetCameraViewMatrix(view);

KRNKRS
記事: 40
登録日時: 10年前
連絡を取る:

Re: 行列を用いた注視カメラの円周回転行列の求め方

#3

投稿記事 by KRNKRS » 7年前

動きましたありがとうございます!
こんなに短くできるんですね...

Idra

Re: 行列を用いた注視カメラの円周回転行列の求め方

#4

投稿記事 by Idra » 7年前

上手くいって良かったです。
ベクトルや行列を使いこなすのはなかなか難しいので、
一度「実例で学ぶゲーム3D数学」などの参考書でがっつり勉強するといいですよ。

返信

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