Shitty uniform Poisson Disk Sampling

This is just a very basic implementation of the algorithm, just to test and for me to understand it better, next commit I'm gonna implement the last version of it with variable density
This commit is contained in:
Bruno Couto 2020-02-28 12:42:00 +00:00
commit 86b86eef32
26 changed files with 542 additions and 129 deletions

View file

@ -0,0 +1,90 @@
using System;
using System.Collections;
using System.Collections.Generic;
using Unity.Mathematics;
using UnityEngine;
using Random = UnityEngine.Random;
public static class PoissonDiskSampling
{
public static List<Vector2> PoissonGenerate(float radius, Vector2 sampleRegionSize,
int numSamplesBeforeRejection = 30)
{
float cellSize = radius / Mathf.Sqrt(2);
int[,] grid = new int[Mathf.CeilToInt(sampleRegionSize.x / cellSize), Mathf.CeilToInt(sampleRegionSize.y / cellSize)];
List<Vector2> points = new List<Vector2>();
List<Vector2> spawnPoints = new List<Vector2>();
spawnPoints.Add(sampleRegionSize / 2);
while (spawnPoints.Count > 0)
{
int spawnIndex = Random.Range(0, spawnPoints.Count);
Vector2 spawnCentre = spawnPoints[spawnIndex];
bool isCandidateAccepted = false;
for (int i = 0; i < numSamplesBeforeRejection; i++)
{
float angle = Random.value * Mathf.PI * 2;
Vector2 dir = new Vector2(Mathf.Sin(angle), Mathf.Cos(angle));
Vector2 candidate = spawnCentre + dir * Random.Range(radius, 2 * radius);
if (IsValid(candidate, sampleRegionSize, cellSize, radius, points, grid))
{
points.Add(candidate);
spawnPoints.Add(candidate);
grid[(int)(candidate.x / cellSize), (int)(candidate.y / cellSize)] = points.Count;
isCandidateAccepted = true;
break;
}
}
if (!isCandidateAccepted)
spawnPoints.RemoveAt(spawnIndex);
}
return points;
}
static bool IsValid(Vector2 candidate, Vector2 sampleRegionSize, float cellSize, float radius, List<Vector2> points, int[,] grid)
{
if (candidate.x >= 0 && candidate.x < sampleRegionSize.x && candidate.y >= 0 && candidate.y < sampleRegionSize.y)
{
int cellX = (int) (candidate.x / cellSize);
int cellY = (int) (candidate.y / cellSize);
int searchStartX = Mathf.Max(0, cellX - 2);
int searchEndX = Mathf.Min(cellX + 2, grid.GetLength(0) - 1);
int searchStartY = Mathf.Max(0, cellY - 2);
int searchEndY = Mathf.Min(cellY + 2, grid.GetLength(1) - 1);
for (int x = searchStartX; x <= searchEndX; x++)
{
for (int y = searchStartY; y <= searchEndY; y++)
{
int pointIndex = grid[x, y] - 1;
if (pointIndex != -1)
{
float sqrDst = (candidate - points[pointIndex]).sqrMagnitude;
if (sqrDst < radius * radius)
{
return false;
}
}
}
}
return true;
}
return false;
}
// float squaredEuclideanDistance(Array point1, Array point2)
// {
//
// }
//
//
// void PoissonDiskGenerate()
// {
//
// }
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 57fd96a54b211924aaf17bb990812215
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,32 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Test : MonoBehaviour
{
public float radius = 1;
public Vector2 regionSize = Vector2.one;
public int rejectionSamples = 30;
public float displayRadius = 1;
private List<Vector2> points;
private void OnValidate()
{
points = PoissonDiskSampling.PoissonGenerate(radius, regionSize, rejectionSamples);
}
private void OnDrawGizmos()
{
Gizmos.DrawWireCube(regionSize/2, regionSize);
if (points != null)
{
foreach (Vector2 p in points)
{
Gizmos.DrawSphere(p, displayRadius);
}
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 5c5e780ee090df142929fc2b1806e78c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: