MQO file viewer

ForumにMQOの表示方法の質問があったので、スケッチ書きました。MQOファイルをHiroマーカの上に表示します。

Source code

MqoView.java


import javax.media.opengl.*;

import jp.nyatla.kGLModel.KGLException;
import jp.nyatla.kGLModel.KGLExtensionCheck;
import jp.nyatla.kGLModel.KGLModelData;
import jp.nyatla.kGLModel.contentprovider.LocalContentProvider;
import jp.nyatla.nyartoolkit.core.NyARException;
import jp.nyatla.nyartoolkit.jmf.utils.*;
import jp.nyatla.nyartoolkit.jogl.sketch.GlSketch;
import jp.nyatla.nyartoolkit.jogl.utils.*;
import jp.nyatla.nyartoolkit.markersystem.NyARMarkerSystemConfig;
/**
 * This program shows a Mqo model.
 */
public class MqoView extends GlSketch
{
  private NyARJmfCamera camera;
  private NyARGlMarkerSystem nyar;
  private NyARGlRender render;
  private KGLModelData model_data; // kei add
  public void setup(GL gl)throws NyARException
  {
    this.size(640,480);
    NyARMarkerSystemConfig config = new NyARMarkerSystemConfig(640,480);
    JmfCaptureDeviceList devlist = new JmfCaptureDeviceList();
    JmfCaptureDevice d = devlist.getDevice(0);
    d.setCaptureFormat(config.getScreenSize(),30.0f);
    this.camera=new NyARJmfCamera(d);//create sensor system
    this.nyar=new NyARGlMarkerSystem(config);   //create MarkerSystem
    this.render=new NyARGlRender(this.nyar);

    this.id=this.nyar.addARMarker("data/patt.hiro",16,25,80);
    try {
      LocalContentProvider content_provider=new LocalContentProvider("data/miku_xx08/miku.mqo");
      model_data = KGLModelData.createGLModel(gl,null,content_provider,0.015f, KGLExtensionCheck.IsExtensionSupported(gl,"GL_ARB_vertex_buffer_object"));
    } catch (KGLException e) {
      e.printStackTrace();
      throw new NyARException(e);
    }
    gl.glEnable(GL.GL_DEPTH_TEST);
    this.camera.start();
  }
  private int id;

  public void draw(GL gl)
  {
    synchronized(this.camera){
      try {
        this.render.drawBackground(gl, this.camera.getSourceImage());
        this.render.loadARProjectionMatrix(gl);
        this.nyar.update(this.camera);
        if(this.nyar.isExistMarker(this.id)){
          // Viewing transformation.
          gl.glLoadIdentity();
          this.render.loadMarkerMatrix(gl,this.id);
          gl.glTranslatef(0.0f,0.0f,0.0f) ;//position
          gl.glRotatef(90.0f,1.0f, 0.0f, 0.0f); //OpenGL座標系→ARToolkit座標系
          gl.glEnable(GL.GL_CULL_FACE);
          gl.glCullFace(GL.GL_FRONT);
          model_data.enables(10.0f);
          model_data.draw() ;
          model_data.disables() ;
        }
        Thread.sleep(1);
      } catch (Exception e) {
        e.printStackTrace();
      }
    }
  }
  public static void main(String[] args)
  {
    try {
      new MqoView();
    } catch (Exception e) {
      e.printStackTrace();
    }
    return;
  }
}

解説

MQOの表示には、keiさん作のKGLを若干改変したものを使用しています。
スケッチの重要な部分は2箇所です。

setupでは、MQOファイルを読み込みます。

  LocalContentProvider content_provider=new LocalContentProvider("data/miku_xx08/miku.mqo");
  model_data = KGLModelData.createGLModel(gl,null,content_provider,0.015f, KGLExtensionCheck.IsExtensionSupported(gl,"GL_ARB_vertex_buffer_object"));

