本篇使用旧版Unity(2019)的WorldAnchor功能实现将物体锁定于虚拟空间的特定位置,多个物体可分别锁定锚点位置。
官方文档:https://learn.microsoft.com/zh-cn/windows/mixed-reality/develop/unity/spatial-anchors-in-unity?tabs=worldanchor
一、新建空物体挂载脚本WorldAnchorManager
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR.WSA.Persistence;
public class WorldAnchorManager : MonoBehaviour
{
public static WorldAnchorManager Instance;
public bool canChangeAnchor; //控制改变物体锚点的开关
public WorldAnchorStore anchorStore;//保存锚点的库
public string[] ids;
void Awake()
{
Instance = this;
//加载世界锚点
WorldAnchorStore.GetAsync(StoreLoaded);
}
private void StoreLoaded(WorldAnchorStore store)
{
//读取所有已保存的空间锚
anchorStore = store;
ids = anchorStore.GetAllIds();
}
public void ChangeAnchor()
{
canChangeAnchor = !canChangeAnchor;
}
}
二、在物体上添加组件WorldAnchor
三、在物体上添加WorldAnchorTest
将RemoveAnchor和AddAnchor方法注册到物体MRTK的操作脚本上
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.XR.WSA;
public class WorldAnchorTest : MonoBehaviour
{
void Start()
{
Invoke("LoadAnchor", .1f);
}
void LoadAnchor()
{
if (WorldAnchorManager.Instance.ids.Contains(transform.name))
{
WorldAnchorManager.Instance.anchorStore.Load(transform.name, gameObject);
}
}
/// <summary>
/// 添加世界锚点
/// </summary>
public void AddAnchor()
{
if (!WorldAnchorManager.Instance.canChangeAnchor)
{
return;
}
Debug.Log("添加锚点");
if (WorldAnchorManager.Instance.anchorStore == null)
{
return;
}
WorldAnchor anchor = gameObject.AddComponent<WorldAnchor>();
if (anchor.isLocated)
{
WorldAnchorManager.Instance.anchorStore.Save(transform.name, anchor);
}
else
{
anchor.OnTrackingChanged += Anchor_OnTrackingChanged;
}
}
void Anchor_OnTrackingChanged(WorldAnchor self, bool located)
{
if (located)
{
WorldAnchorManager.Instance.anchorStore.Save(transform.name, self);
//取消事件监听
self.OnTrackingChanged -= Anchor_OnTrackingChanged;
}
}
/// <summary>
/// 删除世界锚点
/// </summary>
public void RemoveAnchor()
{
if (!WorldAnchorManager.Instance.canChangeAnchor)
{
return;
}
Debug.Log("删除锚点");
DestroyImmediate(gameObject.GetComponent<WorldAnchor>());
if (WorldAnchorManager.Instance.anchorStore.GetAllIds().Contains(transform.name))
{
WorldAnchorManager.Instance.anchorStore.Delete(transform.name);
}
}
}
四、结语
这样就可以通过操作bool值canChangeAnchor的开关来控制是否可以移动物体添加锚点(因为有WorldAnchor存在时,物体是不可以进行操作的)。
当canChangeAnchor为flase时不可以移动操作物体(将物体锁定在场景中的某个位置)。
当canChangeAnchor为true时可以移动操作物体,并在操作结束后改变锚点的位置。