当前位置:   article > 正文

Hololens入门之空间锚与场景保持_空间锚点同步与保持技术

空间锚点同步与保持技术

Hololens入门之空间锚与场景保持

World Anchor(空间锚)提供了一种能够将物体保留在特定位置和旋转状态上的方法。这保证了全息对象的稳定性,同时提供了后续在真实世界中保持全息对象位置的能力。简单地说,你可以为全息物体来添加空间锚点,这样就能在后续步骤中将全息物体准确恢复到它原来的位置。

场景保持是HoloLens全息体验的一个关键特性,当用户离开原场景中时,原场景中全息对象会保持在特定位置,当用户回到原场景时,能够准确还原原场景的全息内容。WorldAnchorStore类是实现此特性的关键API,这保证了用户能够将任何全息对象贴到任何他们想要放置的位置。

WorldAnchorStore能够允许你保持场景中空间锚的位置,为了能够真正保持全息对象,你需要单独使用特定的空间锚来追踪每一个对象。通常创建一个根GameObject并附上空间锚,同时对它的子GameObject也附上具有相对位置偏移的空间锚组件。

本文实现以下功能

移动两个Cube的位置,关闭应用,,然后通过场景保持在下一次启动应用时,能够恢复应用关闭前Cube所处的位置

本文示例在 Hololens入门之凝视 的基础上进行修改开发

1、在Manager中添加GestureManager.cs脚本组件(直接使用HoloToolkit中的GestureManager.cs)


  1. // Copyright (c) Microsoft Corporation. All rights reserved.
  2. // Licensed under the MIT License. See LICENSE in the project root for license information.
  3. using UnityEngine;
  4. using UnityEngine.VR.WSA.Input;
  5. namespace HoloToolkit.Unity
  6. {
  7. /// <summary>
  8. /// GestureManager creates a gesture recognizer and signs up for a tap gesture.
  9. /// When a tap gesture is detected, GestureManager uses GazeManager to find the game object.
  10. /// GestureManager then sends a message to that game object.
  11. /// </summary>
  12. [RequireComponent(typeof(GazeManager))]
  13. public partial class GestureManager : Singleton<GestureManager>
  14. {
  15. /// <summary>
  16. /// Key to press in the editor to select the currently gazed hologram
  17. /// </summary>
  18. public KeyCode EditorSelectKey = KeyCode.Space;
  19. /// <summary>
  20. /// To select even when a hologram is not being gazed at,
  21. /// set the override focused object.
  22. /// If its null, then the gazed at object will be selected.
  23. /// </summary>
  24. public GameObject OverrideFocusedObject
  25. {
  26. get; set;
  27. }
  28. /// <summary>
  29. /// Gets the currently focused object, or null if none.
  30. /// </summary>
  31. public GameObject FocusedObject
  32. {
  33. get { return focusedObject; }
  34. }
  35. private GestureRecognizer gestureRecognizer;
  36. private GameObject focusedObject;
  37. void Start()
  38. {
  39. // Create a new GestureRecognizer. Sign up for tapped events.
  40. gestureRecognizer = new GestureRecognizer();
  41. gestureRecognizer.SetRecognizableGestures(GestureSettings.Tap);
  42. gestureRecognizer.TappedEvent += GestureRecognizer_TappedEvent;
  43. // Start looking for gestures.
  44. gestureRecognizer.StartCapturingGestures();
  45. }
  46. private void OnTap()
  47. {
  48. if (focusedObject != null)
  49. {
  50. focusedObject.SendMessage("OnSelect");
  51. }
  52. }
  53. private void GestureRecognizer_TappedEvent(InteractionSourceKind source, int tapCount, Ray headRay)
  54. {
  55. OnTap();
  56. }
  57. void LateUpdate()
  58. {
  59. GameObject oldFocusedObject = focusedObject;
  60. if (GazeManager.Instance.Hit &&
  61. OverrideFocusedObject == null &&
  62. GazeManager.Instance.HitInfo.collider != null)
  63. {
  64. // If gaze hits a hologram, set the focused object to that game object.
  65. // Also if the caller has not decided to override the focused object.
  66. focusedObject = GazeManager.Instance.HitInfo.collider.gameObject;
  67. }
  68. else
  69. {
  70. // If our gaze doesn't hit a hologram, set the focused object to null or override focused object.
  71. focusedObject = OverrideFocusedObject;
  72. }
  73. if (focusedObject != oldFocusedObject)
  74. {
  75. // If the currently focused object doesn't match the old focused object, cancel the current gesture.
  76. // Start looking for new gestures. This is to prevent applying gestures from one hologram to another.
  77. gestureRecognizer.CancelGestures();
  78. gestureRecognizer.StartCapturingGestures();
  79. }
  80. #if UNITY_EDITOR
  81. if (Input.GetMouseButtonDown(1) || Input.GetKeyDown(EditorSelectKey))
  82. {
  83. OnTap();
  84. }
  85. #endif
  86. }
  87. void OnDestroy()
  88. {
  89. gestureRecognizer.StopCapturingGestures();
  90. gestureRecognizer.TappedEvent -= GestureRecognizer_TappedEvent;
  91. }
  92. }
  93. }

