SSブログ

OpenGL ライティング ディフューズとアンビエント 光源の位置を決める [Android OpenGL]

回転させることで、ずいぶん3Dらしくなったが、まだそれらしくない。それは、色は付いたが、完全な赤でしか表示されないから。映画などで普通に目にするCGは、光の加減をちゃんと「シミュレートして」表示するポリゴンの色を計算している。光の方に向いている面は明るくなるし、反対側を向いていれば、暗くなる。普通の言葉でいうなら「陰影」。陰影を付ければ、もっとリアルに表示できるはず。

「陰影を付ける」ことを英語でいうと「シェーディング」という。シェーディングってよく聞くでしょ?そのくらい重要なのです「陰影」が。3DCGの用語は英語で難しいが、慣れてしまえばどうってことはない。

さて、OpenGLでは、どうやってシェーディングさせるかというと、GL_LIGHTINGを有効にする。シェーディングは光のシミュレーションなので、どこに光源があるのか、といった情報が必要になる。これをglLightfとかで、設定していく。光源のデータは、光源の位置や色などがある。また、光源データは複数作成できる。

まずは、基本的な設定のみを行って、どうなるかみてみよう。

glLightfvには、4つの引数が必要になる。最初の引数は、光源番号となる。OpenGLでは複数の光源を扱うことができるが、これらを「GL_LIGHTx」で指定することができる。xの部分には0~7の番号が入る。次の引数は、光源関係のどのパラメータを設定するかといった指定。GL_POSITIONなら光源位置の指定になる。

