(1) gluLookAt はどんな matrix を生成するのか? | Chandler@Berlin

Chandler@Berlin

ベルリン在住

テーマ:
gluLookAt function


3次元のシーンを描画するために,ゲームなどでも利用されている OpenGL というAPI を使うことがある.OpenGL の世界で閉じていれば,内部で実際にどんなmatrixが生成されているかはあまり気にすることはないが,OpenGL で描画しているシーンに何かを overlay したいなどという時,たとえば,独自の renderer を趣味で書いている人達でかつ OpenGL も使う人達は,OpenGL の内部でどんなmatrixが生成されているか知っていると有用なことがある.

したがってこの話はかなり特殊なものなので,まあ,ここまでの話で興味のない人はまた次の機会にお会いしましょう.

今回は gluLookAt という OpenGL のユーティリティ関数の作る matrix についてである.

gluLookAt は三次元のシーンにカメラを方向を考えて配置するものである.最近,この matrix をどう生成するかということを知る必要があったが,どうも説明している Page がみつからなかった.結局 Mesa の実装の内部を見ることになった.(Mesa-7.5.1/src/glu/sgi/libutil/project.c) このコードはわかりやすい変数名を使っており,コメントも書いてある.以下が Mesa 7.5.1 の該当部分のソースコードである.


/*
* SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
* Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
*/
void GLAPIENTRY
gluLookAt(GLdouble eyex, GLdouble eyey, GLdouble eyez, GLdouble centerx,
GLdouble centery, GLdouble centerz, GLdouble upx, GLdouble upy,
GLdouble upz)
{
float forward[3], side[3], up[3];
GLfloat m[4][4];

forward[0] = centerx - eyex;
forward[1] = centery - eyey;
forward[2] = centerz - eyez;

up[0] = upx;
up[1] = upy;
up[2] = upz;

normalize(forward);

/* Side = forward x up */
cross(forward, up, side);
normalize(side);

/* Recompute up as: up = side x forward */
cross(side, forward, up);

__gluMakeIdentityf(&m[0][0]);
m[0][0] = side[0];
m[1][0] = side[1];
m[2][0] = side[2];

m[0][1] = up[0];
m[1][1] = up[1];
m[2][1] = up[2];

m[0][2] = -forward[0];
m[1][2] = -forward[1];
m[2][2] = -forward[2];

glMultMatrixf(&m[0][0]);
glTranslated(-eyex, -eyey, -eyez);
}



ところで,OpenGL の座標系や matrix の実装は私にはとても混乱しやすい.実
際,OpenGL の official の page にも,http://www.opengl.org/resources/faq/technical/transformations.htm

Column-major notation suggests that matrices are not laid out in memory
as a programmer would expect.

行列でColumn-major記法を使うという時には,(行列の要素は)プログラマが通常思っているようにはメモリ上に格納されていないことを示唆している.


と,わざわざ思った通りとはまず違うんだよ,と書いてあったりするほどである.


そこで私は最初には数学の通常の表記を使って考え,実装時に解釈することにしている.というわけで,ここでは matrix には数学の通常の記法を使うが,C/C++などで array を使って実装する時には注意されたい.

図1にはカメラを基準にした座標(左)とカメラの座標は他の座標にはよらないことを示している.

カメラは剛体と考えて良いので,できることは回転と移動である.カメラを伸ばしたり縮めたり,あるいは壊すこともできるが,OpenGL のカメラはそういうものではないとする.

Chandler@Berlin-cam1
Chandler@Berlin-cam2
Figure 1: Camera coordinates. Camera coordinates and other coordinates

ここで model view の duality ということに注意しておく.これは

- シーン全体は停止していて,カメラが 1m 前進すること
- カメラが停止していて,シーン全体が 1m 後退すること

では,実はカメラに映るものは変化しない.電車の駅にて,電車に乗り込み発車を待っている時,時に自分が動いたのか相手が動いたのか間違えることがあるが,自分(カメラ)が動いた時に見える相手と,相手が動いた時(シーン全体が動いた)に見える相手が実はほとんど同じ場合がある.この変換を示す matrix をmodel view matrix と言う.model の動きと view の動きを組合せたものである.

今回の話はカメラの位置と方向が作る matrix に関してなので view matrix とでも言うべきだが,OpenGL では上記の model view duality からこれらを一つにまとめている.そこで実装では model view matrix となっているが,ここで話をしているのは view matrix のみである.


次回は gluLookAt の生成する回転と移動を表現する matrix に関して述べよう.