drawでは、読み込んだモデルを表示しています。

        if(this.nyar.isExistMarker(this.id)){
          // Viewing transformation.
          gl.glLoadIdentity();
          this.render.loadMarkerMatrix(gl,this.id);
          gl.glTranslatef(0.0f,0.0f,0.0f) ;//position
          gl.glRotatef(90.0f,1.0f, 0.0f, 0.0f); //OpenGL座標系→ARToolkit座標系
          gl.glEnable(GL.GL_CULL_FACE);
          gl.glCullFace(GL.GL_FRONT);
          model_data.enables(10.0f);
          model_data.draw() ;
          model_data.disables() ;
        }

Setup

projectファイルは MqoModel-20120326.zip からダウンロードできます。実効には、JMF、JOGL、NyARToolkit version 4.xが必要です。あらかじめセットアップして置いてください。

Hiroマーカを撮影すると、プリセットされているミクさんのモデルが表示されます。

3D modelについて

プリセットされている3Dmodelは、三次元CG@七葉 nh0072.zipを編集して使用しています。

English

This sketch shows MQO-model above  “Hiro” marker.

Source code

Main program is MqoView.java

Description of source code

MQO library is KGL by kei-san.
The changed parts are below.

  • setup –  MQO loader codes.
  • draw – MQO drawing codes.

Setup

The eclipse project is MqoModel-20120326.zip . The project requires external libraries, JMF ,JOGL, NyARToolkit version 4.x.  Please set up these libraries.

NyARToolkit for Android のデモ

NyARToolkit for Androidのパフォーマンスが劇的に上がったので、NyMmdと組み合わせて、ありがちなデモを作ってみました。

はい。Nyanyanyanyanya!!!です。モーションとかモデルとかBGMは使わしてもらってます。(BGMは編集です。)

ソフトウェアは、NyARToolkit for Android 4.0.3と、Android向けチューニングしたNyMmd 2.0(trunk)です。

気になる動作速度は、Nexus oneで30fps程度。Xperia miniで50fpsくらいでした。1万頂点未満のモデルで物理演算無しなら、MMDのモデルをリアルタイムに動かしても余裕があります。

ソースコード

ソースコードはNyARToolkitのAndSketchを使って書きましたので、大変コンパクトです。
SimpleLiteのコードに、NyMmdの初期化処理と描画処理を足しただけですね。

package jp.nyatla.andnya3;

import javax.microedition.khronos.opengles.GL10;

import jp.androidgroup.nyartoolkit.markersystem.*;
import jp.androidgroup.nyartoolkit.sketch.*;
import jp.androidgroup.nyartoolkit.utils.camera.CameraPreview;
import jp.androidgroup.nyartoolkit.utils.gl.*;
import jp.nyatla.arbozu.R;
import jp.nyatla.nyartoolkit.markersystem.NyARMarkerSystemConfig;
import jp.nyatla.nymmd.*;
import android.content.res.AssetManager;
import android.hardware.Camera;
import android.view.ViewGroup.LayoutParams;
import android.widget.*;

