泊松盘采样(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来生成随机数据,这在需要 ''' #常 ...
随机推荐
- CSP2020-S 游记
10.11 CSP-S1 自从国庆假期回到学校我申请停课, 从此开始了长达近一个的停课生活. 初赛也是有惊无险地过去了. 一出来发现自己仍旧是大考必败型选手, 对了答案发现我其实错了挺多的, 可能是因 ...
- C++ 编程入门指南:深入了解 C++ 语言及其应用领域
C++ 简介 什么是 C++? C++ 是一种跨平台的编程语言,可用于创建高性能应用程序. C++ 是由 Bjarne Stroustrup 开发的,作为 C 语言的扩展. C++ 为程序员提供了对系 ...
- C# 方法详解:定义、调用、参数、默认值、返回值、命名参数、方法重载全解析
C# Methods 方法是一段代码,只有在调用时才会运行. 您可以将数据(称为参数)传递给方法. 方法用于执行某些操作,也被称为函数. 为什么使用方法?为了重用代码:定义一次代码,然后多次使用. 创 ...
- PDF库 libharu 简单操作
libharu官网:http://libharu.org/ 直接下载下来编译就可以使用了(*:我下载的版本是:libharu-libharu-v2.4.3-0-g8dbcfe4.tar) 一.编译 ...
- IDEA快捷键快速补齐类和对象名
CTRL+ALT+V ----------快速补齐 类和对象名 如: new String("123") 光标放到最后 按下快捷键补齐为红色部分 String s = ne ...
- .NET周刊【4月第1期 2024-04-07】
国内文章 一个程序员的编年史 https://www.cnblogs.com/lunacy/p/18117213 作者拥有15年软件开发经验,曾在多家公司工作,项目和团队起伏充满变数.2007年,在太 ...
- HDC2021技术分论坛:跨端分布式计算技术初探
作者:zhengkai,分布式通信首席技术专家 当今的移动应用都向着智能化和多样化方向发展,例如AI辅助,VR/AR应用,沉浸式游戏等.然而现实中的移动设备,因为便携性要求受限于尺寸.电池容量以及温控 ...
- centos6.5下安装配置apache2.4.9
centos6.5下安装配置apache2.4.9 摘要: 需要下载的包 apr-1.5.0.tar.gz apr-util-1.5.3.tar.gz pcre-8.33.tar.gz httpd-2 ...
- android android7以上无法连接蓝牙
前言 在开发android 蓝牙的时候,发现一个问题,那就是android7无法连接上蓝牙. 原因 <!-- 管理蓝牙设备的权限 --> <uses-permission andro ...
- react native 如何用vs code 进行调试
前言 以前做react-native 写的文章,在此分享一下. 在react-native 中有两种方式调试,一种是crome 调试,一种是本地调试,接下来介绍的是本地调试. 解决方案 在vs cod ...