ナビゲーション・メッシュの追加方法
ナビゲーション・メッシュは、ポイント・アンド・クリックのタッチ入力を使って、キャラクター( エージェント)がARシーンをナビゲートすることを可能にする。
前提条件
Lightship ARとLightship Meshingを有効にしたUnityプロジェクトが必要です。 詳細については、ARDK 3.0のインストールおよびメッシュの作成方法を参照してください:物理演算の追加」を参照してください。
また、Unity GameObject
と AR Mesh Manager および Lightship Meshing Extension コンポネントが必要です。 詳しくは、 メッシュの作成のセクション1の手順に従ってください。
このチュートリアルを始める前に、あなたのシーンがこの画像のようなメッシュを生成していることを確認してください。 その後、プレハブのシェーダーを変更してメッシュを不可視にし、このガイドに従ってナビゲーションの追加を開始します。
Navigation Mesh Managerの追加
LightshipNavMeshManager
を追加する:
- 空の
GameObject
を作成する。- Hierarchyで、シーンのルートを選択します。
- メインメニューから、GameObjectを選択し、Create Emptyを選択します。
- 名前は NavMeshManager。
- NavMeshManager オブジェクトに
LightshipNavMeshManager
コンポーネントを追加します。- Inspector ウィンドウで、 Add Componentをクリックします。
- 検索窓に「LightshipNavMeshManager」と入力し、選択します。
- メインカメラをコンポーネントに追加します。 これは、マネージャーがメッシュ上の有効なパスをスキャンする中心である。
- LightshipNavMesh を表示したい場合は、
LightshipNavMeshRenderer
コンポーネントを NavMeshManager にも追加してください。 これにより、カメラが動くと LightshipNavMesh が画面上にレンダリングされます。- Inspector ウィンドウで、 Add Component を再度クリックします。
- 今回は、代わりに "LightshipNavMeshRenderer "を検索して選択します。
LightshipNavMeshManager
を Component に追加します。- ナビゲーションメッシュのレンダリングに使用するマテリアルを作成し、コンポーネントに追加します。
NavMesh サンプルプロジェクトの LightshipNavMeshManager
プレハブを追加することもできます。 詳しくは、 サンプルプロジェクトをご覧ください。
エディターで再生ボタンを押すと、タイルのグリッドが生成されるのが見えるはずだ。 次に、ナビゲーションメッシュ上を移動できるエージェントを追加します。
LightshipNavMeshManagerの
Scan Rangeを
大きくすることで、カメラの周りに大きなタイルのグリッドを作ることができます。
LightshipNavMeshへのエージェントの追加
LightshipNavMeshをテストするには、シーンにエージェントを追加して、その上 を動き回る必要があります。 NavMeshサンプルプロジェクトには、テストに使用できるAgentプレハブが含まれていますが、代わりに自分で作成することもできます。
Agent プレハブを作成します:
- エージェントとして動作するオブジェクトをシーンに追加します:
- Hierarchyで、シーンのルートを選択します。
- 右クリックし、Create Emptyを選択。 新しい Empty
TestAgent
に名前を付けます。
LightshipNavMeshAgent
とLightshipNavMeshAgentPathRenderer
コンポーネントを新しいエージェントに追加します。- Hierarchyで、
TestAgent
を選択します。 - Inspector ウィンドウで、 Add Componentをクリックします。 「LightshipNavMeshAgent」を検索し、選択してコンポーネントを追加します。
- Hierarchyで、
LightshipNavMeshAgentPathRenderer
コンポーネントを追加して、 Agent がシーン内で通ることができるパスを表示します。- Inspector ウィンドウで、 Add Componentをクリックし、"LightshipNavMeshAgentPathRenderer" を検索して選択し、コンポーネントを追加します。
LightshipNavMeshAgent
とMaterialプロパティを設定します。
- エージェントを表すキューブを追加します:
- 階層で、
TestAgent
を右クリックし、3D Object にカーソルを合わせる。 この例では、 Cube を 選択して、基本キューブをテスト Agentとして追加します。 - インスペクタの変形ウィンドウで、立方体のスケールを(0.2, 0.2, 0.2)に設定して縮小します。
- Positionを(0, 0.1, 0)に変更し、立方体の底が(0, 0, 0)にくるようにする。
- Box Colliderの隣のチェックボックスをオフにすると、Box Colliderが無効になります。 これにより、キューブエージェントが生成されたメッシュと衝突するのを防ぐことができます。
- 階層で、
- Agent を Assets ウィンドウにドラッグしてプレハブにし、シーンから削除します。
エージェントを制御するスクリプトを作成する
Agentにコントロールスクリプトを追加するには:
- エージェントを制御するためのユーザ入力を管理するスクリプトアセットを作成します。
- Assetsウィンドウの何もない場所で右クリックし、Createにカーソルを合わせてC# Script を選択します。
- 新しいスクリプトの名前
NavMeshHowTo
。
- コードエディターでスクリプトを開く。
- タッチ入力を処理するコードを設定する:
- HandleTouch "という名前のプライベート・メソッドを作成する。
- エディターでは、マウスのクリックを検出するために "Input.MouseDown "を使用します。
- 電話の場合、"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
{
// タッチで何かする
}.
} - スクリーンのタッチポイントを3D座標に変換する
-
スクリプトの先頭にCameraフィールドを追加する:
[SerializeField]
private Camera _camera;[SerializeField]
は、プライベート・プロパティをインスペクタ・ウィンドウで利用できるようにします。
-
:::
-
これはUnityの
カメラ.ScreenPointToRay
関数を使用します。 HandleTouch "内のメソッドを呼び出して、カメラを指すレイを作成する。#if UNITY_EDITOR
Ray ray = _camera.ScreenPointToRay(Input.mousePosition);
#else
Ray ray = _camera.ScreenPointToRay(touch.position);
#endif -
"Physics.Raycast "を使ってレイがメッシュに当たるかどうかをチェックし、結果のポイントを取得します。
{
// タッチで何かする
RaycastHit hit;
if (Physics.Raycast(ray, out hit))
{
// エージェントを誘導するために 3D ポイントを使用する
}.
} -
タッチの3Dポイントを使ってエージェントを誘導する
- 先ほど作成したプレハブからエージェントをインスタンス化する必要があります。
- エージェント・プレハブのクラストップに
LightshipNavMeshAgent
フィールドを追加します:[SerializeField]
private LightshipNavMeshAgent _agentPrefab; - エージェントプレファブの下に、エージェントのインスタンスとして使用するプライベート
LightshipNavMeshAgent
フィールドを追加します:private LightshipNavMeshAgent _agentInstance;
- エージェントインスタンスは、シーン内のエージェントプレファブの特定のオカレンスになります。 プレハブはインスタンスを作成するための青写真として使われるだけだ。
- エージェントがまだ存在しない場合は、ヒットポイントに作成されます。 そうでなければ、
ナブメッシュ
上の新しい目的地をヒットポイントにする。// タッチで何かする
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);
}.
}
-
Updateメソッドに "HandleTouch "メソッドを追加し、スクリプトが毎フレームタッチをチェックするようにする。
void Update()
{
HandleTouch();
}.
1. スクリプトを**NavMeshManagerに**アタッチする。
1. 階層で**NavMeshManager**GameObjectを選択し、**Inspector**ウィンドウで "Add Component "をクリックします。
1. NavMeshHowTo "を検索し、それを選択してコントローラスクリプトをプレハブに追加します。
1. **カメラと** **エージェントプレファブの**プロパティを設定してください。
<img src={navmesh_howto_editor} alt="エディターでのLightship NavMesh Script" width="600px" />
1. これで、キューブをスポーンして**ナビゲーション・メッシュ**上の任意のタイルに向けることができるはずだ。
<div style={{textAlign: 'center'}}>
<img src={navmesh_with_agent_debug} alt="Agent Visualizerを使ったLightship NavMesh" width="400px" />
</div>
1. **ナビメッシュの**ビジュアルをオプションにして、すっきりとした表示にしよう。 `NavMeshHowTo`スクリプトの中で:
1. `LightshipNavMeshManager`にフィールドを追加し、レンダラー コンポーネントへの参照を取得します。
```cs
[SerializeField]
private LightshipNavMeshManager _navmeshManager;
- NavMeshRendererコンポーネントを取得し 、その状態を設定する "SetVisualization "という新しいメソッドを作成する。
public void SetVisualisation(bool isVisualizationOn)
{
//ナビメッシュのレンダリングをオフにする
_navmeshManager.GetComponent<LightshipNavMeshRenderer>().enabled = isVisualizationOn;
if (_agentInstance != null)
{
//任意のエージェントのパスレンダリングをオフにする
_agentInstance.GetComponent<LightshipNavMeshAgentPathRenderer>().enabled = isVisualizationOn;
}.
} - UIボタンまたはスクリプトでこのメソッドを呼び出す。
ここをクリックすると、最終的な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);
}.
}
}
}
}