NyARToolkit for Androidのパフォーマンスが劇的に上がったので、NyMmdと組み合わせて、ありがちなデモを作ってみました。
VIDEO
はい。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のソースコードと使い方 で公開しました。