前回は画面をタップしたところに穴を表示するプログラムを作りました。今回はARのモグラを生成して上下するようにするところまでを作ります。完成イメージはこんな感じです。
関連記事はこちらです。前回はタッチしたところにARで穴を表示するところまでを解説しています。
今回もUnityとARKit Pluginを使ってすすめていきます。
手前味噌ですが・・・Swiftを使ってARKitを学びたい方はこちらの書籍がオススメです
モグラのPrefabを作る
まずはプロジェクトウィンドウからシーンビューにmoleをドラッグします。そのmoleにmoletexをアタッチしてテクスチャを設定しましょう。
今回もモグラのテカリが気になる方は、moletexマテリアルのインスペクタからSmoothnessを「0」に設定してください。
次にモグラを叩いたときの判定をするために、コライダをアタッチしておきます。ヒエラルキーウインドウでmoleを選択した状態で、インスペクタの「Add Component」から「Capsule Collider」を選択してください。
Capsule Colliderがモグラにフィットするようにパラメータを次のように調節してください。
ここまでで、一旦モグラのPrefabを作っておきましょう。ヒエラルキーウインドウからプロジェクトウィンドウにmoleをドラッグ&ドロップしてください。ファイル名はmolePrefabに変更しておきます。
ヒエラルキーウインドウにあるモグラは「右クリック」→「Delete」で消しておきます。
穴の場所にモグラを生成する
今作成したモグラのPrefabを穴の位置に生成するスクリプトを作ります。
プロジェクトウィンドウのHolePlacerスクリプトに、GenerateMolesメソッドとその呼び出し部分のプログラムを追加してください。
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.XR.iOS; public class HolePlacer : MonoBehaviour { bool isGenerated = false; public GameObject holesPrefab; public GameObject molePrefab; public void GenerateMoles(GameObject holes) { foreach (Transform t in holes.transform) { GameObject child = t.gameObject; if(child.tag == "Hole") { Vector3 pos = child.transform.position; Instantiate(molePrefab, pos, molePrefab.transform.rotation); } } } void HitTest(ARPoint point) { List<ARHitTestResult> hitResults = UnityARSessionNativeInterface .GetARSessionNativeInterface() .HitTest(point, ARHitTestResultType.ARHitTestResultTypeExistingPlaneUsingExtent); // 平面とあたっていた場合 if (hitResults.Count > 0) { // 穴を生成する GameObject holes = Instantiate(holesPrefab); holes.transform.position = UnityARMatrixOps.GetPosition(hitResults[0].worldTransform); holes.transform.rotation = UnityARMatrixOps.GetRotation(hitResults[0].worldTransform); // モグラを生成する GenerateMoles(holes); this.isGenerated = true; } } // Update is called once per frame void Update() { if (!isGenerated && Input.touchCount > 0 ) { var touch = Input.GetTouch(0); if (touch.phase == TouchPhase.Began) { var screenPosition = Camera.main.ScreenToViewportPoint(touch.position); ARPoint point = new ARPoint { x = screenPosition.x, y = screenPosition.y }; // 平面との当たり判定 HitTest(point); } } } }
前回のプログラムにGenerateMolesメソッドを追加しています。このメソッドは引数に穴(3つの穴を子要素にもつオブジェクト)のオブジェクトを受け取ります。その子要素を調べて「Hole」というタグを持っていれば、その位置にモグラを生成しています。また、HitTestメソッドの中でこのGenerateMolesメソッドを呼び出しています。
プログラムが追加できたら、GameオブジェクトにアタッチしたHolePlacerスクリプトのMole Prefabの欄にmolePrefabの実体をセットしてください。
ここまでで実行してみましょう。画面をタップすると穴が配置され、その上にモグラが表示されるかを確かめてください。
モグラを動かす
次にモグラが穴から出たり入ったりするようにしましょう。MoleControllerというスクリプトを作成して、次のプログラムを入力して下さい。
using System.Collections; using System.Collections.Generic; using UnityEngine; public class MoleController : MonoBehaviour { Vector3 groundLevel; Vector3 undergroundLevel; public GameObject effect; bool isOnGround = true; float time = 0; void Up() { transform.position = groundLevel; this.isOnGround = true; } void Down() { transform.position = this.undergroundLevel; this.isOnGround = false; } void Start () { this.groundLevel = transform.position; this.undergroundLevel = this.groundLevel - new Vector3(0, 0.2f, 0); // 地中に隠す Down(); } void Update () { this.time += Time.deltaTime; if( this.time > 2.0f ) { this.time = 0; if( this.isOnGround) { Down(); } else { Up(); } } } }
このスクリプトでは、time変数を使って時間をカウントして、2秒ごとにモグラを上下させています。プログラムの分かりやすさを優先して、ここではアニメーションの設定はまだしていません。なのでモグラは地上と地中の間を瞬間移動します。次の記事でDOTweenを使ったアニメーションの方法を紹介します。
作成したMoleControllerスクリプトをモグラのPrefabにドラッグ&ドロップしてアタッチします。
実機にインストールして、モグラが上下するか確認してみましょう。
モグラは上下していますが、穴の下にいるモグラまで見えてしまっていますね。これはARKitが現実世界にあるものとARオブジェクトの前後関係を認識できないのが原因です。この地中のモグラが見えてしまう対策をしていきます。
オクルージョン対策
現実世界にあるものとの前後関係がわからない問題は、昔からARにはつきものの問題です。ARKitではカメラ映像の上にARオブジェクトを強制的にべた書きするため、このように前後関係が崩れてしまいます。
Depthカメラを使えば、画像の奥行きがわかるため、多少の前後判別はできるようになります。ただ、現状ではリアルタイムで計算するにはコストが高く、根本的に解決されたわけではありません。
そこでARKitを使ってオクルージョンを実現するには手動で、オクルージョン用の平面を設定する必要があります。この平面を設定することで、それよりも奥にあるオブジェクトは描画されなくなります。
まずはヒエラルキーウインドウで「Create」→「3D Object」→「Plane」を選択して穴の真下に設定します。
また、今作成した平面をHolesの子要素にしておきます。
次に平面にオクルージョン用のマテリアルを設定します。UnityARKitPlugin/Common/MaterialsにあるocclusionPlaneMaterialを平面にドラッグしてください。これにより、この平面より下にあるオブジェクトは描画されないようになります。
HolesPrefabにも変更を反映するため、ヒエラルキーウインドウでHolesを選んでからインスペクタの「Apply」ボタンを押してください。
オクルージョンに使ったシェーダを少しだけ見ておきましょう。UnityARKitPlugin/Example/Common/Shaders/MobileOcclusion.shaderです。ポイントは次の3行です。
ZWrite On
ZTest LEqual
ColorMask 0
ZWriteをOnにしてデプステストは行いつつ、ColorMaskに0を設定することで描画は行わないようにしています。つまりデプステスト的にはそこにオブジェクトがあるけど、見た目にはなにもないというおばけ状態ですね(笑)
これにより背後のオブジェクトがデプステストにかかって描画されなくなります。シェーダについては次の記事を参照下さい。
実行してみる
オクルージョン用の平面を使用したことで、穴の下にいるモグラは描画されなくなりました。
今回はココまでにしましょう。次回は最終回です。最後の仕上げにモグラのアニメーションとパーティクルの発生、GUIの設定などをしていきますよ!