2010年6月9日水曜日

NyARToolkit + NyMmd をやってみた ( MacOSX 10.6 ( Snow Leopard ) / Eclipse )

追記(2010/06/13):'やってみた(2010/06/13 追加)'を追加

追記(2010/06/10):'やってみた(追加)'を修正



動機
元動画のようにARToolkit(前回(NyARToolkit)),とMMD(前々回(NyMmd))をくっつけたい!


感謝
各種リソース作者やマトメ等記事を書かれている方に感謝


やってみた
0. 前回前々回がそれぞれできていること.

1. NyARToolkit側の前回実行に用いたjp.nyatla.nyartoolkit.jogl.sample.JavaSimpleLite.javaを編集していくのでNyARToolkitプロジェクトにNyMmdプロジェクトのクラスパスを追加する.

1.a プロジェクトの'Properties'で'Java Build Path'タブを開き'Add Class Folder…'ボタンで選択ダイアログを出す.

1.b NyMmdプロジェクトのbinフォルダを選択し,追加する.


1.c NyMmdプロジェクト中のMmdフォルダ(pmd, vmdを入れたフォルダ)をNyARToolkitプロジェクトルートにDnD等で複写する.
1.c NyARToolkitプロジェクトルートにMmdフォルダを作成し,pmd, vmdファイル(およびテクスチャ)をDnD等で配置する.
 2.eのコードで調整してもらってもよい.


2. jp.nyatla.nyartoolkit.jogl.sample.JavaSimpleLite.javaを編集

2.a NyMmdプロジェクトのjp.nyatla.nymmd.test.MmdTest.javaより
 MmdTestクラス中のinit(GLAutoDrawable drawable)メソッドをJavaSimpleLiteクラスに複写する.
 ただし同名のメソッド名は既にあるので'mmd_'というprefixをつけて'mmd_init(…)'にする.

2.b NyMmdプロジェクトのjp.nyatla.nymmd.test.MmdTest.javaより
 MmdTestクラス中のdisplay(GLAutoDrawable drawable)メソッドをJavaSimpleLiteクラスに複写する.
 ただし同名のメソッド名は既にあるので'mmd_'というprefixをつけて'mmd_display(…)'にする.

2.c NyMmdプロジェクトのjp.nyatla.nymmd.test.MmdTest.javaより
 MmdTestクラス中の以下のフィールド定義をJavaSimpleLiteクラスに複写する.

  • animation_start_time

  • _pmd

  • _vmd

  • _player

  • _render

  • _data_io

  • prev_time



2.d NyMmdプロジェクトのjp.nyatla.nymmd.test.MmdTest.javaより
 FileIOクラスをJavaSimpleLiteファイルに複写する.

2.e 以下のメソッドをに追加
 private void init_mmd_files() {
String pmd_file = "./Mmd/pmdfile.pmd";
String vmd_file = "./Mmd/vmdfile.vmd";
try {
this._pmd = new MmdPmdModel(new FileInputStream(pmd_file));
this._vmd = new MmdVmdMotion(new FileInputStream(vmd_file));
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (MmdException e) {
e.printStackTrace();
}
this._player = new MmdMotionPlayer(this._pmd, this._vmd);
this._player.setLoop(true);
File f = new File(pmd_file);
this._data_io = new FileIO(f.getParentFile().getPath());
}


2.f JavaSimpleLiteクラスのdisplayメソッド中でdrawCubeメソッドを呼ぶところをコメントアウトする.
 直後に
  
mmd_display(drawable);

 を追加する.

2.g JavaSimpleLiteクラスのinitメソッド中最後のreturn直前にある
 _animatorフィールドへの値の代入と同フィールドインスタンスのメソッド呼び出しをコメントアウトする.
 直後に
  
mmd_init(drawable);

 を追加する.

2.h JavaSimpleLiteクラスのコンストラクタの中,
 最初に
  
mmd_init_files();

 を追加する.

2.i mmd_displayメソッド内で以下の修正を加える.

  • glClearメソッドを用いている行をコメントアウトする.

  • glLoadIdentityメソッドを用いている行をコメントアウトする.

  • glTranslatefメソッドを用いている行をコメントアウトする.

  • glScalefで1.0,1.0,1.0としているところをモデルに合わせて調整する.0.1, 0.1, 0.1など

  • 上記直後にx軸を90度まわしてやる.
    _gl.glRotatef(90.0f, 1.0f, 0.0f, 0.0f);




2.j mmd_initメソッド内で以下の修正を加える.

  • 光源位置のZ軸を負にしてあげる



3.実行
前回同様VM引数として'-d32 -Djava.library.path=./library:./lib'を与えて実行



やってみた(追加)
カメラ目線モード(?)を実行するにはJavaSimpleLiteクラスmmd_displayメソッド中の
以下のコメントアウト行の下に
// this._player.updateNeckBone(100.0f,10f,10f);

次のコードを追加してみた.
   float x = (float) __display_wk[12];
float y = (float) __display_wk[13];
float z = (float) __display_wk[14];
this._player.updateNeckBone(-x, -y, -z);


それっぽく見えるときもあるんだけどやっぱり違うのかな,所々おかしな方向向いているきもする.


やってみた(追加)
モデル側座標系でみたカメラ(グローバル)側座標系の原点ということだろう.ということで以下のように訂正.

カメラ目線モード(?)を実行するにはJavaSimpleLiteクラスmmd_displayメソッド中の
以下のコメントアウト行の下に
// this._player.updateNeckBone(100.0f,10f,10f);

次のコードを追加してみた.
   NyARMat a = new NyARMat(4, 4);
double[][] a_ary = a.getArray();
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
a_ary[j][i] = __display_wk[j * 4 + i];
}
}
a.matrixSelfInv();
float x = (float) a_ary[3][0];
float y = (float) a_ary[3][1];
float z = (float) a_ary[3][2];
this._player.updateNeckBone(x, y, z);


どうだろう?
(NyARMat aはフィールドにする方がよいかもね)


やってみた(2010/06/13 追加)
上のやつをちょっと書き換えてみた.
   float m[] = new float[16];
_gl.glGetFloatv(GL.GL_MODELVIEW_MATRIX, m, 0);
NyARMat a = new NyARMat(4, 4);
double[][] a_ary = a.getArray();
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
a_ary[j][i] = m[j * 4 + i];
}
}

a.matrixSelfInv();

double[] o = { 0.0, 0.0, 0.0, 1.0 };
double[] v = { 0.0, 0.0, 0.0 };
//o[2] = 10 * Math.sin(iTime / 1000.0);
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 4; j++) {
v[i] += a_ary[j][i] * o[j];
}
}

float x = (float) v[0];
float y = (float) v[1];
float z = (float) v[2];

this._player.updateNeckBone(x, y, z);

0 件のコメント: