Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.

Question Fix game-object at the center of the camera after image recognition even when the user walks

Discussion in 'AR' started by cpoggianti, Apr 19, 2022.

  1. cpoggianti

    cpoggianti

    Joined:
    Mar 8, 2022
    Posts:
    2
    Hi everyone!
    I am making an app with ARFoundation that does image tracking. When the user frames a marker, an object is instantiated on top of the image. However, if I move the tablet and no longer frame the marker, the object remains attached to it and I no longer see it.
    What I would like is: to make the object appear when the marker is recognized but the object should not stick on top of the marker, but should remain central on the screen and if the user walks and moves, the object will follow him.

    I will leave you the image of my ARSession Origin and the code of the script I currently have. How should I modify it?
    Code (CSharp):
    1. using System;
    2. using System.Collections.Generic;
    3. #if UNITY_EDITOR
    4. using UnityEditor;
    5. #endif
    6. using UnityEngine;
    7. using UnityEngine.UI;
    8. using UnityEngine.XR.ARSubsystems;
    9. using UnityEngine.XR.ARFoundation;
    10.  
    11. namespace UnityEngine.XR.ARFoundation.Samples
    12. {
    13.     /// <summary>
    14.     /// This component listens for images detected by the <c>XRImageTrackingSubsystem</c>
    15.     /// and overlays some prefabs on top of the detected image.
    16.     /// </summary>
    17.     [RequireComponent(typeof(ARTrackedImageManager))]
    18.     public class PrefabImagePairManager : MonoBehaviour, ISerializationCallbackReceiver
    19.     {
    20.         /// <summary>
    21.         /// Used to associate an `XRReferenceImage` with a Prefab by using the `XRReferenceImage`'s guid as a unique identifier for a particular reference image.
    22.         /// </summary>
    23.         [Serializable]
    24.         struct NamedPrefab
    25.         {
    26.             // System.Guid isn't serializable, so we store the Guid as a string. At runtime, this is converted back to a System.Guid
    27.             public string imageGuid;
    28.             public GameObject imagePrefab;
    29.  
    30.             public NamedPrefab(Guid guid, GameObject prefab)
    31.             {
    32.                 imageGuid = guid.ToString();
    33.                 imagePrefab = prefab;
    34.             }
    35.         }
    36.  
    37.         [SerializeField]
    38.         [HideInInspector]
    39.         List<NamedPrefab> m_PrefabsList = new List<NamedPrefab>();
    40.  
    41.         Dictionary<Guid, GameObject> m_PrefabsDictionary = new Dictionary<Guid, GameObject>();
    42.         Dictionary<Guid, GameObject> m_Instantiated = new Dictionary<Guid, GameObject>();
    43.         ARTrackedImageManager m_TrackedImageManager;
    44.  
    45.         [SerializeField]
    46.         [Tooltip("Reference Image Library")]
    47.         XRReferenceImageLibrary m_ImageLibrary;
    48.  
    49.         /// <summary>
    50.         /// Get the <c>XRReferenceImageLibrary</c>
    51.         /// </summary>
    52.         public XRReferenceImageLibrary imageLibrary
    53.         {
    54.             get => m_ImageLibrary;
    55.             set => m_ImageLibrary = value;
    56.         }
    57.  
    58.         public void OnBeforeSerialize()
    59.         {
    60.             m_PrefabsList.Clear();
    61.             foreach (var kvp in m_PrefabsDictionary)
    62.             {
    63.                 m_PrefabsList.Add(new NamedPrefab(kvp.Key, kvp.Value));
    64.             }
    65.         }
    66.  
    67.         public void OnAfterDeserialize()
    68.         {
    69.             m_PrefabsDictionary = new Dictionary<Guid, GameObject>();
    70.             foreach (var entry in m_PrefabsList)
    71.             {
    72.                 m_PrefabsDictionary.Add(Guid.Parse(entry.imageGuid), entry.imagePrefab);
    73.             }
    74.         }
    75.  
    76.         void Awake()
    77.         {
    78.             m_TrackedImageManager = GetComponent<ARTrackedImageManager>();
    79.         }
    80.  
    81.         void OnEnable()
    82.         {
    83.             m_TrackedImageManager.trackedImagesChanged += OnTrackedImagesChanged;
    84.         }
    85.  
    86.         void OnDisable()
    87.         {
    88.             m_TrackedImageManager.trackedImagesChanged -= OnTrackedImagesChanged;
    89.         }
    90.  
    91.         void OnTrackedImagesChanged(ARTrackedImagesChangedEventArgs eventArgs)
    92.         {
    93.             foreach (var trackedImage in eventArgs.added)
    94.             {
    95.                 // Give the initial image a reasonable default scale
    96.                 var minLocalScalar = Mathf.Min(trackedImage.size.x, trackedImage.size.y) / 2;
    97.                 trackedImage.transform.localScale = new Vector3(minLocalScalar, minLocalScalar, minLocalScalar);
    98.                 AssignPrefab(trackedImage);
    99.             }
    100.         }
    101.  
    102.         void AssignPrefab(ARTrackedImage trackedImage)
    103.         {
    104.             if (m_PrefabsDictionary.TryGetValue(trackedImage.referenceImage.guid, out var prefab))
    105.                 m_Instantiated[trackedImage.referenceImage.guid] = Instantiate(prefab, trackedImage.transform);
    106.         }
    107.  
    108.         public GameObject GetPrefabForReferenceImage(XRReferenceImage referenceImage)
    109.             => m_PrefabsDictionary.TryGetValue(referenceImage.guid, out var prefab) ? prefab : null;
    110.  
    111.         public void SetPrefabForReferenceImage(XRReferenceImage referenceImage, GameObject alternativePrefab)
    112.         {
    113.             m_PrefabsDictionary[referenceImage.guid] = alternativePrefab;
    114.             if (m_Instantiated.TryGetValue(referenceImage.guid, out var instantiatedPrefab))
    115.             {
    116.                 m_Instantiated[referenceImage.guid] = Instantiate(alternativePrefab, instantiatedPrefab.transform.parent);
    117.                 Destroy(instantiatedPrefab);
    118.             }
    119.         }
    120.  
    121. #if UNITY_EDITOR
    122.         /// <summary>
    123.         /// This customizes the inspector component and updates the prefab list when
    124.         /// the reference image library is changed.
    125.         /// </summary>
    126.         [CustomEditor(typeof(PrefabImagePairManager))]
    127.         class PrefabImagePairManagerInspector : Editor
    128.         {
    129.             List<XRReferenceImage> m_ReferenceImages = new List<XRReferenceImage>();
    130.             bool m_IsExpanded = true;
    131.  
    132.             bool HasLibraryChanged(XRReferenceImageLibrary library)
    133.             {
    134.                 if (library == null)
    135.                     return m_ReferenceImages.Count == 0;
    136.  
    137.                 if (m_ReferenceImages.Count != library.count)
    138.                     return true;
    139.  
    140.                 for (int i = 0; i < library.count; i++)
    141.                 {
    142.                     if (m_ReferenceImages[i] != library[i])
    143.                         return true;
    144.                 }
    145.  
    146.                 return false;
    147.             }
    148.  
    149.             public override void OnInspectorGUI()
    150.             {
    151.                 //customized inspector
    152.                 var behaviour = serializedObject.targetObject as PrefabImagePairManager;
    153.  
    154.                 serializedObject.Update();
    155.                 using (new EditorGUI.DisabledScope(true))
    156.                 {
    157.                     EditorGUILayout.PropertyField(serializedObject.FindProperty("m_Script"));
    158.                 }
    159.  
    160.                 var libraryProperty = serializedObject.FindProperty(nameof(m_ImageLibrary));
    161.                 EditorGUILayout.PropertyField(libraryProperty);
    162.                 var library = libraryProperty.objectReferenceValue as XRReferenceImageLibrary;
    163.  
    164.                 //check library changes
    165.                 if (HasLibraryChanged(library))
    166.                 {
    167.                     if (library)
    168.                     {
    169.                         var tempDictionary = new Dictionary<Guid, GameObject>();
    170.                         foreach (var referenceImage in library)
    171.                         {
    172.                             tempDictionary.Add(referenceImage.guid, behaviour.GetPrefabForReferenceImage(referenceImage));
    173.                         }
    174.                         behaviour.m_PrefabsDictionary = tempDictionary;
    175.                     }
    176.                 }
    177.  
    178.                 // update current
    179.                 m_ReferenceImages.Clear();
    180.                 if (library)
    181.                 {
    182.                     foreach (var referenceImage in library)
    183.                     {
    184.                         m_ReferenceImages.Add(referenceImage);
    185.                     }
    186.                 }
    187.  
    188.                 //show prefab list
    189.                 m_IsExpanded = EditorGUILayout.Foldout(m_IsExpanded, "Prefab List");
    190.                 if (m_IsExpanded)
    191.                 {
    192.                     using (new EditorGUI.IndentLevelScope())
    193.                     {
    194.                         EditorGUI.BeginChangeCheck();
    195.  
    196.                         var tempDictionary = new Dictionary<Guid, GameObject>();
    197.                         foreach (var image in library)
    198.                         {
    199.                             var prefab = (GameObject) EditorGUILayout.ObjectField(image.name, behaviour.m_PrefabsDictionary[image.guid], typeof(GameObject), false);
    200.                             tempDictionary.Add(image.guid, prefab);
    201.                         }
    202.  
    203.                         if (EditorGUI.EndChangeCheck())
    204.                         {
    205.                             Undo.RecordObject(target, "Update Prefab");
    206.                             behaviour.m_PrefabsDictionary = tempDictionary;
    207.                             EditorUtility.SetDirty(target);
    208.                         }
    209.                     }
    210.                 }
    211.  
    212.                 serializedObject.ApplyModifiedProperties();
    213.             }
    214.         }
    215. #endif
    216.     }
    217. }
    218.  
    Schermata 2022-04-19 alle 09.31.22.png
     
  2. andyb-unity

    andyb-unity

    Unity Technologies

    Joined:
    Feb 10, 2022
    Posts:
    525
    If you wish for your content to remain in some position relative to the camera, you should spawn the content GameObject as a child of your
    ARCamera
    GameObject instead of as a child of the image trackable.

    In particular in line 105 of your script I would try using something like
    m_ARCamera.transform
    as the parent argument in the Instantiate call instead of
    trackedImage.transform
    .