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

ARCore:扫描足够空间后通过C#脚本随机生成预制体

如何在ARCore扫描到指定面积地板后随机生成预制体

嘿,这个需求其实很好实现,核心就是先检测扫描到的地板总面积是否达标,再在合格的地板平面范围内随机生成预制体。下面是我整理的分步方案和代码,直接就能用:

1. 核心逻辑拆解

首先得明确ARCore的平面检测机制:ARCore会自动识别平面并分类(比如地板、墙面),我们可以通过ARPlaneManager获取这些平面数据。我们要做的就是:

  • 筛选出所有标记为「地板」的平面
  • 计算它们的总面积,判断是否达到你设定的阈值
  • 一旦达标,就在这些地板的范围内随机生成预制体

2. 完整C#代码实现

第一步:配置基础变量和引用

先创建一个脚本,绑定到场景中的AR Session Origin对象上,然后引用ARCore的核心组件:

using UnityEngine;
using UnityEngine.XR.ARFoundation;
using UnityEngine.XR.ARSubsystems;

public class RandomFloorSpawner : MonoBehaviour
{
    [Header("AR组件引用")]
    public ARPlaneManager planeManager; // 拖拽场景中的AR Plane Manager进来

    [Header("生成参数")]
    public GameObject prefabToSpawn; // 要生成的预制体
    public float requiredFloorArea = 2.5f; // 你需要的最小地板面积(单位:平方米)
    public int spawnAmount = 6; // 生成的预制体数量
    private bool hasCompletedSpawn = false; // 防止重复生成的标记

    void OnEnable()
    {
        // 订阅平面更新事件,每次ARCore更新平面数据时触发检查
        planeManager.planeUpdated += CheckAndSpawn;
    }

    void OnDisable()
    {
        planeManager.planeUpdated -= CheckAndSpawn;
    }
}

第二步:检测地板面积是否达标

添加方法来计算所有地板平面的总面积,判断是否满足要求:

private bool IsFloorAreaEnough()
{
    float totalFloorArea = 0f;

    foreach (var plane in planeManager.trackables)
    {
        // 只统计分类为地板的平面
        if (plane.classification == PlaneClassification.Floor)
        {
            // ARPlane的size属性是平面在X和Z方向的长度,相乘就是面积
            totalFloorArea += plane.size.x * plane.size.z;
        }
    }

    // 打印当前总面积,方便调试(可以删掉)
    Debug.Log($"当前扫描到的地板总面积:{totalFloorArea:F2} 平方米");
    return totalFloorArea >= requiredFloorArea;
}

第三步:在地板上随机生成预制体

当面积达标后,随机选择地板平面,并在平面范围内生成预制体:

private void SpawnRandomPrefabs()
{
    if (hasCompletedSpawn) return;

    // 收集所有地板平面
    var floorPlanes = new System.Collections.Generic.List<ARPlane>();
    foreach (var plane in planeManager.trackables)
    {
        if (plane.classification == PlaneClassification.Floor)
        {
            floorPlanes.Add(plane);
        }
    }

    if (floorPlanes.Count == 0) return;

    for (int i = 0; i < spawnAmount; i++)
    {
        // 随机选一个地板平面
        ARPlane targetPlane = floorPlanes[Random.Range(0, floorPlanes.Count)];

        // 计算平面内的随机局部坐标:X和Z方向在平面的一半范围内随机
        float randomLocalX = Random.Range(-targetPlane.size.x / 2f, targetPlane.size.x / 2f);
        float randomLocalZ = Random.Range(-targetPlane.size.z / 2f, targetPlane.size.z / 2f);

        // 转换为世界空间坐标
        Vector3 spawnPos = targetPlane.transform.TransformPoint(new Vector3(randomLocalX, 0f, randomLocalZ));

        // 让预制体和平面保持同一旋转(可选,根据你的需求调整)
        Quaternion spawnRot = targetPlane.transform.rotation;

        // 生成预制体
        Instantiate(prefabToSpawn, spawnPos, spawnRot);
    }

    hasCompletedSpawn = true;
    // 可选:关闭平面检测,避免后续平面更新干扰
    planeManager.enabled = false;
    // 可选:隐藏所有已检测的平面
    foreach (var plane in planeManager.trackables)
    {
        plane.gameObject.SetActive(false);
    }
}

第四步:关联事件触发逻辑

在之前订阅的CheckAndSpawn方法里,把检测和生成逻辑串起来:

private void CheckAndSpawn(ARPlane plane)
{
    if (IsFloorAreaEnough())
    {
        SpawnRandomPrefabs();
        // 取消订阅事件,避免重复触发
        planeManager.planeUpdated -= CheckAndSpawn;
    }
}

3. 实用优化建议

  • 单平面判断:如果你只需要单个地板平面达到面积(而不是累加),修改IsFloorAreaEnough方法,遍历的时候判断单个平面的面积是否大于等于阈值即可。
  • 位置去重:如果不想让预制体重叠,可以记录已生成的位置,每次生成前判断距离是否足够。
  • 对象池优化:如果生成大量预制体,建议用对象池代替Instantiate,减少GC开销。
  • 调试UI:可以在场景中加一个Text组件,实时显示当前地板总面积,方便调整阈值。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 04:04:42