Skip to content

Commit df2a2f8

Browse files
sleal-unityaryan-mann
authored andcommitted
Merge pull request #285 from Unity-Technologies/poisson-disk-super-sampling
Poisson disk super sampling
1 parent 40fbbf9 commit df2a2f8

File tree

1 file changed

+71
-15
lines changed

1 file changed

+71
-15
lines changed

com.unity.perception/Runtime/Randomization/Randomizers/RandomizerExamples/Utilities/PoissonDiskSampling.cs

Lines changed: 71 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,15 @@ public static class PoissonDiskSampling
2121
/// <param name="minimumRadius">The minimum distance required between each sampled point</param>
2222
/// <param name="seed">The random seed used to initialize the algorithm state</param>
2323
/// <param name="samplingResolution">The number of potential points sampled around every valid point</param>
24+
/// <param name="allocator">The allocator to use for the samples container</param>
2425
/// <returns>The list of generated poisson points</returns>
2526
public static NativeList<float2> GenerateSamples(
2627
float width,
2728
float height,
2829
float minimumRadius,
2930
uint seed = 12345,
30-
int samplingResolution = k_DefaultSamplingResolution)
31+
int samplingResolution = k_DefaultSamplingResolution,
32+
Allocator allocator = Allocator.TempJob)
3133
{
3234
if (width < 0)
3335
throw new ArgumentException($"Width {width} cannot be negative");
@@ -40,17 +42,29 @@ public static NativeList<float2> GenerateSamples(
4042
if (samplingResolution <= 0)
4143
throw new ArgumentException($"SamplingAttempts {samplingResolution} cannot be <= 0");
4244

43-
var samples = new NativeList<float2>(Allocator.TempJob);
44-
new SampleJob
45+
var superSampledPoints = new NativeList<float2>(allocator);
46+
var sampleJob = new SampleJob
4547
{
46-
width = width,
47-
height = height,
48+
width = width + minimumRadius * 2,
49+
height = height + minimumRadius * 2,
4850
minimumRadius = minimumRadius,
4951
seed = seed,
5052
samplingResolution = samplingResolution,
51-
samples = samples
52-
}.Schedule().Complete();
53-
return samples;
53+
samples = superSampledPoints
54+
}.Schedule();
55+
56+
var croppedSamples = new NativeList<float2>(allocator);
57+
new CropJob
58+
{
59+
width = width,
60+
height = height,
61+
minimumRadius = minimumRadius,
62+
superSampledPoints = superSampledPoints.AsDeferredJobArray(),
63+
croppedSamples = croppedSamples
64+
}.Schedule(sampleJob).Complete();
65+
superSampledPoints.Dispose();
66+
67+
return croppedSamples;
5468
}
5569

5670
[BurstCompile]
@@ -71,6 +85,50 @@ public void Execute()
7185
}
7286
}
7387

88+
/// <summary>
89+
/// This job is for filtering out all super sampled Poisson points that are found outside of the originally
90+
/// specified 2D region. This job will also shift the cropped points back to their original region.
91+
/// </summary>
92+
[BurstCompile]
93+
struct CropJob : IJob
94+
{
95+
public float width;
96+
public float height;
97+
public float minimumRadius;
98+
[ReadOnly] public NativeArray<float2> superSampledPoints;
99+
public NativeList<float2> croppedSamples;
100+
101+
public void Execute()
102+
{
103+
var results = new NativeArray<bool>(
104+
superSampledPoints.Length, Allocator.Temp, NativeArrayOptions.UninitializedMemory);
105+
106+
// The comparisons operations made in this loop are done separately from the list-building loop
107+
// so that burst can automatically generate vectorized assembly code for this portion of the job.
108+
for (var i = 0; i < superSampledPoints.Length; i++)
109+
{
110+
var point = superSampledPoints[i];
111+
results[i] = point.x >= minimumRadius && point.x <= width + minimumRadius
112+
&& point.y >= minimumRadius && point.y <= height + minimumRadius;
113+
}
114+
115+
// This list-building code is done separately from the filtering loop
116+
// because it cannot be vectorized by burst.
117+
for (var i = 0; i < superSampledPoints.Length; i++)
118+
{
119+
if (results[i])
120+
croppedSamples.Add(superSampledPoints[i]);
121+
}
122+
123+
// Remove the positional offset from the filtered-but-still-super-sampled points
124+
var offset = new float2(minimumRadius, minimumRadius);
125+
for (var i = 0; i < croppedSamples.Length; i++)
126+
croppedSamples[i] -= offset;
127+
128+
results.Dispose();
129+
}
130+
}
131+
74132
// Algorithm sourced from Robert Bridson's paper "Fast Poisson Disk Sampling in Arbitrary Dimensions"
75133
// https://www.cs.ubc.ca/~rbridson/docs/bridson-siggraph07-poissondisk.pdf
76134
/// <summary>
@@ -95,9 +153,9 @@ static NativeList<float2> Sample(
95153

96154
// Calculate occupancy grid dimensions
97155
var random = new Unity.Mathematics.Random(seed);
98-
var cellSize = minimumRadius / math.sqrt(2);
99-
var rows = Mathf.FloorToInt(height / cellSize);
100-
var cols = Mathf.FloorToInt(width / cellSize);
156+
var cellSize = minimumRadius / math.sqrt(2f);
157+
var rows = Mathf.CeilToInt(height / cellSize);
158+
var cols = Mathf.CeilToInt(width / cellSize);
101159
var gridSize = rows * cols;
102160
if (gridSize == 0)
103161
return samples;
@@ -115,10 +173,8 @@ static NativeList<float2> Sample(
115173
// This list will track all points that may still have space around them for generating new points
116174
var activePoints = new NativeList<float2>(Allocator.Temp);
117175

118-
// Randomly place a seed point in a central location within the generation space to kick off the algorithm
119-
var firstPoint = new float2(
120-
random.NextFloat(0.4f, 0.6f) * width,
121-
random.NextFloat(0.4f, 0.6f) * height);
176+
// Randomly place a seed point to kick off the algorithm
177+
var firstPoint = new float2(random.NextFloat(0f, width), random.NextFloat(0f, height));
122178
samples.Add(firstPoint);
123179
var firstPointCol = Mathf.FloorToInt(firstPoint.x / cellSize);
124180
var firstPointRow = Mathf.FloorToInt(firstPoint.y / cellSize);

0 commit comments

Comments
 (0)