ライティング(Lighting)

SAMPLE http://ooo.iiyudana.net/bin/gl/simplecube.exe( ライティング計算 ) https://www.dropbox.com/s/dz538quy6ah5wpx/light.exe( カメラの移動とライティング計算 ) https://www.dropbox.com/s/op36eeycfyrsfdd/light_world.exe( ワールド座標指定のライティング )


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 をつかえばいい。 __LINK__(テクスチャのブレンド方法を指定する)