public class AndMmdActivity extends AndSketch implements AndGLView.IGLFunctionEvent
{
  CameraPreview _camera_preview;
  AndGLView _glv;
  Camera.Size _cap_size;
  /**
   * onStartでは、Viewのセットアップをしてください。
   */
  @Override
  public void onStart()
  {
    super.onStart();
    FrameLayout fr=((FrameLayout)this.findViewById(R.id.sketchLayout));
    int sw=this.getWindowManager().getDefaultDisplay().getWidth();
    int sh=this.getWindowManager().getDefaultDisplay().getHeight();
    if(sw>640){
      sw/=2;
      sh/=2;
    }
    //カメラの取得
    this._camera_preview=new CameraPreview(this);
    this._cap_size=this._camera_preview.getRecommendPreviewSize(sw,sh);
    //画面サイズの計算
    int h = this.getWindowManager().getDefaultDisplay().getHeight();
    int screen_w,screen_h;
    screen_w=(this._cap_size.width*h/this._cap_size.height);
    screen_h=h;
    //camera
    fr.addView(this._camera_preview, 0, new LayoutParams(screen_w,screen_h));
    //GLview
    this._glv=new AndGLView(this);
    fr.addView(this._glv, 0,new LayoutParams(screen_w,screen_h));
  }
  private int _mid;
  AndGLTextLabel text;
  AndGLBox box;
  AndGLFpsLabel fps;
  AndMmdMotionPlayer _player;
  NyARAndMarkerSystem _ms;
  NyARAndSensor _ss;
  public void setupGL(GL10 gl)
  {
    try
    {
      AssetManager assetMng = getResources().getAssets();
      //create sensor controller.
      this._ss=new NyARAndSensor(this._camera_preview,this._cap_size.width,this._cap_size.height,30);
      //create marker system
      this._ms=new NyARAndMarkerSystem(new NyARMarkerSystemConfig(this._cap_size.width,this._cap_size.height));
      this._mid=this._ms.addARMarker(assetMng.open("AR/data/hiro.pat"),16,25,80);
      this._ss.start();
      //setup openGL Camera Frustum
      gl.glMatrixMode(GL10.GL_PROJECTION);
      gl.glLoadMatrixf(this._ms.getGlProjectionMatrix(),0);

      this._player=new AndMmdMotionPlayer(gl);
      this._player.setPmd(new AndMmdPmdModel(assetMng,"Model/1052siki.pmd"));
      this._player.setVmd(new AndMmdVmdMotion(assetMng,"Motion/nyanyanya.vmd"));

      this._debug=new AndGLDebugDump(this._glv);
      this.text=new AndGLTextLabel(this._glv);
      this.fps=new AndGLFpsLabel(this._glv,"MarkerPlaneActivity");
      this.box=new AndGLBox(this._glv,1);
      gl.glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
      gl.glEnable(GL10.GL_DEPTH_TEST);

      gl.glEnable(GL10.GL_BLEND);
      gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);

      gl.glEnable(GL10.GL_ALPHA_TEST);
      gl.glAlphaFunc(GL10.GL_GEQUAL, 0.05f);

      float[] fLightPos = { 0.45f, 0.55f, 1.0f, 0.0f };
      float[] fLightDif = { 0.9f, 0.9f, 0.9f, 0.0f };
      float[] fLightAmb = { 1.0f, 1.0f, 1.0f, 0.0f };
      float[] fLightSpq = { 0.9f, 0.9f, 0.9f, 0.0f };
      gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_POSITION, fLightPos, 0);
      gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_DIFFUSE, fLightDif, 0);
      gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_AMBIENT, fLightAmb, 0);
      gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_SPECULAR, fLightSpq, 0);
      gl.glEnable(GL10.GL_LIGHT0);
      gl.glEnable(GL10.GL_LIGHTING);
      this.animation_start_time=System.currentTimeMillis();
    } catch (Exception e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
      this.finish();
    }
  }
  AndGLDebugDump _debug=null;
  private long animation_start_time;
  public void drawGL(GL10 gl)
  {
    try{
      //背景塗り潰し色の指定
      gl.glClearColor(0,0,0,0);
      //背景塗り潰し
      gl.glClear(GL10.GL_COLOR_BUFFER_BIT|GL10.GL_DEPTH_BUFFER_BIT);
      if(ex!=null){
        _debug.draw(ex);
        return;
      }
      this._player.updateMotion((System.currentTimeMillis()-this.animation_start_time)%this._player.getTimeLength());

      synchronized(this._ss){
        this._ms.update(this._ss);
        if(this._ms.isExistMarker(this._mid)){
              this.text.draw("found"+this._ms.getConfidence(this._mid),0,16);
          gl.glPushMatrix();
          gl.glMatrixMode(GL10.GL_MODELVIEW);
          gl.glEnable(GL10.GL_LIGHTING);
          gl.glLoadIdentity();
          gl.glLoadMatrixf(this._ms.getGlMarkerMatrix(this._mid),0);
          gl.glRotatef(90,1,0,0);
          gl.glScalef(8.0f, 8.0f, -8.0f); // 左手系 → 右手系
          this._player.render();
          gl.glPopMatrix();
        }
      }
      fps.draw(0, 0);
    }catch(Exception e)
    {
      ex=e;
    }
  }
  Exception ex=null;
}

