Nice to meet you. I am currently trying to apply NavMesh to the spatial mesh obtained by spatial recognition using unity2022.3.52 and MRTK3. I would be grateful for your help.
I’m trying to apply NavMesh using the attached script, but the creation of NavMesh fails.
As I cannot attach files for new users,I will put it in text.
SpatialAwarenessNavMesh.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR.ARFoundation;
using Unity.AI.Navigation;
namespace SpatialAwarenessNavMesh
{
public class SpatialAwarenessNavMesh : MonoBehaviour
{
/// <summary>
/// Value indicating whether or not this script has registered for spatial awareness events.
/// このスクリプトが SpatialAwareness イベントに登録されているかどうかを示す値。
/// </summary>
private bool isRegistered = false;
private ARMeshManager arMeshManager;
private void Start()
{
// AR Mesh Managerの取得
arMeshManager = FindObjectOfType<ARMeshManager>();
RegisterEventHandlers();
}
private void OnEnable()
{
RegisterEventHandlers();
}
private void OnDisable()
{
UnregisterEventHandlers();
}
private void OnDestroy()
{
UnregisterEventHandlers();
}
/// <summary>
/// Registers for the spatial awareness system events.
/// </summary>
private void RegisterEventHandlers()
{
if (!isRegistered && arMeshManager != null)
{
// メッシュの生成イベントをリッスン
arMeshManager.meshesChanged += OnMeshesChanged;
isRegistered = true;
}
}
/// <summary>
/// Unregisters from the spatial awareness system events.
/// </summary>
private void UnregisterEventHandlers()
{
if (isRegistered && arMeshManager != null)
{
arMeshManager.meshesChanged -= OnMeshesChanged;
isRegistered = true;
}
}
private void OnMeshesChanged(ARMeshesChangedEventArgs args)
{
if (args.added != null)
{
foreach (var meshFilter in args.added)
{
// NavMeshSourceTag をオブジェクトに追加
meshFilter.gameObject.AddComponent<NavMeshSourceTag>();
Debug.Log($"Tracking mesh");
}
}
if (args.updated != null)
{
foreach (var meshFilter in args.updated)
{
Debug.Log($"Update mesh");
// NavMeshSourceTag をオブジェクトに追加
NavMeshSourceTag tag = meshFilter.gameObject.GetComponent<NavMeshSourceTag>();
if (tag == null)
{
meshFilter.gameObject.AddComponent<NavMeshSourceTag>();
}
}
}
}
}
}
LocalNavMeshBuilder.cs
using UnityEngine;
using UnityEngine.AI;
using System.Collections;
using System.Collections.Generic;
using NavMeshBuilder = UnityEngine.AI.NavMeshBuilder;
// Build and update a localized navmesh from the sources marked by NavMeshSourceTag
[DefaultExecutionOrder(-102)]
public class LocalNavMeshBuilder : MonoBehaviour
{
// The center of the build
public Transform m_Tracked;
// The size of the build bounds
public Vector3 m_Size = new Vector3(80.0f, 20.0f, 80.0f);
NavMeshData m_NavMesh;
AsyncOperation m_Operation;
NavMeshDataInstance m_Instance;
List<NavMeshBuildSource> m_Sources = new List<NavMeshBuildSource>();
IEnumerator Start()
{
while (true)
{
UpdateNavMesh(true);
yield return m_Operation;
}
}
void OnEnable()
{
// Construct and add navmesh
m_NavMesh = new NavMeshData();
m_Instance = NavMesh.AddNavMeshData(m_NavMesh);
if (m_Tracked == null)
m_Tracked = transform;
UpdateNavMesh(false);
}
void OnDisable()
{
// Unload navmesh and clear handle
m_Instance.Remove();
}
void UpdateNavMesh(bool asyncUpdate = false)
{
NavMeshSourceTag.Collect(ref m_Sources);
var defaultBuildSettings = NavMesh.GetSettingsByID(0);
var bounds = QuantizedBounds();
bool isUpdateNavMesh = false;
if (asyncUpdate)
m_Operation = NavMeshBuilder.UpdateNavMeshDataAsync(m_NavMesh, defaultBuildSettings, m_Sources, bounds);
else
isUpdateNavMesh = NavMeshBuilder.UpdateNavMeshData(m_NavMesh, defaultBuildSettings, m_Sources, bounds);
Debug.Log("UpdateNavMesh:"+ isUpdateNavMesh);
Debug.Log("m_NavMesh:" + m_NavMesh);
Debug.Log("defaultBuildSettings,:" + defaultBuildSettings);
Debug.Log("m_Sources:" + m_Sources);
Debug.Log("bounds:" + bounds);
}
static Vector3 Quantize(Vector3 v, Vector3 quant)
{
float x = quant.x * Mathf.Floor(v.x / quant.x);
float y = quant.y * Mathf.Floor(v.y / quant.y);
float z = quant.z * Mathf.Floor(v.z / quant.z);
return new Vector3(x, y, z);
}
Bounds QuantizedBounds()
{
// Quantize the bounds to update only when theres a 10% change in size
var center = m_Tracked ? m_Tracked.position : transform.position;
return new Bounds(Quantize(center, 0.1f * m_Size), m_Size);
}
void OnDrawGizmosSelected()
{
if (m_NavMesh)
{
Gizmos.color = Color.green;
Gizmos.DrawWireCube(m_NavMesh.sourceBounds.center, m_NavMesh.sourceBounds.size);
}
Gizmos.color = Color.yellow;
var bounds = QuantizedBounds();
Gizmos.DrawWireCube(bounds.center, bounds.size);
Gizmos.color = Color.green;
var center = m_Tracked ? m_Tracked.position : transform.position;
Gizmos.DrawWireCube(center, m_Size);
}
}
NavMeshSourceTag.cs
using UnityEngine;
using UnityEngine.AI;
using System.Collections.Generic;
// Tagging component for use with the LocalNavMeshBuilder
// Supports mesh-filter and terrain - can be extended to physics and/or primitives
[DefaultExecutionOrder(-200)]
public class NavMeshSourceTag : MonoBehaviour
{
// Global containers for all active mesh/terrain tags
public static List<MeshFilter> m_Meshes = new List<MeshFilter>();
public static List<Terrain> m_Terrains = new List<Terrain>();
void OnEnable()
{
var m = GetComponent<MeshFilter>();
if (m != null)
{
m_Meshes.Add(m);
}
var t = GetComponent<Terrain>();
if (t != null)
{
m_Terrains.Add(t);
}
}
void OnDisable()
{
var m = GetComponent<MeshFilter>();
if (m != null)
{
m_Meshes.Remove(m);
}
var t = GetComponent<Terrain>();
if (t != null)
{
m_Terrains.Remove(t);
}
}
// Collect all the navmesh build sources for enabled objects tagged by this component
public static void Collect(ref List<NavMeshBuildSource> sources)
{
sources.Clear();
for (var i = 0; i < m_Meshes.Count; ++i)
{
var mf = m_Meshes[i];
if (mf == null) continue;
var m = mf.sharedMesh;
if (m == null) continue;
var s = new NavMeshBuildSource();
s.shape = NavMeshBuildSourceShape.Mesh;
s.sourceObject = m;
s.transform = mf.transform.localToWorldMatrix;
s.area = 0;
sources.Add(s);
}
for (var i = 0; i < m_Terrains.Count; ++i)
{
var t = m_Terrains[i];
if (t == null) continue;
var s = new NavMeshBuildSource();
s.shape = NavMeshBuildSourceShape.Terrain;
s.sourceObject = t.terrainData;
// Terrain system only supports translation - so we pass translation only to back-end
s.transform = Matrix4x4.TRS(t.transform.position, Quaternion.identity, Vector3.one);
s.area = 0;
sources.Add(s);
}
}
}