今回は、GL_LIGHT0のみを使うことにする。使う光源はglEnableで有効にしてやる必要がある。ライティング機能のON/OFFは、GL_LIGHTINGで行う。これも忘れずにglEnableで有効にしておこう。
光源の位置は、GL_POSITIONで指定するが、このときx,y,z座標の他、光源の種類が必要になるので、要素数が4の配列を渡してやる必要がある。光源の種類には、並行光線(0)か、点光源(1)かを指定する。
レンダラークラスのlightposフィールドで光源の位置データを定義した。

	// レンダラークラス
	class OpenGLRenderer implements Renderer {
		float lightpos[] = {0.0f, 0.0f, 4.0f, 0.0f};

		@Override
		public void onDrawFrame(GL10 gl) {
			gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
			// ライティングをON
			gl.glEnable(GL10.GL_LIGHTING);
			// 光源を有効にして位置を設定
			gl.glEnable(GL10.GL_LIGHT0);
			gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_POSITION, lightpos, 0);
			gl.glMatrixMode(GL10.GL_MODELVIEW);
			gl.glLoadIdentity();


ライティングを有効にして、実行してみると以下のように白黒な三角形が表示される。




光源位置と法線ベクトル

ライティングを行うと白黒になってしまう理由は、オブジェクトに色の設定をしていないから。しかし、明暗が変化していることがわかる。これがライティング(シェーディング)の効果である。

モデルの面の色は、「法線データ」と「面に設定された色」で計算される。
法線というのは、面に対して垂直に立っている感じのベクトル。面がX-Y平面にベタっと置いてある状態にあると法線ベクトルは、Z軸方向に向いている。
三角形のモデルでは、特に法線を計算して設定はしていないが、OpenGLの方で自動的に計算されるようだ。

三角形を回転させると、法線ベクトルもそれに合わせて回転していく。光源の位置は変化しないので、光源の方向と法線の方向が一致する状態で一番明るくなる(左の三角形)。
光源は、ちょうど視点の方向にある。なので、ちょうどこちらを向いたときに最大に明るい。

法線は面の表の側の方向に立っている。左の三角形は表面を表示している。右の三角形は、裏面を表示している。右の三角形がこちらを向いても暗いままなのは、本当は向う側に向いているから。

さて、法線ベクトルと光源との位置関係で、その面の明暗を決めることがわかった。面にはもともとの色が指定されている(そう今までは、赤で表示されていたではないか)。しかし、ライティングを有効にすると、「glColor4fで設定した、もともとの色」は有効にはならない。

ではどうやって色を決めればいいのか...

ディフューズ

ライティングを有効にすると、明暗を計算する「もともとの色」が必要になる。これは「ディフューズ」で設定できる。
ディフューズもRGBAで指定する。1,0,0,1なら、赤いオブジェクトになる。0,1,0,1なら緑色となる。1,1,1,1は白。

ディフューズがオブジェクトの「メインの色」と考えてもらってよい。

では、ディフューズを設定して左の三角形は「青」、右の三角形には「赤」の色を付けててみよう。

	// レンダラークラス
	class OpenGLRenderer implements Renderer {
		float lightpos[] = {0.0f, 0.0f, 4.0f, 0.0f};
		float red[] = {1.0f, 0.0f, 0.0f, 1.0f};
		float blue[] = {0.0f, 0.0f, 1.0f, 1.0f};

		@Override
		public void onDrawFrame(GL10 gl) {
			gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
			// ライティングをON
			gl.glEnable(GL10.GL_LIGHTING);
			// 光源を有効にして位置を設定
			gl.glEnable(GL10.GL_LIGHT0);
			gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_POSITION, lightpos, 0);
			gl.glMatrixMode(GL10.GL_MODELVIEW);
			gl.glLoadIdentity();
			gl.glPushMatrix();		// マトリックス記憶
			gl.glTranslatef(1f, 0, -3f);
			gl.glRotatef(angle, 0, 1, 0);
			gl.glEnable(GL10.GL_CULL_FACE);
			gl.glCullFace(GL10.GL_FRONT);
			gl.glMaterialfv(GL10.GL_FRONT_AND_BACK, GL10.GL_DIFFUSE, red, 0);
			model.draw(gl);
			gl.glPopMatrix();		// マトリックスを戻す

			// ふたつめの描画
			gl.glPushMatrix();		// マトリックス記憶
			gl.glTranslatef(-1f, 0, -3f);
			gl.glRotatef(angle, 0, 1, 0);
			gl.glCullFace(GL10.GL_BACK);
			gl.glMaterialfv(GL10.GL_FRONT_AND_BACK, GL10.GL_DIFFUSE, blue, 0);
			model.draw(gl);
			gl.glPopMatrix();		// マトリックスを戻す
			angle += 0.5;			// 回転角度は最後に計算
		}




ディフューズなどの色データは、glMaterialfvで設定することができる。色データは、RGBAの4つの値なので、配列としてレンダラークラスのフィールドとして準備した。redやらblueがそのフィールド。

glMaterialfvには、4つの引数を与える必要がある。最初の引数は、面のどちら側に色データを設定するかの設定。次の引数は、色属性の種類。ディフューズ、アンビエントなどを指定する。次の引数は色データの入った配列。最後に配列のどこから使用するかを決定するインデックスオフセットを指定する。

今回は、redやblueといった色別に配列を用意して、色データを設定していったが、大きな配列にいくつかの色を準備しておき、オフセットで指定する、といった使い方もできる。

ちなみに、Materialは、マテリアルと読み「材質」という意味。


アンビエント

光源と法線の関係だけで純粋にシミュレートすると、光源と真反対の側は「真っ黒」になってしまう。実際は、宇宙空間でもない限り、光は反射するので、拡散した光の影響で反対にあっても「真っ黒」にはならない。この点を考慮してやらないと、「宇宙空間的」な画像になってしまう。

これを設定するのが、「アンビエント」。アンビエントは、通常はディフューズと同じような色にするが、ここでは、その効果をみるために、赤の三角形には青のアンビエント、と逆になるように設定してみる。

			gl.glPushMatrix();		// マトリックス記憶
			gl.glTranslatef(1f, 0, -3f);
			gl.glRotatef(angle, 0, 1, 0);
			gl.glEnable(GL10.GL_CULL_FACE);
			gl.glCullFace(GL10.GL_FRONT);
			gl.glMaterialfv(GL10.GL_FRONT_AND_BACK, GL10.GL_AMBIENT, blue, 0);
			gl.glMaterialfv(GL10.GL_FRONT_AND_BACK, GL10.GL_DIFFUSE, red, 0);
			model.draw(gl);
			gl.glPopMatrix();		// マトリックスを戻す

			// ふたつめの描画
			gl.glPushMatrix();		// マトリックス記憶
			gl.glTranslatef(-1f, 0, -3f);
			gl.glRotatef(angle, 0, 1, 0);
			gl.glCullFace(GL10.GL_BACK);
			gl.glMaterialfv(GL10.GL_FRONT_AND_BACK, GL10.GL_AMBIENT, red, 0);
			gl.glMaterialfv(GL10.GL_FRONT_AND_BACK, GL10.GL_DIFFUSE, blue, 0);
			model.draw(gl);
			gl.glPopMatrix();		// マトリックスを戻す
			angle += 0.5;			// 回転角度は最後に計算




アンビエントも、glMaterialfvで設定することができる。引数の説明はディフューズと同じなので、省略。

面がこっちに向いていない場合に、アンビエントの色が出ていることがわかる。




サイト内を検索

タグ:Android OpenGL
nice!(0)  コメント(0) 

nice! 0

コメント 0

コメントを書く

お名前:
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。



Copyright Atsushi Asai Google+朝井淳
[改訂第4版]SQLポケットリファレンス

[改訂第4版]SQLポケットリファレンス

  • 作者: 朝井 淳
  • 出版社/メーカー: 技術評論社
  • 発売日: 2017/02/18
  • メディア: 単行本(ソフトカバー)

イラストで理解 SQL はじめて入門

イラストで理解 SQL はじめて入門

  • 作者: 朝井 淳
  • 出版社/メーカー: 技術評論社
  • 発売日: 2019/05/16
  • メディア: 単行本(ソフトカバー)

[データベースの気持ちがわかる]SQLはじめの一歩 (WEB+DB PRESS plus)

[データベースの気持ちがわかる]SQLはじめの一歩 (WEB+DB PRESS plus)

  • 作者: 朝井 淳
  • 出版社/メーカー: 技術評論社
  • 発売日: 2015/03/03
  • メディア: 単行本(ソフトカバー)

Access クエリ 徹底活用ガイド ~仕事の現場で即使える

Access クエリ 徹底活用ガイド ~仕事の現場で即使える

  • 作者: 朝井 淳
  • 出版社/メーカー: 技術評論社
  • 発売日: 2018/05/25
  • メディア: 大型本