NyARToolKit

NyARToolKit for Android

Section 13 メイン部分のソースコード説明

サンプルソースのメイン(NyARToolkitAndroidActivity.java)解説を行っていきます。

暫定版

この記事は暫定版です。順次更新されます。
この表示が消えるまで突っ込み禁止。

Androidのライフサイクル

onCreate

@Override
public void onCreate(Bundle icicle) {
	super.onCreate(icicle);

	// min3Dの初期化
	_initSceneHander = new Handler();
	_updateSceneHander = new Handler();

	// These 4 lines are important.
	//3Dレンダー準備
	Shared.context(this);
	scene = new Scene(this);
	scene.backgroundTransparent(true);
	mRenderer = new Renderer(scene);
	Shared.renderer(mRenderer);

	//プログレスバーの表示
	requestWindowFeature(Window.FEATURE_PROGRESS);
	//windowのオプション設定
	Window win = getWindow();
	win.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
	win.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
	//メインレイアウト設定
	setContentView(R.layout.main);
	//カメラ出力のデータ領域確保
	mSurfaceView = (SurfaceView) findViewById(R.id.camera_preview);
	mPreferences = PreferenceManager.getDefaultSharedPreferences(this);

	mSurfaceView.setKeepScreenOn(true);

	// don't set mSurfaceHolder here. We have it set ONLY within
	// surfaceChanged / surfaceDestroyed, other parts of the code
	// assume that when it is set, the surface is also set.
	SurfaceHolder holder = mSurfaceView.getHolder();
	holder.addCallback(this);
	holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}

onCreateは起動時に処理されます。ここでは初期化を行っています。
ARで表示する3DモデルはGLSurfaceViewを使用し、カメラの表示はSurfaceViewを使用しています。
GLSurfaceViewはOpenGL ESを使用して部分的または全体的にレンダリングを行うアプリケーションを作成することができるものです。

また、コメント中にmin3Dという名前がありますが、それについては次で説明します。

initScene: min3D設定

ソースコードの説明に入る前に、min3Dについて簡単に説明します。

min3Dは下記のサイトで公開されているオープンソース(MIT License)のモデルレンダラーです。

min3d(code.google.com)
A 3d library/framework for Android using Java and OpenGL ES

モデルデータの表示用にメタセコイアのローダーがありましたが、なにやら重い事と、obj や 3ds に対応している事から採用されたものになります。
もっとも、現状含まれているのはmd2のローダーに対応させたものだけとなっています。

それではソースコードを見てみましょう。

public void initScene()
{
	//ライト設定と奥行き設定
	scene.lights().add(new Light());
	scene.camera().frustum.zFar(10000.0f);

	IParser parser;
	AnimationObject3d animationObject3d = null;

	//モデルデータ取得
	parser = Parser.createParser(Parser.Type.MD2,
			getResources(), "jp.androidgroup.nyartoolkit:raw/droid", false);
	parser.parse();

	//モデルデータの大きさ、角度、アニメーション設定
	animationObject3d = parser.getParsedAnimationObject();
	animationObject3d.rotation().z = -90.0f;
	animationObject3d.scale().x = animationObject3d.scale().y = animationObject3d.scale().z = 1.0f;
	scene.addChild(animationObject3d);
	animationObject3d.setFps(30);
}

ここではモデルデータの読込みとアプリケーションで使用するための設定を行っています。
モデルデータは>jp.androidgroup.nyartoolkit:raw/droidで読み込むデータを指定しています。
これは、res/rawフォルダにある、droid.md2を意味し、それのテクスチャファイルは、res/drawableフォルダにあるdroid.jpgになります。

テクスチャファイルとモデルデータのファイルを同じ場所に置かないということに注意してください。

onResume

