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
90 lines
3.1 KiB
C#
90 lines
3.1 KiB
C#
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()
|
|
// {
|
|
//
|
|
// }
|
|
}
|