PICO+Unity MR空间锚点

官方链接:空间锚点 | PICO 开发者平台

注意:该功能只能打包成APK在PICO 4 Ultra上真机运行,无法通过串流或PICO developer center在PC上运行。使用之前要开启视频透视。

Inspector 窗口中的 PXR_Manager (Script) 面板上,勾选 Spatial Anchor 选框,为应用开启空间锚点能力。然后,你可以调用空间锚点相关接口,在应用内实现空间锚点功能。

新建一个空物体名为SpatialAnchor,添加SpatialAnchor组件(指定地方放置物体)、SeethroughManager代码(开启透视)

编写代码SpatialAnchor

cs 复制代码
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Unity.XR.PXR;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.UI;

public class SpatialAnchor : MonoBehaviour
{
    public GameObject prerefAnchor;
    public GameObject anchorPreview;
    public GameObject firePoint;

    public Text textPrompt;
    public Button btnLoadAllAnchors;
    public Button btnClearAllAnchors;
    [SerializeField]
    private InputActionReference rightGrip;

    public Dictionary<ulong, AnchorInfo> anchorList = new Dictionary<ulong, AnchorInfo>();
    // Start is called before the first frame update
    void Start()
    {
        btnLoadAllAnchors.onClick.AddListener(OnBtnPressedLoadAllAnchors);
        btnClearAllAnchors.onClick.AddListener(OnBtnPressedClearAllAnchors);
        StartSpatialAnchorProvider();
    }

    private void OnEnable()
    {
        rightGrip.action.started += OnRightGripPressed;
        rightGrip.action.canceled += OnRightGripReleased;
    }

    private void OnDisable()
    {
        rightGrip.action.started -= OnRightGripPressed;
        rightGrip.action.canceled -= OnRightGripReleased;
    }

    //called on action.started
    private void OnRightGripPressed(InputAction.CallbackContext callback)
    {
        ShowAnchorPreview();
    }

    //called on action.release
    private void OnRightGripReleased(InputAction.CallbackContext callback)
    {
        CreateAnchor();
    }

    private void ShowAnchorPreview()
    {
        //Show anchor
        anchorPreview.SetActive(true);
    }

    private async void StartSpatialAnchorProvider()
    {
        var result0 = await PXR_MixedReality.StartSenseDataProvider(PxrSenseDataProviderType.SpatialAnchor);
        Debug.unityLogger.Log($"StartSenseDataProvider: {result0}");
    }    

    private async void CreateAnchor()
    {
        anchorPreview.SetActive(false);
        //Use Spatial Anchor Api to create anchor
        //This will  trigger AnchorEntityCreatedEvent
        var result1 = await PXR_MixedReality.CreateSpatialAnchorAsync(firePoint.transform.position, firePoint.transform.rotation);
        if (result1.result == PxrResult.SUCCESS)
        {
            GameObject anchorObject = Instantiate(prerefAnchor);
            anchorObject.SetActive(true);
            anchorObject.transform.localScale = new Vector3(0.1f, 0.1f, 0.1f);
            anchorObject.transform.rotation = firePoint.transform.rotation;
            anchorObject.transform.position = firePoint.transform.position;

            AnchorInfo info = anchorObject.GetComponent<AnchorInfo>();

            var result2 = await PXR_MixedReality.PersistSpatialAnchorAsync(result1.anchorHandle);
            if (result2 == PxrResult.SUCCESS)
            {
                info.ShowSaveIcon(true);
            }
            else
            {
                info.ShowSaveIcon(false);
            }
            anchorList.Add(result1.anchorHandle, info); // 添加到锚点列表
        }
    }

