あなたは次の形式の行列を扱っていると思います
[ side_x up_x forward_x position_x ]
[ side_y up_y forward_y position_y ]
[ side_z up_z forward_z position_z ]
[ 0 0 0 1 ]
したがって、ローカル アップ ベクトルa
ラジアンを中心に回転するには、ローカル変換行列に、Y ベクトルを中心に回転する回転行列を掛けます。つまり、
[ side_x up_x forward_x position_x ] [ cos(a) 0 -sin(a) 0 ]
[ side_y up_y forward_y position_y ] *= [ 0 1 0 0 ]
[ side_z up_z forward_z position_z ] [ sin(a) 0 cos(a) 0 ]
[ 0 0 0 1 ] [ 0 0 0 1 ]
それがどうなるか教えてください。
大きな編集
ここにいくつかの詳細情報があります。
定義 (フレーム)
フレームF は、4 つの同次座標 x_F、y_F、z_F、o_F の集合であり、x_F、y_F、z_F の 4 番目の座標はゼロであり、o_F の 4 番目の座標は 1 であり、x_F、y_F、z_F はペアワイズ直交 (直交性)実際には必要ありませんが、ここではこのように定義しています)。o_F はフレームの原点と呼ばれます。頂点の集合は、それらの座標が F に対して表現されている場合、フレーム F に対して相対的であると言われます。
例 1
Blender または Maya で作成されたメッシュの頂点は、モデルのフレームに対して相対的に表現されます。
定義(フレーム変換行列)
2 つのフレーム F と G が与えられた場合、フレーム変換行列M は、次のような 4x4 行列 M です。
- M * x_F = x_G
- M * y_F = y_G
- M * z_F = z_G
- M * o_F = o_G
別の書き方をすると、これを M * [x_F, y_F, z_F, o_F] = [x_G, y_G, z_G, o_G] と表すことができます。ここで、[ ... ] はそれぞれ列にまたがる行列を意味します。ここでも別の書き方をしますが、可逆性は問題ではないと仮定すると、次のように書くことができます。
M = [x_G y_G z_G o_G] * [x_F y_F z_F o_F]^{-1}
例 2
ワールド空間からビュー (または目) 空間に変換する必要があるとします。ワールド空間座標は単なる標準の基底ベクトルであると仮定し、ビュー空間のカメラは o_V を中心としており、ベクトル x_V、y_V、および z_V を取得するように回転が適用されていると仮定します。その場合、M は次のようになります。
M = [x_V y_V z_V o_V] * I^{-1} = [x_V y_V z_V o_V]
例 3
モデルからの頂点に対するバッチがあり、頂点の座標がモデル空間で表現されているとします。モデルはワールド空間のどこかに配置され、向きがあります。したがって、モデルには原点 o_M といくつかの回転 x_M、y_m、z_M があります。頂点をモデル空間からワールド空間に変換する行列は、次のようになります。
M = I * [x_M y_M z_M o_M]^{-1} = [x_M y_M z_M o_M]^{-1}
行列を反転する必要があることに注意してください。
例 4
モデル空間からビュー空間に直接行きたいとしましょう。model -> world と world -> view の行列を既に推定しているので、これは簡単です。したがって
M = [x_V y_V z_V o_V] * [x_M y_M z_M o_M]^{-1}
誰も気にしない?
フレームは、必要な効果を実装するための便利なツールです。私たちの世界のすべてのオブジェクトがposition
、 a 、forward
およびup
ベクトルを持っているとします。私たちが見ている私たちのカメラも世界のオブジェクトです。したがって、 a position
、 a 、forward
およびup
ベクトルもあります。Frame
クラスの最初のバージョンは
struct Frame { // version 1
vec3 position;
vec3 forward;
vec3 up;
};
Frame
しかし、私たちは便利なことをしたいと考えています。したがって、メンバー関数を追加できます。
struct Frame { // version 2
vec3 position;
vec3 forward;
vec3 up;
mat4 getLocalToWorldTransform() const;
mat4 getWorldToLocalTransform() const;
}
メンバー関数は次のmat4 Frame::getWorldToLocalTransform() const
ようになります。
mat4 Frame::getWorldToLocalTransform() const {
vec3 side = crossProduct(forward, up);
// [x_F y_F z_F o_F ] (!!)
return mat4(side, up, -forward, position); // +forward or -forward depending on the graphics API
}
気がついたら、問題があるかもしれません。常に直交しているup
ことを保証するのは誰ですか? forward
あなたはそれを自分で処理する必要があります。たとえば、ベクトルが常に直交するようforward
に、ベクトルを中心に方向のみを回転させることができます。up
実装の詳細はお任せmat4 Frame::getLocalToWorldTransform() const
します。
今、私たちFrame
は世界を動き回れるようにしたいと考えています。メンバー関数をさらに追加できます
struct Frame { // version 3
vec3 position;
vec3 forward;
vec3 up;
mat4 getLocalToWorldTransform() const;
mat4 getWorldToLocalTransform() const;
void moveForward(const float steps);
void moveBackward(const float steps);
void rotateClockwiseAroundUp(const float radians);
void rotateCounterClockwiseAroundUp(const float radians);
}
の実装は次のvoid Frame::rotateCounterClockwiseAroundUp(const float radians)
ようになります。
void Frame::rotateCounterClockwiseAroundUp(const float radians) {
direction = mat3::rotationFromAngleAndAxis(radians, up) * direction;
}
したがって、カメラは独自のFrame
クラスを維持する必要があります。カメラを回転するには、メンバー関数rotateCounterClockwiseAroundUp
と を使用しrotateClockwiseAroundUp
ます。カメラを前後に移動するには、メンバー関数moveForward
と を使用しmoveBackward
ます。変換行列を取得するには、メンバー関数を使用しますgetWorldToLocalTransform
。これは、ワールド -> ビュー空間から移動する必要があるためです。