Unity环境下C#生成圆内中心密边缘疏无重叠随机点方案咨询
圆内非均匀分布无重叠随机点高效生成方案
适配圆形区域的改进泊松圆盘采样(最优方案)
适配圆形区域的泊松采样是存在的,将常规笛卡尔网格替换为极坐标网格即可完全适配圆形边界,同时保留你原有的「中心密度高、边缘密度低」的分布特性,效率远高于暴力检测:
核心实现逻辑:
- 首先确定最小点间距:取值为你UIImage的直径,即
2 * 32 = 64(可根据scale参数换算成生成逻辑内的坐标单位),保证两个点间距大于该值就不会重叠 - 对圆形区域做极坐标网格划分:径向(r方向)每个网格的长度设为
最小间距/√2,角度方向(θ方向)每个网格的弧度值设为最小间距/(r * √2),保证每个网格内最多只能存在1个点 - 候选点生成复用你原有逻辑:直接用
rdm.NextDouble()作为r值不用开平方,保留你需要的非均匀分布特性 - 重叠检测仅需要检查候选点所在网格及周围8个相邻网格的点,不需要遍历所有已生成点,时间复杂度为O(n)
- 用活跃列表维护待扩展的点,避免重复生成无效候选点
轻量替代方案:空间哈希分桶检测
如果不想改动原有生成逻辑,可将暴力遍历替换为空间哈希分桶,同样能大幅提升检测效率:
- 虚拟划分桶的边长等于最小点间距,每个生成的点按坐标存入对应哈希桶
- 新点生成时仅需要检查自身所在桶和周围8个桶内的点,不需要遍历全量点,大部分场景下检测次数比暴力法少90%以上
以下是适配你现有逻辑的空间哈希核心实现示例:
// 最小间距对应32半径UI的直径,可根据scale自行换算 private const float MinDistance = 64f; private Dictionary<(int, int), List<IPoint>> _bucketDict = new(); // 计算点所属的桶坐标 private (int x, int y) GetBucketKey(IPoint point) { int bucketX = Mathf.FloorToInt(point.X / MinDistance); int bucketY = Mathf.FloorToInt(point.Y / MinDistance); return (bucketX, bucketY); } // 重叠检测 private bool CheckOverlap(IPoint newPoint) { var key = GetBucketKey(newPoint); // 仅检查周围9个桶的点,无需遍历全量已生成点 for (int xOffset = -1; xOffset <= 1; xOffset++) { for (int yOffset = -1; yOffset <= 1; yOffset++) { var checkKey = (key.x + xOffset, key.y + yOffset); if (_bucketDict.TryGetValue(checkKey, out var pointsInBucket)) { foreach (var p in pointsInBucket) { // 用平方距离避免开根号运算,进一步提升性能 float disSqr = (p.X - newPoint.X) * (p.X - newPoint.X) + (p.Y - newPoint.Y) * (p.Y - newPoint.Y); if (disSqr < MinDistance * MinDistance) return true; } } } } return false; }
原有代码优化提示
你现有生成逻辑中直接用rdm.NextDouble()作为r值的写法,刚好符合你需要的中心高密度分布特性,不需要修改为Math.Sqrt(rdm.NextDouble())(后者是均匀分布的写法),仅需要把重叠检测逻辑替换为上述两种方案即可。
内容的提问来源于stack exchange,提问作者ACour008
相关产品推荐
相关产品推荐

