您最多选择25个主题 主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

214 行
8.1 KiB

using System;
using System.Collections.Generic;
#if UNITY_EDITOR
using UnityEditor;
#endif
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.XR.ARSubsystems;
using UnityEngine.XR.ARFoundation;
namespace UnityEngine.XR.ARFoundation.Samples
{
/// <summary>
/// This component listens for images detected by the <c>XRImageTrackingSubsystem</c>
/// and overlays some information as well as the source Texture2D on top of the
/// detected image.
/// </summary>
[RequireComponent(typeof(ARTrackedImageManager))]
public class MultiTrackedImageInfoManager : MonoBehaviour, ISerializationCallbackReceiver
{
/// <summary>
/// Used to associate an `XRReferenceImage` with a Prefab by using the `XRReferenceImage`'s guid as a unique identifier for a particular reference image.
/// </summary>
[Serializable]
struct NamedPrefab
{
// System.Guid isn't serializable, so we store the Guid as a string. At runtime, this is converted back to a System.Guid
public string imageGuid;
public GameObject imagePrefab;
public NamedPrefab(Guid guid, GameObject prefab)
{
imageGuid = guid.ToString();
imagePrefab = prefab;
}
}
[SerializeField]
[HideInInspector]
List<NamedPrefab> m_PrefabsList = new List<NamedPrefab>();
Dictionary<Guid, GameObject> m_PrefabsDictionary = new Dictionary<Guid, GameObject>();
Dictionary<Guid, GameObject> m_Instantiated = new Dictionary<Guid, GameObject>();
ARTrackedImageManager m_TrackedImageManager;
[SerializeField]
[Tooltip("Reference Image Library")]
XRReferenceImageLibrary m_ImageLibrary;
/// <summary>
/// Get the <c>XRReferenceImageLibrary</c>
/// </summary>
public XRReferenceImageLibrary imageLibrary
{
get => m_ImageLibrary;
set => m_ImageLibrary = value;
}
public void OnBeforeSerialize()
{
m_PrefabsList.Clear();
foreach (var kvp in m_PrefabsDictionary)
{
m_PrefabsList.Add(new NamedPrefab(kvp.Key, kvp.Value));
}
}
public void OnAfterDeserialize()
{
m_PrefabsDictionary = new Dictionary<Guid, GameObject>();
foreach (var entry in m_PrefabsList)
{
m_PrefabsDictionary.Add(Guid.Parse(entry.imageGuid), entry.imagePrefab);
}
}
void Awake()
{
m_TrackedImageManager = GetComponent<ARTrackedImageManager>();
}
void OnEnable()
{
m_TrackedImageManager.trackedImagesChanged += OnTrackedImagesChanged;
}
void OnDisable()
{
m_TrackedImageManager.trackedImagesChanged -= OnTrackedImagesChanged;
}
void OnTrackedImagesChanged(ARTrackedImagesChangedEventArgs eventArgs)
{
foreach (var trackedImage in eventArgs.added)
{
// Give the initial image a reasonable default scale
var minLocalScalar = Mathf.Min(trackedImage.size.x, trackedImage.size.y) / 2;
trackedImage.transform.localScale = new Vector3(minLocalScalar, minLocalScalar, minLocalScalar);
AssignPrefab(trackedImage);
}
}
void AssignPrefab(ARTrackedImage trackedImage)
{
if (m_PrefabsDictionary.TryGetValue(trackedImage.referenceImage.guid, out GameObject prefab))
m_Instantiated.Add(trackedImage.referenceImage.guid, Instantiate(prefab, trackedImage.transform));
}
public GameObject GetPrefabForReferenceImage(XRReferenceImage referenceImage)
=> m_PrefabsDictionary.TryGetValue(referenceImage.guid, out var prefab) ? prefab : null;
public void SetPrefabForReferenceImage(XRReferenceImage referenceImage, GameObject alternativePrefab)
{
m_PrefabsDictionary[referenceImage.guid] = alternativePrefab;
if (m_Instantiated.TryGetValue(referenceImage.guid, out GameObject instantiatedPrefab))
{
m_Instantiated[referenceImage.guid] = Instantiate(alternativePrefab, instantiatedPrefab.transform.parent);
Destroy(instantiatedPrefab);
}
}
#if UNITY_EDITOR
[CustomEditor(typeof(MultiTrackedImageInfoManager))]
class MultiTrackedImageInfoManagerInspector : Editor
{
List<XRReferenceImage> m_ReferenceImages = new List<XRReferenceImage>();
bool m_IsExpanded = true;
bool HasLibraryChanged(XRReferenceImageLibrary library)
{
if (library == null)
return m_ReferenceImages.Count == 0;
if (m_ReferenceImages.Count != library.count)
return true;
for (int i = 0; i < library.count; i++)
{
if (m_ReferenceImages[i] != library[i])
return true;
}
return false;
}
public override void OnInspectorGUI ()
{
//customized inspector
var behaviour = serializedObject.targetObject as MultiTrackedImageInfoManager;
serializedObject.Update();
using (new EditorGUI.DisabledScope(true))
{
EditorGUILayout.PropertyField(serializedObject.FindProperty("m_Script"));
}
var libraryProperty = serializedObject.FindProperty(nameof(m_ImageLibrary));
EditorGUILayout.PropertyField(libraryProperty);
var library = libraryProperty.objectReferenceValue as XRReferenceImageLibrary;
//check library changes
if (HasLibraryChanged(library))
{
if (library)
{
var tempDictionary = new Dictionary<Guid, GameObject>();
foreach (var referenceImage in library)
{
tempDictionary.Add(referenceImage.guid, behaviour.GetPrefabForReferenceImage(referenceImage));
}
behaviour.m_PrefabsDictionary = tempDictionary;
}
}
// update current
m_ReferenceImages.Clear();
if (library)
{
foreach (var referenceImage in library)
{
m_ReferenceImages.Add(referenceImage);
}
}
//show prefab list
m_IsExpanded = EditorGUILayout.Foldout(m_IsExpanded, "Prefab List");
if (m_IsExpanded)
{
using (new EditorGUI.IndentLevelScope())
{
EditorGUI.BeginChangeCheck();
var tempDictionary = new Dictionary<Guid, GameObject>();
foreach (var image in library)
{
var prefab = (GameObject)EditorGUILayout.ObjectField(image.name, behaviour.m_PrefabsDictionary[image.guid], typeof(GameObject), false);
tempDictionary.Add(image.guid, prefab);
}
if (EditorGUI.EndChangeCheck())
{
Undo.RecordObject(target, "Update Prefab");
behaviour.m_PrefabsDictionary = tempDictionary;
EditorUtility.SetDirty(target);
}
}
}
serializedObject.ApplyModifiedProperties();
}
}
#endif
}
}