@@ -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