    // 异步加载所有锚点
    private async void OnBtnPressedLoadAllAnchors()
    {
        anchorList.Clear();
        var result = await PXR_MixedReality.QuerySpatialAnchorAsync(); // 查询所有空间锚点
        //SetLogInfo("LoadSpatialAnchorAsync:" + result.result.ToString() + result.anchorHandleList.Count); // 记录日志
        if (result.result == PxrResult.SUCCESS) // 成功查询
        {
            int i = 0;
            foreach (var key in result.anchorHandleList) // 遍历锚点句柄
            {
                if (!anchorList.ContainsKey(key)) // 如果锚点列表中不存在该锚点
                {
                    i++;
                    PXR_MixedReality.LocateAnchor(key, out var position, out var orientation);
                    GameObject anchorObject = Instantiate(prerefAnchor);
                    anchorObject.SetActive(true);
                    anchorObject.transform.localScale = new Vector3(0.1f, 0.1f, 0.1f);
                    anchorObject.transform.rotation = orientation;
                    anchorObject.transform.position = position;
                    AnchorInfo anchor = anchorObject.GetComponent<AnchorInfo>(); // 获取锚点组件
                    anchor.SetAnchorHandle(key); // 设置锚点句柄
                    // 定位锚点
                    anchorList.Add(key, anchor); // 添加到锚点列表
                    anchorList[key].ShowSaveIcon(true); // 显示保存图标
                }
                else
                {
                    textPrompt.text = "无法加载:" + i.ToString();
                }
            }
        }
        else
        {
            textPrompt.text = "查询失败...";
        }
    }

    // 异步删除所有锚点
    private async void OnBtnPressedClearAllAnchors()
    {
        List<ulong> keys = anchorList.Keys.ToList();
        for(int i = 0; i < keys.Count; i++)
        {
            ulong key = keys[i];
            await PXR_MixedReality.UnPersistSpatialAnchorAsync(anchorList[key].anchorHandle);

            textPrompt.text = "正在删除..."+i.ToString();
            DestroyImmediate(anchorList[key].gameObject);
        }

        anchorList.Clear();
        textPrompt.text = "删除完成";
    }
}

锚点信息类

cs 复制代码
using System.Collections;
using System.Collections.Generic;
using Unity.XR.PXR;
using UnityEngine;
using UnityEngine.UI;

public class AnchorInfo : MonoBehaviour
{
    public Text text;
    public GameObject savedIcon;

    [HideInInspector]
    public ulong anchorHandle;
    // 设置锚点句柄并更新 UI 显示
    public void SetAnchorHandle(ulong handle)
    {
        anchorHandle = handle;
        text.text = "ID: " + anchorHandle;
    }

    // 显示保存图标
    public void ShowSaveIcon(bool show)
    {
        savedIcon.SetActive(show);
    }

    private void LateUpdate()
    {
        // 尝试定位空间锚点
        var result = PXR_MixedReality.LocateAnchor(anchorHandle, out var position, out var rotation);
        if (result == PxrResult.SUCCESS)
        {
            // 如果成功,更新当前对象的位置和旋转
            transform.position = position;
            transform.rotation = rotation;
        }
    }
}

rightGrip输入赋值

相关推荐
Thomas_YXQ2 小时前
Unity3D 动态骨骼性能优化详解
开发语言·网络·游戏·unity·性能优化·unity3d
Yungoal5 小时前
Unity入门1
unity·游戏引擎
杀死一只知更鸟debug18 小时前
Unity自学之旅04
unity
k56946216619 小时前
失业ing
unity·游戏引擎
橘子遇见BUG21 小时前
Unity Shader学习日记 part5 CG基础
学习·unity·游戏引擎·图形渲染
来恩10032 天前
Unity 学习之旅:从新手到高手的进阶之路
学习·unity·游戏引擎
创世界---2 天前
unity插件Excel转换Proto插件-ExcelToProtobufferTool
unity·excel·exceltoproto·protobuffer
向宇it2 天前
【从零开始入门unity游戏开发之——C#篇46】C#补充知识点——命名参数和可选参数
开发语言·unity·c#·编辑器·游戏引擎
快乐觉主吖3 天前
使用Newtonsoft.Json插件,打包至Windows平台显示不支持
unity·json
ellis19703 天前
详解C#反射(Reflection)
unity·c#