You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity AR:用GameObject预制体替换ARPlane并支持ARAnchor

解决方案:用ARAnchor绑定3D物体适配ARPlane

原代码的问题在于没关联ARAnchor,也没处理ARPlane的动态更新,而且缩放计算没考虑物体原始尺寸。按下面的步骤改:

  • 给目标ARPlane创建ARAnchor,把3D物体作为Anchor的子物体,这样Anchor会自动追踪平面的位置/旋转变化
  • 基于物体原始尺寸计算缩放,避免缩放失真
  • 订阅ARPlane的更新事件,实时调整3D物体的大小

完整代码示例:

using UnityEngine;
using UnityEngine.XR.ARFoundation;

public class PlaneObjectPlacer : MonoBehaviour
{
    [SerializeField] private ARPlaneManager planeManager;
    [SerializeField] private GameObject objectToPlacePrefab;
    
    private GameObject placedObject;
    private ARAnchor planeAnchor;
    private Vector3 originalObjectScale;

    void Awake()
    {
        // 提前获取预制体的原始尺寸
        if (objectToPlacePrefab != null)
        {
            originalObjectScale = objectToPlacePrefab.transform.localScale;
        }
        
        // 订阅平面检测和更新事件
        planeManager.planesChanged += OnPlanesChanged;
    }

    void OnPlanesChanged(ARPlanesChangedEventArgs args)
    {
        // 处理新检测到的平面
        foreach (var plane in args.added)
        {
            PlaceObjectOnTrackedPlane(plane);
        }
        
        // 处理平面更新(比如扫描范围扩大后尺寸变化)
        foreach (var plane in args.updated)
        {
            if (planeAnchor != null && planeAnchor.plane == plane)
            {
                UpdateObjectScale(plane);
            }
        }
    }

    void PlaceObjectOnTrackedPlane(ARPlane plane)
    {
        // 避免重复创建
        if (placedObject != null) return;

        // 创建绑定到该平面的ARAnchor
        planeAnchor = plane.GetComponent<ARAnchor>();
        if (planeAnchor == null)
        {
            planeAnchor = plane.gameObject.AddComponent<ARAnchor>();
        }

        // 实例化3D物体并设置为Anchor的子物体
        placedObject = Instantiate(objectToPlacePrefab, planeAnchor.transform);
        
        // 初始化位置、旋转和缩放
        placedObject.transform.localPosition = Vector3.zero;
        placedObject.transform.localRotation = Quaternion.identity;
        UpdateObjectScale(plane);
    }

    void UpdateObjectScale(ARPlane plane)
    {
        if (placedObject == null || originalObjectScale == Vector3.zero) return;

        // 根据平面尺寸和物体原始尺寸计算缩放比例
        Vector2 planeSize = plane.size;
        Vector3 scale = new Vector3(
            planeSize.x / originalObjectScale.x,
            1f, // 保持Y轴缩放不变,按需调整
            planeSize.y / originalObjectScale.z
        );
        
        placedObject.transform.localScale = scale;
    }

    void OnDestroy()
    {
        // 取消订阅避免内存泄漏
        if (planeManager != null)
        {
            planeManager.planesChanged -= OnPlanesChanged;
        }
    }
}

关键说明:

  1. ARAnchor绑定:ARAnchor会自动关联到所属的ARPlane,当平面的位置、旋转或大小更新时,Anchor会同步变化,子物体自然跟着更新
  2. 缩放计算:用平面的实际尺寸除以物体的原始尺寸,确保3D物体刚好覆盖平面区域,不会因为物体本身初始尺寸导致缩放错误
  3. 事件订阅:通过planesChanged事件处理新平面和平面更新,保证物体始终适配最新的平面数据
  4. 避免重复创建:加判断确保每个场景只创建一个物体(如果需要多个平面都创建,去掉判断即可)

使用时记得:

  • 把ARPlaneManager组件拖到planeManager字段
  • 把你的3D物体预制体拖到objectToPlacePrefab字段
  • 确保ARSession和ARSessionOrigin已经在场景中

内容的提问来源于stack exchange,提问作者Grandma Kisses

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 10:32:44