/* * 自由軸回転 (クォータニオン) */ #include #include #include #define SCREEN_WIDTH 400 #define SCREEN_HEIGHT 300 GLuint cube0; double sc_x, sc_y; int cr_x, cr_y; #define PAI 3.14159 static double rt[16]; static double tq[4]; static double cq[4] = { 1.0, 0.0, 0.0, 0.0 }; /* クォータニオンの積 q = q1*q2 */ void qmul(double q[], double q1[], double q2[]) { q[0] = q1[0] * q2[0] - q1[1] * q2[1] - q1[2] * q2[2] - q1[3] * q2[3]; q[1] = q1[0] * q2[1] + q1[1] * q2[0] + q1[2] * q2[3] - q1[3] * q2[2]; q[2] = q1[0] * q2[2] - q1[1] * q2[3] + q1[2] * q2[0] + q1[3] * q2[1]; q[3] = q1[0] * q2[3] + q1[1] * q2[2] - q1[2] * q2[1] + q1[3] * q2[0]; } /* クォータニオンのよる自由軸回転 */ void qrot(double r[], double q[]) { double x2 = q[1] * q[1] * 2.0; double y2 = q[2] * q[2] * 2.0; double z2 = q[3] * q[3] * 2.0; double xy = q[1] * q[2] * 2.0; double yz = q[2] * q[3] * 2.0; double zx = q[3] * q[1] * 2.0; double xw = q[1] * q[0] * 2.0; double yw = q[2] * q[0] * 2.0; double zw = q[3] * q[0] * 2.0; r[0] = 1.0 - y2 - z2; r[1] = xy + zw; r[2] = zx - yw; r[3] = 0.0; r[4] = xy - zw; r[5] = 1.0 - z2 - x2; r[6] = yz + xw; r[7] = 0.0; r[8] = zx + yw; r[9] = yz - xw; r[10] = 1.0 - x2 - y2; r[11] = 0.0; r[12] = 0.0; r[13] = 0.0; r[14] = 0.0; r[15] = 1.0; } /* 立方体 */ void cube(void) { int i, j; /* 座標を8個用意 */ GLdouble vertex[][3] = { { -0.5, 0.5, 0.5 }, { -0.5, -0.5, 0.5 }, { 0.5, -0.5, 0.5 }, { 0.5, 0.5, 0.5 }, { -0.5, 0.5, -0.5 }, { -0.5, -0.5, -0.5 }, { 0.5, -0.5, -0.5 }, { 0.5, 0.5, -0.5 }, }; /* 座標をつないで面を作るデータを6個用意 */ int face[][4] = { { 0, 1, 2, 3 }, { 4, 0, 3, 7 }, { 7, 3, 2, 6 }, { 6, 2, 1, 5 }, { 5, 1, 0, 4 }, { 7, 6, 5, 4 } }; /* 面ごとの法線データ */ GLdouble normal[][3] = { { 0.0, 0.0, 1.0 }, { 0.0, 1.0, 0.0 }, { 1.0, 0.0, 0.0 }, { 0.0, -1.0, 0.0 }, { -1.0, 0.0, 0.0 }, { 0.0, 0.0, -1.0 } }; /* 面ごとの色データ */ GLfloat color[][4] = { { 0.0, 0.0, 1.0, 1.0 }, { 0.0, 1.0, 0.0, 1.0 }, { 1.0, 0.0, 0.0, 1.0 }, { 1.0, 1.0, 0.0, 1.0 }, { 1.0, 0.5, 0.0, 1.0 }, { 0.0, 1.0, 1.0, 1.0 } }; glBegin(GL_QUADS); for (j = 0; j < 6; j++) { glMaterialfv(GL_FRONT, GL_DIFFUSE, color[j]); glNormal3dv(normal[j]); for (i = 0; i < 4; i++) { glVertex3dv(vertex[face[j][i]]); } } glEnd(); } /* 初期化 */ void init(void) { GLfloat lightAmb[] = {0.0, 0.0, 0.0, 1.0}; GLfloat lightPos[] = {0.0, 0.0, -1.0, 1.0}; GLfloat lightDif[] = {1.0, 1.0, 1.0, 1.0}; /* 背景色の指定 RGBA */ glClearColor(1.0, 1.0, 1.0, 0.0); /* デプスバッファの有効化 */ glEnable(GL_DEPTH_TEST); /* カリングの有効化 */ glEnable(GL_CULL_FACE); /* Culling GL_BACK or GL_FRONT */ glCullFace(GL_BACK); /* 光源の設定 */ glLightfv(GL_LIGHT0, GL_AMBIENT, lightAmb); glLightfv(GL_LIGHT0, GL_POSITION, lightPos); glLightfv(GL_LIGHT0, GL_DIFFUSE, lightDif); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); qrot(rt, cq); } void resize(int w, int h) { sc_x = 1.33 / (double)w; sc_y = 1.0 / (double)h; /* ビューポートの設定 */ glViewport(0, 0, w, h); /* 射影変換モードに */ glMatrixMode(GL_PROJECTION); /* 変換行列を単位行列に */ glLoadIdentity(); /* 透視射影の視野台形 左、右、下、上、手前、奥 */ glFrustum(w * -1.33 / (double)SCREEN_WIDTH, w * 1.33 / (double)SCREEN_WIDTH, h * -1.0 / (double)SCREEN_HEIGHT, h * 1.0 / (double)SCREEN_HEIGHT, 2.0, 4.0); /* モデル変換モードに戻す */ glMatrixMode(GL_MODELVIEW); } void idle(void) { glutPostRedisplay(); } void mouse(int button, int state, int x, int y) { switch(button){ case GLUT_LEFT_BUTTON: switch(state){ case GLUT_DOWN: cr_x = x; cr_y = y; /* 関数 idle を有効に */ glutIdleFunc(idle); break; case GLUT_UP: /* 関数 idle を無効に */ glutIdleFunc(NULL); cq[0] = tq[0]; cq[1] = tq[1]; cq[2] = tq[2]; cq[3] = tq[3]; break; default: break; } break; default: break; } } void mousemove(int x, int y) { double a; double dx, dy; dx = (x - cr_x) * sc_x; dy = (y - cr_y) * sc_y; a = sqrt(dx * dx + dy * dy); if (a != 0.0) { double ar = a * PAI; double as = sin(ar) / a; double dq[4]; dq[0] = cos(ar); dq[1] = dy * as; dq[2] = dx * as; dq[3] = 0.0; qmul(tq, dq, cq); qrot(rt, tq); } } void key(unsigned char key, int x, int y) { /* ESC */ if(key == '\033'){ exit(0); } } /* 画面表示 */ void display(void) { int i, t; /* 背景色でクリア */ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity(); glTranslated(0.0, 0.0, -3.0); /* クォータニオンによる自由軸回転 */ glMultMatrixd(rt); glCallList(cube0); glutSwapBuffers(); } int main(int argc, char *argv[]) { /* GLUT の初期設定 */ glutInit(&argc, argv); glutInitWindowPosition(100, 50); glutInitWindowSize(SCREEN_WIDTH, SCREEN_HEIGHT); glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH); glutCreateWindow(argv[0]); /* 各関数の指定 */ glutDisplayFunc(display); glutReshapeFunc(resize); glutMouseFunc(mouse); glutMotionFunc(mousemove); glutKeyboardFunc(key); /* 初期設定 */ init(); /* ディスプレイリストの作成 */ cube0 = glGenLists(1); glNewList(cube0, GL_COMPILE); cube(); glEndList(); /* メインループ */ glutMainLoop(); glDeleteLists(cube0, 1); return 0; }