第 7 章 座標変換
7.8 投影変換
7.8.2 直交投影
7.8 投影変換
図 97 視体積
この視点に近いほうの平面を前方面 (hither) 、遠い方の面を後方面 (yon) といいます。ビュー 変換によって視点は z 軸方向の負の方向に向いていますから、前方面と後方面の z 値は、それ ぞれ -near、-far になります。
この視体積内の図形を標準視体積に収めるには、視体積の中心が原点になるように平行移動し、
一辺の長さが 2 になるように拡大縮小します。
図 98 直交投影の手順
l 中心が原点になるよう平行移動
まず、視体積の中心の位置を求め、そこが原点になるように平行移動する変換行列を求めます。
視体積の中心は ((right + left) / 2, (top + bottom) / 2, -(far + near) / 2) です。
前方面 (hither)
視体積 (view volume)
後方面 (yon)
視点
x y
z
−near −far left
left
right right bottom bottom top top
x
z
y
x
z
y
x
z
y
O O O O
O OOO
中心が原点になるよう平行移動 大きさを正規化
図 99 中心が原点となるように平行移動
この変換行列は平行移動の変換行列 (19) より、(63) 式のようになります。far と near に負号 が付いているので、Z に関しては逆に負号が無くなっています。
(63)
l 大きさを正規化
視体積の幅、高さ、および深度を求め、それを一辺の長さが 2 になるように拡大縮小する変換 行列を求めます。視体積の幅、高さ、深度は、それぞれ right – left、top – bottom、–(far – near) で す。
図 100 一辺の長さが 2 になるよう拡大縮小
この変換行列は (22) 式の拡大縮小の変換行列より (64) 式のようになります。これも far と
near に負号が付いているので、Z に関しては負号が付いています。
+ 2
+ 2
Mcentering = 0 BB BB BB BB
@
1 0 0 right+lef t 2 0 1 0 top+bottom
2 0 0 1 f ar+near
2
0 0 0 1
1 CC CC CC CC A
1
1
1 22 1
22
(64)
l 直交投影変換行列
直交投影変換行列 Mo は、この二つの変換行列 Mcentering と Mscaling を乗じたものです。
(65)
l 直交投影変換行列を作成するメソッドの追加 (Matrix.h)
Matrix クラスにビュー変換行列を作るメソッド orthogonal() を追加します。引数に指定した視
体積 (left, bottom)、(right, top)、(near, far) から式 (65) によって変換行列を求めます。これもイン スタンスを生成せずに呼び出せるように static メソッドにします。
// 直交投影変換行列を作成する
static Matrix orthogonal(GLfloat left, GLfloat right, GLfloat bottom, GLfloat top,
GLfloat zNear, GLfloat zFar) {
Matrix t;
const GLfloat dx(right - left);
const GLfloat dy(top - bottom);
const GLfloat dz(zFar - zNear);
if (dx != 0.0f && dy != 0.0f && dz != 0.0f) {
t.loadIdentity();
t.matrix[ 0] = 2.0f / dx;
t.matrix[ 5] = 2.0f / dy;
t.matrix[10] = -2.0f / dz;
t.matrix[12] = -(right + left) / dx;
t.matrix[13] = -(top + bottom) / dy;
t.matrix[14] = -(zFar + zNear) / dz;
}
return t;
}
Mscaling= 0 BB BB BB B@
2
right lef t 0 0 0
0 2
top bottom 0 0
0 0 2
f ar near 0
0 0 0 1
1 CC CC CC CA
Mo =MscalingMcentering
= 0 BB BB BB BB
@
2
right lef t 0 0 right+lef t
right lef t
0 2
top bottom 0 top+bottom
top bottom
0 0 2
f ar near
f ar+near f ar near
0 0 0 1
1 CC CC CC CC A
l メインプログラム (main.cpp) の変更点
投影変換行列をバーテックスシェーダに渡すために、モデルビュー変換行列 modelview とは 別の uniform 変数を用意します。変数名は projection にします。
int main() {
《省略》
// プログラムオブジェクトを作成する
const GLuint program(loadProgram("point.vert", "point.frag"));
// uniform 変数の場所を取得する
const GLint modelviewLoc(glGetUniformLocation(program, "modelview"));
const GLint projectionLoc(glGetUniformLocation(program, "projection"));
// 図形データを作成する
std::unique_ptr<const Shape> shape(new Shape(2, 4, rectangleVertex));
ウィンドウのサイズの変更に対する表示図形の縦横比の維持 (6.1.4) やサイズの固定 (6.1.5) のような処理は、一般には投影変換の際に行われます。そこで前方面の表示領域として、図 64 に 示す left = -w / 2s、right = w / 2s、bottom = -h / 2s、top = h / 2sを設定します。
// ウィンドウが開いている間繰り返す
while (window.shouldClose() const == GL_FALSE) {
// ウィンドウを消去する
glClear(GL_COLOR_BUFFER_BIT);
// シェーダプログラムの使用開始 glUseProgram(program);
// 直交投影変換行列を求める
const GLfloat *const size(window.getSize());
const GLfloat scale(window.getScale() * 2.0f);
const GLfloat w(size[0] / scale), h(size[1] / scale);
const Matrix projection(Matrix::orthogonal(-w, w, -h, h, 1.0f, 10.0f));
これに伴って、モデルビュー変換行列には平行移動とビュー変換だけを設定します。ビュー変 換では、目標点を図形の位置の (初期値の) 原点に設定すれば、視点位置は任意の位置に設定で きます。ただし、目標点は視点から見て zNear (1) から zFar (10) の間にある必要があります。
// モデル変換行列を求める
const GLfloat *const location(window.getLocation());
const Matrix model(Matrix::translate(location[0], location[1], 0.0f));
// ビュー変換行列を求める
const Matrix view(Matrix::lookat(3.0f, 4.0f, 5.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f));
// モデルビュー変換行列を求める
const Matrix modelview(view * model);
変換行列 projection の内容をシェーダプログラムの uniform 変数 projection に設定して描画 します。
// uniform 変数に値を設定する
glUniformMatrix4fv(projectionLoc, 1, GL_FALSE, projection.data());
glUniformMatrix4fv(modelviewLoc, 1, GL_FALSE, modelview.data());
// 図形を描画する shape->draw();
// カラーバッファを入れ替えてイベントを取り出す window.swapBuffers();
} }
l バーテックスシェーダ (point.vert) の変更点
バーテックスシェーダに mat4 型の uniform 変数 projection を追加し、それをモデルビュー変 換後の頂点の座標値に乗じます。
#version 150 core uniform mat4 modelview;
uniform mat4 projection;
in vec4 position;
void main() {
gl_Position = projection * modelview * position;
}
n サンプルプログラム step15
l 実行結果
図 101 直交投影変換を実装した実行結果