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输入赋值

相关推荐
★YUI★7 小时前
学习游戏制作记录(克隆技能)7.25
学习·游戏·unity·c#
不绝19110 小时前
ARPG开发流程第一章——方法合集
算法·游戏·unity·游戏引擎
玩代码10 小时前
Unity里的加力
开发语言·unity
贵州晓智信息科技11 小时前
Unity 性能优化全攻略
unity·性能优化·游戏引擎
UWA13 小时前
UWA DAY 2025 游戏开发者大会|全议程
游戏·unity·性能优化·游戏开发·uwa·unreal engine
unicrom_深圳市由你创科技14 小时前
Unity 的UI动画调节
ui·unity·游戏引擎
咩咩觉主17 小时前
Unity编辑器拓展 IMGUI与部分Utility知识总结(代码+思维导图)
unity·c#·编辑器·游戏引擎
龚子亦1 天前
【Unity开发】数据存储——XML
xml·unity·游戏引擎·数据存储·游戏开发
write_the_code1 天前
Unity国际版下载链接分享(非c1国内版)
unity·游戏引擎
Bulling_1 天前
unity动态背景制作
unity·游戏引擎