合計 昨日 今日

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

フォーラムルール
フォーラムルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
Name: KRNKRS
[URL]
入門者(4,770 ポイント)
Date: 2017年4月14日(金) 19:33
No: 1
(OFFLINE)

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

私は現在、DXライブラリ(C++)を用いて「対象とする座標を見つつ、その周りを"角度指定で"回る」という処理を行列を用いて実装しようとしています。
こちら(http://i-libro.net/wpmu/blog/archives/618)のページや、こちら(viewtopic.php?f=3&t=10136)のトピックを参考にすることで、「回転x移動」「移動x回転」の行列の計算結果の違いについて理解したつもりで以下のコードを書いたのですが期待したとおりの動きにはならず、こちらで質問させていただきました。
以下、回転処理のコードになります。
コード[C++]: 全て選択
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
//回転(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);


コード[C++]: 全て選択
1
2
3
4
5
//行列から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間での最大角度)と指定がされているのに中途半端な位置で止まってしまいます。
この件については、
コード[C++]: 全て選択
1
2
3
//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)のみですと、横方向回転はしますが縦方向回転が行われなくなってしまいます。

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

Name: Idra
[URL]
Date: 2017年4月15日(土) 10:00
No: 2
(OFFLINE)

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

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

コード[C++]: 全て選択
1
2
3
4
5
6
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);

Name: KRNKRS
[URL]
入門者(4,770 ポイント)
Date: 2017年4月15日(土) 16:56
No: 3
(OFFLINE)

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

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

Name: Idra
[URL]
Date: 2017年4月15日(土) 20:18
No: 4
(OFFLINE)

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

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


Return to C言語何でも質問掲示板

オンラインデータ

このフォーラムを閲覧中のユーザー: なし & ゲスト[4人]