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

Vector3位置生成方法未满足最小间距要求,求问题排查

问题分析:按平面区域权重生成Vector3时最小间距不达标

我实现了一个按平面区域权重生成指定数量Vector3的方法,要求生成的位置间距不小于设定值,但实例化对象后仍存在间距小于指定值的情况。相关代码如下:

// Generate random point based on plane area
public List<Vector3> GeneratePositions(int numberOfPositions, float minDistanceBetweenPositions)
{
    float entireArea = 0f;
    List<AreasWeight> areasWeights = new List<AreasWeight>();
    List<Vector3> positions = new List<Vector3>();

    foreach (GeneratorPlane plane in GeneratorPlanes.GetCollectionAsList())
    {
        entireArea += plane.GetArea();
    }
    foreach (GeneratorPlane plane in GeneratorPlanes.GetCollectionAsList())
    {
        float weight = plane.GetArea() / entireArea;
        int numOfPositionsInArea = Mathf.RoundToInt(numberOfPositions * weight);
        areasWeights.Add(new(plane, weight, numOfPositionsInArea));
    }

    foreach (AreasWeight areaWeight in areasWeights)
    {
        for (int i = 0; i < areaWeight.NumOfPointsInArea; i++)
        {
            Vector3 generatedPoint = areaWeight.Plane.GetRandomPointOnPlane();

            foreach (Vector3 position in positions)
            {
                int attempts = 1;

                while ((position - generatedPoint).magnitude < minDistanceBetweenPositions)
                {
                    generatedPoint = areaWeight.Plane.GetRandomPointOnPlane();
                    attempts++;

                    if (attempts > 2000)
                    {
                        Debug.Log("Can't generate all positions.");
                        break;
                    }
                }

            }
            positions.Add(generatedPoint);
        }
    }

    return positions;
}

随机点生成方法:

public Vector3 GetRandomPointOnPlane()
{
    float xPosition = Random.Range(Mathf.Min(DownPoint.x, DownPointHelper.x), Mathf.Max(DownPoint.x, DownPointHelper.x));
    float zPosition = Random.Range(Mathf.Min(DownPoint.z, UpPointHelper.z), Mathf.Max(DownPoint.z, UpPointHelper.z));

    return new(xPosition, DownPoint.y + 0.002f, zPosition);
}

错误原因分析

  • 间距检查逻辑漏洞:当前遍历每个已存在点时,仅针对单个点重新生成新坐标,但新生成的坐标只通过了当前单个点的间距校验,没有重新检查所有已存在点。比如新点满足和点A的间距要求,但可能和点B的间距仍不达标,却直接被加入列表。
  • 尝试次数变量作用域错误:attempts变量放在foreach (Vector3 position in positions)循环内部,每次遍历一个已存在点都会重置尝试次数,导致实际总尝试次数被分散,即使累计尝试远超2000次也无法触发终止逻辑,甚至可能生成不符合要求的点。

修正后的代码

// Generate random point based on plane area
public List<Vector3> GeneratePositions(int numberOfPositions, float minDistanceBetweenPositions)
{
    float entireArea = 0f;
    List<AreasWeight> areasWeights = new List<AreasWeight>();
    List<Vector3> positions = new List<Vector3>();

    foreach (GeneratorPlane plane in GeneratorPlanes.GetCollectionAsList())
    {
        entireArea += plane.GetArea();
    }
    foreach (GeneratorPlane plane in GeneratorPlanes.GetCollectionAsList())
    {
        float weight = plane.GetArea() / entireArea;
        int numOfPositionsInArea = Mathf.RoundToInt(numberOfPositions * weight);
        areasWeights.Add(new(plane, weight, numOfPositionsInArea));
    }

    foreach (AreasWeight areaWeight in areasWeights)
    {
        for (int i = 0; i < areaWeight.NumOfPointsInArea; i++)
        {
            Vector3 generatedPoint;
            int attempts = 0;
            bool isPointValid;

            do
            {
                attempts++;
                generatedPoint = areaWeight.Plane.GetRandomPointOnPlane();
                // 校验新点与所有已存在点的间距
                isPointValid = true;
                foreach (Vector3 position in positions)
                {
                    if ((position - generatedPoint).magnitude < minDistanceBetweenPositions)
                    {
                        isPointValid = false;
                        break;
                    }
                }

                if (attempts > 2000)
                {
                    Debug.Log("Can't generate all positions.");
                    break;
                }
            } while (!isPointValid);

            // 仅添加有效点
            if (isPointValid)
            {
                positions.Add(generatedPoint);
            }
            else
            {
                // 无法生成有效点时可选择终止或跳过
                break;
            }
        }
    }

    return positions;
}

额外优化建议

  • 提前校验可行性:先估算所有平面的总可容纳点数(每个点所需最小面积为π*(minDistanceBetweenPositions/2)²),如果需求点数超过可容纳上限,直接提前提示,避免无效尝试。
  • 优化间距检查效率:若生成点数较多,遍历所有点检查间距会降低性能,可使用网格分区、四叉树等数据结构,仅检查同区域或相邻区域的点,提升校验速度。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 01:00:59