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のソースコードと使い方で公開しました。