はじめに
CGなどを勉強しているとどうしてもさけて通れない分野の中の1つとして線形代数があるかと思いますが、今回はそのうちの行列演算などにスポットを当ててメモを残しておきたいと思います.
oF上での行列を扱うにはofMatrix3x3
, ofMatrix4x4
などと言ったクラスが存在しており、それらを扱って変換行列など用意し行列演算を行っていきます.
行列データの保存形式
行優先、列優先
行列の保存形式には行優先形式と列優先形式というものが存在します.
data = [a_{1}, a_{2}, a_{3}, a_{4}]
- 列優先(Column-Major)
matrix_{col} =
\left(
\begin{matrix}
a_{1} & a_{3} \\
a_{2} & a_{4}
\end{matrix}
\right)
- 行優先(Row-Major)
matrix_{row} =
\left(
\begin{matrix}
a_{1} & a_{2} \\
a_{3} & a_{4}
\end{matrix}
\right)
APIごとでの保存形式の違い
このうちopenFrameworksでは行優先形式、GLSLでは列優先形式が採用されています.
こちらはofMatrix4x4.hに書かれているドキュメントです.
/// oF uses row-vector style by default, meaning that when transforming a vector
/// by multiplying with a matrix, you should put the vector on the left side and
/// the matrix (or matrices) to its right. When multiplying by multiple matrices,
/// the order of application of the transforms is left-to-right. This means that
/// the standard order of manipulation operations is
/// vector * scale * rotate * translate.
///
/// Note that in GLSL, this convention is reversed, and column-vector style is
/// used. oF uploads the matrices to the GL context correctly, but you should
/// reverse the order of your vertex manipulations to right-to-left style, e.g.
/// translate * rotate * scale * vector.
上に記されているように、行優先形式ではベクトルに対して後から変換行列を掛け、列優先形式ではベクトルに対して前から変換行列を掛けることに注意してください.(行列は掛け算の順序によって計算結果が変わってしまいます.)
サンプルコード
全てではありませんが参考になりそうなコードを貼っておきます.
void ofApp::setup(){
scaleMatrix.set(scale->x, 0.0, 0.0, 0.0,
0.0 , scale->y, 0.0, 0.0,
0.0, 0.0, scale->z, 0.0,
0.0, 0.0, 0.0, 1.0);
translateMatrix.set(1.0, 0.0, 0.0, 0.0,
0.0 , 1.0, 0.0, 0.0,
0.0, 0., 1.0, 0.0,
translate->x, translate->y, translate->z, 1.0);
modelMatrix = ofMatrix4x4::newIdentityMatrix();
modelMatrix.preMult(scaleMatrix);
modelMatrix.preMult(translateMatrix);
}
void ofApp::draw(){
cam.begin();
ofMatrix4x4 viewMatrix;
viewMatrix = ofGetCurrentViewMatrix();
ofMatrix4x4 projMatrix = cam.getProjectionMatrix();
ofDrawAxis(1000.0);
shader.begin();
shader.setUniformMatrix4f("modelMatrix", translateMatrix);
shader.setUniformMatrix4f("viewMatrix", viewMatrix);
shader.setUniformMatrix4f("projMatrix", projMatrix);
cam.getProjectionMatrix();
ofDrawRectangle(0.0, 0.0, 300.0, 300.0);
shader.end();
cam.end();
}
uniform mat4 modelViewProjectionMatrix;
uniform mat4 viewMatrix;
uniform mat4 projMatrix;
uniform mat4 modelMatrix;
in vec4 position;
void main()
{
vec4 p = projMatrix * viewMatrix * modelMatrix * position;
gl_Position = p;
}