NyARToolkit for AndroidとNyMmdのソースコードは、以下のURLから取得できます。

Source code

NyARToolkit for Android demoのソースコードと使い方で公開しました。

NyARToolkit for Android 4.0.3 released

NyARToolkit for Android 4.0.3のリリースします。

http://sourceforge.jp/projects/nyartoolkit-and/releases/?package_id=12943

更新内容

更新内容は以下の通りです。

  • 基本ライブラリをNyARToolkit4.0.3へ更新
  • 画処理系の更新。YUV、Bitmap形式画像への対応
  • Android固有の高速化
  • ProcessingのスケッチライクなActivityの追加

画処理系の最適化により、以前のものより5-10倍ほど速度が向上しています。また、スケッチシステムの採用により、簡単にアプリケーションを作ることが出来るようになりました。

サンプルコード

立方体を表示するSimpleLiteの、スケッチを使用した実装例です。

package jp.nyatla.nyartoolkit.and;

import javax.microedition.khronos.opengles.GL10;

import jp.androidgroup.nyartoolkit.R;
import jp.androidgroup.nyartoolkit.markersystem.NyARAndMarkerSystem;
import jp.androidgroup.nyartoolkit.markersystem.NyARAndSensor;
import jp.androidgroup.nyartoolkit.sketch.AndSketch;
import jp.androidgroup.nyartoolkit.utils.camera.CameraPreview;
import jp.androidgroup.nyartoolkit.utils.gl.*;
import jp.nyatla.nyartoolkit.markersystem.NyARMarkerSystemConfig;
import android.content.res.AssetManager;
import android.hardware.Camera;
import android.view.ViewGroup.LayoutParams;
import android.widget.FrameLayout;

/**
 * Hiroマーカの上にカラーキューブを表示します。
 * 定番のサンプルです。
 *
 */
public class SimpleLiteActivity extends AndSketch implements AndGLView.IGLFunctionEvent
{
  CameraPreview _camera_preview;
  AndGLView _glv;
  Camera.Size _cap_size;
  /**
   * onStartでは、Viewのセットアップをしてください。
   */
  @Override
  public void onStart()
  {
    super.onStart();
    FrameLayout fr=((FrameLayout)this.findViewById(R.id.sketchLayout));
    //カメラの取得
    this._camera_preview=new CameraPreview(this);
    this._cap_size=this._camera_preview.getRecommendPreviewSize(320,240);
    //画面サイズの計算
    int h = this.getWindowManager().getDefaultDisplay().getHeight();
    int screen_w,screen_h;
    screen_w=(this._cap_size.width*h/this._cap_size.height);
    screen_h=h;
    //camera
    fr.addView(this._camera_preview, 0, new LayoutParams(screen_w,screen_h));
    //GLview
    this._glv=new AndGLView(this);
    fr.addView(this._glv, 0,new LayoutParams(screen_w,screen_h));
  }

  NyARAndSensor _ss;
  NyARAndMarkerSystem _ms;
  private int _mid;
  AndGLTextLabel text;
  AndGLBox box;
  AndGLFpsLabel fps;

