SAMPLE
ライティング計算
カメラの移動とライティング計算
ワールド座標指定のライティング
■ Lighting
DESC
ライティング結果は
ライトの設定である glLight() と オブジェクトの材質設定の glMaterial() によって決まる。
計算結果は各頂点の色(プライマリーカラー)となり、
照明がオフの場合は glColor() で指定したカラーが適用される。
テクスチャなどのフラグメント処理は頂点カラーの決定後にされる。
POINT
ライトの位置( 向き )の指定も頂点変換と同じように、モデルビュー変換の影響を受ける。
glLight( GL_POSITION ); をコールした時点で指定した座標が変換される。
常に正面から照らす設定は以下になる。
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
float dir[] = { 0, 0, 1, 0 };
glLightfv( GL_LIGHT0, GL_POSITION, dir );
ワールド座標で指定するにはカメラ座標系から変換する。
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
convertCameraSpace( 0, 0, 500, cy, cx );
// ワールド座標の 0 0 1 の方向から照らす。
float dir[] = { 0, 0, 1, 0 };
glLightfv( GL_LIGHT0, GL_POSITION, dir );
ライティング計算のための初期化をする。
App::onInit() {
// Lighting 処理を有効化( DEFAULT : オフ )
glEnable( GL_LIGHTING );
// ライト数は 少なくとも 8 つ
// 個別に ON/OFF できる。
glEnable( GL_LIGHT0 );
// ライトの位置を設定する
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
float dir [] = { -0.3f, 0, 1, 0 };
glLightfv( GL_LIGHT0, GL_POSITION, dir );
}
描画時は法線( glNormal )を設定したモデルを描画する。
App::onDraw() {
// 法線をもつプリミティブを描画
// 残りの Light の parameter はすべてデフォルトを使う
drawNormalCube();
// WARNING
// Lighting ON は 不要ならばオフにする。
// 以下の 頂点処理に影響をうける
glDisable( GL_LIGHTING );
}
■ ライトの色
ライティングは次の3つの要素で近似する。
環境光 : 間接光
拡散光 : 面に対して均等に拡散する面
鏡面光 : 光沢のある面
ライティングの内部計算。
L : ライト
M : マテリアル
Env * aM +
aL * aM +
dL * dM * ( N.L ) +
sL * sM + ( N.R )
■ 法線(Normal)
DESC
OpenGL は Normal を見て面の向きを決める。
ライティング計算をするためには、面の向きを指定する必要がある。
WARNING
頂点と同じくモデルビュー行列の影響をうけるため Scale 成分の影響をうける。
// Normalize を ON
glEnable( GL_NORMALIZE );
// Scaling のみの調整をする
// Scale Matrix が 等しいなら これで十分
glEnable( GL_RESCALE_NORMAL );
// 最も効率的なのは init 時に normal を再計算すること
recalcNormal();
■ LightParameter
GLInt nr;
glGetIntegerv( GL_MAX_LIGHTS, &nr );
// 各 Light を有効化 ( GL_LIGHTi )
glEnable( GL_LIGHT0 );
// 各 Light の parameter 設定
glLightfv( GL_LIGHT0, GL_DIFFUSE, col );
glLightfv( GL_LIGHT0, GL_POSITION, pos );
■ glLight
SYNTAX
glLight(
GLenum light,
GLenum pramName, // GL_AMBIENT, GL_DIFFUSE, GL_SPECULAR, GL_POSITION
TYPE *val // color | position
)
DESC
ライトのパラメータ( 色、位置 )を設定する。
DEFAULT
GL_AMBIENT : 0, 0, 0 // Ambient とは 間接光 ( N 回 Bounce ) の近似
GL_LIGHT0
GL_DIFFUSE : 1, 1, 1
GL_SPECULAR : 1, 1, 1
GL_LIGHT1 - N
GL_DIFFUSE : 0, 0, 0
GL_SPECULAR : 0, 0, 0
DESC
ライトの位置の設定も頂点と同じく、glLight() をコールした時点での
モデルビュー行列変換の影響を受ける。
平行光( DirectionLight )を利用するには, 位置指定のw成分を 0 にする。
無限遠の 0, 0, 1 の位置に置いたことになり 0, 0, -1 方向への平行光として計算される。
// 平行光
float dir [] = { 0, 0, 1, 0 };
glLightfv( GL_LIGHT0, GL_POSITION, dir );
// 位置で指定
float pos [] = { 0, 0, 1, 1 };
glLightfv( GL_LIGHT0, GL_POSITION, pos );
■ glMaterial
SYNTAX
glMaterial(
GLenum face, // 表裏の指定
GLenum pramName, // GL_AMBIENT | GL_DIFFUSE | GL_SPECULAR | GL_SHININESS
const TYPE *val
)
DESC
オブジェクトの色を指定する。
ライトの各成分と乗算される。
POINT
アルファ成分は GL_DIFFUSE で指定したアルファ成分が頂点のアルファ色になる。
GL_AMBIENT, GL_SPECULAR の指定は無視される。
float col[] = { 0, 1, 0, 1 };
glMaterialfv( GL_FRONT, GL_AMBIENT, col );
glMaterialfv( GL_FRONT, GL_DIFFUSE, col );
glMaterialfv( GL_FRONT, GL_SPECULAR, col );
// GL_SHININESS [0:128] DEFAULT 0
glMaterialf( GL_FRONT, GL_SHININESS, 128 );
■ レイトレース(RayTrace)
物が見えるのは、レンズに光(レイ)が飛びこんでくる結果なのでこれを逆からトレースするという考え方。
Direct
1 Bound : 通常のライティングモデル ( )
2 Bound : 照り返し
画素の数だけ、このトレースを繰り返す
2 バウンド
光源からライトがでる ---> 赤い壁にあたる ---> 白い布を照らす ---> カメラのレンズに届く
カメラから画素へ向かってレイをとばす。
何かにあたる
その何かは、全方向からの光の影響をうけるので、全方向にライトをとばす
これを N 階の深さまで繰り返す。
光源方のみに絞ったは 1 バウンドは、直接の光源のみなので、反対領域は黒くなる。
そこで、1バウンドに限定して、暗い部分は適当にバイアスを足しておく( アンビエント )
1バウンドも、ライトという光源方向のみに限定する。
これで画素数だけの計算回数になる。
明るさは 面積あたりの光の粒の数( 密度 )なので、距離の2乗に比例する。
しかし、太陽などの十分に長い距離に対しては、100m などは 0m として近似できるため
距離の減衰を無視できる。
反射の割合( 分布 )
ある方向からきた光は、必ず一定方向にだけ反射するわけではない。
そうだとしたら見る方向をかえると、黒く見えてしまう。
そこで、全方向に一様に反射すると仮定する。
これを計算式として表現すると、ディフューズモデルができる
I = I0 * R * cos(theta), cos(theta) = dot(L , N)
L : 頂点から光源へのベクトル
N : 頂点の法線ベクトル
I0 : 光源の色
R : 反射する割合
■ ライティング計算を自前でする
OpenGL にはライティング計算をするための API があるが
自前で計算式から明るさを求めて、頂点カラーとして渡すこともできる。
テクスチャを貼るときは、 GL_MODULATE をつかえばいい。
REFERENCE テクスチャのブレンド方法を指定する