2、新增两个Cube GameObject,添加脚本组件CubeScript.cs

CubeScript.cs如下

  1. using UnityEngine;
  2. using System.Collections;
  3. using UnityEngine.VR.WSA.Persistence;
  4. using System;
  5. using UnityEngine.VR.WSA;
  6. public class CubeScript : MonoBehaviour {
  7. public string ObjectAnchorStoreName;
  8. WorldAnchorStore anchorStore;
  9. bool Placing = false;
  10. void Start () {
  11. //获取WorldAnchorStore 对象
  12. WorldAnchorStore.GetAsync(AnchorStoreReady);
  13. }
  14. private void AnchorStoreReady(WorldAnchorStore store)
  15. {
  16. anchorStore = store;
  17. string[] ids = anchorStore.GetAllIds();
  18. //遍历之前保存的空间锚,载入指定id场景对象信息
  19. for (int index = 0; index < ids.Length; index++)
  20. {
  21. if (ids[index] == ObjectAnchorStoreName)
  22. {
  23. WorldAnchor wa = anchorStore.Load(ids[index], gameObject);
  24. break;
  25. }
  26. }
  27. }
  28. // Update is called once per frame
  29. void Update () {
  30. if (Placing)
  31. {
  32. //当Cube处于可移动状态,根据凝视射线的位置,更新Cube的位置
  33. gameObject.transform.position = Camera.main.transform.position + Camera.main.transform.forward * 2;
  34. }
  35. }
  36. void OnSelect()
  37. {
  38. if (anchorStore == null)
  39. {
  40. return;
  41. }
  42. if (Placing)
  43. {
  44. //当再次点击全息对象时,保存空间锚信息
  45. WorldAnchor attachingAnchor = gameObject.AddComponent<WorldAnchor>();
  46. if (attachingAnchor.isLocated)
  47. {
  48. bool saved = anchorStore.Save(ObjectAnchorStoreName, attachingAnchor);
  49. }
  50. else
  51. {
  52. //有时空间锚能够立刻被定位到。这时候,给对象添加空间锚后,空间锚组件的isLocated属性
  53. //值将会被设为true,这时OnTrackingChanged事件将不会被触发。因此,在添加空间锚组件
  54. //后,推荐立刻使用初始的isLocated状态去调用OnTrackingChanged事件
  55. attachingAnchor.OnTrackingChanged += AttachingAnchor_OnTrackingChanged;
  56. }
  57. }
  58. else
  59. {
  60. //当全息对象已附加空间锚组件后,它不能被移动。如果你需要移动全息对象的话,那么你必须这样做:
  61. //1.立刻销毁空间锚组件
  62. //2.移动全息对象
  63. //3.添加一个新的空间锚到全息对象上
  64. WorldAnchor anchor = gameObject.GetComponent<WorldAnchor>();
  65. if (anchor != null)
  66. {
  67. DestroyImmediate(anchor);
  68. }
  69. string[] ids = anchorStore.GetAllIds();
  70. for (int index = 0; index < ids.Length; index++)
  71. {
  72. if (ids[index] == ObjectAnchorStoreName)
  73. {
  74. bool deleted = anchorStore.Delete(ids[index]);
  75. break;
  76. }
  77. }
  78. }
  79. Placing = !Placing;
  80. }
  81. private void AttachingAnchor_OnTrackingChanged(WorldAnchor self, bool located)
  82. {
  83. if (located)
  84. {
  85. bool saved = anchorStore.Save(ObjectAnchorStoreName, self);
  86. self.OnTrackingChanged -= AttachingAnchor_OnTrackingChanged;
  87. }
  88. }
  89. }


3、修改CubeScript中Cube的 ObjectAnchorStoreName(用来作为空间锚的key)

4、运行测试

1) 启动应用,可以看到Cube的初始位置


2) 选中Cube,移动头部,然后再次选中Cube将Cube放置到新的位置


3)关闭应用


4)再次打开应用,能够看到两个Cube所处的位置为关闭应用前的位置,非初始位置






声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/89358
推荐阅读
相关标签
  

闽ICP备14008679号