  public void setupGL(GL10 gl)
  {
    try
    {
      AssetManager assetMng = getResources().getAssets();
      //create sensor controller.
      this._ss=new NyARAndSensor(this._camera_preview,this._cap_size.width,this._cap_size.height,30);
      //create marker system
      this._ms=new NyARAndMarkerSystem(new NyARMarkerSystemConfig(this._cap_size.width,this._cap_size.height));
      this._mid=this._ms.addARMarker(assetMng.open("AR/data/hiro.pat"),16,25,80);
      this._ss.start();
      //setup openGL Camera Frustum
      gl.glMatrixMode(GL10.GL_PROJECTION);
      gl.glLoadMatrixf(this._ms.getGlProjectionMatrix(),0);
      this.text=new AndGLTextLabel(this._glv);
      this.box=new AndGLBox(this._glv,40);
      this._debug=new AndGLDebugDump(this._glv);
      this.fps=new AndGLFpsLabel(this._glv,"MarkerPlaneActivity");
      this.fps.prefix=this._cap_size.width+"x"+this._cap_size.height+":";

    } catch (Exception e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
      this.finish();
    }
  }
  AndGLDebugDump _debug=null;

  public void drawGL(GL10 gl)
  {
    try{
      //背景塗り潰し色の指定
      gl.glClearColor(0,0,0,0);
          //背景塗り潰し
          gl.glClear(GL10.GL_COLOR_BUFFER_BIT|GL10.GL_DEPTH_BUFFER_BIT);
          if(ex!=null){
            _debug.draw(ex);
            return;
          }
          fps.draw(0, 0);
      synchronized(this._ss){
        this._ms.update(this._ss);
        if(this._ms.isExistMarker(this._mid)){
              this.text.draw("found"+this._ms.getConfidence(this._mid),0,16);
          gl.glMatrixMode(GL10.GL_MODELVIEW);
          gl.glLoadMatrixf(this._ms.getGlMarkerMatrix(this._mid),0);
          this.box.draw(0,0,20);
        }
    }
    }catch(Exception e)
    {
      ex=e;
    }
  }
  Exception ex=null;
}

AndSketchは、スケッチシステムのベースクラスです。Activityを継承しています。関数は、OnStart,setupGL,drawGLの3つです。

  1. OnStart – ActivityのOnStartをオーバライドします。ここでは、レイアウトと、ビューを構築しています。
  2. setupGL – OpenGLのセットアップを書きます。text,box,debugはそれぞれ、OpenGL向けの描画クラスです。
  3. drawGL – OpenGLの描画処理を書きます。 synchronizedの場所に注意してください。非同期に更新されるNyARAndSensorと同期を取る為に、オブジェクトにアクセスするときはsynchronizedが必要です。

サンプルの構造は、他のNyARシリーズのスケッチシステムとほぼ同じです。

MarkerSystemで敷居値探索アルゴリズムを変える方法

映像にマーカは映っているのに、何故か認識しないことがありますね。
そんなときに、敷居値探索アルゴリズムを変えると、うまく認識する場合があります。

MarkerSystemを使う場合には、敷居値探索アルゴリズムを簡単に切り替えることができます。

変更方法

アルゴリズムの変更には2つの実装が必要です。

  1. 敷居値決定アルゴリズムを導入したMarkerSystemConfigを定義する。
  2. 新しく定義したMarkerSystemConfigをMarkerSystemへセットする。

次の例では、敷居値探索アルゴリズムを判別法に切り替えています。

MyMarkerSystemConfigの定義

  class MyNyARMarkerSystemConfig extends NyARMarkerSystemConfig
  {
    public MyNyARMarkerSystemConfig(InputStream i_ar_param_stream,int i_width,int i_height) throws NyARException
    {
      super(i_ar_param_stream,i_width,i_height);
    }
    public MyNyARMarkerSystemConfig(int i_width,int i_height) throws NyARException
    {
      super(i_width,i_height);
    }
    public INyARHistogramAnalyzer_Threshold createAutoThresholdArgorism()
    {
      return new NyARHistogramAnalyzer_DiscriminantThreshold();
    }

  }

MarkerSystemへセット

  NyARMarkerSystemConfig config = new MyNyARMarkerSystemConfig(320,240);
  NyARMarkerSystem s=new NyARMarkerSystem(config);

実装済のアルゴリズム

