VisualC++ と OpenGL を利用した仮想物理実験室
ARToolkit を利用した拡張現実
今回試してみた「ARToolkit」は、手軽に拡張現実を実現するためのツールで、C言語 + OpenGL で利用することができます。
特に【図書】拡張現実感を実現するARToolkitプログラミングテクニックでは、VisualC++ を利用した際に必要な設定がバージョンごとに詳細に解説されています。
コンピュータ・シミュレーション講座は、VisualC++ + OpenGL を利用しているので、
早速利用してみます。
ARToolkitを利用してみる
拡張現実(Augmented Reality)とは、現実世界の上に新しく情報が付加されたものを指します。 ARToolkit は、予め印刷しておいた目印を WEBカメラで読み取り、現実世界に新しく情報を付加します。 今回は、受講生の作品(小学5年生)を現実世界に付加します。
ARToolkit の利用方法
ARToolkit のインストールから、コンパイル方法は、次のページに非常に詳しく紹介されていますので参照ください。
【WEB】工学ナビ - 「攻殻機動隊」「電脳コイル」の世界を実現! - ARToolKitを使った拡張現実感プログラミング
【図書】拡張現実感を実現するARToolkitプログラミングテクニック
【図書】3Dキャラクターが現実世界に誕生! ARToolKit拡張現実感プログラミング入門
VisualC++ + OpenGL + ARToolkit のプログラムソース
以下のプログラムソースは、ARToolkit のサンプルプログラム「simpleTest.c」を元にしています。
////////////////////////////////////////////////////////////////////////// // 拡張現実の世界(ver 1.0.0) // simpleTest.c をベースとした ////////////////////////////////////////////////////////////////////////// #include <windows.h> #include <math.h> #include <stdio.h> #include <stdlib.h> #include <direct.h> #include <fstream> #include <sstream> #include <iostream> #include <GL/gl.h> #include <GL/glut.h> #include <GL/gl_material.h> //物質材質の構造体 #include <GL/gl_screenshot.h> //ビットマップデータを取り扱うクラス #include <AR/gsub.h> #include <AR/video.h> #include <AR/param.h> #include <AR/ar.h> using namespace std; double PI = acos(-1.0); double theta=0; int tn=0; #define _BITMAP 1 //アニメーション作成用ビットマップの保存 0:しない 1:する // // Camera configuration. // #ifdef _WIN32 char *vconf = "Data/WDM_camera_flipV.xml"; #else char *vconf = ""; #endif int xsize, ysize; int thresh = 100; int count = 0; char *cparam_name = "Data/camera_para.dat"; ARParam cparam; char *patt_name = "Data/patt.hiro"; int patt_id; double patt_width = 80.0; double patt_center[2] = {0.0, 0.0}; double patt_trans[3][4]; static void init(void); static void cleanup(void); static void keyEvent( unsigned char key, int x, int y); static void mainLoop(void); static void draw( void ); void DrawStructure(void); //描画 void drowCuboid(double a, double b, double c, double x, double y, double z, MaterialStruct color); //直方体の描画 void DrawFloor(bool); gl_screenshot gs; //「gl_screenshot」クラスのインスタンス「gs」を宣言 int main(int argc, char **argv) { #if _BITMAP _mkdir("bitmap"); //bmpファイル保存用のフォルダの作成 #endif glutInit(&argc, argv); //glutInitDisplayMode(GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE | GLUT_STENCIL); //ディスプレイモードの指定 init(); arVideoCapStart(); argMainLoop( NULL, keyEvent, mainLoop ); return (0); } static void keyEvent( unsigned char key, int x, int y) { /* quit if the ESC key is pressed */ if( key == 0x1b ) { printf("*** %f (frame/sec)\n", (double)count/arUtilTimer()); cleanup(); exit(0); } } /* main loop */ static void mainLoop(void) { ARUint8 *dataPtr; ARMarkerInfo *marker_info; int marker_num; int j, k; /* grab a vide frame */ if( (dataPtr = (ARUint8 *)arVideoGetImage()) == NULL ) { arUtilSleep(2); return; } if( count == 0 ) arUtilTimerReset(); count++; argDrawMode2D(); argDispImage( dataPtr, 0,0 ); /* detect the markers in the video frame */ if( arDetectMarker(dataPtr, thresh, &marker_info, &marker_num) < 0 ) { cleanup(); exit(0); } arVideoCapNext(); /* check for object visibility */ k = -1; for( j = 0; j < marker_num; j++ ) { if( patt_id == marker_info[j].id ) { if( k == -1 ) k = j; else if( marker_info[k].cf < marker_info[j].cf ) k = j; } } if( k == -1 ) { argSwapBuffers(); return; } /* get the transformation between the marker and the real camera */ arGetTransMat(&marker_info[k], patt_center, patt_width, patt_trans); draw(); argSwapBuffers(); } static void init( void ) { ARParam wparam; /* open the video path */ cout << vconf << endl; if( arVideoOpen( vconf ) < 0 ) exit(0); /* find the size of the window */ if( arVideoInqSize(&xsize, &ysize) < 0 ) exit(0); printf("Image size (x,y) = (%d,%d)\n", xsize, ysize); /* set the initial camera parameters */ if( arParamLoad(cparam_name, 1, &wparam) < 0 ) { printf("Camera parameter load error !!\n"); exit(0); } arParamChangeSize( &wparam, xsize, ysize, &cparam ); arInitCparam( &cparam ); printf("*** Camera Parameter ***\n"); arParamDisp( &cparam ); if( (patt_id=arLoadPatt(patt_name)) < 0 ) { printf("pattern load error !!\n"); exit(0); } /* open the graphics window */ argInit( &cparam, 1.0, 0, 0, 0, 0 ); } /* cleanup function called when program exits */ static void cleanup(void) { arVideoCapStop(); arVideoClose(); argCleanup(); } static void draw( void ) { double gl_para[16]; GLfloat mat_ambient[] = {0.0, 0.0, 1.0, 1.0}; GLfloat mat_flash[] = {0.0, 0.0, 1.0, 1.0}; GLfloat mat_flash_shiny[] = {50.0}; GLfloat light_position[] = {100.0,-200.0,500.0,0.0}; GLfloat ambi[] = {0.1, 0.1, 0.1, 0.1}; GLfloat lightZeroColor[] = {0.9, 0.9, 0.9, 0.1}; argDrawMode3D(); argDraw3dCamera( 0, 0 ); glClearDepth( 1.0 ); glClear(GL_DEPTH_BUFFER_BIT); glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LEQUAL); /* load the camera transformation matrix */ argConvGlpara(patt_trans, gl_para); glMatrixMode(GL_MODELVIEW); glLoadMatrixd( gl_para ); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glLightfv(GL_LIGHT0, GL_POSITION, light_position); glLightfv(GL_LIGHT0, GL_AMBIENT, ambi); glLightfv(GL_LIGHT0, GL_DIFFUSE, lightZeroColor); glMatrixMode(GL_MODELVIEW); //glTranslatef( 0.0, 0.0, 25.0 ); //glutSolidCube(20.0); theta += 0.0; glPushMatrix(); glRotated( theta , 0, 0, 1.0); glTranslatef( -30.0, 30.0, 0.0 ); drowCuboid(5.0,5.0,100.0,2.5,2.5,50.0,ms_black_rubber); drowCuboid(50.0,3.0,3.0,30.0,1.5,38.5,ms_black_rubber); drowCuboid(50.0,3.0,3.0,30.0,1.5,44.5,ms_black_rubber); drowCuboid(50.0,3.0,3.0,30.0,1.5,50.5,ms_black_rubber); drowCuboid(50.0,3.0,3.0,30.0,1.5,56.5,ms_black_rubber); drowCuboid(50.0,3.0,3.0,30.0,1.5,62.5,ms_black_rubber); drowCuboid(50.0,3.0,3.0,30.0,1.5,68.5,ms_black_rubber); drowCuboid(50.0,3.0,3.0,30.0,1.5,74.5,ms_black_rubber); drowCuboid(50.0,3.0,3.0,30.0,1.5,80.5,ms_black_rubber); drowCuboid(50.0,3.0,3.0,30.0,1.5,86.5,ms_black_rubber); drowCuboid(50.0,3.0,3.0,30.0,1.5,92.5,ms_black_rubber); drowCuboid(5.0,5.0,100.0,57.5,2.5,50.0,ms_black_rubber); drowCuboid(60.0,60.0,5.0,30.0,-30.0,42.5,ms_yellow_plastic); drowCuboid(5.0,5.0,40.0,2.5,-56.0,20.0,ms_black_rubber); drowCuboid(5.0,5.0,40.0,57.5,-56.0,20.0,ms_black_rubber); drowCuboid(5.0,5.0,40.0,57.5,-56.0,20.0,ms_black_rubber); drowCuboid(5.0,60.0,5.0,2.5,-25.0,32.5,ms_black_rubber); drowCuboid(5.0,60.0,5.0,57.5,-25.0,32.5,ms_black_rubber); glPopMatrix(); glDisable( GL_LIGHTING ); glDisable( GL_DEPTH_TEST ); ////////////////////////////////////////// //ビットマップの保存 #if _BITMAP tn++; ostringstream fname; fname << "bitmap/" << tn+10000 << ".bmp" ;//出力ファイル名 string name = fname.str(); gs.screenshot(name.c_str(), 24); #endif } ///////////////////////////////////////////// // 直方体 void drowCuboid(double a, double b, double c, double x, double y, double z, MaterialStruct color){ GLdouble vertex[][3] = { { -a/2.0, -b/2.0, -c/2.0 }, { a/2.0, -b/2.0, -c/2.0 }, { a/2.0, b/2.0, -c/2.0 }, { -a/2.0, b/2.0, -c/2.0 }, { -a/2.0, -b/2.0, c/2.0 }, { a/2.0, -b/2.0, c/2.0 }, { a/2.0, b/2.0, c/2.0 }, { -a/2.0, b/2.0, c/2.0 } }; int face[][4] = {//面の定義 { 3, 2, 1, 0 }, { 1, 2, 6, 5 }, { 4, 5, 6, 7 }, { 0, 4, 7, 3 }, { 0, 1, 5, 4 }, { 2, 3, 7, 6 } }; 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 } }; glPushMatrix(); glMaterialfv(GL_FRONT, GL_AMBIENT, color.ambient); glMaterialfv(GL_FRONT, GL_DIFFUSE, color.diffuse); glMaterialfv(GL_FRONT, GL_SPECULAR, color.specular); glMaterialfv(GL_FRONT, GL_SHININESS, &color.shininess); glTranslated( x, y, z);//平行移動値の設定 glBegin(GL_QUADS); for (int j = 0; j < 6; ++j) { glNormal3dv(normal[j]); //法線ベクトルの指定 for (int i = 0; i < 4; ++i) { glVertex3dv(vertex[face[j][i]]); } } glEnd(); glPopMatrix(); }
ARToolkit とは別に下記のヘッダーファイルを利用しました。
・gl_material.h
gl_screenshot.h