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

相关推荐
鹿野素材屋1 小时前
Unity Dots下的动画合批工具:GPU ECS Animation Baker
unity·游戏引擎
小春熙子8 小时前
Unity图形学之着色器之间传递参数
unity·游戏引擎·技术美术·着色器
Java Fans13 小时前
在Unity中实现电梯升降功能的完整指南
unity·游戏引擎
GrimRaider19 小时前
[Unity]TileMap开发,TileMap地图缝隙问题
unity·游戏引擎·tilemap
无敌最俊朗@19 小时前
unity3d——基础篇小项目(开始界面)
unity·游戏引擎
suzh1qian19 小时前
Unity类银河战士恶魔城学习总结(P133 Merge skill tree with Parry skill把技能树和格挡技能相组合)
学习·unity·c#·游戏引擎
泠曦れいひ19 小时前
Unity的反射机制及游戏场景
游戏·unity·游戏引擎
tealcwu19 小时前
【Unity踩坑】在Mac上安装Cocoapods失败
unity·ios·游戏引擎
作孽就得先起床20 小时前
cesium for unity的使用
unity·游戏引擎
白茶等风121381 天前
准备阶段 Profiler性能分析工具的使用(一)
unity·性能优化