Comments
Description
Transcript
OpenGL 基本プログラム例
OpenGL 基本プログラム例 ■関数のグラフ (基本) #include <GL/glut.h> #include <math.h> #define PI 3.14159265 void function_graph() { int j; float x, y; glBegin( GL_LINE_STRIP );// sine curve by line glColor3f( 0.0f, 1.0f, 1.0f );// line color for( j=0; j<100; j++ ){ x = -2.0*PI+4.0*PI*(float)j/100.0; y = sin(x); glVertex2f(x, y); }; glEnd(); glPointSize( 3.0 ); glBegin( GL_POINTS );// cosine curve by points glColor3f( 1.0f, 1.0f, 0.0f );// point color for( j=0; j<100; j++ ){ x = -2.0*PI+4.0*PI*(float)j/100.0; y = cos(x); glVertex2f(x, y); }; glEnd(); glBegin( GL_LINES );/* x-axis */ glColor3f( 1.0f, 1.0f, 1.0f ); glVertex2f( -2.0*PI, 0.0f ); glVertex2f( 2*PI, 0.0f ); glEnd(); glBegin( GL_LINES );/* y-axis */ glVertex2f(0.0f, 1.5f); glVertex2f(0.0f, -1.5f ); glEnd(); return; } void init() { glClearColor( 0.0f, 0.0f, 0.0f, 1.0f);// backgound color /* window coordinate */ glMatrixMode( GL_MODELVIEW ); glLoadIdentity(); gluOrtho2D( -2.0*PI, 2.0*PI, -1.5, 1.5 ); } void display(void) { glClear( GL_COLOR_BUFFER_BIT ); 1 /* drawing function */ function_graph();// drawing graph glFlush(); } int main(int argc, char **argv ) { glutInit( &argc, argv ); glutInitDisplayMode( GLUT_RGB | GLUT_SINGLE ); glutInitWindowSize( 500, 400 ); glutInitWindowPosition( 100, 100 ); glutCreateWindow( "Sine-Cosine curve" ); init(); glutDisplayFunc( display ); glutMainLoop(); return 0; } 2 ■関数のグラフ (リスト) 初めの例と同じグラフであるが,描画オブジェクトのリストを作成してから描画す る.リストを使う利点は,図形を移動やウィンドウの重なり合いの変化などによる再描画をするときに,計算 しなおす必要がないために描画速度が速くなる.ただし,この例くらいでは特に利点とは云えない. #include <GL/glut.h> #include <math.h> #define PI 3.14159265 /* static parameter for displaylist */ static GLuint index; /* generating displaylist for drawing a function graph */ void createFunctionList() { int j; float x, y; /* generating displaylist */ index = glGenLists( 1 ); /* starting making displaylist */ glNewList( index, GL_COMPILE_AND_EXECUTE ); { glBegin( GL_LINE_STRIP );/* sine curve by line */ glColor3f( 0.0f, 1.0f, 1.0f );// line color for( j=0; j<100; j++ ){ x = -2.0*PI+4.0*PI*(float)j/100.0; y = sin(x); glVertex2f(x, y); }; glEnd(); glPointSize( 3.0 ); glBegin( GL_POINTS );/* cosine curve by points */ glColor3f( 1.0f, 1.0f, 0.0f );// point color for( j=0; j<100; j++ ){ x = -2.0*PI+4.0*PI*(float)j/100.0; y = cos(x); glVertex2f(x, y); }; glEnd(); glBegin( GL_LINES );/* x-axis */ glColor3f( 1.0f, 1.0f, 1.0f ); glVertex2f( -2.0*PI, 0.0f ); glVertex2f( 2*PI, 0.0f ); glEnd(); glBegin( GL_LINES );/* y-axis */ glVertex2f(0.0f, 1.5f); glVertex2f(0.0f, -1.5f ); glEnd(); } /* end of displaylist */ glEndList(); return; } 3 void init() { glClearColor( 0.0f, 0.0f, 0.0f, 1.0f);// backgound color /* window coordinate */ glMatrixMode( GL_MODELVIEW ); glLoadIdentity(); gluOrtho2D( -2.0*PI, 2.0*PI, -1.5, 1.5 ); } void display(void) { glClear( GL_COLOR_BUFFER_BIT ); /* drawing function */ glCallList( index );// drawing graph glFlush(); } int main( int argc, char **argv ) { glutInit( &argc, argv ); glutInitDisplayMode( GLUT_RGB | GLUT_SINGLE ); glutInitWindowSize( 500, 400 ); glutInitWindowPosition( 100, 100 ); glutCreateWindow( "Sine-Cosine curve" ); init(); createFunctionList();// creating graph glutDisplayFunc( display ); glutMainLoop(); return 0; } 4 ■色々な 2 次元図形 (マンデルブロート集合) 色々な 2 次元図形を描いてみよう. これから 3 つの例は,複雑系の図として良く紹介されている.この例と次の例は複素力学系の図で,共に f (z) = z + c による力学系の軌道が発散するかしないかで点の色づけをしている.この例はマンデルブロート 集合 M = {c|z0 = 0, zn+1 = f (zn ), zn 有界 } の図である.描画の範囲 c = x + iy (α ≤ x ≤ β, γ ≤ y ≤ δ) は最初の所の rL, rR, iB, iT で定めている.α =rL, β =rR, γ =iB, δ =iT である.軌道は無限に続けら れないので,Mx までの軌道で判断する.また,有界性の判定も |zn | < 2 で有界としている.この 2 という値 が面白い図ができるクリティカルな値である. 図は |zn | > 2 となったときの n の値で c に色付けをする.カラーリングによって全く印象の異なる図が得 られる.代表的なカラーリングの方法の 1 つは,ループを抜け出したインデックス毎に異なる色をつける方法 で,もう 1 つの方法は,ループを抜け出したインデックスをグループ化して段階的に色をつける方法である. このマンデルブロート集合の場合は,抜け出した色毎に異なる色をつけている.次のジュリア集合の場合は, 段階的に色をつけている. #include <GL/glut.h> #define win_width 500 #define win_height 500 static double rL=-2.5, rR=0.5, iB=-1.5, iT=1.5;// window area static int Mx = 200;// iteration limit static double Prl=0.0, Pim=0.0; // start point static GLuint index; struct compn { double rl; double im; }; /* evaluation of iteration */ int kernel(double s_rl, double s_im, double p_rl, double p_im, int Max) { struct compn z, z2, c; double absq; int itr=0; z.rl = p_rl; z.im = p_im; // start c.rl = s_rl; c.im = s_im; // parameter absq = z.rl*z.rl + z.im*z.im; while(absq < 4.0 && itr < Max) { z2.rl = z.rl * z.rl - z.im * z.im + c.rl; z2.im = 2.0 * z.rl * z.im + c.im; z = z2; absq = z.rl*z.rl + z.im*z.im; itr++; } return itr; } /* generating displaylist */ 5 void createList() { int i, j, k;// iteration index double x, y;// window coordinate double rstep, istep;// iteration step int pcl;// paint color /* iteration step */ rstep = (rR-rL)/win_width; istep = (iT-iB)/win_height; /* generating displaylist */ index = glGenLists( 1 ); /* making displaylist */ glNewList( index, GL_COMPILE_AND_EXECUTE ); { glPointSize(1.5); glBegin(GL_POINTS); { for (i=0; i<win_width; i++){ for (j=0; j<win_height; j++) { x = rL + i*rstep; y = iB + j*istep; k = kernel(x, y, Prl, Pim, Mx); pcl = k % 10; /* add to diplay list */ if (pcl < 1) glColor3f(0.2, 0.1, 0.3); else if (1<=pcl && pcl<2) glColor3f(0.4, 0.2, 0.6); else if (2<=pcl && pcl<3) glColor3f(0.3, 0.4, 0.5); else if (3<=pcl && pcl<4) glColor3f(0.5, 0.6, 0.4); else if (4<=pcl && pcl<5) glColor3f(0.6, 0.7, 0.4); else if (5<=pcl && pcl<6) glColor3f(0.9, 0.9, 0.9); else if (6<=pcl && pcl<7) glColor3f(0.5, 0.6, 0.3); else if (7<=pcl && pcl<8) glColor3f(0.7, 0.7, 0.5); else if (8<=pcl && pcl<9) glColor3f(0.6, 0.5, 0.7); else if (9<=pcl && pcl<10) glColor3f(0.9, 0.4,0.4); else glColor3f(0.1, 0.0, 0.1); glVertex2f(x, y); } } } glEnd(); } glEndList(); } void display() { glClear(GL_COLOR_BUFFER_BIT); glCallList(index); glFlush(); } void reshape(int w, int h) 6 { glViewport(0,0,w,h); glMatrixMode( GL_MODELVIEW ); glLoadIdentity(); gluOrtho2D( rL, rR, iB, iT); } void init() { glClearColor(0.0, 0.0, 0.0, 1.0); glColor3f(1.0, 1.0, 1.0); } int main( int argc, char** argv ) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB); glutInitWindowSize(win_width, win_height); glutInitWindowPosition(100, 100); glutCreateWindow("Mandelbrot"); createList(); init(); glutDisplayFunc(display); glutReshapeFunc(reshape); glutMainLoop(); return 0; } 7 ■色々な 2 次元図形 (ジュリア集合) 前の例と同じく f (z) = z + c による力学系の軌道を考えて,ジュリア集 合 Jc = {z|z0 = z, zn+1 = f (zn ), zn 有界 } の図を描く.プログラムでは c = p + iq に対し p =Prl, q =Pim, z = x + iy (α ≤ x ≤ β, γ ≤ y ≤ δ) に対し α =rL, β =rR, γ =iB, δ =iT とおいている. ジュリア集合の図はマンデルブロートの図と異なり,z, c に非常に敏感で,面白い図が得られる z, c は実際 に試してみなければならない.図は |zn | > 2 となったときの n により点 z に色付けをしており,このプログ ラムでは 10 段階に色付けをしている. #include <GL/glut.h> #define win_width 500 #define win_height 500 static double rL=-1.5, rR=1.5, iB=-1.5, iT=1.5;// window area static int Mx = 500;// iteration limit static double Prl = -0.74543, Pim = 0.11301; //parameter //static double Prl =-0.195, Pim = 0.656; static GLuint index; struct compn { double rl; double im; }; /* evaluation of iteration */ int kernel(double s_rl, double s_im, double p_rl, double p_im, int Max) { struct compn z, z2, c; double absq; int itr=0; z.rl = s_rl; z.im = s_im; // start c.rl = p_rl; c.im = p_im; // parameter absq = z.rl*z.rl + z.im*z.im; while(absq < 4.0 && itr < Max) { z2.rl = z.rl * z.rl - z.im * z.im + c.rl; z2.im = 2.0 * z.rl * z.im + c.im; z = z2; absq = z.rl*z.rl + z.im*z.im; itr++; } return itr; } /* generating displaylist */ void createList() { int i, j, k;// iteration index double x, y;// window coordinate double rstep, istep;// iteration step // int pcl;// paint color 8 /* iteration step */ rstep = (rR-rL)/win_width; istep = (iT-iB)/win_height; /* generating displaylist */ index = glGenLists( 1 ); /* making displaylist */ glNewList( index, GL_COMPILE_AND_EXECUTE ); { glPointSize(1.5); glBegin(GL_POINTS); { for (i=0; i<win_width; i++){ for (j=0; j<win_height; j++) { x = rL + i*rstep; y = iB + j*istep; k = kernel(x, y, Prl, Pim, Mx); //pcl = k % 7; /* add to diplay list */ if (k <= Mx/10) glColor3f(0.2, 0.1, 0.3); else if (k <= Mx*2/10) glColor3f(0.4, 0.2, 0.6); else if (k <= Mx*3/10) glColor3f(0.3, 0.4, 0.5); else if (k <= Mx*4/10) glColor3f(0.5, 0.6, 0.4); else if (k <= Mx*5/10) glColor3f(0.6, 0.7, 0.4); else if (k <= Mx*6/10) glColor3f(0.9, 0.9, 0.9); else if (k <= Mx*7/10) glColor3f(0.5, 0.6, 0.3); else if (k <= Mx*8/10) glColor3f(0.7, 0.7, 0.5); else if (k <= Mx*9/10) glColor3f(0.6, 0.5, 0.7); else if (k <= Mx*9.9/10) glColor3f(0.9, 0.4,0.4); else glColor3f(0.1, 0.0, 0.1); glVertex2f(x, y); } } } glEnd(); } glEndList(); } void display() { glClear(GL_COLOR_BUFFER_BIT); glCallList(index); glFlush(); } void reshape(int w, int h) { glViewport(0,0,w,h); glMatrixMode( GL_MODELVIEW ); glLoadIdentity(); gluOrtho2D( rL, rR, iB, iT); } void init() 9 { glClearColor(0.0, 0.0, 0.0, 1.0); glColor3f(1.0, 1.0, 1.0); } int main( int argc, char** argv ) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB); glutInitWindowSize(win_width, win_height); glutInitWindowPosition(100, 100); glutCreateWindow("Julia"); createList(); init(); glutDisplayFunc(display); glutReshapeFunc(reshape); glutMainLoop(); return 0; } 10 ■コッホ曲線 複雑系の図形の代表的なコッホ曲線を描く.アルゴリズムは初歩的である. #include <GL/glut.h> #include <math.h> #define WIN_WIDTH 400 #define WIN_HEIGHT 600 void koch(int level, double sx, double sy, double ex, double ey) { double x0 = sx; double y0 = sy; double x1 = (ex+2*sx)/3; double y1 = (ey+2*sy)/3; double x3 = (2*ex+sx)/3; double y3 = (2*ey+sy)/3; double x2 = (x1+x3)/2-sqrt(3)*(y3-y1)/2; double y2 = (y1+y3)/2+sqrt(3)*(x3-x1)/2; double x4 = ex; double y4 = ey; if(level <= 0) { glBegin(GL_LINE_STRIP); glVertex2f(x0,y0); glVertex2f(x1,y1); glVertex2f(x2,y2); glVertex2f(x3,y3); glVertex2f(x4,y4); glEnd(); return; } koch(level-1, koch(level-1, koch(level-1, koch(level-1, x0, x1, x2, x3, y0, y1, y2, y3, x1, x2, x3, x4, y1); y2); y3); y4); } void display() { glClear(GL_COLOR_BUFFER_BIT); koch(0, 0.0, WIN_HEIGHT*5/7, WIN_WIDTH, WIN_HEIGHT*5/7); koch(1, 0.0, WIN_HEIGHT*4/7, WIN_WIDTH, WIN_HEIGHT*4/7); koch(2, 0.0, WIN_HEIGHT*3/7, WIN_WIDTH, WIN_HEIGHT*3/7); koch(3, 0.0, WIN_HEIGHT*2/7, WIN_WIDTH, WIN_HEIGHT*2/7); koch(6, 0.0, WIN_HEIGHT/7, WIN_WIDTH, WIN_HEIGHT/7); glFlush(); } void reshape(int w, int h) { glViewport(0, 0, w, h); } void init() 11 { glClearColor(0.0, 0.0, 0.0, 0.0); glColor3f(1.0, 1.0, 1.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluOrtho2D(0.0, WIN_WIDTH, 0.0, WIN_HEIGHT); } int main(int argc, char** argv) { glutInit(&argc, argv); glutInitWindowSize(WIN_WIDTH, WIN_HEIGHT); glutInitWindowPosition(100, 100); glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB); glutCreateWindow("Koch curve"); init(); glutDisplayFunc(display); glutReshapeFunc(reshape); glutMainLoop(); return 0; } 12 ■対話とアニメーション この例では,2 つの問題を同時に扱う.1 つはバッファーの違いを示す.図形を動 かす場合,毎回図を書き換えながら描画する方法とバッファを用意しておいて,1 つの図を表示している間に 裏で次の図を描き,裏の図が完成したときに現在表示している表の図と入れ替える方法がある.前者をシング ルバッファの方法,後者をダブルバッファの方法という.シングルバッファの方法は,次の描画の際に現在表 示しているバッファを消さなければならないので画面がちらつくことになるので,画像が変化している場合は ダブルバッファ方の優れているといえる.ただし,現在のハードウェアは非常に高速のためにシングルバッ ファとダブルバッファの違いが見れない.この例題ではバッファの定義方法を示す例とする. 画像は回転する正方形であるが,上で説明したようにハードウェアが高速のために歪んだ図になるために ポーズを入れている.標準では time.h には sleep というポーズ関数があるが,これは整数秒間隔のポーズ しか取れないので, sleepf() というポーズ関数を定義した.この関数の最小間隔は 0.01 秒である. シングルバッファの正方形の上で左ボタンを押すと回転運動がとまり,中ボタンを押すと回転運動が始まる. また, Q または q ボタンでプログラムは停止する. #include #include #include #include <stdio.h> <GL/glut.h> <math.h> <time.h> #define DEG2RAD 0.017453292 /* 1 radian/1 degree */ int singleb, doubleb; GLfloat theta = 0.0; void sleepf(float dt) { clock_t time1,time2,interval; interval=CLOCKS_PER_SEC*dt; time1=time2=clock(); while(time2-time1<interval) time2=clock(); return; } void displays() { glColor3f(0.0, 1.0, 1.0); glClear(GL_COLOR_BUFFER_BIT); glBegin(GL_POLYGON); glVertex2f(cos(theta*DEG2RAD),sin(theta*DEG2RAD)); glVertex2f(-sin(theta*DEG2RAD),cos(theta*DEG2RAD)); glVertex2f(-cos(theta*DEG2RAD),-sin(theta*DEG2RAD)); glVertex2f(sin(theta*DEG2RAD),-cos(theta*DEG2RAD)); glEnd(); glFlush(); } void displayd() { glColor3f(1.0, 1.0, 0.0); glClear(GL_COLOR_BUFFER_BIT); 13 glBegin(GL_POLYGON); glVertex2f(cos(theta*DEG2RAD),sin(theta*DEG2RAD)); glVertex2f(-sin(theta*DEG2RAD),cos(theta*DEG2RAD)); glVertex2f(-cos(theta*DEG2RAD),-sin(theta*DEG2RAD)); glVertex2f(sin(theta*DEG2RAD),-cos(theta*DEG2RAD)); glEnd(); glutSwapBuffers(); } void spinDisplay(void) { /* increment rotation angle */ theta += 2.0; if(theta >= 360.0) theta -= 360.0; /* draw single buffer window */ glutSetWindow(singleb); glutPostRedisplay(); /* draw double buffer window */ glutSetWindow(doubleb); glutPostRedisplay(); /* delay */ sleepf(0.1); } void mymouse(int btn, int state, int x, int y) { if(btn == GLUT_LEFT_BUTTON && state == GLUT_DOWN) glutIdleFunc(spinDisplay); if(btn == GLUT_MIDDLE_BUTTON && state == GLUT_DOWN) glutIdleFunc(0); } void myReshape(int w, int h) { glViewport(0,0,w,h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluOrtho2D(-2.0, 2.0, -2.0, 2.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } void mykey(int key, int x, int y) { if(key == ’Q’ || key == ’q’) exit(0); } void quit_menu(int id) { if(id == 1) exit(0); } void myinit() { 14 glClearColor(0.0, 0.0, 0.0, 0.0); //glColor3f(1.0, 1.0, 1.0); } int main(int argc, char **argv) { glutInit(&argc,argv); glutInitWindowSize(300,300); /* single buffer display */ glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB); singleb = glutCreateWindow("single buffered"); myinit(); glutDisplayFunc(displays); glutReshapeFunc(myReshape); glutIdleFunc(spinDisplay); glutMouseFunc(mymouse); glutKeyboardFunc(mykey); /* double buffer display */ glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGB); doubleb = glutCreateWindow("double buffered"); myinit(); glutDisplayFunc(displayd); glutReshapeFunc(myReshape); glutIdleFunc(spinDisplay); glutMouseFunc(mymouse); glutCreateMenu(quit_menu); glutAddMenuEntry("quit",1); glutAttachMenu(GLUT_RIGHT_BUTTON); /* event loop */ glutMainLoop(); } 15 ■3DCG,直投影 (平行投影) と透写投影 これから先の例で 3DCG を扱う.このプログラムはサーフェース モデルで立方体を定義し,直投影 (平行投影) と透写投影を扱う. 直投影図を得るには glOrtho を使う.透写投影図を得るには glFrustum または gluPerspective を使 う.それぞれパラメータの指定の仕方が異なるので,注意する. 陰線処理・陰面処理は Z バッファ法で行うが,その機能を有効にするために GL_DEPTH_* の宣言が必要で ある. #include <GL/glut.h> GLfloat vertices[][3] = {{-1.0, -1.0, 1.0,}, {-1.0, 1.0, 1.0}, {1.0, 1.0, 1.0}, {1.0, -1.0, 1.0}, {-1.0, -1.0, -1.0}, {-1.0, 1.0, -1.0}, {1.0, 1.0, -1.0}, {1.0, -1.0, -1.0}}; GLfloat colors[][3] = {{0.0, 0.0, 1.0}, {0.0, 1.0, 0.0}, {0.0, 1.0, 1.0}, {1.0, 0.0, 0.0}, {1.0, 0.0, 1.0}, {1.0, 1.0, 0.0}}; void polygon(int a, int b, int c, int d) { glColor3fv(colors[a]); glBegin(GL_POLYGON); glVertex3fv(vertices[a]); glVertex3fv(vertices[b]); glVertex3fv(vertices[c]); glVertex3fv(vertices[d]); glEnd(); } void cube() { polygon(0, polygon(2, polygon(3, polygon(1, polygon(4, polygon(5, } 3, 3, 0, 2, 5, 4, 2, 7, 4, 6, 6, 0, 1); 6); 7); 5); 7); 1); void display() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(4.0, 4.5, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0); //glutWireCube(0.5);/* for emergency test */ cube(); glutSwapBuffers(); } void reshape(int w, int h) { glMatrixMode(GL_PROJECTION); glLoadIdentity(); /* perspective projection (tosha-toei) 1: */ /*left, right, bottom, top, near, far */ 16 glFrustum(-1.0, 1.0, -1.0, 1.0, 2.0, 10.0); /* perspective projection (tosha-toei) 2: fov, aspect, near, far */ //gluPerspective(60.0, (double)w/(double)h, 1.0, 50.0); //perspective projection(tousha-touei) 2 /* parallel projection (heiko/choku-toei):*/ /* left, right, bottom, top, near, far */ //glOrtho(-4.0, 4.0, -4.0, 4.0, -10.0, 10.0); // parallelprojection(choku-touei) glViewport(0, 0, w, h); } void init() { glClearColor(0.0, 0.0, 0.0, 0.0); glColor3f(1.0, 1.0, 1.0); glEnable(GL_DEPTH_TEST);// z-buffer test } int main(int argc, char **argv) { /* initilization */ glutInit(&argc,argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); glutInitWindowSize(500, 500); glutInitWindowPosition(0, 0); glutCreateWindow("Cube"); init(); glutDisplayFunc(display); glutReshapeFunc(reshape); /* main loop */ glutMainLoop(); return 0; } 17 ■回転する立体図形 立方体の回転を扱う.この例では,行列やベクトルの計算及び回転に必要な行列を全て 自前で用意することにする. #include <GL/glut.h> #include <math.h> #include <time.h> GLfloat vertices[][3]={{-1.0,-1.0,1.0},{-1.0,1.0,1.0},{1.0,1.0,1.0}, {1.0,-1.0,1.0},{-1.0,-1.0,-1.0},{-1.0,1.0,-1.0}, {1.0,1.0,-1.0},{1.0,-1.0,-1.0}}; GLfloat colors[][3]={{1.0,0.0,0.0},{0.0,1.0,1.0},{1.0,1.0,0.0}, {0.0,1.0,0.0},{0.0,0.0,1.0},{1.0,0.0,1.0}}; int dpCube; // spin object float u[] = {0.0, 0.0, 1.0}; // rotation vector float theta = 3.141592653/360; // rotation angle float dtime = 0.1; // refresh interval/sec float rotMat[3][3]; // rotation matrix float tv[] = {2.0, 0.0, 0.0};// translation vector void mulMat(float a[][3], float b[][3], float c[][3], int msize){ int i, j, k; for(i=0; i<msize; i++){ for(j=0; j<msize; j++){ c[i][j] = 0; for(k=0; k<msize; k++) c[i][j] = c[i][j]+a[i][k]*b[k][j]; } } return; } void mulVec(float a[][3], float v[], float w[], int msize){ int i, k; for(i=0; i<msize; i++){ w[i] = 0; for(k=0; k<msize; k++) w[i] = w[i]+a[i][k]*v[k]; } return; } void tranMat(float u[][3], float v[][3], int msize){ int i,j; for(i=0; i<msize; i++) for(j=0; j<msize; j++) v[j][i]=u[i][j]; return; } void orthMat(float v[], float u[][3], int msize){ float l1=0.0, l2=0.0, inner=0.0; int i; 18 for(i=0; i<msize; i++) l1 = l1+v[i]*v[i]; l1=sqrt(l1); for(i=0; i<msize; i++) u[i][0] = v[i]/l1; if(u[1][0]==0 && u[2][0]==0){ u[0][1]=0; u[1][1]=1; u[2][1]=0; } else{ u[0][1]=1; u[1][1]=0; u[2][1]=0; } for(i=0; i<msize; i++) inner=inner+u[i][0]*u[i][1]; for(i=0; i<msize; i++) u[i][1] = u[i][1]-inner*u[i][0]; for(i=0; i<msize; i++) l2 = l2+u[i][1]*u[i][1]; l2=sqrt(l2); for(i=0; i<msize; i++) u[i][1] = u[i][1]/l2; u[0][2] = u[1][0]*u[2][1]-u[2][0]*u[1][1]; u[1][2] = u[2][0]*u[0][1]-u[0][0]*u[2][1]; u[2][2] = u[0][0]*u[1][1]-u[1][0]*u[0][1]; } void rotBase(float theta, float t[][3], int msize) { t[0][0]=1; t[0][1]=0; t[0][2]=0; t[1][0]=0; t[1][1]=cos(theta); t[1][2]=-sin(theta); t[2][0]=0; t[2][1]=sin(theta); t[2][2]=cos(theta); } void sleepf(float dt){ clock_t time1, time2, interval; interval = CLOCKS_PER_SEC*dt; time1=time2=clock(); while(time2-time1<interval) time2=clock(); return; } void tranvec(float u[], float tv[], float v[], int vsize) { int i; for(i=0;i<vsize;i++) v[i] = u[i]+tv[i]; } void polygon(int a, int b, int c, int d) { glColor3fv(colors[a]); glBegin(GL_POLYGON); glVertex3fv(vertices[a]); glVertex3fv(vertices[b]); glVertex3fv(vertices[c]); glVertex3fv(vertices[d]); glEnd(); } void cube() { polygon(0,3,2,1); 19 polygon(2,3,7,6); polygon(3,0,4,7); polygon(1,2,6,5); polygon(4,5,6,7); polygon(5,4,0,1); } void display() { glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(5.0, 5.0, 5.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0); //glutWireCube(1.5);/* for emergency test */ cube(); glutSwapBuffers(); } void spinDisplay(void){ int i,j; float o_tmp[3], n_tmp[3]; for(i=0; i<8; i++){ for(j=0;j<3;j++) o_tmp[j]=vertices[i][j]; mulVec(rotMat, o_tmp, n_tmp, 3); for(j=0;j<3;j++) vertices[i][j]=n_tmp[j]; } glutSetWindow(dpCube); glutPostRedisplay(); sleepf(dtime); return; } void reshape(int w, int h){ glMatrixMode(GL_PROJECTION); glLoadIdentity(); glFrustum(-1.0, 1.0, -1.0, 1.0, 2.0, 30.0); //gluPerspective(60.0, (double)w/(double)h, 1.0, 50.0); //glOrtho(-4.0, 4.0, -4.0, 4.0, -10.0, 10.0); glViewport(0, 0, w, h); } void init(){ glEnable(GL_DEPTH_TEST); glClearColor(0.0, 0.0, 0.0, 0.0); glColor3f(1.0, 1.0, 0.5); } int main(int argc, char **argv){ int i; float p[3][3], q[3][3], r[3][3], tmp[3][3]; /* setting rotation Matrix */ rotBase(theta, r, 3); 20 orthMat(u, p, 3); tranMat(p, q, 3); mulMat(p, r, tmp, 3); mulMat(tmp, q, rotMat, 3); /* translation of object */ for(i=0;i<8;i++) tranvec(vertices[i],tv,vertices[i],3); /* Graphic tool init */ glutInit(&argc,argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); glutInitWindowSize(500, 500); glutInitWindowPosition(0, 0); dpCube = glutCreateWindow("Cube"); init(); glutDisplayFunc(display); glutReshapeFunc(reshape); /* idling */ glutIdleFunc(spinDisplay); /* main loop */ glutMainLoop(); return 0; } 21 ■Transformation OpenGL では前の例で計算した平行移動,回転の行列はそれぞれパラメータを指定するだ けで得るとこができる. /* Program showing an effect of rotation and translation to a cube */ /* Comp on Oct 8, 2005 by Kimio Sugita */ #include <GL/glut.h> #include <math.h> #include <time.h> GLfloat vertices[][3] = {{-1.0,-1.0,1.0},{-1.0,1.0,1.0},{1.0,1.0,1.0}, {1.0,-1.0,1.0},{-1.0,-1.0,-1.0},{-1.0,1.0,-1.0},{1.0,1.0,-1.0}, {1.0,-1.0,-1.0}}; GLfloat colors[][3] = {{1.0,0.0,0.0},{0.0,1.0,1.0},{1.0,1.0,0.0}, {0.0,1.0,0.0},{0.0,0.0,1.0},{1.0,0.0,1.0}}; GLfloat theta1 = 0.0, theta2 = 0.0; void polygon(int a,int b,int c,int d) { glColor3fv(colors[a]); glBegin(GL_POLYGON); glVertex3fv(vertices[a]); glVertex3fv(vertices[b]); glVertex3fv(vertices[c]); glVertex3fv(vertices[d]); glEnd(); } void cube() { polygon(0,3,2,1); polygon(2,3,7,6); polygon(3,0,4,7); polygon(1,2,6,5); polygon(4,5,6,7); polygon(5,4,0,1); } void sleepf(float intv) { clock_t time1,time2,interval; interval = CLOCKS_PER_SEC*intv; time1 = time2 = clock(); while(time2-time1<interval) time2 = clock(); return; } void myDisplay() { glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(5.0,5.0,5.0,0.0,0.0,0.0,0.0,1.0,0.0); glTranslatef(3.0*cos(theta2),0.0,3.0*sin(theta2)); 22 glRotatef(theta1,0.0,1.0,0.0); //glutWireCube(1.5); cube(); glFlush(); glutSwapBuffers(); } void myIdle() { theta1 += 1.0; if(theta1>360.0) theta1 -= 360.0; theta2 += 3.1415926535/720.0; if(theta2>2*3.1415926535) theta2 = 0.0; glutPostRedisplay(); sleepf(0.01); } void myReshape(int w,int h) { glViewport(0,0,w,h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); //glOrtho(-10.0,10.0,-10.0,10.0,-20.0,20.0); //glFrustum(-1.0,1.0,-1.0,1.0,2.0,30.0); gluPerspective(60.0, (double)w/(double)h,1.0,50.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } void myInit() { glEnable(GL_DEPTH_TEST); glClearColor(0.0,0.0,0.0,0.0); glColor3f(1.0,1.0,1.0); } int main(int argc, char** argv) { glutInit(&argc,argv); glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGB|GLUT_DEPTH); glutInitWindowSize(500,500); glutInitWindowPosition(0,0); glutCreateWindow("cube"); myInit(); glutDisplayFunc(myDisplay); glutReshapeFunc(myReshape); glutIdleFunc(myIdle); glutMainLoop(); return 0; } 23 ■色々な立体図形と光線 これから先の例では 3DCG の光線処理の内 shade を扱う.光線処理が機能するた めに GL_LIGHT* の宣言が必要である. glut の球,トーラス,ティーポットと幾つかの立体を用意してあるので,試してみよう. #include <GL/glut.h> #include <math.h> GLUquadricObj *mySphere;//2 GLfloat GLfloat GLfloat GLfloat position0[] = {4.0, 4.0, 4.0, 0.0};/* {dx, dy, dz, 1.0}*/ //3 ambient0[] = {0.2, 0.2, 0.2, 1.0};/* {R, G, B, 1.0} */ //4 diffuse0[] = {1.0, 1.0, 1.0, 1.0};/* {R, G, B, 1.0} */ //4 specular0[] = {1.0, 1.0, 1.0, 1.0};/* {R, G, B, 1.0} */ //4 void display(){ glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(8.0, 8.0, 8.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0); //glutWireCube(1.0); //glutWireSphere(1.0, 12, 12);//1 //gluSphere(mySphere, 2.0, 24, 24);//2 glutSolidTorus(1.0, 2.0, 24, 24);//5 //glutSolidTeapot(2.0);//6 glutSwapBuffers(); } void init(){ glClearColor(0.0, 0.0, 0.0, 0.0); glColor3f(1.0, 1.0, 1.0); mySphere = gluNewQuadric();//2 gluQuadricDrawStyle(mySphere, GLU_FILL);//2->GLU_LINE, 3->GLU_FILL glEnable(GL_AUTO_NORMAL);//3 //gluQuadricNormals(mySphere,GLU_SMOOTH);//3 glShadeModel(GL_SMOOTH);//3 glEnable(GL_DEPTH_TEST);//2 glEnable(GL_LIGHTING);//3 glEnable(GL_LIGHT0);//3 glMatrixMode(GL_MODELVIEW);//3 glLoadIdentity();//3 glLightfv(GL_LIGHT0, GL_POSITION, position0);//3 glLightfv(GL_LIGHT0, GL_AMBIENT, ambient0);//4 glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse0);//4 glLightfv(GL_LIGHT0, GL_SPECULAR, specular0);//4 } void reshape(int w, int h) { glMatrixMode(GL_PROJECTION); glLoadIdentity(); glFrustum(-1.0, 1.0, -1.0, 1.0, 2.0, 100.0); //glOrtho(-4.0, 4.0, -4.0, 4.0, -4.0, 4.0); glViewport(0, 0, w, h); } int main(int argc, char **argv){ 24 glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGB|GLUT_DEPTH); glutInitWindowSize(500,500); glutInitWindowPosition(100,100); glutCreateWindow(" Sphere "); init(); glutDisplayFunc(display); glutReshapeFunc(reshape); glutMainLoop(); return 0; } 25 ■回転する光源 このプログラムでは光源が移動していく際の shade の変化を扱う.光源の位置は display() 中の lighting process で変化させている.OpenGL では shade を作るための光源の移動は,この例のよ うに glLightfv に translation の行列を並べるだけで簡単にできる. #include <GL/glut.h> #include <math.h> #include <time.h> int rot_light;// rot object GLUquadricObj *mySphere; GLfloat position0[] = {3.0, 2.0, 1.0, 1.0};// light position GLfloat ambient0[] = {0.1, 0.1, 0.1, 0.5};// ambient light GLfloat specular0[] = {1.0, 0.0, 0.0, 1.0};// specular light GLfloat theta = 0.0; void sleepf(float intt){ clock_t time1, time2, interval; interval = CLOCKS_PER_SEC*intt; time1 = time2 = clock(); while(time2-time1<interval) time2 = clock(); return; } void idle(){ theta += 3.0; if(theta>360.0) theta -=360.0; glutSetWindow(rot_light); glutPostRedisplay(); sleepf(0.2); return; } void display(){ glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0); /* lighting process */ glPushMatrix(); glRotatef(theta, 1.0, 0.0, 1.0); glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE); glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambient0); glLightfv(GL_LIGHT0, GL_POSITION, position0); glLightfv(GL_LIGHT0, GL_SPECULAR, specular0); //glLightfv(GL_LIGHT0, GL_AMBIENT, ambient0); glPopMatrix(); /* choose your object from following list */ //glutWireCube(1.0); 26 //glutWireSphere(1.0, 12, 12); //gluSphere(mySphere, 2.0, 24, 24); //glutSolidTorus(1.0, 2.0, 24, 24); glutSolidTeapot(2.0); /* list end */ glutSwapBuffers(); } void init(){ glClearColor(0.0, 0.0, 0.0, 0.0); glColor3f(1.0, 1.0, 1.0); mySphere = gluNewQuadric(); gluQuadricDrawStyle(mySphere, GLU_FILL); glEnable(GL_AUTO_NORMAL); glShadeModel(GL_SMOOTH); glEnable(GL_DEPTH_TEST); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); } void reshape(int w, int h){ glViewport(0, 0, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(-5.0, 5.0, -5.0, 5.0, -6.0, 6.0); } int main(int argc, char **argv){ glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGB|GLUT_DEPTH); glutInitWindowSize(500,500); glutInitWindowPosition(100,100); rot_light = glutCreateWindow(" Sphere "); init(); glutDisplayFunc(display); glutReshapeFunc(reshape); glutIdleFunc(idle); glutMainLoop(); return 0; } 27 ■物質光線 3dCG を完成させるには,陰線・陰面処理,と shade 処理だけでは粘土作りの物体が現れるだけ で,物質感が得られない.物質感はフォンモデルを使う. #include <GL/glut.h> #include <math.h> #include <time.h> GLUquadricObj *mySphere; GLfloat position0[] = {10.0, 10.0, 10.0, 0.0};// light position typedef struct materialStruct{ GLfloat ambient[4]; GLfloat diffuse[4]; GLfloat specular[4]; GLfloat shininess[1]; } materialStruct; struct materialStruct brassMaterials = { {0.33, 0.22, 0.03, 1.0}, {0.78, 0.57, 0.11, 1.0}, {0.99, 0.91, 0.81, 1.0}, {27.8} }; struct materialStruct redPlasticMaterials = { {0.3, 0.0, 0.0, 1.0}, {0.6, 0.0, 0.0, 1.0}, {0.8, 0.6, 0.6, 1.0}, {32.0} }; struct materialStruct whiteShineyMaterials = { {1.0, 1.0, 1.0, 1.0}, {1.0, 1.0, 1.0, 1.0}, {1.0, 1.0, 1.0, 1.0}, {100.0} }; void material(struct materialStruct matlist){ glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, matlist.ambient); glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, matlist.diffuse); glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, matlist.specular); glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, matlist.shininess); } void display(){ glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0); material(whiteShineyMaterials); gluSphere(mySphere, 1.5, 24, 24); //glutSolidTorus(1.0, 2.0, 24, 24); //glutSolidTeapot(2.0); glPushMatrix(); 28 glTranslatef(-6.0, 0.0, 0.0); material(redPlasticMaterials); //gluSphere(mySphere, 1.5, 24, 24); glutSolidTorus(0.6, 1.2, 24, 24); //glutSolidTeapot(2.0); glPopMatrix(); glPushMatrix(); glTranslatef(6.0, 0.0, 0.0); material(brassMaterials); gluSphere(mySphere, 1.5, 24, 24); //glutSoliTorus(1.0, 2.0, 24, 24); //glutSolidTeapot(1.5); glPopMatrix(); glutSwapBuffers(); } void init(){ glClearColor(0.0, 0.0, 0.0, 0.0); glColor3f(1.0, 1.0, 1.0); mySphere = gluNewQuadric(); gluQuadricDrawStyle(mySphere, GLU_FILL); glEnable(GL_AUTO_NORMAL); glShadeModel(GL_SMOOTH); glEnable(GL_DEPTH_TEST); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE); glLightfv(GL_LIGHT0, GL_POSITION, position0); } void reshape(int w, int h){ glViewport(0, 0, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(-10.0, 10.0, -5.0, 5.0, -6.0, 6.0); } int main(int argc, char **argv){ glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGB|GLUT_DEPTH); glutInitWindowSize(900,450); glutInitWindowPosition(100,100); glutCreateWindow(" Material lights "); init(); glutDisplayFunc(display); glutReshapeFunc(reshape); glutMainLoop(); return 0; } 29 ■回転物体と shade の変化 このプログラムで立方体の回転と shade の変化を扱う.shade 処理ができるた めには,サーフェースモデルで定義した面の法線が定義されてなければならない.glNormal3fv で定義して いる. /* Program showing a moving cube with shade */ /* Comp on Oct 8, 2005 by Kimio Sugita */ #include <GL/glut.h> #include <math.h> #include <time.h> GLfloat vertices[][3] = {{-1.0,-1.0,1.0},{-1.0,1.0,1.0},{1.0,1.0,1.0}, {1.0,-1.0,1.0},{-1.0,-1.0,-1.0},{-1.0,1.0,-1.0}, {1.0,1.0,-1.0},{1.0,-1.0,-1.0}}; GLfloat normal[][3] ={{1.0,0.0,0.0,},{-1.0,0.0,0.0},{0.0,1.0,0.0}, {0.0,-1.0,0.0},{0.0,0.0,1.0},{0.0,0.0,-1.0}}; GLfloat colors[][3] = {{1.0,0.0,0.0},{0.0,1.0,1.0},{1.0,1.0,0.0}, {0.0,1.0,0.0},{0.0,0.0,1.0},{1.0,0.0,1.0}}; GLfloat GLfloat GLfloat GLfloat position0[] = {5.0,0.0,5.0,1.0}; ambient0[] = {0.5,0.5,0.5,1.0}; diffuse0[] = {1.0,1.0,1.0,1.0}; mat_diffuse[] = {0.78,0.57,0.11,1.0}; GLfloat theta1 = 0.0, theta2 = 0.0; void polygon(int a,int b,int c,int d) { glBegin(GL_POLYGON); glVertex3fv(vertices[a]); glVertex3fv(vertices[b]); glVertex3fv(vertices[c]); glVertex3fv(vertices[d]); glEnd(); } void cube() { glNormal3fv(normal[4]); polygon(0,3,2,1); glNormal3fv(normal[0]); polygon(2,3,7,6); glNormal3fv(normal[3]); polygon(3,0,4,7); glNormal3fv(normal[2]); polygon(1,2,6,5); glNormal3fv(normal[5]); polygon(4,5,6,7); glNormal3fv(normal[1]); polygon(5,4,0,1); glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,mat_diffuse); } void sleepf(float intv) { clock_t time1,time2,interval; 30 interval = CLOCKS_PER_SEC*intv; time1 = time2 = clock(); while(time2-time1<interval) time2 = clock(); return; } void myDisplay() { glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(5.0,5.0,5.0,0.0,0.0,0.0,0.0,1.0,0.0); glTranslatef(0.0,2.0*cos(theta2),2.0*sin(theta2)); glRotatef(theta1,0.0,1.0,0.0); //glutWireCube(1.5); cube(); glFlush(); glutSwapBuffers(); } void myIdle() { theta1 += 1.0; if(theta1>360.0) theta1 -= 360.0; theta2 += 3.1415926535/720.0; if(theta2>2*3.1415926535) theta2 = 0.0; glutPostRedisplay(); sleepf(0.01); } void myReshape(int w,int h) { glViewport(0,0,w,h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); //glOrtho(-10.0,10.0,-10.0,10.0,-20.0,20.0); //glFrustum(-1.0,1.0,-1.0,1.0,2.0,30.0); gluPerspective(60.0, (double)w/(double)h,1.0,50.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } void myInit() { glEnable(GL_DEPTH_TEST); glClearColor(0.0,0.0,0.0,0.0); glColor3f(1.0,1.0,1.0); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glShadeModel(GL_FLAT); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glLightfv(GL_LIGHT0,GL_POSITION,position0); glLightfv(GL_LIGHT0,GL_AMBIENT,ambient0); glLightfv(GL_LIGHT0,GL_DIFFUSE,diffuse0); } 31 int main(int argc, char** argv) { glutInit(&argc,argv); glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGB|GLUT_DEPTH); glutInitWindowSize(500,500); glutInitWindowPosition(0,0); glutCreateWindow("cube"); myInit(); glutDisplayFunc(myDisplay); glutReshapeFunc(myReshape); glutIdleFunc(myIdle); glutMainLoop(); return 0; } 32 ■直投影 (斜交投影) このプログラムで直投影の内で,斜交投影を扱う. #include <GL/glut.h> #include <math.h> GLfloat vertices[][3] = {{0.0,0.0,2.0},{0.0,2.0,2.0},{2.0,2.0,2.0}, {2.0,0.0,2.0},{0.0,0.0,0.0},{0.0,2.0,0.0},{2.0,2.0,0.0}, {2.0,0.0,0.0}}; GLfloat colors[][3] = {{1.0,0.0,0.0},{0.0,1.0,1.0},{1.0,1.0,0.0}, {0.0,1.0,0.0},{0.0,0.0,1.0},{1.0,0.0,1.0}}; GLfloat theta1 = 0.0, theta2 = 0.0; void polygon(int a,int b,int c,int d) { glColor3fv(colors[a]); glBegin(GL_POLYGON); glVertex3fv(vertices[a]); glVertex3fv(vertices[b]); glVertex3fv(vertices[c]); glVertex3fv(vertices[d]); glEnd(); } void cube() { polygon(0,3,2,1); polygon(2,3,7,6); polygon(3,0,4,7); polygon(1,2,6,5); polygon(4,5,6,7); polygon(5,4,0,1); } void axises() { glColor3f(1.0,1.0,1.0); glPointSize(3.0); glBegin(GL_LINES); glVertex3f(-4.0,0.0,0.0); glVertex3f(4.0,0.0,0.0); glVertex3f(0.0,-4.0,0.0); glVertex3f(0.0,4.0,0.0); glVertex3f(0.0,0.0,-5.0); glVertex3f(0.0,0.0,5.0); glEnd(); } void myDisplay() { glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(0.0,0.0,8.0,0.0,0.0,0.0,0.0,1.0,0.0); cube(); axises(); glFlush(); 33 glutSwapBuffers(); } void myReshape(int w,int h) { int i; GLfloat oblique[16]; for(i=0;i<16;i++) oblique[i]=0.0; oblique[0]=oblique[5]=oblique[10]=oblique[15]=1.0; oblique[8]=-0.5;oblique[9]=-0.5; glViewport(0,0,w,h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(-1.0,10.0,-1.0,10.0,-20.0,20.0); glMultMatrixf(oblique); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } void myInit() { glEnable(GL_DEPTH_TEST); glClearColor(0.0,0.0,0.0,0.0); glColor3f(1.0,1.0,1.0); } int main(int argc, char **argv) { glutInit(&argc,argv); glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGB|GLUT_DEPTH); glutInitWindowSize(500,500); glutInitWindowPosition(0,0); glutCreateWindow("oblique projection"); myInit(); glutDisplayFunc(myDisplay); glutReshapeFunc(myReshape); glutMainLoop(); return 0; } 34 ■Shadow と shade(平行光源) これから先の例で shadow の処理を扱う.このプログラムでは平行線による 平面への shadow を扱う.OpenGL で shadow は自前で計算しなければならない.shadow の計算は,理論編 で扱っている.shadow() の前半部分で shadow 投影の行列を計算している. /* Program showig a moving cube and following shadow */ /* Com p on Oct 10, 2005 by Kimio Sugita */ #include <GL/glut.h> #include <math.h> #include <time.h> /* object */ GLfloat vertices[][3] = {{-1.0,-1.0,1.0},{-1.0,1.0,1.0},{1.0,1.0,1.0}, {1.0,-1.0,1.0},{-1.0,-1.0,-1.0},{-1.0,1.0,-1.0}, {1.0,1.0,-1.0},{1.0,-1.0,-1.0}}; GLfloat normal[][3] ={{1.0,0.0,0.0},{-1.0,0.0,0.0},{0.0,1.0,0.0}, {0.0,-1.0,0.0},{0.0,0.0,1.0},{0.0,0.0,-1.0}}; /* shadow object */ GLfloat pn[4] = {0.0,1.0,0.0,2.0}; /* plane equation pn[0]x+pn[1]y+pn[2]z+pn[3] */ GLfloat ambient0[] = {1.0,1.0,1.0,1.0}; GLfloat diffuse0[] = {1.0,1.0,1.0,1.0}; GLfloat mat_diffuse[] = {0.78,0.57,0.11,1.0}; GLfloat lt[] = {5.0,5.0,1.0,1.0}; /* light position (lt[0],lt[1],lt[2]) */ GLfloat theta1 = 0.0, theta2 = 0.0; void polygon(int a,int b,int c,int d) { glBegin(GL_POLYGON); glVertex3fv(vertices[a]); glVertex3fv(vertices[b]); glVertex3fv(vertices[c]); glVertex3fv(vertices[d]); glEnd(); } void cube() { glNormal3fv(normal[4]); polygon(0,3,2,1); glNormal3fv(normal[0]); polygon(2,3,7,6); glNormal3fv(normal[3]); polygon(3,0,4,7); glNormal3fv(normal[2]); polygon(1,2,6,5); glNormal3fv(normal[5]); polygon(4,5,6,7); glNormal3fv(normal[1]); polygon(5,4,0,1); } void sleepf(float intv) 35 { clock_t time1,time2,interval; interval = CLOCKS_PER_SEC*intv; time1 = time2 = clock(); while(time2-time1<interval) time2 = clock(); return; } void shadow() { /* shadow projection matrix */ int i; GLfloat shadowm[16]; for(i=0;i<16;i++) shadowm[i] = 0.0; shadowm[0] = shadowm[10] = shadowm[15] = 1.0; shadowm[4] = -lt[0]/lt[1]; shadowm[6] = -lt[2]/lt[1]; shadowm[12] = -pn[3]*lt[0]/lt[1]; shadowm[13] = -pn[3]; shadowm[14] = -pn[3]*lt[2]/lt[1]; glPushMatrix(); glPushAttrib(GL_CURRENT_BIT); glDisable(GL_LIGHT0); glMultMatrixf(shadowm); /* defining shadow object */ glTranslatef(0.0,cos(theta2),sin(theta2)); glRotatef(theta1,0.0,1.0,0.0); glColor3f(0.0,0.0,0.0); cube(); glPopAttrib(); glPopMatrix(); } void object() { glEnable(GL_LIGHT0); glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,mat_diffuse); glPushMatrix(); glPushAttrib(GL_CURRENT_BIT); glTranslatef(0.0,cos(theta2),sin(theta2)); glRotatef(theta1,0.0,1.0,0.0); cube(); glPopAttrib(); glPopMatrix(); } void myDisplay() { glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(5.0,5.0,5.0,0.0,0.0,0.0,0.0,1.0,0.0); object(); shadow(); glFlush(); glutSwapBuffers(); 36 } void myIdle() { theta1 += 1.0; /* for rotation use degree */ if(theta1>360.0) theta1 -= 360.0; theta2 += 3.1415926535/720.0; /* for translation use radian */ if(theta2>2*3.1415926535) theta2 = 0.0; glutPostRedisplay(); sleepf(0.02); } void myReshape(int w,int h) { glViewport(0,0,w,h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(-5.0,5.0,-5.0,5.0,-20.0,20.0); //glFrustum(-1.0,1.0,-1.0,1.0,2.0,30.0); //gluPerspective(60.0, (double)w/(double)h,1.0,50.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } void myInit() { glEnable(GL_DEPTH_TEST); glClearColor(0.7,0.7,0.7,1.0); glEnable(GL_LIGHTING); glShadeModel(GL_FLAT); glLightfv(GL_LIGHT0,GL_POSITION,lt); glLightfv(GL_LIGHT0,GL_AMBIENT,ambient0); glLightfv(GL_LIGHT0,GL_DIFFUSE,diffuse0); } int main(int argc, char** argv) { glutInit(&argc,argv); glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGB|GLUT_DEPTH); glutInitWindowSize(500,500); glutInitWindowPosition(0,0); glutCreateWindow("cube"); myInit(); glutDisplayFunc(myDisplay); glutReshapeFunc(myReshape); glutIdleFunc(myIdle); glutMainLoop(); return 0; } 37 ■Shadow と shade(点光源) このプログラムでは点光源による shadow を扱う.shadow() の前半で shadow 投影の行列を計算している. /* Program showig a moving cube and following shadow */ /* Com p on Oct 10, 2005 by Kimio Sugita */ #include <GL/glut.h> #include <math.h> #include <time.h> /* object */ GLfloat vertices[][3] = {{-1.0,-1.0,1.0},{-1.0,1.0,1.0},{1.0,1.0,1.0}, {1.0,-1.0,1.0},{-1.0,-1.0,-1.0},{-1.0,1.0,-1.0}, {1.0,1.0,-1.0},{1.0,-1.0,-1.0}}; GLfloat normal[][3] ={{1.0,0.0,0.0},{-1.0,0.0,0.0},{0.0,1.0,0.0}, {0.0,-1.0,0.0},{0.0,0.0,1.0},{0.0,0.0,-1.0}}; /* shadow object */ GLfloat pn[4] = {0.0,1.0,0.0,2.0}; /* plane equation pn[0]x+pn[1]y+pn[2]z+pn[3] */ GLfloat ambient0[] = {1.0,1.0,1.0,1.0}; GLfloat diffuse0[] = {1.0,1.0,1.0,1.0}; GLfloat mat_diffuse[] = {1.0,0.1,0,1,1.0}; GLfloat lt[] = {15.0,15.0,15.0,1.0}; /* light position (lt[0],lt[1],lt[2]) */ GLfloat theta1 = 0.0, theta2 = 0.0; void polygon(int a,int b,int c,int d) { glBegin(GL_POLYGON); glVertex3fv(vertices[a]); glVertex3fv(vertices[b]); glVertex3fv(vertices[c]); glVertex3fv(vertices[d]); glEnd(); } void cube() { glNormal3fv(normal[4]); polygon(0,3,2,1); glNormal3fv(normal[0]); polygon(2,3,7,6); glNormal3fv(normal[3]); polygon(3,0,4,7); glNormal3fv(normal[2]); polygon(1,2,6,5); glNormal3fv(normal[5]); polygon(4,5,6,7); glNormal3fv(normal[1]); polygon(5,4,0,1); } void sleepf(float intv) { 38 clock_t time1,time2,interval; interval = CLOCKS_PER_SEC*intv; time1 = time2 = clock(); while(time2-time1<interval) time2 = clock(); return; } void shadow() { /* shadow projection matrix */ int i; GLfloat shadowm[16]; for(i=0;i<16;i++) shadowm[i] = 0.0; shadowm[0] = shadowm[5] = shadowm[10] = 1.0; shadowm[7] = -1.0/(lt[1]+pn[3]); glPushMatrix(); glPushAttrib(GL_CURRENT_BIT); glDisable(GL_LIGHT0); glTranslatef(lt[0],lt[1],lt[2]); glMultMatrixf(shadowm); glTranslatef(-lt[0],-lt[1],-lt[2]); /* defining shadow object */ glTranslatef(0.0,cos(theta2),sin(theta2)); glRotatef(theta1,0.0,1.0,0.0); glColor3f(0.0,0.0,0.0); cube(); glPopAttrib(); glPopMatrix(); } void object() { glEnable(GL_LIGHT0); glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,mat_diffuse); glPushMatrix(); glPushAttrib(GL_CURRENT_BIT); glTranslatef(0.0,cos(theta2),sin(theta2)); glRotatef(theta1,0.0,1.0,0.0); cube(); glPopAttrib(); glPopMatrix(); } void myDisplay() { glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(5.0,4.0,5.0,0.0,0.0,0.0,0.0,1.0,0.0); object(); shadow(); glFlush(); glutSwapBuffers(); } 39 void myIdle() { theta1 += 1.0; /* for rotation use degree */ if(theta1>360.0) theta1 -= 360.0; theta2 += 3.1415926535/720.0; /* for translation use radian */ if(theta2>2*3.1415926535) theta2 = 0.0; glutPostRedisplay(); sleepf(0.05); } void myReshape(int w,int h) { glViewport(0,0,w,h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(-5.0,5.0,-5.0,5.0,-20.0,20.0); //glFrustum(-1.0,1.0,-1.0,1.0,2.0,30.0); //gluPerspective(60.0, (double)w/(double)h,1.0,50.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } void myInit() { glEnable(GL_DEPTH_TEST); glClearColor(0.7,0.7,0.7,1.0); glEnable(GL_LIGHTING); glShadeModel(GL_FLAT); glLightfv(GL_LIGHT0,GL_POSITION,lt); glLightfv(GL_LIGHT0,GL_AMBIENT,ambient0); glLightfv(GL_LIGHT0,GL_DIFFUSE,diffuse0); } int main(int argc, char** argv) { glutInit(&argc,argv); glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGB|GLUT_DEPTH); glutInitWindowSize(500,500); glutInitWindowPosition(0,0); glutCreateWindow("cube"); myInit(); glutDisplayFunc(myDisplay); glutReshapeFunc(myReshape); glutIdleFunc(myIdle); glutMainLoop(); return 0; } 40 ■移動する光源 このプログラムでは,点光源が移動する際の shadow を扱う.OpnGL では shadow 用の光 源の位置は自前で計算する必要がある. /* Program showig a moving light and following shadow */ /* Com p on Oct 10, 2005 by Kimio Sugita */ #include <GL/glut.h> #include <math.h> #include <time.h> /* object */ GLfloat vertices[][3] = {{-1.0,-1.0,1.0},{-1.0,1.0,1.0},{1.0,1.0,1.0}, {1.0,-1.0,1.0},{-1.0,-1.0,-1.0},{-1.0,1.0,-1.0}, {1.0,1.0,-1.0},{1.0,-1.0,-1.0}}; GLfloat normal[][3] ={{1.0,0.0,0.0},{-1.0,0.0,0.0},{0.0,1.0,0.0}, {0.0,-1.0,0.0},{0.0,0.0,1.0},{0.0,0.0,-1.0}}; /* shadow plane */ GLfloat pn[] = {0.0,1.0,0.0,1.0}; /* plane equation pn[0]x+pn[1]y+pn[2]z+pn[3]=0 /* light source */ GLfloat ambient0[] = {1.0,1.0,1.0,1.0}; GLfloat diffuse0[] = {1.0,1.0,1.0,1.0}; GLfloat mat_diffuse[] = {0.8,0.7,0,0.1,1.0}; GLfloat lt[] = {10.0,10.0,0.0,1.0}; /* light position (lt[0],lt[1],lt[2],lt[3]) */ /* idle parameter */ GLfloat theta1 = 0.0, slide = -15.0; void polygon(int a,int b,int c,int d) { glBegin(GL_POLYGON); glVertex3fv(vertices[a]); glVertex3fv(vertices[b]); glVertex3fv(vertices[c]); glVertex3fv(vertices[d]); glEnd(); } void cube() { glNormal3fv(normal[4]); polygon(0,3,2,1); glNormal3fv(normal[0]); polygon(2,3,7,6); glNormal3fv(normal[3]); polygon(3,0,4,7); glNormal3fv(normal[2]); polygon(1,2,6,5); glNormal3fv(normal[5]); polygon(4,5,6,7); glNormal3fv(normal[1]); polygon(5,4,0,1); } 41 */ /* timer */ void sleepf(float intv) { clock_t time1,time2,interval; interval = CLOCKS_PER_SEC*intv; time1 = time2 = clock(); while(time2-time1<interval) time2 = clock(); return; } void shadow() { /* shadow projection matrix */ int i; GLfloat shadowm[16]; for(i=0;i<16;i++) shadowm[i] = 0.0; shadowm[0] = shadowm[5] = shadowm[10] = 1.0; shadowm[7] = -1.0/(lt[1]+pn[3]); glPushMatrix(); glPushAttrib(GL_CURRENT_BIT); glDisable(GL_LIGHT0); glTranslatef(0.0,0.0,slide); //glRotatef(theta1,0.0,1.0,0.0); /* Shadow projection by light source */ glTranslatef(lt[0],lt[1],lt[2]); glMultMatrixf(shadowm); glTranslatef(-lt[0],-lt[1],-lt[2]); /* defining shadow object */ //glRotatef(-theta1,0.0,1.0,0.0); glTranslatef(0.0,0.0,-slide); glColor3f(0.0,0.0,0.0); cube(); glPopAttrib(); glPopMatrix(); } void object() { glEnable(GL_LIGHT0); glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,mat_diffuse); glPushMatrix(); //glRotatef(theta1,0.0,1.0,0.0); glTranslatef(0.0,0.0,slide); glLightfv(GL_LIGHT0,GL_POSITION,lt); glPopMatrix(); cube(); } void myDisplay() { glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(3.0,4.0,5.0,0.0,0.0,0.0,0.0,1.0,0.0); 42 object(); shadow(); glFlush(); glutSwapBuffers(); } void myIdle() { theta1 += 1.0; /* for rotation use degree */ if(theta1>360.0) theta1 -= 360.0; slide += 0.1; if(slide>15.0){ sleepf(3.0); slide = -15.0; }; glutPostRedisplay(); sleepf(0.05); } void myReshape(int w,int h) { glViewport(0,0,w,h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(-8.0,8.0,-8.0,8.0,-20.0,20.0); //glFrustum(-1.0,1.0,-1.0,1.0,2.0,30.0); //gluPerspective(60.0, (double)w/(double)h,1.0,50.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } void myInit() { glEnable(GL_DEPTH_TEST); glClearColor(0.7,0.7,0.7,1.0); glEnable(GL_LIGHTING); glShadeModel(GL_FLAT); glLightfv(GL_LIGHT0,GL_POSITION,lt); glLightfv(GL_LIGHT0,GL_AMBIENT,ambient0); glLightfv(GL_LIGHT0,GL_DIFFUSE,diffuse0); } int main(int argc, char** argv) { glutInit(&argc,argv); glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGB|GLUT_DEPTH); glutInitWindowSize(500,500); glutInitWindowPosition(0,0); glutCreateWindow("shadow"); myInit(); glutDisplayFunc(myDisplay); glutReshapeFunc(myReshape); glutIdleFunc(myIdle); glutMainLoop(); return 0; } 43