ARプレイカードをNy/FLARToolkitで使う

SCEさんがARマーカを大量印刷してくれるそうなので、NyARToolkitのMarkerSystemからARプレイカードを使えるようにしました。

 

紹介記事→SCEJ、PS Vita「ARプレイ」を6月28日より開始

パッケージ化はしていないので、リポジトリから直接チェックアウトしてください。

使い方

SimpleLiteをARプレイカードで動かすには、次のコードを書きます。
個のサンプルはJavaですが、ActionScriptでも同じAPIが用意されています。


package jp.nyatla.nyartoolkit.jogl.sample.sketch;

import javax.media.opengl.*;
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;

public class SimpleLite extends GlSketch
{
  private NyARJmfCamera camera;
  private NyARGlMarkerSystem nyar;
  private NyARGlRender render;
  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.addPsARPlayCard(5,80);
    gl.glEnable(GL.GL_DEPTH_TEST);
    this.camera.start();
  }
  private final static String ARCODE_FILE = "../../Data/patt.hiro";
  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)){
          this.render.loadMarkerMatrix(gl,this.id);
          this.render.colorCube(gl,40,0,0,20);
        }
        Thread.sleep(1);
      } catch (Exception e) {
        e.printStackTrace();
      }
    }
  }
  public static void main(String[] args)
  {
    try {
      new SimpleLite();
    } catch (Exception e) {
      e.printStackTrace();
    }
    return;
  }
}

重要なのは次の行で、ARプレイカードの5番を、マーカサイズ8cmで登録しています。(ARプレイカードの標準的な大きさがわからなかったので・・・)
this.id=this.nyar.addPsARPlayCard(5,80);

使えるカードは1番から6番までです。もちろん、従来のARマーカやNyIdマーカと混在して使うことも出来ます。

FLARTK、NyARToolKitCSには順次移植していきます。

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 demoのソースコードと使い方

NyARToolkit for Android のデモで紹介したAndroidアプリのソースコードと、その組み立て方を説明します。

準備

Android開発環境を事前にセットアップしてあるものとして説明します。API はAPI8を使えるようにしてください。

セットアップ

  1. 以下のURLから、ソースコードのセットをダウンロードします。
    andmmd-fileset-20120612
  2. Eclipseへ必要なプロジェクトをImportします。


    必要なのは次の4つです。

    • AndMmd – アプリケーションスケッチ本体
    • NyARToolkit for Android – AndUtils Android用のお道具箱
    • NyARToolkit for Android – NyARToolkit本体
    • NyMmdForAndroid – Android用のNyMmd

    NyMmc,NyMmdTest,src.pc.JOGLはPC用ですので、インポートするとエラーになります。

  3. もしかしたらエラーが発生するかもしれません。その時は文字コードをチェックしてください。NyMmd/NyARToolKitは、UTF-8で書かれています。

実行

通常のAndroidアプリケーションと同じように実行します。なお、実機/エミュレータでのデバック実行は、実行速度が1/100くらいになってしまうので、大変ストレス(起動まで1分くらい)があります。

Androidから直接起動すると、それなりの速度で動作します。

ライセンスについて

NyMmd(GPLv2)+NyARToolkit(GPLv3)のため、GPLv3となります。改造してアプリケーションを配布するときは、GPLの表示と、ソースコードの取得方法(問い合わせメールアドレスか、配布URLの表示)をお願いします。

English

This is explanation of how to make NyARToolkit for android demo program with NyMmd for Android.

Preparation

NyARToolkit for Android requires API8. Please prepare the development environment of API8 before setup.

Setup

  1. Download a fileset from below  URL. The file contains NyARToolkit, NyMmd and Application file.
    andmmd-fileset-20120612
  2. Import projects to Eclipse. Required projects are in list.
    • AndMmd – Application activity
    • NyARToolkit for Android – library
    • NyARToolkit for Android – NyARToolkit library
    • NyMmdForAndroid – NyMmd library
  3. If an error occurs, check  a character code is UTF-8.

Start Application

Start debug the AndMmd project.
In debug mode or an emulation, application is very a slow (100 times slower).
When it is started from Android, it runs at usual speed.

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シリーズのスケッチシステムとほぼ同じです。