2005年6月21日火曜日

第3回タイトル 「光源設定」

さて前回までで形状を表示することが出来ました。
今回は表示した形状をより3次元に見せるようにします。

より3次元っぽく見せるには光源の設定を行います。
今回は少し長いですが気長にやってください。ちょっと光の設定はめんどくさいのです。



まず光について説明します。
光には3種類あり、環境光反射(AMBIENT)、鏡面反射(SPECULAR)、拡散反射(DIFFUSE)があります。
環境光反射とは直接光源は見えなくとも辺りの色が分かると言うもの、みなさんは部屋に電気を点けないで廊下など外の明かりで部屋のものを認識するときがあるかと思います。それが環境光反射です。
鏡面反射とは光源から出た光が形状に反射し見えると言うものです。これを設定する上では光源の位置、形状の位置、視点の位置が重要となってきます。太陽からの光が鏡面反射に近いと言えます。
最後に拡散反射とは鏡面反射の全体版です。光源から反射するのは全体に反射するものです。さすがに裏から光を当てたものは反射しませんがその他は全体に反射するようになります。


さてこれを頭に入れたところで光源の設定です。
DrawOpenGL関数のglLoadIdentity();の下に入れて下さい。


 float lightAmbient0[]={0.3f,0.3,0.3,1.0f};  //環境光反射
 float lightSpecular0[]={0.3f,0.3,0.3,1.0f};  //鏡面反射
 float lightDiffuse0[]={1.0f,1.0f,1.0f,0.8f};  //拡散反射
 glLightfv(GL_LIGHT0,GL_AMBIENT,lightAmbient0);   //環境光反射設定
 glLightfv(GL_LIGHT0,GL_SPECULAR,lightSpecular0);  //鏡面反射設定
 glLightfv(GL_LIGHT0,GL_DIFFUSE,lightDiffuse0);    //拡散反射設定
 float lightPosition0[]={ 0.0f, 0.0f, 100.0f};   //光源位置
 glLightfv(GL_LIGHT0,GL_POSITION,lightPosition0);  //光源位置設定
 glEnable(GL_LIGHTING);    //光源有効
 glEnable(GL_LIGHT0);     //光源0有効

光の色は好きなように設定してかまいません。青い光にするのも赤い光にするのも自由です。
今回は普通に白の光を当てています。


これで光の設定は出来ました。次は形状に色の設定を行います。
形状も光同様に設定します。


 float MaterialAmbient0[]={0.3f,0.3,0.3,1.0f};    //環境光反射
 float MaterialSpecular0[]={0.3f,0.3,0.3,1.0f};    //鏡面反射
 float MaterialDiffuse0[]={1.0f,1.0f,1.0f,0.8f};    //拡散反射
 glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT,MaterialAmbient0);
 glMaterialfv(GL_FRONT_AND_BACK,GL_SPECULAR,MaterialSpecular0);
 glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,MaterialDiffuse0);

ここで注意しなければならないのが以前色の設定に使用したglColor3d関数は使用できないと言うことです。glColor3d関数はglEnable(GL_LIGHTING);をした時点で効果はなくなります。


色の設定の変わりに面に法線方向を設定しなければなりません。


 glNormal3d(0.0, 0.0, 1.0);   //法線方向ベクトルの設定

必ず単位ベクトルで設定しなければなりません。この設定で光源をどう反射するかが決定します。


これで光源の設定は終わりです。あとは形状をうまく配置すれば3次元っぽく見えるはずです。


ためしに私はこんな形状を用意しました。
視点の設定を

 gluLookAt(           //カメラの設定
         0, 0, 0,     //カメラの焦点位置、X,Y,Z
         40, 0, 10,    //カメラの位置 X,Y,Z
         0, 1, 0);    //画面の縦座標軸


に変更し、形状を次のようにしました。


 double x = 0.0,y = 1.0,z = 0.0,w = 0.2;
 glBegin(GL_QUADS);
     glNormal3d(0.0, 0.0, 1.0);
     glVertex3d(0.0+x, 0.0+y, w+z);
     glVertex3d(0.0+x, 0.0, w+z);
     glVertex3d(w+x, 0.0, w+z);
     glVertex3d(w+x, 0.0+y, w+z);
 glEnd();
 glBegin(GL_QUADS);
     glNormal3d(0.0, 0.0, -1.0);
     glVertex3d(0.0+x, 0.0, z);
     glVertex3d(0.0+x, 0.0+y, z);
     glVertex3d(w+x, 0.0+y, z);
     glVertex3d(w+x, 0.0, z);
 glEnd();
 glBegin(GL_QUADS);
     glNormal3d(-1.0,0.0,0.0);
     glVertex3d(0.0+x, 0.0+y, z);
     glVertex3d(0.0+x, 0.0, z);
     glVertex3d(0.0+x, 0.0, w+z);
     glVertex3d(0.0+x, 0.0+y, w+z);
 glEnd();
 glBegin(GL_QUADS);
     glNormal3d(1.0,0.0,0.0);
     glVertex3d(w+x, 0.0, z);
     glVertex3d(w+x, 0.0+y, z);
     glVertex3d(w+x, 0.0+y, w+z);
     glVertex3d(w+x, 0.0, w+z);
 glEnd();
 glBegin(GL_QUADS);
     glNormal3d(0.0,1.0,0.0);
     glVertex3d(w+x, y, z);
     glVertex3d(x, y, z);
     glVertex3d(x, y, w+z);
     glVertex3d(w+x, y, w+z);
 glEnd();

ビルのようなものが見えるかと思います。上記までのソースはこちら
ビルをたくさん建てて町並みを表現することも可能ですね。


次回は物体の移動を行います。


 第1引数:光源番号(GL_LIGHT0~GL_LIGHT4)
 第2引数:光源の種類(GL_AMBIENT、GL_SPECULAR、
                GL_DIFFUSE、GL_POSITION)
 第3引数:光源の数値設定GL_POSITION の場合はfloat
       の配列3個の3次元座標(X,Y,Z)
       上記以外はfloatの配列4個(赤、緑、青、アルファ)

 glMaterialfv関数説明:glLightfvと同様

 第1引数:X座標ベクトル
 第2引数:Y座標ベクトル
 第3引数:Z座標ベクトル