本文へスキップ

ナビゲーション・メッシュの追加方法

ナビゲーション・メッシュは、ポイント・アンド・クリックのタッチ入力を使って、キャラクター( エージェント)がARシーンをナビゲートすることを可能にする。

Dotyを使ったLightship NavMesh

前提条件

Lightship ARとLightship Meshingを有効にしたUnityプロジェクトが必要です。 詳細については、ARDK 3.0のインストールおよびメッシュの作成方法を参照してください:物理演算の追加」を参照してください。

また、Unity GameObjectAR Mesh Manager および Lightship Meshing Extension コンポネントが必要です。 詳しくは、 メッシュの作成のセクション1の手順に従ってください。

このチュートリアルを始める前に、あなたのシーンがこの画像のようなメッシュを生成していることを確認してください。 その後、プレハブのシェーダーを変更してメッシュを不可視にし、このガイドに従ってナビゲーションの追加を開始します。

Lightship NavMesh Visual

LightshipNavMeshManagerを追加する:

  1. 空の GameObjectを作成する。
    1. Hierarchyで、シーンのルートを選択します。
    2. メインメニューから、GameObjectを選択し、Create Emptyを選択します。
    3. 名前は NavMeshManager
  2. NavMeshManager オブジェクトに LightshipNavMeshManager コンポーネントを追加します。
    1. Inspector ウィンドウで、 Add Componentをクリックします。
    2. 検索窓に「LightshipNavMeshManager」と入力し、選択します。
    3. メインカメラをコンポーネントに追加します。 これは、マネージャーがメッシュ上の有効なパスをスキャンする中心である。
  3. LightshipNavMesh を表示したい場合は、 LightshipNavMeshRenderer コンポーネントを NavMeshManager にも追加してください。 これにより、カメラが動くと LightshipNavMesh が画面上にレンダリングされます。
    1. Inspector ウィンドウで、 Add Component を再度クリックします。
    2. 今回は、代わりに "LightshipNavMeshRenderer "を検索して選択します。
    3. LightshipNavMeshManagerを Component に追加します。
    4. ナビゲーションメッシュのレンダリングに使用するマテリアルを作成し、コンポーネントに追加します。
Lightship NavMesh Manager

NavMesh サンプルプロジェクトの LightshipNavMeshManager プレハブを追加することもできます。 詳しくは、 サンプルプロジェクトをご覧ください。

エディターで再生ボタンを押すと、タイルのグリッドが生成されるのが見えるはずだ。 次に、ナビゲーションメッシュ上を移動できるエージェントを追加します。

Lightship NavMesh Visual
インフォメーション

LightshipNavMeshManagerの Scan Rangeを大きくすることで、カメラの周りに大きなタイルのグリッドを作ることができます。

LightshipNavMeshへのエージェントの追加

LightshipNavMeshをテストするには、シーンにエージェントを追加して、その上を動き回る必要があります。 NavMeshサンプルプロジェクトには、テストに使用できるAgentプレハブが含まれていますが、代わりに自分で作成することもできます。

Agent プレハブを作成します:

  1. エージェントとして動作するオブジェクトをシーンに追加します:
    1. Hierarchyで、シーンのルートを選択します。
    2. 右クリックし、Create Emptyを選択。 新しい EmptyTestAgent に名前を付けます。
  2. LightshipNavMeshAgentLightshipNavMeshAgentPathRendererコンポーネントを新しいエージェントに追加します。
    1. Hierarchyで、 TestAgentを選択します。
    2. Inspector ウィンドウで、 Add Componentをクリックします。 「LightshipNavMeshAgent」を検索し、選択してコンポーネントを追加します。
  3. LightshipNavMeshAgentPathRenderer コンポーネントを追加して、 Agent がシーン内で通ることができるパスを表示します。
    1. Inspector ウィンドウで、 Add Componentをクリックし、"LightshipNavMeshAgentPathRenderer" を検索して選択し、コンポーネントを追加します。
    2. LightshipNavMeshAgentMaterialプロパティを設定します。
  4. エージェントを表すキューブを追加します:
    1. 階層でTestAgent を右クリックし、3D Object にカーソルを合わせる。 この例では、 Cube を選択して、基本キューブをテスト Agentとして追加します。
    2. インスペクタ変形ウィンドウで、立方体のスケールを(0.2, 0.2, 0.2)に設定して縮小します。
    3. Positionを(0, 0.1, 0)に変更し、立方体の底が(0, 0, 0)にくるようにする。
    4. Box Colliderの隣のチェックボックスをオフにすると、Box Colliderが無効になります。 これにより、キューブエージェントが生成されたメッシュと衝突するのを防ぐことができます。