NyARToolKitには3種類の敷居値探索アルゴリズムが実装済みです。これらは、ヒストグラムから敷居値を探索します。

  1. 判別法 NyARHistogramAnalyzer_DiscriminantThreshold
  2. Kittler法 NyARHistogramAnalyzer_KittlerThreshold
  3. Spタイル法 NyARHistogramAnalyzer_SlidePTile

判別法、Kitter法は、良く知られたものです。Spタイル法は、NyARToolKit固有のものです。
NyARToolkitは、標準ではSpタイル法を使っています。

Spタイル法

Spタイル法は、白黒マーカの検出の為に考案した敷居値検出方式です。明点、暗点の両側から、一定割合の画素を除外して、その中心点を敷居値とします。


この方式は、入力画像の暗/明点付近にマーカの構成要素(白/黒)が集中している場合に、良好な結果が得られます。そうでない場合、あまり良い結果が得られません。
例えば、自然画の中にある浅い色のマーカが認識できないようなことが起こります。

独自の敷居値探索アルゴリズムの実装方法

INyARHistogramAnalyzer_Thresholdインタフェイスを実装したクラスを定義し、MarkerSystemConfigにセットすることで、ヒストグラムベースの敷居値探索アルゴリズムを使うことが出来ます。
例えば、次のコードは固定敷居値を返します。

public class MyHistogramAnalyzer implements INyARHistogramAnalyzer_Threshold
{
  public int getThreshold(NyARHistogram i_histogram)
  {
     return 128;
  }
}

敷居値探索オブジェクトは、MarkerSystem起動時に1度だけ作られます。検出してその値を返す以外に、フレーム間で敷居値の平均を取る処理等を追加することも出来ると思います。

NyARToolkitAS3 途中経過

FLARToolKitV4に使うためのNyARToolkitAS3ができました。で、FLARToolKitV4を作っています。
新しいFLARToolKitは、NyARToolKitV4に実装したMarkerSystemと、簡易スケッチが使えるようになります。

Code

次のコードは、SimpleLiteをスケッチとMarkerSystemで実装したものです。

