• 検索結果がありません。

直交投影

ドキュメント内 GLFW による OpenGL 入門 (ページ 155-161)

第 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 – lefttop – 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 は、この二つの変換行列 McenteringMscaling を乗じたものです。

(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 直交投影変換を実装した実行結果

ドキュメント内 GLFW による OpenGL 入門 (ページ 155-161)