@Override
public void onResume() {
	super.onResume();
	Log.d(TAG, "onResume");

	mPausing = false;

	// Start the preview if it is not started.
	if (!mPreviewing && !mStartPreviewFail && (mSurfaceHolder != null)) {
		try {
			//カメラのセットアップ
			startPreview();
		} catch (Exception e) {
			showCameraErrorAndFinish();
			return;
		}
	}

	if (mSurfaceHolder != null) {
		// If first time initialization is not finished, put it in the
		// message queue.
		if (!mFirstTimeInitialized) {
			//初回時起動
			mHandler.sendEmptyMessage(FIRST_TIME_INIT);
		} else {
			//初回以外起動
			initializeSecondTime();
		}
	}
	keepScreenOnAwhile();
}

onResumeは起動した後や中断していた状態から再開した時などに処理されます。
カメラのセットアップではカメラの表示サイズを設定しディスプレイにカメラ出力を表示させる処理を行います。
初回起動時にはHandlerにFIRST_TIME_INITを送信し、初期initializeFirstTime()が呼び出されます。
ここで端末の角度を常に取得するListenerを設定し、角度による処理を行うように設定しています。

initializeGLSurfaceView

private void initializeGLSurfaceView() {

	// ARToolkit初期化
	if (arToolkitDrawer == null) {
		InputStream camePara = getResources().openRawResource(R.raw.camera_para);
		int[] width = new int[2];
		for (int i = 0; i < 2; i++) {
			//マーカーサイズ指定
			width[i] = 80;
		}
		ArrayList<InputStream> patt = new ArrayList<InputStream>();
		//マーカーパターン設定
		patt.add(getResources().openRawResource(R.raw.patthiro));
		patt.add(getResources().openRawResource(R.raw.pattkanji));
		arToolkitDrawer = new ARToolkitDrawer(camePara, width, patt, mRenderer);
	}

	FrameLayout frame = (FrameLayout) findViewById(R.id.frame);
	mGLSurfaceView = new GLSurfaceView(this);
	//R,G,B,A,depth,stencilサイズの指定
	mGLSurfaceView.setEGLConfigChooser(8, 8, 8, 8, 16, 0);
	mGLSurfaceView.getHolder().setFormat(PixelFormat.TRANSLUCENT);
	//mGLSurfaceViewが一番上に描画されるように明示的に使用
	mGLSurfaceView.setZOrderOnTop(true);
	mGLSurfaceView.setRenderer(mRenderer);
	frame.addView(mGLSurfaceView);
}

ARToolkitの初期化を行っています。またAR表示用のGLSurfaceViewの初期化を行います
mGLSurfaceView.setZOrderOnTop(true)の処理は起動速度の関係でSurfaceViewとGLSurfaceViewの表示順が期待通りにならないため追加をしています。
とりあえずこれで処理の準備が終了します。

PreviewCallback:カメラ画像の取得

/**
 * Callback interface used to deliver copies of preview frames as they are displayed.
 */
private final class PreviewCallback
        implements android.hardware.Camera.PreviewCallback {

	//プレビュー画像を連続取得
	@Override
	public void onPreviewFrame(byte [] data, Camera camera) {
		Log.d(TAG, "PreviewCallback.onPreviewFrame");

		if (mPausing) {
			return;
		}

		if(data != null) {
			Log.d(TAG, "data exist");

			if (arToolkitDrawer != null)
				//ARの表示
				arToolkitDrawer.draw(data);
			
		} else {
			try {
				// The measure against over load.
				Thread.sleep(500);
			} catch (InterruptedException e) {
				;
			}
		}
		//カメラの再セットアップ
		restartPreview();
	}
}

カメラのプレビュー画像の取得を行います。画像データを取得し、drawにて表示を行います。
注意としては、現状カメラからの画像データがYUV420フォーマットでしか取得できない状態です。基本的に、このままではARToolKit側で処理ができないため、ARToolkitDrawer内の処理でRGB変換処理を行ってから解析しています。

表示されるまでのメイン処理は以上のような感じです。
メモリの開放やカメラの開放などの後処理についてはソースで確認してください。
次回はARToolkitDrawerの説明を行います。