OpenGL座標処理
OpenGLがシーンを描画するには、シーンの各頂点に座標変換を施します。
その手順は下記のとうりです。
(1)モデルビュー座標変換
視点にたいしてモデルを位置付ける。
例えば、視点を原点として視点の方向をZ軸にとる視点座標系。
(2)投影座標変換
シーンにたいしてクリッピングと透視投影を実行する。
クリッピングはビューボリューム(視体積)を用います。
透視投影により3Dらしくなる。
(3)ビューポート座標変換
シーンの各頂点がスクリーンのどのように写像されるかを決める。
投影座標変換
透視投影(遠近投影法)の行列を指定する。
glMatrixMode(GL_PROJECTION);
現在選択されている行列に単位行列をロードする。
glLoadIdentity();
ビューボリューム(視体積)を指定します。
引数は視体積の左、右、下、上、近クリップ面、遠クリップ面の座標を定義
glFrustum(-1.0, 1.0, -1.0, 1.0, 2.0, 7.0);
平行投影を利用する場合は、glOrtho()を使用する。
モデルビュー座標変換
モデルビューの行列を用いて作業する事を指定する。
glMatrixMode(GL_MODELVIEW);
現在選択されている行列に単位行列をロードする。
glLoadIdentity();
物体を平行移動をさせる場合。
glTranslatef(0.0f, 0.0f, -5.0f);
物体をスケールリングさせる場合。
glScalef(2.0f, 2.0f, 2.0f);
物体を回転させる場合。
glRotatef(45, 1.0f, 0.0f, 0.0f);
ポートビュー座標変換
glViewport(Left, Bottom, Width, Height);
正方形を正方形として見る為に、アスペクト比を利用する。
gldAspect = Width / Height;
gluPerspective(30.0f, 視野角
gldAspect, 視体積のアスペクト比
1.0, 近クリップ面の距離
100.0); 遠クリップ面の距離
glViewport(0, 0, Width, Height);
光源の定義
OpenGLでは8個の光源を持っています。
GL_LIGHT0、GL_LIGHT1、・・・・・・、GL_LIGHT7です。
各光源には、4つのタイプを設定できます。
(1)環境光(ambient):一度に全方向からくるような光。
(2)拡散光(diffuse):一方から来る光で、全ての方向に反射。
(3)鏡面光(specular):明るい、白いスポットを反射面に形ずくるような光。
(4)放射光(emission):ランプのような物体から出る光。
光の値の配列を作成する。
GLfloat glfLightAmbient[] = {0.1, 0.1, 0.1, 1.0};
GLfloat glfLightDiffuse[] = {0.7, 0.7, 0.7, 1.0};
GLfloat glfLightSpecular[] = {0.0, 0.0, 0.0, 1.0};
光の値の配列をOpenGLに与える。
glLightfv(GL_LIGHT0, GL_AMBIENT, glfLightAmbient);
glLightfv(GL_LIGHT0, GL_DIFFUSE, glfLightDiffuse);
glLightfv(GL_LIGHT0, GL_SPECULAR,glfLightSpecular);
glLightfvで使える属性定数
GL_AMBIENT
GL_DIFFUSE
GL_SPECULAR
GL_POSITION
GL_SPOT_DIRECTION
GL_SPOT_EXPONENT
GL_SPOT_CUTOFF
GL_CONSTANT_ATTENUATION
GL_LINEAR_ATTENUATION
GL_QUADRATIC_ATTENUATION
ここで、照明モデルを有効にします。
glEnable(GL_LIGHTING);
次に、どの光源を使用するか伝えます。
glEnable(GL_LIGHT0);
マテリアルの定義
シーン中のオブジェクトの表面の属性を定義する。
(1)環境光(ambient):オブジェクトの回りを漂う光
(2)散乱光(diffuse):表面がザラザラした感じ、つや消しを表現する成分。
(3)鏡面光(specular):金属のつるつるした表面が一定の方向に鋭く反射。
(4)放射光(emission):白いスッポトを反射面に形ずくる成分。
などが考えられます。
光の反射に対する値を格納した配列を作成する。RGBAの値。
GLfloat glfMaterialColor[] = {0.0, 0.0, 1.0, 1.0};
OpenGLに与える。
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, glfMaterialColor);
第1パラメータ
GL_FRONT
GL_BACK
GL_FRONT_AND_BACK
第2パラメータ
GL_AMBIENT
GL_DIFFUSE
GL_SPECULAR
GL_EMISSION
GL_SHININESS
GL_AMBIENT_AND_DIFFUSE
GL_COLOR_INDEXES
光沢を現す場合
glMaterialfv(GL_FRONT, GL_SHININESS, 90.0f);
第3パラメータは0から128
法線の定義
OpenGLで、照明モデルを正常に作用させるには、
オブジェクトの頂点だけではなく
オブジェクト中の各頂点を基に法線を定義する必要がある。
OpenGLはこの法線を利用してその頂点で受けている光を特定している。
現在の法線を指定するにには、glNormal3f()を使用します。
そのあとglVertex3f()を呼び出すと、
指定した頂点に、その法線が割り当てられます。
例)
glBegin(GL_POLYGON);
glNormal3f(1.0, 0.0, 0.0);
glVertex3f(1.0, 1.0, 1.0);
glVertex3f(1.0, -1.0, 1.0);
glVertex3f(1.0, -1.0, -1.0);
glVertex3f(1.0, 1.0, -1.0);
glEnd;
シェーディングモデル
OpenGLは、シーンをスムースシェーディング、フラットシェーディングします。
フラットシェーディング:オブジェクトを構成するポリゴンに対し
ポリゴンの中心のピクセルで輝度を求め
その値で塗りつぶす。
スムースシェーディング:平面のポリゴンを曲面に見せかける処理。
フォンシェーディング、グーローシェーディングがある。
glShadeModel(GL_SMOOTH);
パラメータ
GL_FLAT
GL_SMOOTH
デプステスト
多角形に影を付けるには、各多角形の前後関係を決定する必要がある。
これをするのが、デプステストである。
このデプステストを有効にします。
glEnable(GL_DEPTH_TEST);
デプステストでは、あるバファーを使用するので
シーンをレンダリングするのにバファーをクリアします。
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
隠面消去処理
隠面消去の代表的なアルゴリズムに、
(1)Zソートアルゴリズム
(2)Zバッファーアルゴリズム
1280x1024x32bit = 5MBytesのZバッファーが必要です。
(3)スキャンラインアルゴリズム
があります。
ダブルバッファ処理
ダブルバッファ処理をする場合、
OpenGLにダブルバッファ環境を設定したことを知らせる必要がある。
フロント/バックバッファーの切り替えの命令文があるとおもう。
また、この部分は、使用プラットホーム環境で異なるのかもしれません。
現在は、Windowsのみ確認しています。
ワールド座標、ローカル座標
小さなオブジェクトを集めて大きなオブジェクトを作成する場合、
ワールドとローカルのそれぞれの原点を用いた座標変換を考えるほうが
簡単であることが多い。
ワールド座標の原点は、3次元デカルト座標の原点である。
ローカル座標の原点は、オブジェクトの中心である。
この系を用いると、ブロックを積みたてるように、
3次元オブジェクトを作成することができます。
例えば、下記のように立方体を作成できます。
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.0f, 0.0f, -1.0f);
glRotatef(m_angle2, 0.0f, 1.0f, 0.0f);
auxSolidCube(1.0f);
glTranslatef(0.0f, -1.1f, 0.0f);
auxSolidCube(0.9f);
glTranslatef(0.0f, 2.1f, 0.0f);
auxSolidCube(0.75f);
glFlush();
描画操作
バッファリングされたOpenGL描画命令を完了させます。
glFlush(void);
バッファリングされたOpenGL描画命令を完了させ、
それらの操作が完了した時のみ戻ってきます。
glFinish(void);
行列スタック
基本のモデルビューを設定しておき、
その行列で座標変換を実行していき、
その後、その行列を元に戻せる
(基本のモデルビューを設定した時の行列に)
と便利です。
これを実現してくれるのが、行列スタックです。
glPushMatrix()、glPopMatrix()です。
[基本のモデルビューを設定]
glPushMatrix();
[その行列で座標変換]
[描画]
glPopMatrix();
[元のモデルビューの状態]
glNewList
glNewList(List名, GL_COMPILE) と glEndList()
の間に記述されたOpenGL命令は
[List名]という名前で記憶されます。
そして、これを glCallList(List名) で呼び出せます。
図形を定義しておく。
glNewList(DRAWCUBE, GL_COMPILE);
[正方形を定義する]
glEndList ();
次に、下記のように呼び出します。
for (i=-3.0;i <= 3.0; i++) {
for (j=-3.0;j <= 3.0; j++){
for (k=-3.0;k <= 3.0; k++){
glPushMatrix;
glTranslatef(i, j, k);
glCallList(DRAWCUBE);
glPopMatrix;
}
}
}
混合
混合の有効化
glEnable(GL_BLEND);
混合の無効化
glDisable(GL_BLEND);
混合関数の設定
glBlendFunc(GLenum sfactor, GLenum dfactor);
第1パラメータ sfactor:RGBAソース混合割合関数の指定
GL_ZERO
GL_ONE
GL_DST_COLOR
GL_ONE_MINUS_DST_COLOR
GL_SRC_ALPHA
GL_ONE_MINUS_SRC_ALPHA
GL_DST_ALPHA
GL_ONE_MINUS_DST_ALPHA
GL_SRC_ALPHA_SATURATE
第2パラメータ dfactor:RGBAテスティネーション混合割合関数の指定
GL_ZERO
GL_ONE
GL_SRC_COLOR
GL_ONE_MINUS_SRC_COLOR
GL_SRC_ALPHA
GL_ONE_MINUS_SRC_ALPHA
GL_DST_ALPHA
GL_ONE_MINUS_DST_ALPHA
例)glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2個の多角形の一部が重なっているとする。その重なった
一方をソース、もうひとつをテスティネーションとします。
glClearColor(1,1,1,1);
glClear(GL_COLOR_BUFFER_BIT);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glColor4f(0,1,1,1);
[テスティネーション多角形描画]
glColor4f(1,0,0,0.5);
[ソース多角形描画]
glFlush();
glDisable(GL_BLEND);
この例の処理は、2度目のglColor4f(1,0,0,0.5)のアルファ値0.5が使用されます。
ソースの重なりの部分の各ピクセルにたいして本アルファ値がかけられます。
また、もうひとつのテスティネーションの重なりの部分の各ピクセルにたいして、
(1−本アルファ値)がかけられます。
ここでは、アルファ値が大きければ不透明となる。
アルファ値が小さければ透明となる。
三次元の混合
三次元の半透明なオブジェクトを描画する場合、
デプステストを無効(リードオンリー)に設定する必要があります。
すなわち、
(1)デプステスト有効
(2)不透明なオブジェクトを全て描画
(3)デプステストをリードオンリーに設定
(4)半透明なオブジェクトを描画
(5)デプステストをリードオンリー/ライトに戻す
として描画させる必要があります。
例)
glClearColor(0.3,0.3,0.3,0.0);
glClear(GL_COLOR_BUFFER_BIT, GL_DEPTH_BUFFER_BIT);
glEnable(GL_BLEND);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_DEPTH_TEST);
glBlendFunc(GL_ONE, GL_ZERO);
GLfloat lightAmbient[] = {0.1f, 0.1f, 0.1f, 0.0f};
GLfloat lightDiffuse[] = {1.0f, 1.0f, 1.0f, 0.0f};
GLfloat lightSpecular[] = {1.0f, 1.0f, 1.0f, 0.0f};
GLfloat lightPosition[] = {2.0f, 0.5f, 3.0f, 1.0f};
GLfloat materialSpecular[] = {1.0f, 1.0f, 1.0f, 0.0f};
GLfloat materialSphere1[] = {1.0f, 0.0f, 0.0f, 0.0f};
GLfloat materialSphere2[] = {0.0f, 1.0f, 0.0f, 0.0f};
GLfloat materialCube[] = {1.0f, 1.0f, 0.0f, 0.0f};
materialCube[] = {1.0f, 1.0f, 0.0f, 0.5f};
glLightfv(GL_LIGHT0, GL_AMBIENT, lightAmbient);
glLightfv(GL_LIGHT0, GL_DIFFUSE, lightDiffuse);
glLightfv(GL_LIGHT0, GL_SPECULAR, lightSpecular);
glLightfv(GL_LIGHT0, GL_POSITION, lightPosition);
glMaterialfv(GL_FRONT, GL_SPECULAR, materialSpecular);
glMaterialf(GL_FRONT, GL_SHININESS, 50.0f);
glTranslatef(-1.5f, 0.5f, -3.0f);
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, materialSphere1);
auxSolidSphere(1.0);
glTranslatef(2.0f, -0.8f, 3.0f);
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, materialSphere2);
auxSolidSphere(0.75);
glDepthMask(GL_FALSE);
glBlendFunc(GL_SRC_ALPHA, GL_DST_ALPHA);
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, materialCube);
glTranslatef(-1.0f, 0.0f, -1.5f);
glRotatef(40.0f, 1.0f, 0.0f, 0.0f);
glRotatef(40.0f, 0.0f, 1.0f, 0.0f);
auxSolidCube(1.0);
glFlush();
glDepthMask(GL_TRUE);
glDisable(GL_LIGHTING);
glDisable(GL_DEPTH_TEST);
glDisable(GL_BLEND);
アンチエリアシング
スクリーン上の線のジャギーを滑らかに見せる処理です。
(1)アンチエリアシングを有効にする
glEnable(GL_LINE_SMOOTH);
この他、GL_POINT_SMOOTH、GL_POLYGON_SMOOTHがあります。
(2)混合の有効化
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
(3)OpenGLにスムージングのヒントを設定
glHint(GL_LINE_SMOOTH_HINT,GL_DONT_CARE);
第1パラメータ
( GL_FOG_HINT )
GL_LINE_SMOOTH_HINT
( GL_PERSPECTIVE_CORRECTION_HINT )
GL_POINT_SMOOTH_HINT
GL_POLYGON_SMOOTH_HINT
第2パラメータ
GL_DONT_CARE:好きなようにせよ
GL_FASTTEST:最も速い方法を使用せよ
GL_NICEST:正確な方法を使用せよ
例)線のアンチエリアシング
glClearColor(0.3,0.3,0.3,0.0);
glClear(GL_COLOR_BUFFER_BIT);
glEnable(GL_LINE_SMOOTH);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glHint(GL_LINE_SMOOTH_HINT, GL_DONT_CARE);
glLineWidth(2.0f);
glShadeModel(GL_FLAT);
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
auxWireSphere(1.0);
glDisable(GL_LINE_SMOOTH);
glDisable(GL_BLEND);
フォグ
(1)フォグの有効化
glEnable(GL_FOG);
(2)フォグの関数の設定
glFogi(GL_FOG_MODE,GL_LINEAR);
第1パラメータ
GL_FOG_MODE
第2パラメータ
GL_LINEAR, GL_EXP, GL_EXP2
ここで、GL_LINEARを設定した場合、
フォグの開始点と終了点を設定できます。
glFogf(GL_FOG_START, 0.0f);
glFogf(GL_FOG_END,10.0f);
また、GL_EXP, GL_EXP2を設定した場合、
フォグの濃度を指定できます。
glFogf(GL_FOG_DENSITY, 3.0f);
(3)フォグの色の設定
glFloat fogc[]={0.6f,0.6f,0.5f,1.0f};
glFogfv(GL_FOG_COLOR,fogc);
(4)フォグのヒントの設定
glHint(GL_FOG_HINT,GL_DONT_CARE);
第1パラメータ
GL_FOG_HINT
第2パラメータ
GL_DONT_CARE:好きなようにせよ
GL_FASTTEST:最も速い方法を使用せよ
GL_NICEST:正確な方法を使用せよ
頂点配列の利用
OpenGL Ver 1.1の対応。
幾何学的プリミティブをレンダリングするのに便利。
(1)最大6個の配列を有効化できます。
glEnableClientState(GL_NORMAL_ARRAY); 面の法線
glEnableClientState(GL_VERTEX_ARRAY); 頂点座標
この他、 GL_COLOR_ARRAY:RGBAカラー
GL_INDEX_ARRAY:カラー指標
GL_TEXTURE_COLORD_ARRAY:テクスチャ座標
GL_EDGE_FLAG_ARRAY:ポリゴンのエッジフラグ
がある。
無効にするのは、glDisableClientState(GL_NORMAL_ARRAY);
(2)配列データを作成
例えば、
static GLint vert{25,25,
100,325,
175,25,
175,325};
(3)OpenGLに配列を指定
glVertexPointer(size,type,stride,pointer)
glVertexPointer(2,GLint,0,vert);
この他、
glColorPointer()
glNormalPointer()
gltexCoordPointer()
glEdgeFlagPointer()
glInterleavedArrays(format,stride,pointer)
同時に複数の配列を指定できます。
データ配列は、各種のデータを一つにまとめておける。
(4)レンダリング
glArrayElement(i)
有効な配列すべてに対して、i番目の頂点を取り出します。
例)
glBegin(GL_TRIANGLES);
glArrayElement(1);
glArrayElement(2);
glArrayElement(3);
glEnd();
glDrawElements(mode,count,type,indices)
count個の要素を使用して、modeの物体を構築。
typeは、indicesの型を指定します。
indicesは、データ配列。
glDrawArrays(mode,first,count)
有効化した配列のfirstからfirst+count-1個の配列要素を用いて、
物体を作成します。