3. 3D ビューイング 1. 3Dグラフィックス処理の一般過程 2. 射影と射影変換 3. ビューボリュームとクリッピング 4. 陰面処理とデプスバッファ 5. ビューポート変換 6. 3Dグラフィックスを描く 7. モデルビュー変換
3D グラフィックス処理の一般過程 1. 3D グラフィックス処理の一般過程
3D グラフィックス処理の一般過程 1. モデリング変換 座標系の異なる複数のオブジェクトを仮想世界に配置し, 統一的に扱うために, それぞれの座標系をワールド座標系に変換する 2. ビューイング変換 ワールド座標系におけるオブジェクトの各座標系を, 視点座標系における座標値に変換する uvn 座標系 ; 投影面を定義するための座標系視点座標系の Z 軸は,uvn 座標系の原点を通り,uv 平面と直交する
3D グラフィックス処理の一般過程 1. 正規化変換 1 x,y 成分は,-1.0 ~ +1.0 の範囲あるいは,0.0 ~ +1.0 の範囲 2 z 成分は,0.0 ~ +1.0 の範囲あるいは, -1.0 ~ +1.0 の範囲
射影と射影変換 1. 透視投影
射影と射影変換 1. 投影面における投影点座標の計算 投影面における投影点 (x,y) 座標は相似三角形理論で計算できる 投影点の x 座標と点 P の x 座標 P x の比, 投影点の y 座標と点 P の y 座標 P y の比, 投影面の距離 Nと点 Pの投影中心との距離 -P z の比は等しい x y N P P P x y z 従って, P P x y x, y N, N Pz Pz 投影点の座標は, 視点との距離に反比例する. 遠いものは小さく, 近いものは大きく見える 投影面の透視点の座標は投影面との距離に比例する 投影される図形は投影面の距離によってスケーリングされるしかし, 射影変換された座標は最後にビューポートに変換されるので射影される図形の大きさは結果には影響しない
ビューボリュームとクリッピング 1. ビューボリュームとクリッピング OpenGL; glfrustum(gldouble left, Gldouble right, Gldouble bottom, Gldouble top, Fldouble nera, G;double far); gluperspective(gldouble fovy, /* y,z 平面における視角 */ Gldouble aspect, /* 錐台の幅対高さ比 */ Gldouble near, Gldouble far);
ビューボリュームとクリッピング 正射影変換のビューボリューム OpenGL; glortho(gldouble left, Gldouble right, Gldouble bottom, Gldouble top, Gldouble near, Gldouble far);
陰面処理とデプスバッファ 射影中心から放射する直線上にある全ての点は同じ場所に射影される右図の場合,P 1 が P 2 に隠されているので P 1 を描く必要はない隠されていることを見つける方法の 1 つ視点から見る頂点の距離を利用すること, 即ち遠い頂点が近い頂点に隠される 距離の表現 : デプス (depth) --- 頂点の遠さを [-1, 1] の範囲で正規化したもの F N a near plane[n]; z=-1, F N apz b z 2FN b P far plane[f]; z=1 F N z 3 次元空間の点が射影変換により新たな3 次元の点にマッピングされる, x,yは射影面の座標,zは視点からの距離 P x y apz b P x, Py, Pz x, y, z N, N, Pz Pz Pz P
陰面処理とデプスバッファ OpenGL depth-buffer/z-buffer pixel 毎にデプス値を記憶する Depth test; frame-bufferにある輝度あるいは色の値を更新するか否かを判断する被射影の頂点のデプス値は現在より小さければ, そのバッファ値を更新する処理終了時, デプスバッファの値は一番近い点の値が保存されるこの結果, 陰面 ( 陰線 ) を除去され, 見える部分のみが描画される OpenGL; glcleardepthmask(glclampd depth); 初期値を指定 glclear(); 初期化 glenable(gl_depth_test); デプステストを有効にする gldepthfunc(glenum func); func=gl_less; 値が小さい場合更新
ビューポート変換 1. ビューポート変換一連の変換で計算される図形が最後に, この viewport にマッピングされる 2. OpenGl glviewport(glint x, GLint y, Glsizei width, Glsizei height); デバイス座標またはウィンドウ座標初期値は,(0, 0, winwidth, winheight) 注 : ビューポート変換には, 並行移動に加えスケーリング変換も含むこのために, 図形が変形する ( ゆがみ が生じる ) ビューポートの縦横比を near plane と同じにすると, ゆがみは生じない
3D グラフィックスを描く 1. 3D グラフィックスを描く program 3.1 faces; 6 個の面を構成する頂点の番号を保存 カメラは, 初期には原点にある 投影関係は, reshape() の中で次のように指定する gluperspective(60.0, (Glfloat)w/(GLfloat)h, 1.0, 20.0); 視界角 fovy=60, 視点と前面, 後面との距離は,1.0, 20.0 カメラ位置は原点だから, 全面 z=-1.0, 後面 z=-20.0 reshape() は, ウィンドウを再描画する度にパラメータとして幅 w と高さ h が, 渡されるので, この縦横比を調整する 立方体の描画は,display() の中で DrawBox() を呼び出して行う各面毎に, 面の頂点を用いて, プリミティブ GL_LINE_LOOP を指定する
モデルビュー変換 1. モデルビュー変換 program 3.2 program 3.1 では, 物体を視点座標で定義し, カメラ位置を考慮して, 物体の座標を決めている これは不自然 モデルを移動したり, カメラ位置と視線方向を変えるモデルビュー変換により物体は, カメラとは無関係にユーザ座標で設計できる 2. モデリング変換 移動 回転 スケーリング 3. ビューイング変換 カメラ位置と視線方向
3.1 #include <stdlib.h> #include <GL/glut.h> GLint faces[6][4]={ /* 頂点番号と面の情報 */ {0,1,2,3,{3,2,6,7,{7,6,5,4,{4,5,1,0,{5,6,2,1,{7,4,0,3; GLfloat v[8][3]; /* 頂点座標 {x 0,y 0,z 0, {x 1,y 1,z 1,.*/ void drawbox(void){ int i; for(i=0; i<6; i++){ 2 glbegine(gl_line_loop); 6 glvertex3fv(&v[faces[i][0]][0]); 3 7 glvertex3fv(&v[faces[i][1]][0]); 1 5 glvertex3fv(&v[faces[i][2]][0]); glvertex3fv(&v[faces[i][3]][0]); 0 4 glend(); /* pointer i/f */ void init(void){ glclearcolor(0.0,0.0,0.0,0.0); v[0][0]=v[1][0]=v[2][0]=v[3][0]=-1; v[4][0]=v[5][0]=v[6][0]=v[7][0]=1; v[0][1]=v[1][1]=v[4][1]=v[5][1]=-1; v[2][1]=v[3][1]=v[6][1]=v[7][1]=1; v[0][2]=v[3][2]=v[4][2]=v[7][2]=-4; v[1][2]=v[2][2]=v[5][2]=v[6][2]=-6; void display(void){ glclear(gl_color_buffer_bit); glcolor3f(1.0, 1.0, 1.0); drawbox(); glflush(); /* x-axis*/ /* y-axis*/ /* z-axis*/ void reshape(int w, int h){ glviewport(0, 0, (GLsizei)w, (GLsizei)h); glloadidentity(); glmatrixmode(gl_projection); /* 射影変換 */ gluperspective(60.0, (GLfloat)w/(GLfloat)h, 1.0, 20.0); /* camera = origine */ /* ViewVolume w/h = ViewPort w/h*/ void keyboard(unsigned char key, int x, int y){ switch(key){ case 27; exit(0); break; int main(int argc, char **argv){ glutinit(&argc, argv); glutinitdisplaymode(glut_single GLUT_RGB); glutinitwindowsize(200, 200); glutinitwindowposition(100, 100); glutcreatwindow(argv[0]); init(); glutdisplayfunc(display); glutreshapefunc(reshape); glutkeyboardfunc(keyboard); glutmainloop(); return 0;
#include <stdlib.h> # include <GL/glut.h> GLint faces[6][4]={ {0,1,2,3,{3,2,6,7,{7,6,5,4,{4,5,1,0,{5,6,2,1,{7,4,0,3; GLfloat v[8][3]; void drawbox(void){ int i; for(i=0; i<6; i++){ glbegine(gl_line_loop); glvertex3fv(&v[faces[i][0]][0]); glvertex3fv(&v[faces[i][1]][0]); glvertex3fv(&v[faces[i][2]][0]); glvertex3fv(&v[faces[i][3]][0]); glend(); void init(void){ /* オブジェクトをユーザ座標で定義 */ glclearcolor(0.0,0.0,0.0,0.0); v[0][0]=v[1][0]=v[2][0]=v[3][0]=-1; v[4][0]=v[5][0]=v[6][0]=v[7][0]=1; v[0][1]=v[1][1]=v[4][1]=v[5][1]=-1; v[2][1]=v[3][1]=v[6][1]=v[7][1]=1; v[0][2]=v[3][2]=v[4][2]=v[7][2]=1; // -4 1 v[1][2]=v[2][2]=v[5][2]=v[6][2]=-1; // -6-1 void display(void){ 3.2 モデル ビュー変換 glclear(gl_color_buffer_bit); glcolor3f(1.0, 1.0, 1.0); glloadidentity(); glutlookat(0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0); drawbox(); /* camera 位置の設定 */ glflush(); void reshape(int w, int h){ glviewport(0, 0, (GLsizei)w, (GLsizei)h); glloadidentity(); glmatrixmode(gl_projection); gluperspective(60.0, (GLfloat)w/(GLfloat)h, 1.0, 20.0); glmatrixmode(gl_modelview); void keyboard(unsigned char key, int x, int y){ switch(key){ case 27; exit(0); break; int main(int argc, char **argv){ glutinit(&argc, argv); glutinitdisplaymode(glut_single GLUT_RGB); glutinitwindowsize(200, 200); glutinitwindowposition(100, 100); glutcreatwindow(argv[0]); init(); glutdisplayfunc(display); glutreshapefunc(reshape); glutkeyboardfunc(keyboard); glutmainloop(); return 0;
OpenGLにおけるカメラの設定 glulookat( GLdouble eyex, GLdouble eyey, GLdouble eyez, /* camera 位置 */ GLdouble centerx, GLdouble centery, GLdouble centerz, /* cameraの注視点 */ GLdouble upx, GLdouble upy, GLdouble upz) /* cameraの上方向 */ OpenGLにおけるモデルビュー変換の一般的な手順 OpenGLにおけるカメラの設定 1. モデルビュー変換を指定 glmatrixmode(gl_modelview); 2. 変換マトリクスの初期化 glloadidentity(); 3. モデルビュウー変換 glulookat();
#include <stdlib.h> #include <GL/glut.h> GLint faces[6][4]={ {0,1,1,3,{3,2,6,7,{7,6,5,4,{4,5,1,0,{5,6,2,1,{7,4,0,3; GLfloat v[8][3]; void drawbox(void){ int i; for(i=0; i<6; i++){ glbegine(gl_line_loop); glvertex3fv(&v[faces[i][0]][0]); glvertex3fv(&v[faces[i][1]][0]); glvertex3fv(&v[faces[i][2]][0]); glvertex3fv(&v[faces[i][3]][0]); glend(); void init(void){ glclearcolor(0.0,0.0,0.0,0.0); 3.3 視点を変化 v[0][0]=v[1][0]=v[2][0]=v[3][0]=-1; v[4][0]=v[5][0]=v[6][0]=v[7][0]=1; v[0][1]=v[1][1]=v[4][1]=v[5][1]=-1; v[2][1]=v[3][1]=v[6][1]=v[7][1]=1; v[0][2]=v[3][2]=v[4][2]=v[7][2]=1; v[1][2]=v[2][2]=v[5][2]=v[6][2]=-1; viod LookAt(void){ /* 視点の変化に対するビューアップベクトルの計算 */ int i; GLdouble look[3], norm; GLdouble ViewAt[3] = {5.0, 7.5, 5.0; /* 位置 */ GLdouble ViewTo[3] = {0.0, 0.0, 0.0; /* 注視方向 */ GLdouble ViewUp[3]; /* 上方向 */ for(i=0; i<3; i++){ look[i] =ViewTo[i] - ViewAt[i]; ViewUp[0] = - look[0] * look[2]; ViewUp[1] = - look[1] * look[2]; ViewUp[2] = look[0] * look[0] + look[1] * look[1] + look[2] * look[2]; norm = ViewUp[0]*ViewUp[0] + ViewUp[1]*ViewUp[1] + ViewUp[2]*ViewUp[2]; norm = sqrt(norm); for(i=0; i<3; i++){ ViewUp[i] /= norm; glulookat(viewat[0], ViewAt[1], ViewAt[2], ViewTo[0], ViewTo[1], ViewTo[2], ViewUp[0], ViewUp[1], ViewUp[2]); void display(void){ glclear(gl_color_buffer_bit); glcolor3f(1.0, 1.0, 1.0); glloadidentity(); LookAt(); drawbox(); glflush();
3.3 void reshape(int w, int h){ glviewport(0, 0, (GLsizei)w, (GLsizei)h); glloadidentity(); glmatrixmode(gl_projection); gluperspective(30.0, (GLfloat)w/(GLfloat)h, 1.0, 20.0); glmatrixmode(gl_modelview); void keyboard(unsigned char key, int x, int y){ switch(key){ case 27; exit(0); break; int main(int argc, char **argv){ glutinit(&argc, argv); glutinitdisplaymode(glut_single GLUT_RGB); glutinitwindowsize(200, 200); glutinitwindowposition(100, 100); glutcreatwindow(argv[0]); init(); glutdisplayfunc(display); glutreshapefunc(reshape); glutkeyboardfunc(keyboard); glutmainloop(); return 0;
#include <stdlib.h> #include <GL/glut.h> GLint faces[6][4]={ {0,1,1,3,{3,2,6,7,{7,6,5,4, {4,5,1,0,{5,6,2,1,{7,4,0,3; GLfloat v[8][3]; GLfloat n[6][3]={ {-1.0, 0.0, 0.0,{0.0, 1.0, 0.0,{1.0, 0.0, 0.0, {0.0, -1.0, 0.0,{0.0, 0.0, -1.0,{0.0, 0.0, 1.0; void drawbox(void){ int i; for(i=0; i<6; i++) glbegin(gl_polygon); glnormal3fv(&n[i][0]); glvertex3fv(&v[faces[i][0]][0]); glvertex3fv(&v[faces[i][1]][0]); glvertex3fv(&v[faces[i][2]][0]); glvertex3fv(&v[faces[i][3]][0]); glend(); void init(void){ 3.4 照明 材料などの光学特性 GLfloat mat_amb_diff[4]={1.0,1.0,1.0,1.0; GLfloat light_amb[4]={1.0,5.5,1.0,1.0; glclearcolor(0.0,0.0,0.0,0.0); glshademodel(gl_smooth); glmaterialfv(gl_front, GL_SPECULAR, mat_amb_diff); gllightfv(gl_light0, GL_POSITION, light_amb); glenable(gl_lighting); glenable(gl_light0); glenable(gl_depth_test); v[0][0]=v[1][0]=v[2][0]=v[3][0]=-1; v[4][0]=v[5][0]=v[6][0]=v[7][0]=1; v[0][1]=v[1][1]=v[4][1]=v[5][1]=-1; v[2][1]=v[3][1]=v[6][1]=v[7][1]=1; v[0][2]=v[3][2]=v[4][2]=v[7][2]=1; v[1][2]=v[2][2]=v[5][2]=v[6][2]=-1; viod LookAt(void){ /* 視点の変化に対するビューアップベクトルの計算 */ int i; GLdouble look[3], norm; GLdouble ViewAt[3] = {5.0, 7.5, 5.0; /* 位置 */ GLdouble ViewTo[3] = {0.0, 0.0, 0.0; /* 注視方向 */ GLdouble ViewUp[3]; /* 上方向 */ for(i=0; i<3; i++){ look[i] =ViewTo[i] - ViewAt[i]; ViewUp[0] = - look[0] * look[2]; ViewUp[1] = - look[1] * look[2]; ViewUp[2] = look[0] * look[0] + look[1] * look[1] + look[2] * look[2]; norm = ViewUp[0]*ViewUp[0] + ViewUp[1]*ViewUp[1] + ViewUp[2]*ViewUp[2]; norm = sqrt(norm); for(i=0; i<3; i++){ ViewUp[i] /= norm; glulookat(viewat[0], ViewAt[1], ViewAt[2], ViewTo[0], ViewTo[1], ViewTo[2], ViewUp[0], ViewUp[1], ViewUp[2]);
3.4 void display(void){ glclear(gl_color_buffer_bit); glcolor3f(1.0, 1.0, 1.0); glloadidentity(); LookAt(); drawbox(); glflush(); void reshape(int w, int h){ glviewport(0, 0, (GLsizei)w, (GLsizei)h); glloadidentity(); glmatrixmode(gl_projection); gluperspective(30.0, (GLfloat)w/(GLfloat)h, 1.0, 20.0); glmatrixmode(gl_modelview); int main(int argc, char **argv){ glutinit(&argc, argv); glutinitdisplaymode(glut_single GLUT_RGB); glutinitwindowsize(200, 200); glutinitwindowposition(100, 100); glutcreatwindow(argv[0]); init(); glutdisplayfunc(display); glutreshapefunc(reshape); glutkeyboardfunc(keyboard); glutmainloop(); return 0; glclear(gl_depth_buffer_bit); void keyboard(unsigned char key, int x, int y){ switch(key){ case 27; exit(0); break;
glmaterialf*( 材質が設定される面, 材質の特性, 設定値 ); 1) 材質が設定される面 GL_FRONT: ポリゴンの表面 GL_BACK: ポリゴンの裏面 GL_FRONT_AND_BACK: ポリゴンの表面と裏面 2) 材質の特性 GL_DIFFUSE: 拡散反射成分,R,G,B,A 強度を 0.0~1.0 で指定 GL_SPECULAR: 鏡面反射成分, 同上 GL_AMBIENT: 環境光反射成分, 同上 GL_EMISSION: 発光物体の設定, 同上 GL_SHININESS: 鏡面反射光の強さを 0.0~128.0 で指定 3) 設定値と設定方法 1> 配列に R,G,B,A 強度を予め定義し,glMaterialfv を用いる float diffuse[ ]={1.0,1.0,10.,1.0; float specular[ ]={ 1.0,1.0,10.,1.0; float ambient[ ]={0.1,0.1,0.1,1.0; glmateialfv(gl_front, GL_DIFFUSE, diffuse); glmaterialv(gl_front, GL_SPECULAR, specular); glmaterialfv(gl_front, GL_AMBIENT, ambient); 2> GL_SHININESS を設定する場合は,glMaterialf を用いる glmaterialf(gl_front, GL_SHINENESS, 128.0);
演習課題 1. P61の演習問題問 1~6を実施 2. 提出は,12 月 2 日 ( 月 ) の授業開始時まで 1. 問 1~3は, 指定の用紙に記載 2. プログラムのソースコードはプリントしたものを提出 3. 実行結果を示すウィンドウの図を PrtScn にてプリントしたも のを提出 ( 当該ソースコードの裏面に ) 3. 作業場所 1. 1207 教室のオープン時間 1. 月 火,3&4 限 2. 木 金,4 限