3Dキューブ・エディタのプロパティ
  1. AgentAssets ウィンドウにドラッグしてプレハブにし、シーンから削除します。
LightshipNavMesh Agent

エージェントを制御するスクリプトを作成する

Agentにコントロールスクリプトを追加するには:

  1. エージェントを制御するためのユーザ入力を管理するスクリプトアセットを作成します。

    1. Assetsウィンドウの何もない場所で右クリックし、Createにカーソルを合わせてC# Script を選択します。
    2. 新しいスクリプトの名前 NavMeshHowTo
  2. コードエディターでスクリプトを開く。

  3. タッチ入力を処理するコードを設定する:

    1. HandleTouch "という名前のプライベート・メソッドを作成する。
    2. エディターでは、マウスのクリックを検出するために "Input.MouseDown "を使用します。
    3. 電話の場合、"Input.GetTouch"
    private void HandleTouch()
    {
    // エディターではマウスクリックを使い、電話ではタッチを使いたい。
    #if UNITY_EDITOR
    if (Input.GetMouseButtonDown(0) || Input.GetMouseButtonDown(1) || Input.GetMouseButtonDown(2))
    #else
    //タッチがないか、タッチでUI要素が選択された場合
    if (Input.touchCount <= 0)
    return;
    var touch = Input.GetTouch(0);

    // 始まったばかりのタッチのみをカウント
    if (touch.phase == UnityEngine.TouchPhase.Began)
    #endif
    {
    // タッチで何かする
    }.
    }
  4. スクリーンのタッチポイントを3D座標に変換する

    1. スクリプトの先頭にCameraフィールドを追加する:

    ```cs
    [SerializeField]
    private Camera _camera;
    ```

    :::note `[SerializeField]`は、プライベート・プロパティをインスペクタ・ウィンドウで利用できるようにします。

    :::

    1. これはUnityの [`カメラ.ScreenPointToRay`](https://docs.unity3d.com/ScriptReference/Camera.ScreenToWorldPoint.html)関数を使用します。 HandleTouch "内のメソッドを呼び出して、カメラを指すレイを作成する。

    ```cs
    #if UNITY_EDITOR
    Ray ray = _camera.ScreenPointToRay(Input.mousePosition);
    #else
    Ray ray = _camera.ScreenPointToRay(touch.position);
    #endif
    ```
    1. "Physics.Raycast "を使ってレイがメッシュに当たるかどうかをチェックし、結果のポイントを取得します。
    ```cs
    {
    // タッチで何かする
    RaycastHit hit;
    if (Physics.Raycast(ray, out hit))
    {
    // エージェントを誘導するために 3D ポイントを使用する
    }.
    }
    ```
  5. タッチの3Dポイントを使ってエージェントを誘導する

    1. 先ほど作成したプレハブからエージェントをインスタンス化する必要があります。
    2. エージェント・プレハブのクラストップにLightshipNavMeshAgentフィールドを追加します:
      [SerializeField]
      private LightshipNavMeshAgent _agentPrefab;
    3. エージェントプレファブの下に、エージェントのインスタンスとして使用するプライベートLightshipNavMeshAgentフィールドを追加します:
      private LightshipNavMeshAgent _agentInstance;
    4. エージェントインスタンスは、シーン内のエージェントプレファブの特定のオカレンスになります。 プレハブはインスタンスを作成するための青写真として使われるだけだ。
    5. エージェントがまだ存在しない場合は、ヒットポイントに作成されます。 そうでなければ、ナブメッシュ上の新しい目的地をヒットポイントにする。
      // タッチで何かする
      RaycastHit hit;
      if (Physics.Raycast(ray, out hit))
      {
      // エージェントを誘導するために3Dポイントを使用する
      if (_creature == null )
      {
      _creature = Instantiate(_agentPrefab);
      _creature.transform.position = hit.point;
      }
      else
      {
      _agent.SetDestination(hit.point);
      }.
      }
  6. Updateメソッドに "HandleTouch "メソッドを追加し、スクリプトが毎フレームタッチをチェックするようにする。

    ```cs
    void Update()
    {
    HandleTouch();

    }.

    ```
  7. スクリプトをNavMeshManagerにアタッチする。

    1. 階層でNavMeshManagerGameObjectを選択し、Inspectorウィンドウで "Add Component "をクリックします。
    2. NavMeshHowTo "を検索し、それを選択してコントローラスクリプトをプレハブに追加します。
    3. カメラと エージェントプレファブのプロパティを設定してください。
    エディターでのLightship NavMesh Script
  8. これで、キューブをスポーンしてナビゲーション・メッシュ上の任意のタイルに向けることができるはずだ。

    Agent Visualizerを使ったLightship NavMesh
  9. ナビメッシュのビジュアルをオプションにして、すっきりとした表示にしよう。 NavMeshHowToスクリプトの中で:

    1. LightshipNavMeshManagerにフィールドを追加し、レンダラー コンポーネントへの参照を取得します。

      [SerializeField]
      private LightshipNavMeshManager _navmeshManager;
    2. NavMeshRendererコンポーネントを取得し、その状態を設定する "SetVisualization "という新しいメソッドを作成する。

      public void SetVisualisation(bool isVisualizationOn)
      {
      //ナビメッシュのレンダリングをオフにする
      _navmeshManager.GetComponent<LightshipNavMeshRenderer>().enabled = isVisualizationOn;

      if (_agentInstance != null)
      {
      //任意のエージェントのパスレンダリングをオフにする
      _agentInstance.GetComponent<LightshipNavMeshAgentPathRenderer>().enabled = isVisualizationOn;
      }.
      }
    3. UIボタンまたはスクリプトでこのメソッドを呼び出す。

エージェントを使ったLightship NavMesh
ここをクリックすると、最終的なNavMeshHowToスクリプトが表示されます。
using UnityEngine;
using Niantic.Lightship.AR.NavigationMesh;

/// SUMMARY:
/// LightshipNavMeshSample
/// このサンプルでは、LightshipNavMeshを使用してユーザー主導のポイント&クリックナビゲーションを追加する方法を示します。
/// 画面を最初にタッチすると、エージェントのプレハブが配置されます。
/// 場所をタップすると、エージェントはその場所に移動する。
/// トグルボタンは、ナビゲーション・メッシュとパスの表示/非表示を切り替えます。
/// _agentPrefabにLightshipNavMeshAgentがあると仮定します。
/// 独自のエージェント・タイプを書いている場合は、それを入れ替えるか、継承する。
///
public class NavMeshHowTo :MonoBehaviour
{
[SerializeField]
private Camera _camera;

[SerializeField]
private LightshipNavMeshManager _navmeshManager;

[SerializeField]
private LightshipNavMeshAgent _agentPrefab;

private LightshipNavMeshAgent _agentInstance;

void Update()
{
HandleTouch();
}

public void SetVisualization(bool isVisualizationOn)
{
//ナビメッシュのレンダリングをオフにする
_navmeshManager.GetComponent<LightshipNavMeshRenderer>().enabled = isVisualizationOn;

if (_agentInstance != null)
{
//アクティブエージェントのパスレンダリングをオフにする
_agentInstance.GetComponent<LightshipNavMeshAgentPathRenderer>().enabled = isVisualizationOn;
}.
}

private void HandleTouch()
{
//エディタではマウスクリックを使用し、電話ではタッチを使用します。
#if UNITY_EDITOR
if (Input.GetMouseButtonDown(0) || Input.GetMouseButtonDown(1) || Input.GetMouseButtonDown(2))
#else
var touch = Input.GetTouch(0);

//タッチがないか、タッチで UI 要素を選択した場合
if (Input.touchCount <= 0)
return;
if (touch.phase == UnityEngine.TouchPhase.Began)
#endif
{
#if UNITY_EDITOR
Ray ray = _camera.ScreenPointToRay(Input.mousePosition);
#else
Ray ray = _camera.ScreenPointToRay(touch.position);
#endif
//タッチポイントをスクリーン空間から3Dに投影し、それをエージェントへデスティネーションとして渡す
RaycastHit hit;
if (Physics.Raycast(ray, out hit))
{
if (_agentInstance == null )
{
_agentInstance = Instantiate(_agentPrefab);
_agentInstance.transform.position = hit.point;
}
else
{
_agentInstance.SetDestination(hit.point);
}.
}
}
}
}