クォータニオンで指定した自機の回転から、追従するカメラの回転を指定したい
Posted: 2013年6月29日(土) 21:34
現在フライトシューティングゲームを作っているのですが、自機のクォータニオンで指定した角度から、カメラの回転行列で指定する角度が計算できなくて悩んでいます。
カメラは、自機の位置の後方に存在するイメージです。
エースコンバットみたいなものをそのまま再現したいです。
どんなふうに回転しているかの説明なのですが
自機クラスでは自機から見た、ピッチ、ロール、ヨーの動作を実現するためにベクトル型のAxisX,Y,Zをメンバとして持ってます。
そしてこれらは、どれか1つの軸が回転するとそれに合わせて回転します。
例えばZ軸を回転させると、3Dモデルはロールに相当する機首の回転をさせます。
つまり、X軸とY軸(ピッチとヨー)が、Z軸に合わせてX軸とY軸のベクトルが回転し、ピッチ・ヨーの回転方向が変わるというものです。
こんなかんじで、自機からみたx,y,z軸を基準に回転させると、操作と回転を直結できて便利だったのですが、
自機の後方を維持して回転をそのままトレースするようなカメラの動きをさせたいと思った時に3つのベクトルから回転行列を作成するにはどうしたらいいかわかりません。
半日ぐらい悩んで
自機の座標から-Z軸方向にある程度距離を作って(平行移動)、自機の回転行列をそのまま適用すればできる気がしなくもないのですが、中々コードで表現できません。
1つのベクトルの回転率はそのまま他の2つのベクトルで表現しているため数値化されていないからでしょうか?
ただ、回転を数値化しても回転する順番で結果が変わる気がするので、あまり意味無いような気もします。
どうしたらいいでしょうか?
メンバ変数
実装
カメラは、自機の位置の後方に存在するイメージです。
エースコンバットみたいなものをそのまま再現したいです。
どんなふうに回転しているかの説明なのですが
自機クラスでは自機から見た、ピッチ、ロール、ヨーの動作を実現するためにベクトル型のAxisX,Y,Zをメンバとして持ってます。
そしてこれらは、どれか1つの軸が回転するとそれに合わせて回転します。
例えばZ軸を回転させると、3Dモデルはロールに相当する機首の回転をさせます。
つまり、X軸とY軸(ピッチとヨー)が、Z軸に合わせてX軸とY軸のベクトルが回転し、ピッチ・ヨーの回転方向が変わるというものです。
こんなかんじで、自機からみたx,y,z軸を基準に回転させると、操作と回転を直結できて便利だったのですが、
自機の後方を維持して回転をそのままトレースするようなカメラの動きをさせたいと思った時に3つのベクトルから回転行列を作成するにはどうしたらいいかわかりません。
半日ぐらい悩んで
自機の座標から-Z軸方向にある程度距離を作って(平行移動)、自機の回転行列をそのまま適用すればできる気がしなくもないのですが、中々コードで表現できません。
1つのベクトルの回転率はそのまま他の2つのベクトルで表現しているため数値化されていないからでしょうか?
ただ、回転を数値化しても回転する順番で結果が変わる気がするので、あまり意味無いような気もします。
どうしたらいいでしょうか?
メンバ変数
//自機クラス
class CFighter{
friend class CCamera;
private:
//位置座標
VECTOR Position;
//角度
VECTOR AxisX;
VECTOR AxisY;
VECTOR AxisZ; //実際に自機が向いている方向はZ方向
CModel* Model;
}
実装
CFighter::CFighter(string ModelPath){
Model = new CModel(ModelPath);
Position=VGet(0.0f, 0.0f, 600.0f);
AxisX= VGet(1,0,0);
AxisY= VGet(0,1,0);
AxisZ= VGet(0,0,1);
}
//位置座標
void CFighter::SetPosition(VECTOR tmpPosition){
Position = tmpPosition;
}
VECTOR CFighter::ReactionQuaternion(VECTOR Axis,VECTOR EffectVector,float Rotation){
//Q = (q; V) 指定軸の回転
float rotaq=cos(Rotation/2);
VECTOR vectq=VGet(Axis.x*sin(Rotation/2),Axis.y*sin(Rotation/2),Axis.z*sin(Rotation/2));
//R = (r; W) Qのベクトルを反転したもの。
float rotar=cos(Rotation/2);
VECTOR vectr=VGet(-Axis.x*sin(Rotation/2),-Axis.y*sin(Rotation/2),-Axis.z*sin(Rotation/2));
//RとPの掛け算をしてCクォータニオンを合成
float rotac=-VDot(vectr,EffectVector);
VECTOR vectc=VAdd(VGet(EffectVector.x*rotar,EffectVector.y*rotar,EffectVector.z*rotar),VCross(vectr,EffectVector));
//CクォータニオンとQクォータニオンを合成してベクトルを返す
return VAdd(VAdd(VGet(vectq.x*rotac,vectq.y*rotac,vectq.z*rotac),VGet(rotaq*vectc.x,rotaq*vectc.y,rotaq*vectc.z)),VCross(vectc,vectq));
}
void CFighter::Update(){
MV1SetRotationZYAxis(ModelHandle,AxisZ,AxisY,0.0f);
}
//ピッチ 引数は -1.0~1.0
void CFighter::Pitch(float Rotation){
float Rot=(DX_PI_F/145);
AxisY=ReactionQuaternion(AxisX,AxisY,Rot*Rotation);
AxisZ=ReactionQuaternion(AxisX,AxisZ,Rot*Rotation);
}
//ロール 引数は -1.0~1.0
void CFighter::Roll(float Rotation){
float Rot=(DX_PI_F/60);
AxisX=ReactionQuaternion(AxisZ,AxisX,Rot*Rotation);
AxisY=ReactionQuaternion(AxisZ,AxisY,Rot*Rotation);
}
//ヨー 引数は -1.0~1.0
void CFighter::Yaw(float Rotation){
float Rot=(DX_PI_F/180);
AxisX=ReactionQuaternion(AxisY,AxisX,Rot*Rotation);
AxisZ=ReactionQuaternion(AxisY,AxisZ,Rot*Rotation);
}