#include <stdlib.h> #include <GL/glut.h> #include <math.h> #define STEPCYCLE 50 /* 手足のひと振りに要する時のフレーム数 */ #define WALKCYCLE 250 /* ロボットの移動に要するフレーム数 */ #define KICKSPEED 600 /* キックの速度に関するパラメータ */ #define M_PI 3.14 struct robotangle{ double ll1; /* ロボットの左足の股関節の角度 */ double ll2; /* ロボットの左足の膝関節の角度 */ double rl1; /* ロボットの右足の股関節の角度 */ double rl2; /* ロボットの右足の膝関節の角度 */ double la1; /* ロボットの左腕の肩関節の角度 */ double la2; /* ロボットの左腕の肘関節の角度 */ double ra1; /* ロボットの右腕の肩関節の角度 */ double ra2; /* ロボットの右腕の肘関節の角度 */ }; /* 直方体を描く */ void myBox(double x, double y, double z) { GLdouble hx = x * 0.5, hz = z * 0.5; static GLfloat flesh[] = { 0.945, 0.733, 0.576, 1.0 }; /* 肌色の定義 */ int i, j; /* 面を構成する頂点 */ GLdouble vertex[][3] = { { -hx, -y, -hz }, { hx, -y, -hz }, { hx, 0.0, -hz }, { -hx, 0.0, -hz }, { -hx, -y, hz }, { hx, -y, hz }, { hx, 0.0, hz }, { -hx, 0.0, hz } }; /* 面の構成 */ static int face[][4] = { { 0, 1, 2, 3 }, { 1, 5, 6, 2 }, { 5, 4, 7, 6 }, { 4, 0, 3, 7 }, { 4, 5, 1, 0 }, { 3, 2, 6, 7 } }; /* 各面の単位法線ベクトル */ static GLdouble normal[][3] = { { 0.0, 0.0,-1.0 }, { 1.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }, {-1.0, 0.0, 0.0 }, { 0.0,-1.0, 0.0 }, { 0.0, 1.0, 0.0 } }; /* 材質を設定する */ glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, flesh); /* 面の描画 */ glBegin(GL_QUADS); for (j = 0; j < 5; j++) { glNormal3dv(normal[j]); for (i = 3; i >= 0;i--) { glVertex3dv(vertex[face[j][i]]); } } glEnd(); } /* 腕/足 */ void armleg(double girth, double length, double r1, double r2) { glRotated(r1, 1.0, 0.0, 0.0); myBox(girth, length, girth); glTranslated(0.0, -0.05 - length, 0.0); glRotated(r2, 1.0, 0.0, 0.0); myBox(girth, length, girth); } /* 地面を描く */ void myGround() { static GLfloat ground[4] = {0.1, 1.0, 0.0, 1.0 }; glBegin(GL_QUADS); glNormal3d(0.0, 1.0, 0.0); glMaterialfv(GL_FRONT, GL_DIFFUSE, ground); glVertex3f(-10, -1.8, -10); glVertex3f(-10, -1.8, 10); glVertex3f( 5, -1.8, 10); glVertex3f( 5, -1.8, -10); glEnd(); } /* ゴールポストを描く */ void mypost() { /* ゴールポストの各頂点 */ static GLdouble vertex[][3] = { { 4.0, -1.7, -5.0 }, /* A */ { 4.0, -1.7, 5.0 }, /* B */ { 4.0, 1.0, 5.0 }, /* C */ { 4.0, 1.0, -5.0 }, /* D */ { 2.0, -1.7, -5.0 }, /* E */ { 2.0, -1.7, 5.0 }, /* F */ { 2.0, 1.0, 5.0 }, /* G */ { 2.0, 1.0, -5.0 } /* H */ }; static int edge[][2] = { { 0, 1 }, /* ア (A-B) */ { 1, 2 }, /* イ (B-C) */ { 2, 3 }, /* ウ (C-D) */ { 3, 0 }, /* エ (D-A) */ { 5, 6 }, /* カ (F-G) */ { 6, 7 }, /* キ (G-H) */ { 7, 4 }, /* ク (H-E) */ { 0, 4 }, /* ケ (A-E) */ { 1, 5 }, /* コ (B-F) */ { 2, 6 }, /* サ (C-G) */ { 3, 7 } /* シ (D-H) */ }; static GLfloat black[] = { 0.0, 0.0, 0.0, 1.0 }; static GLfloat white[] = { 1.0, 1.0, 1.0, 1.0 }; int i,j,k; glLineWidth(5); glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, white); /* 材質を設定する */ glBegin(GL_LINES); for (i = 0; i < 11; ++i) { glVertex3dv(vertex[edge[i][0]]); glVertex3dv(vertex[edge[i][1]]); } glEnd(); glMaterialfv(GL_FRONT, GL_DIFFUSE, black); /* 材質を設定する */ glLineWidth(1.0); /* ゴールネットを描く */ glBegin(GL_LINES); for(j=0;j<=10;j++){ for(k=0;k<=10;k++){ glVertex3f(2.0+0.2*j, -1.7, 5.0); glVertex3f(2.0+0.2*j, 1.0, 5.0); glVertex3f(2.0, -1.7+0.27*k, 5.0); glVertex3f(4.0, -1.7+0.27*k, 5.0); glVertex3f(2.0+0.2*j, -1.7, -5.0); glVertex3f(2.0+0.2*j, 1.0, -5.0); glVertex3f(2.0, -1.7+0.27*k, -5.0); glVertex3f(4.0, -1.7+0.27*k,- 5.0); glVertex3f(4.0, -1.7, 5.0-1.0*j); glVertex3f(4.0, 1.0, 5.0-1.0*j); glVertex3f(4.0, -1.7+0.27*k, -5.0); glVertex3f(4.0, -1.7+0.27*k, 5.0); glVertex3f(2.0, 1.0, 5.0-1.0*j); glVertex3f(4.0, 1.0, 5.0-1.0*j); glVertex3f(2.0+0.2*j, 1.0, 5.0); glVertex3f(2.0+0.2*j, 1.0, -5.0); } } glEnd(); } /* 部位ごとに座標変換 */ void trans(struct robotangle *angle){ /* 頭 */ myBox(0.20, 0.25, 0.22); /* 胴 */ glTranslated(0.0, -0.3, 0.0); myBox(0.4, 0.6, 0.3); /* 左足 */ glPushMatrix(); glTranslated(0.1, -0.65, 0.0); armleg(0.2, 0.4, angle->ll1, angle->ll2); glPopMatrix(); /* 右足 */ glPushMatrix(); glTranslated(-0.1, -0.65, 0.0); armleg(0.2, 0.4, angle->rl1, angle->rl2); glPopMatrix(); /* 左腕 */ glPushMatrix(); glTranslated(0.28, 0.0, 0.0); armleg(0.16, 0.4, angle->la1, angle->la2); glPopMatrix(); /* 右腕 */ glPushMatrix(); glTranslated(-0.28, 0.0, 0.0); armleg(0.16, 0.4, angle->ra1, angle->ra2); glPopMatrix(); } /* 画面表示 */ void display(void) { static GLfloat lightpos[] = { 3.0, 4.0, 1.0, 0.0 }; /* 光源の位置 */ static int frame = 0,i=0,state=0; static double bx=0.0; static GLfloat white[] = { 1.0, 1.0, 1.0, 1.0 }; static struct robotangle angle; static GLUquadricObj *sphere; /* オブジェクトポインタを準備 */ sphere = gluNewQuadric(); /* オブジェクトを生成 */ /* STEPCYCLE に指定した枚数のフレームを描画する間に 0→1 に変化 */ double t; t = (frame % STEPCYCLE) / (double)STEPCYCLE; /* WALKCYCLE に指定した枚数のフレームを描画する間に 0→1 に変化 */ double s; s = (frame % WALKCYCLE) / (double)WALKCYCLE; double px = -10+20*s, pz = 0.0; /* ロボットの位置 */ if(px >= -2.5 && state == 0){ t = 0.8; state = 1; } double r = 90.0; /* ロボットの向き */ double h = 0.01*cos((360*t/360)*2*M_PI*2); /* ロボットの高さ */ angle.ll1 = 30*sin((360*t/360)*2*M_PI); /* ロボットの左足の股関節の角度 */ angle.ll2 = 30-30*cos((360*t/360)*2*M_PI); /* ロボットの左足の膝関節の角度 */ angle.rl1 = 30*cos(((360*t+60)/360)*2*M_PI); /* ロボットの右足の股関節の角度 */ angle.rl2 = 30-30*sin(((360*t+60)/360)*2*M_PI); /* ロボットの右足の膝関節の角度 */ angle.la1 = 30*cos(((360*t+60)/360)*2*M_PI); /* ロボットの左腕の肩関節の角度 */ angle.la2 = -30-30*sin(((360*t+60)/360)*2*M_PI); /* ロボットの左腕の肘関節の角度 */ angle.ra1 = 30*sin((360*t/360)*2*M_PI); /* ロボットの右腕の肩関節の角度 */ angle.ra2 = -30-30*cos((360*t/360)*2*M_PI); /* ロボットの右腕の肘関節の角度 */ if(state != 1) ++frame; /* フレーム数(画面表示を行った回数)をカウントする */ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); /* 画面の塗りつぶし・Zバッファの設定 */ glLoadIdentity(); /* モデルビュー変換行列の初期化 */ glLightfv(GL_LIGHT0, GL_POSITION, lightpos); /* 光源の位置を設定 */ glTranslated(0.0, 0.0, -20.0); /* 視点の移動(物体の方を奥に移す)*/ myGround(); /* 地面 */ mypost(); /* ゴールポスト */ //オブジェクトの描画タイプを設定 gluQuadricDrawStyle(sphere, GLU_FILL); glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, white); /* 材質を設定する */ if(state == 0) /* ドリブル */ glTranslated(px+0.45,-1.7,0); else if(state == 1) /* ボールを蹴る動作中 */ glTranslated(-2.5+0.45,-1.7,0); else if(state == 2){ /* 蹴った後の動作 */ if(bx==0.) bx = px+0.45; glTranslated(bx,bx/4-1.0,0); bx += 0.2; } gluSphere(sphere, 0.1,10.0, 10.0); /* 球を描画 半径0.1,緯経それぞれ10.0分割 */ glLoadIdentity(); /* モデルビュー変換行列の初期化 */ glTranslated(0.0, 0.0, -20.0); /* ロボットの位置と方向 */ if(state == 0) glTranslated(px, h, pz); else glTranslated(-2.5, 0.0, 0.0); glRotated(r, 0.0, 1.0, 0.0); /* ロボットの向きの変更 */ /* ボールを蹴る動作以降の右足以外の角度 */ if(state != 0){ angle.ll1=-45.; angle.ll2=45.; angle.la1=0.; angle.la2=0.; angle.ra1=0.; angle.ra2=0.; if(state == 2){ angle.rl1=-90; angle.rl2=0; } } /* ボールを蹴る動作 */ if(state == 1){ i++; angle.rl1=45*sin(((double)(0.01*KICKSPEED)*i/360)*2*M_PI); angle.rl2=45-45*cos(((double)(0.01*KICKSPEED)*i/360)*2*M_PI); if(i==(int)(22000/KICKSPEED)){ state = 2; i=0; } } /* ゴールネットに突き刺さった場合 */ if(bx >= 4.0){ /* パラメータの初期化 */ state = 0; frame = 0; bx = 0.0; } trans(&angle); /* ロボットの手足の幾何変換 */ glutSwapBuffers(); } void resize(int w, int h) { /* ウィンドウ全体をビューポートにする */ glViewport(0, 0, w, h); /* 透視変換行列の指定 */ glMatrixMode(GL_PROJECTION); /* 透視変換行列の初期化 */ glLoadIdentity(); gluPerspective(30.0, (double)w / (double)h, 1.0, 100.0); /* モデルビュー変換行列の指定 */ glMatrixMode(GL_MODELVIEW); } void keyboard(unsigned char key, int x, int y) { /* ESC か q をタイプしたら終了 */ if (key == '\033' || key == 'q') { exit(0); } } void init(void) { /* 初期設定 */ glClearColor(1.0, 1.0, 1.0, 0.0); /* 画面を塗りつぶす色の設定 */ glEnable(GL_DEPTH_TEST); /* 陰面消去処理を有効にする */ glEnable(GL_LIGHTING); /* 陰影付けを有効にする */ glEnable(GL_LIGHT0); /* 光源の0番目を有効にする */ glEnable(GL_CULL_FACE); /* カリング処理を有効にする */ glCullFace(GL_BACK); /* 裏面を表示しないようにする */ } void idle(void) { glutPostRedisplay(); /* 再描画するイベント発生させる */ } int main(int argc, char *argv[]) { glutInit(&argc, argv); /* GLUTおよび,OpenGL環境の初期化 */ /* GLUT_RGBA:色の指定をRGBで指定 GLUT_DEPTH:陰面消去処理を有効にする GLUT_DOUBLE:ダブルバッファリングを有効にする*/ glutInitDisplayMode(GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE); /* 表示モードの設定 */ glutCreateWindow(argv[0]); /* ウィンドウを開く(引数はタイトルバーに表示する文字) */ glutDisplayFunc(display); /* 再描画する場合に引数の関数が実行される */ glutReshapeFunc(resize); /* ウィンドウがリサイズされたときに引数の関数を実行する */ glutIdleFunc(idle); /* 操作などが無い場合に引数の関数が実行される */ glutKeyboardFunc(keyboard); /* キーボードをタイプした時に実行される */ init(); /* 初期設定 */ glutMainLoop(); /* 無限ループ,待ち状態になる */ return 0; }