77public class WorleyNoise {
88 //TODO Optimise it further
99 //TODO make a 2d version of it -> makes no sens to use 3d version for a 2D map
10- private static final float K = 0.142857142857f ;
11- private static final float Ko = 0.428571428571f ;
12- private static final float K2 = 0.020408163265306f ;
13- private static final float Kz = 0.166666666667f ;
14- private static final float Kzo = 0.416666666667f ;
10+ private static final float K = 1.0f / 8.0f ; // 0.125f — scale permuted into 8 buckets
11+ private static final float Ko = 0.375f ; // center of [-0.375, 0.375] ( = 3 * K)
12+ private static final float K2 = 1.0f / 32.0f ; // 0.03125f — second-level bucket (for Z)
13+ private static final float Kz = 1.0f / 6.0f ; // 0.166666...
14+ private static final float Kzo = 0.5f - Kz ; // = 0.333333... — to center Z
1515 private static final float jitter = 0.8f ;
1616 private final float YMin ;
1717 private final float YMax ;
@@ -28,7 +28,29 @@ public float getYSize() {
2828 private final float XZSize ;
2929 private final float YSize ;
3030 private float x0 ,y0 ,z0 ;
31- private final int [] p = new int [289 ];//TODO go to 256 rather than 289, now that we use the seed it doesn't make sens anymore
31+ private static final int permutations_bits = 8 ;
32+ private static final int permutations_amount = 1 << permutations_bits ; // = 256
33+
34+ private final int [] xp = new int [permutations_amount ];
35+
36+ // Offsets for the 27 neighbor cells in a 3×3×3 cube
37+ private static final int [][] OFFSETS_3D = new int [27 ][3 ];
38+
39+ static {
40+ int index = 0 ;
41+ for (int xi = -1 ; xi <= 1 ; xi ++) {
42+ for (int yi = -1 ; yi <= 1 ; yi ++) {
43+ for (int zi = -1 ; zi <= 1 ; zi ++) {
44+ OFFSETS_3D [index ][0 ] = xi ;
45+ OFFSETS_3D [index ][1 ] = yi ;
46+ OFFSETS_3D [index ][2 ] = zi ;
47+ index ++;
48+ }
49+ }
50+ }
51+ }
52+
53+ //TODO go to 256 rather than 289, now that we use the seed it doesn't make sens anymore
3254 //TODO have 3 permutations for x, y, z for improved performance ? need to do profiling and see if it changes anything.
3355 public WorleyNoise (float XZSize , float YSize , float YMin , float YMax ) {
3456 this .XZSize = XZSize ;
@@ -39,64 +61,73 @@ public WorleyNoise(float XZSize, float YSize, float YMin, float YMax) {
3961 }
4062 public void setSeed (long seed ){
4163 RandomSource random = new XoroshiroRandomSource (seed );
42- this .x0 = random .nextFloat () * 289.0f ;//TODO is this needed ?
43- this .y0 = random .nextFloat () * 289.0f ;
44- this .z0 = random .nextFloat () * 289.0f ;
45-
46- for (int i = 0 ; i < 289 ; this .p [i ] = i ++){
64+ this .x0 = random .nextFloat () * permutations_amount ;//TODO is this needed ?
65+ this .y0 = random .nextFloat () * permutations_amount ;
66+ this .z0 = random .nextFloat () * permutations_amount ;
4767
68+ for (int i = 0 ; i < permutations_amount ; i ++) {
69+ this .xp [i ] = i ;
4870 }
4971
50- for (int l = 0 ; l < 289 ; ++l ) {
51- int j = random .nextInt (289 - l );
52- int k = this .p [l ];
53- this .p [l ] = this .p [j + l ];
54- this .p [j + l ] = k ;
72+ for (int l = 0 ; l < permutations_amount ; ++l ) {
73+ int j = random .nextInt (permutations_amount - l );
74+ int k = this .xp [l ];
75+ this .xp [l ] = this .xp [j + l ];
76+ this .xp [j + l ] = k ;
5577 }
5678
5779 }
58-
59- private int permute (int x ) {
60- return p [x %289 ];
80+ private int permute (int x ){
81+ return xp [x &(permutations_amount - 1 )];
6182 }
62-
6383 public static float frac (float x ) {
6484 return x - Mth .floor (x );
6585 }
6686
6787 public float cellular3x3x3 (float px , float py , float pz ) {
88+ //here a cell is 1 large (because in getValue we
6889 int Pix = Mth .floor (px +x0 ), Piy = Mth .floor (py +y0 ), Piz = Mth .floor (pz +z0 ); // Integer part
6990 float Pfx = frac (px +x0 ),Pfy = frac (py +y0 ),Pfz = frac (pz +z0 ); // Fractional part
7091 float minDist = Float .MAX_VALUE ;
71-
72- for (int xi = -1 ; xi <= 1 ; xi ++) {
73- for (int yi = -1 ; yi <= 1 ; yi ++) {
74- for (int zi = -1 ; zi <= 1 ; zi ++) {
75- // Compute cell coordinates
76- //Vec3 cell = Pi.add(new Vec3(xi, yi, zi));
77- float permuted = permute (permute (permute (Pix + xi )+Piy +yi )+Piz +zi );
78- // Pseudo-random offset inside cell
79- //TODO remove this/change this to a more relevant version (remnants of an old version of this code)
80- float jitterX = ((permuted *K -Mth .floor (permuted *K ))-Ko ) * jitter ;
81- float jitterY = ((Mth .floor (permuted *K )%7.0f ) * K -Ko ) * jitter ;
82- float jitterZ = ((Mth .floor (permuted *K2 )) * Kz -Kzo ) * jitter ;
83-
84-
85- // Compute squared distance
86- float dist = Mth .sqrt ((jitterX +xi -Pfx )*(jitterX +xi -Pfx )+(jitterY +yi -Pfy )*(jitterY +yi -Pfy )+(jitterZ +zi -Pfz )*(jitterZ +zi -Pfz ));
87- if (Piy +jitterY +yi < YMax + y0 && Piy +jitterY +yi > YMin +y0 ) {
88- // Track minimum distance
89- minDist = Math .min (minDist , dist );
90- }
91- }
92- }
92+ //if we do it with a nested loop we have a big overhead
93+ float yMaxOffset = YMax + y0 ;
94+ float yMinOffset = YMin + y0 ;
95+ for (int [] offset : OFFSETS_3D ) {
96+ int xi = offset [0 ];
97+ int yi = offset [1 ];
98+ int zi = offset [2 ];
99+
100+ int cellX = Pix + xi ;
101+ int cellY = Piy + yi ;
102+ int cellZ = Piz + zi ;
103+
104+ float dx = xi - Pfx ;
105+ float dy = yi - Pfy ;
106+ float dz = zi - Pfz ;
107+
108+ float permuted = permute (permute (permute (cellX ) + cellY ) + cellZ );
109+
110+ float fk = permuted * K ;
111+ float jitterX = (fk - Mth .floor (fk ) - Ko ) * jitter ;
112+ float jitterY = ((Mth .floor (fk ) % 8 ) * K - Ko ) * jitter ;
113+ float jitterZ = ((Mth .floor (permuted * K2 )) * Kz - Kzo ) * jitter ;
114+
115+ float ytest = cellY + jitterY + yi ;
116+
117+ if (ytest < yMinOffset || ytest > yMaxOffset ) continue ;
118+
119+ float distX = dx + jitterX ;
120+ float distY = dy + jitterY ;
121+ float distZ = dz + jitterZ ;
122+ float dist = distX * distX + distY * distY + distZ * distZ ;
123+ minDist = Math .min (minDist , dist );
93124 }
94125 return Mth .sqrt (minDist ); // Return the actual distance
95126 }
96127 //use int, that's lighter
97128 public double getValue (int x , int y , int z ) {
98- float F = cellular3x3x3 ((x ) / XZSize ,(y ) / YSize ,(z ) / XZSize );
99- return 1 - (F * 2 ); // Mapping to range [-1, 1]
129+ float F = cellular3x3x3 ((x ) / XZSize ,(y ) / YSize ,(z ) / XZSize );//give a result bwn 0 and 1
130+ return 1 - (F * 2 ); // Mapping to range [-1, 1]
100131 }
101132
102133 public float getYMin () {
0 commit comments