HOME > natural science Laboratory > コンピュータ・シミュレーション講座 > 仮想物理実験室

VisualC++ と OpenGL を利用した仮想物理実験室
ARToolkit を利用した拡張現実

文責:遠藤 理平 (2011年4月21日) カテゴリ:TIPS 集(104)仮想物理実験室(277)

今回試してみた「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



タグ: ,

▲このページのトップNPO法人 natural science トップ

関連記事

TIPS 集

仮想物理実験室







▲このページのトップNPO法人 natural science トップ