より高度なGearVRfアプリケーションを書く

※この文書は[GearVR Framework](http://www.gearvrf.org/)のドキュメント[Writing More Advanced GearVRf Applications](http://www.gearvrf.org/bin/view/GearVRfDeveloperGuide/GearVRfDevGuide400AdvanceApp)の2015年6月9日時点の翻訳です。

ちょっとたくさんのコードを加えれば、ステレオ3DのVRワールドが作れます！

## GVRActivityの実装

アクティビティを実装するためには`GVRActivity`を継承する必要があります。そしてデバイスXMLファイルと`GVRScript`オブジェクトを提供します。
詳細は[GearVRfアプリケーションの基本セクションのステップ1](http://qiita.com/niusounds/items/28c73dd1bc1b190ebfcd#%E3%82%B9%E3%83%86%E3%83%83%E3%83%971-gvractivity%E3%82%92%E7%B6%99%E6%89%BF%E3%81%97%E3%81%A6%E3%82%A2%E3%82%AF%E3%83%86%E3%82%A3%E3%83%93%E3%83%86%E3%82%A3%E3%82%92%E5%AE%9F%E8%A3%85%E3%81%99%E3%82%8B)を見てください。

## カメラリグと左右のカメラのセットアップ

GearVRfはデフォルトでカメラリグを作成します。パラメーターを調整する必要はありません。しかし、アプリケーションはカメラリグの位置は必要に応じて調整する必要があるでしょう。
HMDセンサーは自動的にカメラの向きを調整します。アプリケーション内にこのためのコードを書く必要はありません。カメラの背景色はそれぞれのカメラに設定することができますが、通常は同じ色を設定します。カメラの背景色とポストエフェクトデータはアプリケーションによって設定されます。ポストエフェクトは左右それぞれのカメラに適用されます。

背景色の設定とカメラリグの位置を設定する:

```java
// set camera background color
mGVRContext.getMainScene().getMainCameraRig().getLeftCamera()
   .setBackgroundColor(0.0f, 0.0f, 0.0f, 1.0f);
mGVRContext.getMainScene().getMainCameraRig().getRightCamera()
   .setBackgroundColor(0.0f, 0.0f, 0.0f, 1.0f);

// set up camerarig position (default)
mGVRContext.getMainScene().getMainCameraRig().getOwnerObject()
   .getTransform().setPosition(0.0f, 0.0f, 0.0f);
```

## シーングラフの作成

シーングラフ(VRワールド)はシーンオブジェクトのツリー構造階層です。各シーンオブジェクトは一つの親を持つツリーノードで、一つ以上の子シーンオブジェクトを持つことができます。アプリケーションはシーングラフを構築しなければいけません。カメラリグをルートシーンオブジェクトにセットアップする必要がありますが、カメラリグをそれぞれの低レベルシーンオブジェクトのためにセットアップする必要はありません。シーングラフを初期化時に作成するために、`GVRContext`からメインのシーン(ルートシーンオブジェクト)を取得します。

ルートシーンオブジェクトを取得してシーングラフを作成する:

```java
GVRScene scene = mGVRContext.getMainScene();
```

### シーンオブジェクト

ルートシーンオブジェクトやその他の低レベルシーンオブジェクトにシーンオブジェクトを追加することによってVRワールドのシーングラフのシーンオブジェクトツリーを構築します。

最も共通な方法はGearVRf wrapped Assimpライブラリーを使用してメッシュデータを読み込むことです。Assimpはたくさんの3Dファイルフォーマットを読み込むことができます。メッシュオブジェクトが作られた後は、それはシーンオブジェクトに結び付けられるか、シーンオブジェクトのレンダラーに追加されるべきです。

通常は、各テクスチャーをファイルから読み込んで、それぞれのテクスチャーをマテリアルに追加します。

マテリアルの管理とは、シェーダープログラムを割当てとテクスチャーの追加、そしてシーンオブジェクトへのマテリアルの追加です。シェーダープログラムは頂点シェーダー(vertex shader)とフラグメントシェーダー(fragment shader)で構成されます。アプリケーションで利用可能な7個の事前定義されたシェーダーと2個の事前定義されたポストエフェクトシェーダーがあります。アプリケーションは単純にこのうち一つをマテリアルシェーダータイプに設定するだけです。共通の事前定義されたシェーダーはunlit shaderです。

ファイルから読み込んだテクスチャーとメッシュからシーンオブジェクトを作成する:

```java
// assimpでメッシュを読み込む
GVRMesh sphereMesh = mGVRContext.loadMesh("sphere.obj");

// 事前されたシーンオブジェクトを作成する: テクスチャーメッシュオブジェクト
GVRSceneObject bumpySphere = new GVRTextureMeshObject(mGVRContext, sphereMesh, mGVRContext.loadTexture("bumpyTexture.png"));
```

レンダーデータからシェーダーのみのマテリアルのシーンオブジェクトを作成する:

```java
// メッシュオブジェクトを読み込み
GVRMesh sphereMesh = gvrContext.loadMesh("sphere.obj");

// マテリアルを取得
GVRMaterial sphereMaterial = new GVRMaterial(gvrContext, mScreenShader.getShaderId());

// レンダーデータを作成
GVRRenderData sphereRenderData = new GVRRenderData(gvrContext);

// レンダーデータにマテリアルとメッシュを設定
sphereRenderData.setMesh(sphereMesh);
sphereRenderData.setMaterial(sphereMaterial);

// シーンオブジェクトを作成
sphereObject = new GVRSceneObject(gvrContext);
sphereObject.attachRenderData(sphereRenderData);
```

### シーングラフのTransformsを管理する

シーンオブジェクトがシーングラフに追加された後は、各シーンオブジェクトはtransformsにより制御されます。

シーンオブジェクトの位置を設定して、中心点を指定した回転をする:

```java
GVRSceneObject rotator = new GVRTextureBoardObject(mGVRContext, 2.0f, 1.0f, rotatorTextures.get(i));
rotator.getTransform().setPosition(0.0f, 0.0f, -5.0f);
float degree = 360.0f * i / (rotatorTextures.size() + 1);
rotator.getTransform().rotateByAxisWithPivot(degree, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f);
```

## レンダリング

不透明なシーンオブジェクトは後ろから前の順に描画されます。透明なオブジェクトは前から後ろの順に描画されます。レンダラーは自動的にシーンオブジェクトデータを並び替えます。しかし、アプリケーションはレンダリング順序を指定することができます(低いrender value を最初)。標準的な定数は下に表示します。しかし、いかなる整数値でも可能です。

| レンダータイプ = Render value | レンダー順
| --- | ---
| Background = 1000 | First
| Geometry = 2000 | Second
| Transparent = 3000 | Third
| Overlay = 4000 | Last

スタートアップコードがシーングラフを構築した後、GearVRfはイベントループに入ります。フレーム毎にGearVRfは4つのステップから構成されるレンダーパイプラインを開始します。最初の3ステップはあなたのJavaコールバックをGLスレッドで呼び出します。最後のステップはGearVRfによって管理されます。.

1. GearVRfは全ての一度のみ実行のキューに追加された`Runnable`を実行します。
キューオペレーションはスレッドセーフです。`GVRContext.runOnGlThread()`メソッドをGUIやバックグラウンドのスレッドから呼び出せます。`Activity.runOnUiThread()`を非GUIスレッドから呼び出すのと同じように使えます。ただし、`runOnGlThread()`はGLスレッドから呼び出された場合でも常に`Runnable`をキューに入れます。

2. GearVRfはフレームリスナーを実行します。
GearVRfはアニメーションと定期実行のエンジンを含んでいます。それらはフレームリスナーを使用して時間ベースの処理をGLスレッドで実行します。フレームリスナーを直接追加することもできます。フレームリスナーは最後のフレームからどれだけの時間が経過したかをパラメーターで受け取る`Runnable`のようなものです。アニメーションは停止するまで毎フレーム実行され、シーンオブジェクトをある状態から別の状態まで変化させます。定期的なコールバックは通常の`Runnable`で、特定の時間(もしくは時間の範囲)に`runOnGlThread()`で呼び出されます。アニメーションのon-finishコールバックを使うことで、あるアニメーションの後に実行させたいアニメーションを続けて実行させることができます。それぞれのアニメーションを同時に開始することもできます。

3. GearVRfは`onStep()`コールバックを実行します。これはAndroidやクラウドのイベントを処理してシーングラフへ変更を加える場所です。多くの場合、アニメーションは一つのシーンオブジェクトのプロパティを変更し、`onStep()`はシーングラフそのものを変更します。もちろん、`onStep()`でアニメーションを行うこともできます。

4. GearVRfは両目用に2回シーングラフをレンダリングします。

  1. レンダラーはカメラに何が映るかを決定し、それぞれの三角形をGPUメモリに描画します。

  2. 全てのポストエフェクトはステップ4-1の時に登録された順に適用されます。(通常は、同じエフェクトを両目に適用しますが、両目それぞれのデバッグ情報を出力する時等、異なるエフェクトをそれぞれの目に適用することもできます) 
ポストエフェクトはシーンオブジェクトの表面を描画するシェーダーとほとんど似ています。大きな違いは、マテリアルシェーダーの頂点シェーダー(vertex shader)はとても複雑になりうることです(光源や反射のため)。ポストエフェクトは2Dエフェクトで、全ての動作はそれぞれのピクセルを描画するフラグメントシェーダー(fragment shader)の中です。GearVRfは事前定義されたポストエフェクトシェーダーを含んでいます。自分で作ったものを追加するのも簡単です。

  3. 最後にバレルディストーションがレンダーバッファーに適用され、描画されます。ユーザーが魚眼レンズを通して見た時に歪みのない映像がほとんど視界を覆います。このステップは起動時にスクリーンサイズ情報をXMLで提供できることを除いてプログラマブルではありません。