NyARToolkit for Androidのパフォーマンスが劇的に上がったので、NyMmdと組み合わせて、ありがちなデモを作ってみました。
はい。Nyanyanyanyanya!!!です。モーションとかモデルとかBGMは使わしてもらってます。(BGMは編集です。)
- BGM【初音ミク】Nyanyanyanyanyanyanya!【オリジナループhttp://www.nicovideo.jp/watch/sm11509720
- PMD 初音ミク@七葉1052式(nh0163.zip)
- VMD 【MMD】Nyanyanyanyanyanyanya!【振り付けしてみた】http://www.nicovideo.jp/watch/sm13350648
ソフトウェアは、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から取得できます。
- NyARToolkit for Android – http://sourceforge.jp/projects/nyartoolkit-and/
- NyMmd – http://code.google.com/p/nymmd/