package sketch 
{
	import flash.media.*;
	import flash.geom.*;
	import flash.net.*;
	import flash.text.*;
    import flash.display.*; 
    import flash.events.*;
    import flash.utils.*;
	import jp.nyatla.as3utils.sketch.*;
	import jp.nyatla.as3utils.*;
	import jp.nyatla.nyartoolkit.as3.core.types.*;
	import org.libspark.flartoolkit.core.*;
	import org.libspark.flartoolkit.markersystem.*;
	import org.libspark.flartoolkit.pv3d.*;
	import org.papervision3d.render.*;
	import org.papervision3d.view.*;
	import org.papervision3d.objects.*;
	import org.papervision3d.lights.*;
	import org.papervision3d.materials.*;
	import org.papervision3d.materials.shadematerials.*;
	import org.papervision3d.objects.primitives.*;
	import org.papervision3d.materials.utils.*;
	import org.papervision3d.scenes.*;
	/**
	 * MarkerSystemを使ったSimpleLiteの実装です。
	 * このサンプルは、FLSketchを使用したプログラムです。
	 * PV3Dの初期化、Flashオブジェクトの配置などを省略せずに実装しています。
	 */
	public class SimpleLite extends FLSketch
	{
		private static const _CAM_W:int = 320;
		private static const _CAM_H:int = 240;
		private var _ss:FLARSensor;
		private var _ms:FLARPV3DMarkerSystem;
		public var bitmap:Bitmap = new Bitmap(new BitmapData(_CAM_W,_CAM_H));

		private var _video:Video;
		private var _render:LazyRenderEngine;
		
		private var marker_id:int;
		private var marker_node:DisplayObject3D;
		
		public function SimpleLite()
		{
			//setup UI
			this.bitmap.x = 0;
			this.bitmap.y = 0;
			this.bitmap.width = _CAM_W;
			this.bitmap.height = _CAM_H;
            this.addChild(bitmap);
		}
		private var _fid:Vector.<int>=new Vector.<int>(3);
		public override function setup():void
		{
			//setup content files...
			this._fid[0]=this.setSketchFile("../../../resources/Data/camera_para.dat", URLLoaderDataFormat.BINARY);//0
			this._fid[1]=this.setSketchFile("../../../resources/Data/patt.hiro", URLLoaderDataFormat.TEXT);//1
		}

		public override function main():void
		{
			//webcam
			var webcam:Camera = Camera.getCamera();
			if (!webcam) {
				throw new Error('No webcam!!!!');
			}
			webcam.setMode(_CAM_W, _CAM_H, 30);
			this._video = new Video(_CAM_W, _CAM_H);
			this._video.attachCamera(webcam);			
			//FLMarkerSystem
			var cf:FLARMarkerSystemConfig = new FLARMarkerSystemConfig(this.getSketchFile(this._fid[0]),_CAM_W, _CAM_H);//make configlation
			this._ss = new FLARSensor(new NyARIntSize(_CAM_W, _CAM_H));
			this._ms = new FLARPV3DMarkerSystem(cf);
			this.marker_id = this._ms.addARMarker_2(this.getSketchFile(this._fid[1]), 16, 25, 80); //register AR Marker
			
			//setup PV3d
			var light:PointLight3D = new PointLight3D();
			light.x = 0;
			light.y = 1000;
			light.z = -1000;			
			var viewport3d:Viewport3D = new Viewport3D(_CAM_W,_CAM_H);
			viewport3d.scaleX = 1;
			viewport3d.scaleY = 1;
			viewport3d.x = -4; // 4pix ???
			this.addChild(viewport3d);
			//3d object
			this.marker_node = PV3DHelper.createFLARCube(light,80,0xff22aa, 0x75104e);
			this.marker_node.visible = false;
			//scene
			var s:Scene3D = new Scene3D();
			s.addChild(this.marker_node);
			this._render=new LazyRenderEngine(s,this._ms.getPV3DCamera(),viewport3d);
			
			//start camera
			this.addEventListener(Event.ENTER_FRAME, _onEnterFrame);
		}
		/**
		 * MainLoop
		 * @param	e
		 */
		private function _onEnterFrame(e:Event = null):void
		{
			this._ss.update_2(this._video);//update sensor status
			this._ms.update(this._ss);//update markersystem status
			if (this._ms.isExistMarker(marker_id)){
				this.marker_node.visible = true;
				this._ms.getPv3dMarkerMatrix(this.marker_id, this.marker_node.transform);
			}else {
				this.marker_node.visible = false;
			}
			this.bitmap.bitmapData.draw(this._video);
			this._render.render();
		}
	}
}

解説

  • このプログラムは、Spriteを継承したFLSketchクラスをベースクラスにしています。FLSketchは、ファイルロードに関するサービス関数と、シーケンスを定義します。
  • FLSketchのコンストラクタを実行すると、setup関数→main関数の順で関数がコールされます。
  • setup関数では、外部ファイルの予約関数”setSketchFile”を使うことが出来ます。この関数にURLを渡しておくと、main関数の中でそのファイルを読み取ることが出来ます。
  • main関数では、FLARToolKit,PaperVision3D,Webカメラの準備をします。最後に、カメラ画像のコールバックイベントを、_onEnterFrameに設定します。
  • _onEnterFrameの中では、マーカが見つかったかどうかを判定し、表示物のON/OFFを切替えます。

約140行と少々長いですが、従来と比較すると、スッキリしたかなと思います。また、MarkerSystemは複数マーカ/IDマーカ混在をサポートしているので、従来よりも楽に実装できると思います。

ソースコードはNyARToolkitAS3リポジトリのtrunkにありますが、まだ作業中なので時々動きません。動作するものが必要な方は、@nyatlaまでご連絡ください。