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) {
/* 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; }
■関数のグラフ(リスト) 初めの例と同じグラフであるが,描画オブジェクトのリストを作成してから描画す る.リストを使う利点は,図形を移動やウィンドウの重なり合いの変化などによる再描画をするときに,計算 しなおす必要がないために描画速度が速くなる.ただし,この例くらいでは特に利点とは云えない. #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; }
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; }
■色々な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 */
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(); }
{
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; }
■色々な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
/* 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); }
{
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; }
■コッホ曲線 複雑系の図形の代表的なコッホ曲線を描く.アルゴリズムは初歩的である. #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, x0, y0, x1, y1); koch(level-1, x1, y1, x2, y2); koch(level-1, x2, y2, x3, y3); koch(level-1, x3, y3, x4, 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); }
{
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; }
■対話とアニメーション この例では,2つの問題を同時に扱う.1つはバッファーの違いを示す.図形を動 かす場合,毎回図を書き換えながら描画する方法とバッファを用意しておいて,1つの図を表示している間に 裏で次の図を描き,裏の図が完成したときに現在表示している表の図と入れ替える方法がある.前者をシング ルバッファの方法,後者をダブルバッファの方法という.シングルバッファの方法は,次の描画の際に現在表 示しているバッファを消さなければならないので画面がちらつくことになるので,画像が変化している場合は ダブルバッファ方の優れているといえる.ただし,現在のハードウェアは非常に高速のためにシングルバッ ファとダブルバッファの違いが見れない.この例題ではバッファの定義方法を示す例とする. 画像は回転する正方形であるが,上で説明したようにハードウェアが高速のために歪んだ図になるために ポーズを入れている.標準ではtime.hにはsleep というポーズ関数があるが,これは整数秒間隔のポーズ しか取れないので,sleepf()というポーズ関数を定義した.この関数の最小間隔は0.01秒である. シングルバッファの正方形の上で左ボタンを押すと回転運動がとまり,中ボタンを押すと回転運動が始まる. また,Qまたは qボタンでプログラムは停止する. #include <stdio.h> #include <GL/glut.h> #include <math.h> #include <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);
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() {
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(); }
■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, 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 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 */
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; }
■回転する立体図形 立方体の回転を扱う.この例では,行列やベクトルの計算及び回転に必要な行列を全て 自前で用意することにする. #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;
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);
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);
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; }
■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));
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; }
■色々な立体図形と光線 これから先の例では3DCGの光線処理の内 shadeを扱う.光線処理が機能するた めにGL_LIGHT*の宣言が必要である. glutの球,トーラス,ティーポットと幾つかの立体を用意してあるので,試してみよう. #include <GL/glut.h> #include <math.h> GLUquadricObj *mySphere;//2
GLfloat position0[] = {4.0, 4.0, 4.0, 0.0};/* {dx, dy, dz, 1.0}*/ //3 GLfloat ambient0[] = {0.2, 0.2, 0.2, 1.0};/* {R, G, B, 1.0} */ //4 GLfloat diffuse0[] = {1.0, 1.0, 1.0, 1.0};/* {R, G, B, 1.0} */ //4 GLfloat 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); }
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; }
■回転する光源 このプログラムでは光源が移動していく際の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);
//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; }
■物質光線 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();
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; }
■回転物体と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 position0[] = {5.0,0.0,5.0,1.0}; GLfloat ambient0[] = {0.5,0.5,0.5,1.0}; GLfloat diffuse0[] = {1.0,1.0,1.0,1.0}; GLfloat 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) {
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); }
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; }
■直投影(斜交投影) このプログラムで直投影の内で,斜交投影を扱う. #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();
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; }
■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); }
{
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();
}
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; }
■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) {
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(); }
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; }
■移動する光源 このプログラムでは,点光源が移動する際の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); }
/* 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);
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; }