泊松盘采样(Poisson Disk Sampling)生成均匀随机点
当需要生成随机点且要求随机点自然均匀的分布时,使用泊松盘采样就较为适合。
但该方法与统计学上的概念关联不大,这个只相当于点在面积上服从泊松分布,
而实现这个结果有很多做法。
最终效果:

圆形为含半径的点,圆形的中心代表生成点
B站有一个不错的搬运教程(Bridson方法):
https://www.bilibili.com/video/BV1KV411x7LM
另外Bridson文章里说蓝噪声(BlueNoise)也基于此方法生成
我做了些修改,代码如下:
using System.Collections;
using System.Collections.Generic;
using UnityEngine; public static class PoissonDiscSampling
{
public static List<Vector3> GeneratePoints(float radius, Vector2 sampleRegionSize, int numSamplesBeforeRejection = 32)
{
bool IsValid(Vector3 candidate, Vector2 sampleRegionSize, float cellSize, float radius, List<Vector3> points, int[,] grid)
{
if (candidate.x - radius >= 0f && candidate.x + radius < sampleRegionSize.x && candidate.z - radius >= 0f && candidate.z + radius < sampleRegionSize.y)
{
int cellX = Mathf.RoundToInt(candidate.x / cellSize);
int cellZ = Mathf.RoundToInt(candidate.z / cellSize);
int searchStartX = Mathf.Max(0, cellX - 3);
int searchEndX = Mathf.Min(cellX + 3, grid.GetLength(0) - 1);
int searchStartZ = Mathf.Max(0, cellZ - 3);
int searchEndZ = Mathf.Min(cellZ + 3, grid.GetLength(1) - 1);
//如果要检测其它格子内的球,需要遍历周围6个格子 for (int x = searchStartX; x <= searchEndX; x++)
{
for (int z = searchStartZ; z <= searchEndZ; z++)
{
int pointIndex = grid[x, z] - 1;//存长度不存索引,取时减1,0就变成了-1,不需要初始化数组了
if (pointIndex != -1)
{
float dst = (candidate - points[pointIndex]).magnitude;
if (dst < radius * 2f)
{
return false;
}
}
}
} return true;
} return false;
} float cellSize = radius / Mathf.Sqrt(2); int[,] grid = new int[Mathf.CeilToInt(sampleRegionSize.x / cellSize), Mathf.CeilToInt(sampleRegionSize.y / cellSize)];
List<Vector3> points = new List<Vector3>();
List<Vector3> spawnPoints = new List<Vector3>(); spawnPoints.Add(new Vector3(sampleRegionSize.x / 2f, 0f, sampleRegionSize.y / 2f));
while (spawnPoints.Count > 0)
{
int spawnIndex = Random.Range(0, spawnPoints.Count);
Vector3 spawnCenter = spawnPoints[spawnIndex]; bool candidateAccepted = false;
for (int i = 0; i < numSamplesBeforeRejection; i++)
{
float angle = Random.value * Mathf.PI * 2f;
Vector3 dir = new Vector3(Mathf.Sin(angle), 0f, Mathf.Cos(angle));
Vector3 candidate = spawnCenter + dir * Random.Range(2f, 3f) * radius; if (IsValid(candidate, sampleRegionSize, cellSize, radius, points, grid))
{
points.Add(candidate);
spawnPoints.Add(candidate);
grid[Mathf.RoundToInt(candidate.x / cellSize), Mathf.RoundToInt(candidate.z / cellSize)] = points.Count;
candidateAccepted = true;
break;
}
}
if (!candidateAccepted)
{
spawnPoints.RemoveAt(spawnIndex);
}
} return points;
}
}
测试代码如下:
using System.Collections.Generic;
using UnityEngine; public class Test : MonoBehaviour
{
public float radius = 0.3f;
public Vector2 sampleRegionSize = new Vector2(3f, 3f);
private List<Vector3> mPoints; private void OnEnable()
{
mPoints = PossonDiscSampling.GeneratePoints(radius, sampleRegionSize);
} private void OnDrawGizmos()
{
if (mPoints == null) return; float cellSize = radius / Mathf.Sqrt(2); Color cacheColor = Gizmos.color;
Gizmos.color = new Color(0.5f, 0.5f, 0.5f, 0.5f);
for (float x = 0; x < sampleRegionSize.x; x += cellSize)
{
for (float z = 0; z < sampleRegionSize.y; z += cellSize)
Gizmos.DrawWireCube(new Vector3(x, 0f, z), new Vector3(cellSize, 0f, cellSize));
}//生成对应采样点的调试方格
Gizmos.color = cacheColor; for (int i = 0; i < mPoints.Count; i++)
{
Vector3 vector = mPoints[i]; Gizmos.DrawWireSphere(vector, radius); int x = Mathf.FloorToInt(vector.x / cellSize);
int z = Mathf.FloorToInt(vector.z / cellSize); Gizmos.DrawWireCube(new Vector3(x, 0f, z) * cellSize, new Vector3(cellSize, 0f, cellSize));
//生成当前点所属方格
}
}
}
对于该做法还可以做如下应用层面的扩展:
1.扩展到3D空间,一些鸟的移动轨迹可以直接用这个做路点寻路
2.可以尝试在UV上分布,然后映射到3D空间
3.可以基于这个做三角剖分(https://www.cnblogs.com/hont/p/15310157.html)
泊松盘采样(Poisson Disk Sampling)生成均匀随机点的更多相关文章
- Golang生成区间随机整数
package main import ( "fmt" "math/rand" "time" ) func main() { rand.Se ...
- C#使用 RNGCryptoServiceProvider 生成强随机字符串
为了生成更加可靠的随机数,微软在System.Security.Cryptography命名空间下提供一个名为system.Security.Cryptography.RNGCryptoService ...
- .NET使用Bogus生成大量随机数据
.NET如何生成大量随机数据 在演示Demo.数据库脱敏.性能测试中,有时需要生成大量随机数据.Bogus就是.NET中优秀的高性能.合理.支持多语言的随机数据生成库. Bogus的Github链接: ...
- .NET使用Bogus生成大量随机数据(转载)
原文地址:https://www.cnblogs.com/sdflysha/p/20190821-generate-lorem-data.html 在演示Demo.数据库脱敏.性能测试中,有时需要生成 ...
- 如何生成均匀随机数 C++
#include <iostream> #include <fstream> #include <cstdlib> #include <ctime> u ...
- Python Random模块生成伪随机数字
This module implements pseudo-random number generators for various distributions. 对于整数,有一个范围的均匀选择: 对 ...
- 【代码实现】PHP生成各种随机验证码
原文地址:http://www.phpthinking.com/archives/531 验证码在WEB应用中很重要,通经常使用来防止用户恶意提交表单,如恶意注冊和登录.论坛恶意灌水等.本文将通过实例 ...
- 按条件生成j随机json包:randomjson
前端开发中,在做前后端分离的时候,经常需要手写json数据,有2个问题特别揪心: 1,数据是写死的,不能按一定的条件随机生成长度不一,内容不一的数据 2,写数组的时候,如果有很多条,需要一条一条地写, ...
- [实例]JAVA生成字母+随机数字并生成文件
package com.ishow.control.code; import java.io.*; import java.text.SimpleDateFormat; import java.uti ...
- Python_生成大量随机信息
#coding=utf-8 import random import string import codecs ''' 演示如何使用Python标准库random来生成随机数据,这在需要 ''' #常 ...
随机推荐
- #网络流,树状数组#JZOJ 4020 Revolution with JZOJ 4018 Magic
CF297E Mystic Carvings=JZOJ 4018 Magic JZOJ 4020 Revolution 题目 有一个\(n*m(n,m\leq 20)\)的网格图 这格子有收益当且仅当 ...
- 中文GPTS详尽教程,字节扣子Coze插件使用全输出
今天,斜杠君和大家分享如何在字节扣子Coze中创建插件,并在创建后如何使用这个插件. 一.新建插件 首先,进入到插件页面,创建一个插件. https://www.coze.cn/home 点击左侧的个 ...
- Promise + Async&Await + Array.reduce + 函数递归 解决网络/接口请求的依次/排队不间断间隔访问
背景 试想在一个需要频繁更新数据的场景(例如:监控.图表类),常规方法是设置一个间隔 N 秒的定时器 setInterval:但是这种方式存在一个问题,当前一个请求时间过长时(超过了间隔时间),后一个 ...
- 使用OHOS SDK构建lz4
参照OHOS IDE和SDK的安装方法配置好开发环境. 从github下载源码. 执行如下命令: git clone --depth=1 https://github.com/lz4/lz4.git ...
- C++调用Python-4:调用Python函数,传参数字
# mytest.py def myadd(a, b): print("this is test python print add function") return a+b #i ...
- openGauss事务机制中MVCC技术的实现分析
openGauss 事务机制中 MVCC 技术的实现分析 概述 事务 事务是为用户提供的最核心.最具吸引力的数据库功能之一.简单地说,事务是用户定义的一系列数据库操作(如查询.插入.修改或删除等)的集 ...
- IP路由的工作原理
一.路由 路由在网络中起到什么作用? • 路由器负责将数据报文在IP网段之间进行转发 • 路由是指导路由器如何进行数据转发的路径信息 IP之间连通的前提是什么? • 沿途的每台路由器上都有到达目的网段 ...
- 微软自带的Hyper-V虚拟机使用、VMware16安装Win10虚拟机介绍
一.首先介绍VMware虚拟机. 安装WIN10统虚拟机推荐用VMware16. 1.镜像网址: MSD网址传送门1:https://msdn.itellyou.cn MSD新网址传送门2:https ...
- 【Oracle】使用case when语句导致SQL查询速度很慢的情况
[Oracle]使用case when语句导致SQL查询速度很慢的情况 很多时候会使用到case when语句去对SQL的多种情况进行处理,decode也用的多,但是通常decode会用在固定值的数据 ...
- 力扣171(java)-Excel表列序号(简单)
题目: 给你一个字符串 columnTitle ,表示 Excel 表格中的列名称.返回 该列名称对应的列序号 . 例如: A -> 1B -> 2C -> 3...Z -> ...