001package squidpony.squidmath; 002 003import static squidpony.squidmath.Noise.cerp; 004import static squidpony.squidmath.Noise.fastFloor; 005import static squidpony.squidmath.SeededNoise.phiGrad2; 006import static squidpony.squidmath.SeededNoise.gradient6DLUT; 007import static squidpony.squidmath.SeededNoise.grad3d; 008import static squidpony.squidmath.SeededNoise.grad4d; 009 010/** 011 * "Classic Perlin" noise, as opposed to the Simplex Noise also created by Ken Perlin (which is produced by 012 * {@link SeededNoise}; both can be produced by {@link FastNoise}). 013 * This noise can in theory be scaled up to arbitrary dimensions, but in practice uses unreasonably hefty amounts of 014 * memory when dimensionality exceeds 10 or so, since it needs to hash {@code Math.pow(2, dimensionality)} points per 015 * sample of noise, which involves over a thousand points in 10 dimensions and over a million points in 20 dimensions. 016 * For that reason, it's limited to 6D noise here, and also implements 2D, 3D, and 4D. Its performance is surprisingly 017 * good at 2D, 3D, and 4D but trails off quickly at 6D. Its quality is worse than normal simplex noise in 2D, but you 018 * can use {@link JitterNoise} (which takes the same algorithm and distorts the grid pseudo-randomly) to get unusually 019 * high-quality 2D noise. The quality is actually quite good in 4D and higher; there's often some rhythmic patterns in 020 * 3D when time is z, but with 4 or 6 dimensions this can have fewer artifacts than Simplex in the same dimension. The 021 * 3D and higher dimensionality versions don't seem to need jitter to avoid grid artifacts, at least most of the time. 022 * This uses different gradient vectors than what was recommended in the "Improved Perlin Noise" paper, since the ones 023 * this uses avoid 45-degree angular artifacts in all dimensions implemented. 024 * <br> 025 * ClassicNoise is a good choice with parts of {@link squidpony.squidgrid.mapping.WorldMapGenerator} that need a 026 * Noise3D implementation, and it tends to about as fast as {@link SeededNoise} in 3D. It is not recommended for 2D 027 * use; prefer {@link JitterNoise} or {@link SeededNoise} for that. You can also use {@link FastNoise} with 028 * {@link FastNoise#PERLIN_FRACTAL} as the noiseType if you primarily want to use float input and get float output. 029 * If you want higher-dimensional noise than this supports, you can use {@link PhantomNoise}. 030 */ 031public class ClassicNoise implements Noise.Noise2D, Noise.Noise3D, Noise.Noise4D, Noise.Noise6D { 032 public static final ClassicNoise instance = new ClassicNoise(); 033 public long seed; 034 public ClassicNoise() { 035 this(0x1337BEEFCAFEL); 036 } 037 038 public ClassicNoise(final long seed) { 039 this.seed = seed; 040 } 041 protected static double gradCoord2D(long seed, int x, int y, 042 double xd, double yd) { 043 final int hash = ((int)(((seed ^= 0xB4C4D * x ^ 0xEE2C3 * y) ^ seed >>> 13) * (seed))); 044 //final int hash = (int)((((seed = (((seed * (0x632BE59BD9B4E019L + (x << 23))) ^ 0x9E3779B97F4A7C15L) * (0xC6BC279692B5CC83L + (y << 23)))) ^ seed >>> 27 ^ x + y) * 0xAEF17502108EF2D9L) >>> 56); 045 final double[] grad = phiGrad2[hash >>> 24]; 046 return xd * grad[0] + yd * grad[1]; 047 } 048 protected static double gradCoord3D(long seed, int x, int y, int z, double xd, double yd, double zd) { 049 final int hash = 050 ((int)(((seed ^= 0xB4C4D * x ^ 0xEE2C1 * y ^ 0xA7E07 * z) ^ seed >>> 13) * (seed)) 051 >>> 27) * 3; 052 return (xd * grad3d[hash] + yd * grad3d[hash + 1] + zd * grad3d[hash + 2]); 053 } 054 protected static double gradCoord4D(long seed, int x, int y, int z, int w, 055 double xd, double yd, double zd, double wd) { 056 final int hash = 057 ((int)(((seed ^= 0xB4C4D * x ^ 0xEE2C1 * y ^ 0xA7E07 * z ^ 0xCD5E9 * w) ^ seed >>> 13) * (seed)) 058 >>> 24) & -4; 059 return xd * grad4d[hash] + yd * grad4d[hash + 1] + zd * grad4d[hash + 2] + wd * grad4d[hash + 3]; 060 } 061 protected static double gradCoord6D(long seed, int x, int y, int z, int w, int u, int v, 062 double xd, double yd, double zd, double wd, double ud, double vd) { 063 final int hash = 064 ((int)(((seed ^= 0xB4C4D * x ^ 0xEE2C1 * y ^ 0xA7E07 * z ^ 0xCD5E9 * w ^ 0x94B5B * u ^ 0xD2385 * v) 065 ^ seed >>> 13) * (seed)) 066 >>> 24) * 6; 067 return xd * gradient6DLUT[hash] + yd * gradient6DLUT[hash + 1] + zd * gradient6DLUT[hash + 2] 068 + wd * gradient6DLUT[hash + 3] + ud * gradient6DLUT[hash + 4] + vd * gradient6DLUT[hash + 5]; 069 } 070// protected static double gradCoord2DJitter(long seed, int x, int y, 071// double xd, double yd) { 072// final int hash = ((int)(((seed ^= 0xB4C4D * x ^ 0xEE2C3 * y) ^ seed >>> 13) * (seed))); 073// final double[] grad = phiGrad2[hash >>> 24], jitter = phiGrad2[hash >>> 16 & 0xFF]; 074// return (xd + jitter[0] * 0.5) * grad[0] + (yd + jitter[1] * 0.5) * grad[1]; 075// } 076 077 @Override 078 public double getNoise(final double x, final double y) { 079 return getNoiseWithSeed(x, y, seed); 080 } 081 082 @Override 083 public double getNoiseWithSeed(double x, double y, final long seed) { 084 x *= 2.0; 085 y *= 2.0; 086 final int 087 x0 = fastFloor(x), 088 y0 = fastFloor(y); 089// final double res = 090 return 091 Noise.emphasizeSigned(cerp(cerp(gradCoord2D(seed, x0, y0, x - x0, y - y0), gradCoord2D(seed, x0+1, y0, x - x0 - 1, y - y0), x - x0), 092 cerp(gradCoord2D(seed, x0, y0+1, x - x0, y - y0-1), gradCoord2D(seed, x0+1, y0+1, x - x0 - 1, y - y0 - 1), x - x0), 093 y - y0) * 1.4142);//* 0.875;// * 1.4142; 094// if(res < -1.0 || res > 1.0) System.out.println(res); 095// return res; 096 } 097 098 @Override 099 public double getNoise(final double x, final double y, final double z) { 100 return getNoiseWithSeed(x, y, z, seed); 101 } 102 103 @Override 104 public double getNoiseWithSeed(double x, double y, double z, final long seed) { 105 x *= 2.0; 106 y *= 2.0; 107 z *= 2.0; 108 final int 109 x0 = fastFloor(x), 110 y0 = fastFloor(y), 111 z0 = fastFloor(z); 112// final double res = 113 return 114 Noise.emphasizeSigned(cerp(cerp(cerp(gradCoord3D(seed, x0, y0, z0, x - x0, y - y0, z - z0), gradCoord3D(seed, x0+1, y0, z0, x - x0 - 1, y - y0, z - z0), x - x0), 115 cerp(gradCoord3D(seed, x0, y0+1, z0, x - x0, y - y0-1, z - z0), gradCoord3D(seed, x0+1, y0+1, z0, x - x0 - 1, y - y0 - 1, z - z0), x - x0), 116 y - y0), 117 cerp(cerp(gradCoord3D(seed, x0, y0, z0+1, x - x0, y - y0, z - z0-1), gradCoord3D(seed, x0+1, y0, z0+1, x - x0 - 1, y - y0, z - z0-1), x - x0), 118 cerp(gradCoord3D(seed, x0, y0+1, z0+1, x - x0, y - y0-1, z - z0-1), gradCoord3D(seed, x0+1, y0+1, z0+1, x - x0 - 1, y - y0 - 1, z - z0-1), x - x0), 119 y - y0), z - z0) * 1.0625); 120// if(res < -1 || res > 1) System.out.println(res); 121// return res; 122 } 123 124 @Override 125 public double getNoise(final double x, final double y, final double z, final double w) { 126 return getNoiseWithSeed(x, y, z, w, seed); 127 } 128 129 @Override 130 public double getNoiseWithSeed(double x, double y, double z, double w, final long seed) { 131 x *= 2.0; 132 y *= 2.0; 133 z *= 2.0; 134 w *= 2.0; 135 final int 136 x0 = fastFloor(x), 137 y0 = fastFloor(y), 138 z0 = fastFloor(z), 139 w0 = fastFloor(w); 140// final double res = 141 return 142 Noise.emphasizeSigned(cerp(cerp(cerp(cerp(gradCoord4D(seed, x0, y0, z0, w0, x - x0, y - y0, z - z0, w - w0), gradCoord4D(seed, x0+1, y0, z0, w0, x - x0 - 1, y - y0, z - z0, w - w0), x - x0), 143 cerp(gradCoord4D(seed, x0, y0+1, z0, w0, x - x0, y - y0-1, z - z0, w - w0), gradCoord4D(seed, x0+1, y0+1, z0, w0, x - x0 - 1, y - y0 - 1, z - z0, w - w0), x - x0), 144 y - y0), 145 cerp(cerp(gradCoord4D(seed, x0, y0, z0+1, w0, x - x0, y - y0, z - z0-1, w - w0), gradCoord4D(seed, x0+1, y0, z0+1, w0, x - x0 - 1, y - y0, z - z0-1, w - w0), x - x0), 146 cerp(gradCoord4D(seed, x0, y0+1, z0+1, w0, x - x0, y - y0-1, z - z0-1, w - w0), gradCoord4D(seed, x0+1, y0+1, z0+1, w0, x - x0 - 1, y - y0 - 1, z - z0-1, w - w0), x - x0), 147 y - y0), 148 z - z0), 149 cerp(cerp(cerp(gradCoord4D(seed, x0, y0, z0, w0+1, x - x0, y - y0, z - z0, w - w0 - 1), gradCoord4D(seed, x0+1, y0, z0, w0+1, x - x0 - 1, y - y0, z - z0, w - w0 - 1), x - x0), 150 cerp(gradCoord4D(seed, x0, y0+1, z0, w0+1, x - x0, y - y0-1, z - z0, w - w0 - 1), gradCoord4D(seed, x0+1, y0+1, z0, w0+1, x - x0 - 1, y - y0 - 1, z - z0, w - w0 - 1), x - x0), 151 y - y0), 152 cerp(cerp(gradCoord4D(seed, x0, y0, z0+1, w0+1, x - x0, y - y0, z - z0-1, w - w0 - 1), gradCoord4D(seed, x0+1, y0, z0+1, w0+1, x - x0 - 1, y - y0, z - z0-1, w - w0 - 1), x - x0), 153 cerp(gradCoord4D(seed, x0, y0+1, z0+1, w0+1, x - x0, y - y0-1, z - z0-1, w - w0 - 1), gradCoord4D(seed, x0+1, y0+1, z0+1, w0+1, x - x0 - 1, y - y0 - 1, z - z0-1, w - w0 - 1), x - x0), 154 y - y0), 155 z - z0), 156 w - w0) * 0.555); 157// if(res < -1 || res > 1) System.out.println(res); 158// return res; 159 } 160 161 162 @Override 163 public double getNoise(final double x, final double y, final double z, final double w, final double u, final double v) { 164 return getNoiseWithSeed(x, y, z, w, u, v, seed); 165 } 166 167 @Override 168 public double getNoiseWithSeed(double x, double y, double z, double w, double u, double v, long seed) { 169 x *= 2.0; 170 y *= 2.0; 171 z *= 2.0; 172 w *= 2.0; 173 u *= 2.0; 174 v *= 2.0; 175 final int 176 x0 = fastFloor(x), 177 y0 = fastFloor(y), 178 z0 = fastFloor(z), 179 w0 = fastFloor(w), 180 u0 = fastFloor(u), 181 v0 = fastFloor(v); 182 final double xd = x - x0, yd = y - y0, zd = z - z0, wd = w - w0, ud = u - u0, vd = v - v0; 183// final double res = 184 return Noise.emphasizeSigned( 185 cerp(cerp(cerp( 186 cerp( 187 cerp( 188 cerp(gradCoord6D(seed, x0, y0, z0, w0, u0, v0, xd, yd, zd, wd, ud, vd), 189 gradCoord6D(seed, x0+1, y0, z0, w0, u0, v0, xd-1, yd, zd, wd, ud, vd), xd), 190 cerp(gradCoord6D(seed, x0, y0+1, z0, w0, u0, v0, xd, yd-1, zd, wd, ud, vd), 191 gradCoord6D(seed, x0+1, y0+1, z0, w0, u0, v0, xd-1, yd-1, zd, wd, ud, vd), xd), 192 yd), 193 cerp( 194 cerp(gradCoord6D(seed, x0, y0, z0+1, w0, u0, v0, xd, yd, zd-1, wd, ud, vd), 195 gradCoord6D(seed, x0+1, y0, z0+1, w0, u0, v0, xd-1, yd, zd-1, wd, ud, vd), xd), 196 cerp(gradCoord6D(seed, x0, y0+1, z0+1, w0, u0, v0, xd, yd-1, zd-1, wd, ud, vd), 197 gradCoord6D(seed, x0+1, y0+1, z0+1, w0, u0, v0, xd-1, yd-1, zd-1, wd, ud, vd), xd), 198 yd), 199 zd), 200 cerp( 201 cerp( 202 cerp(gradCoord6D(seed, x0, y0, z0, w0+1, u0, v0, xd, yd, zd, wd-1, ud, vd), 203 gradCoord6D(seed, x0+1, y0, z0, w0+1, u0, v0, xd-1, yd, zd, wd-1, ud, vd), xd), 204 cerp(gradCoord6D(seed, x0, y0+1, z0, w0+1, u0, v0, xd, yd-1, zd, wd-1, ud, vd), 205 gradCoord6D(seed, x0+1, y0+1, z0, w0+1, u0, v0, xd-1, yd-1, zd, wd-1, ud, vd), xd), 206 yd), 207 cerp( 208 cerp(gradCoord6D(seed, x0, y0, z0+1, w0+1, u0, v0, xd, yd, zd-1, wd-1, ud, vd), 209 gradCoord6D(seed, x0+1, y0, z0+1, w0+1, u0, v0, xd-1, yd, zd-1, wd-1, ud, vd), xd), 210 cerp(gradCoord6D(seed, x0, y0+1, z0+1, w0+1, u0, v0, xd, yd-1, zd-1, wd-1, ud, vd), 211 gradCoord6D(seed, x0+1, y0+1, z0+1, w0+1, u0, v0, xd-1, yd-1, zd-1, wd-1, ud, vd), xd), 212 yd), 213 zd), 214 wd), 215 cerp( 216 cerp( 217 cerp( 218 cerp(gradCoord6D(seed, x0, y0, z0, w0, u0+1, v0, xd, yd, zd, wd, ud-1, vd), 219 gradCoord6D(seed, x0+1, y0, z0, w0, u0+1, v0, xd-1, yd, zd, wd, ud-1, vd), xd), 220 cerp(gradCoord6D(seed, x0, y0+1, z0, w0, u0+1, v0, xd, yd-1, zd, wd, ud-1, vd), 221 gradCoord6D(seed, x0+1, y0+1, z0, w0, u0+1, v0, xd-1, yd-1, zd, wd, ud-1, vd), xd), 222 yd), 223 cerp( 224 cerp(gradCoord6D(seed, x0, y0, z0+1, w0, u0+1, v0, xd, yd, zd-1, wd, ud-1, vd), 225 gradCoord6D(seed, x0+1, y0, z0+1, w0, u0+1, v0, xd-1, yd, zd-1, wd, ud-1, vd), xd), 226 cerp(gradCoord6D(seed, x0, y0+1, z0+1, w0, u0+1, v0, xd, yd-1, zd-1, wd, ud-1, vd), 227 gradCoord6D(seed, x0+1, y0+1, z0+1, w0, u0+1, v0, xd-1, yd-1, zd-1, wd, ud-1, vd), xd), 228 yd), 229 zd), 230 cerp( 231 cerp( 232 cerp(gradCoord6D(seed, x0, y0, z0, w0+1, u0+1, v0, xd, yd, zd, wd-1, ud-1, vd), 233 gradCoord6D(seed, x0+1, y0, z0, w0+1, u0+1, v0, xd-1, yd, zd, wd-1, ud-1, vd), xd), 234 cerp(gradCoord6D(seed, x0, y0+1, z0, w0+1, u0+1, v0, xd, yd-1, zd, wd-1, ud-1, vd), 235 gradCoord6D(seed, x0+1, y0+1, z0, w0+1, u0+1, v0, xd-1, yd-1, zd, wd-1, ud-1, vd), xd), 236 yd), 237 cerp( 238 cerp(gradCoord6D(seed, x0, y0, z0+1, w0+1, u0+1, v0, xd, yd, zd-1, wd-1, ud-1, vd), 239 gradCoord6D(seed, x0+1, y0, z0+1, w0+1, u0+1, v0, xd-1, yd, zd-1, wd-1, ud-1, vd), xd), 240 cerp(gradCoord6D(seed, x0, y0+1, z0+1, w0+1, u0+1, v0, xd, yd-1, zd-1, wd-1, ud-1, vd), 241 gradCoord6D(seed, x0+1, y0+1, z0+1, w0+1, u0+1, v0, xd-1, yd-1, zd-1, wd-1, ud-1, vd), xd), 242 yd), 243 zd), 244 wd), 245 ud), 246 cerp( 247 cerp( 248 cerp( 249 cerp( 250 cerp(gradCoord6D(seed, x0, y0, z0, w0, u0, v0+1, xd, yd, zd, wd, ud, vd-1), 251 gradCoord6D(seed, x0+1, y0, z0, w0, u0, v0+1, xd-1, yd, zd, wd, ud, vd-1), xd), 252 cerp(gradCoord6D(seed, x0, y0+1, z0, w0, u0, v0+1, xd, yd-1, zd, wd, ud, vd-1), 253 gradCoord6D(seed, x0+1, y0+1, z0, w0, u0, v0+1, xd-1, yd-1, zd, wd, ud, vd-1), xd), 254 yd), 255 cerp( 256 cerp(gradCoord6D(seed, x0, y0, z0+1, w0, u0, v0+1, xd, yd, zd-1, wd, ud, vd-1), 257 gradCoord6D(seed, x0+1, y0, z0+1, w0, u0, v0+1, xd-1, yd, zd-1, wd, ud, vd-1), xd), 258 cerp(gradCoord6D(seed, x0, y0+1, z0+1, w0, u0, v0+1, xd, yd-1, zd-1, wd, ud, vd-1), 259 gradCoord6D(seed, x0+1, y0+1, z0+1, w0, u0, v0+1, xd-1, yd-1, zd-1, wd, ud, vd-1), xd), 260 yd), 261 zd), 262 cerp( 263 cerp( 264 cerp(gradCoord6D(seed, x0, y0, z0, w0+1, u0, v0+1, xd, yd, zd, wd-1, ud, vd-1), 265 gradCoord6D(seed, x0+1, y0, z0, w0+1, u0, v0+1, xd-1, yd, zd, wd-1, ud, vd-1), xd), 266 cerp(gradCoord6D(seed, x0, y0+1, z0, w0+1, u0, v0+1, xd, yd-1, zd, wd-1, ud, vd-1), 267 gradCoord6D(seed, x0+1, y0+1, z0, w0+1, u0, v0+1, xd-1, yd-1, zd, wd-1, ud, vd-1), xd), 268 yd), 269 cerp( 270 cerp(gradCoord6D(seed, x0, y0, z0+1, w0+1, u0, v0+1, xd, yd, zd-1, wd-1, ud, vd-1), 271 gradCoord6D(seed, x0+1, y0, z0+1, w0+1, u0, v0+1, xd-1, yd, zd-1, wd-1, ud, vd-1), xd), 272 cerp(gradCoord6D(seed, x0, y0+1, z0+1, w0+1, u0, v0+1, xd, yd-1, zd-1, wd-1, ud, vd-1), 273 gradCoord6D(seed, x0+1, y0+1, z0+1, w0+1, u0, v0+1, xd-1, yd-1, zd-1, wd-1, ud, vd-1), xd), 274 yd), 275 zd), 276 wd), 277 cerp( 278 cerp( 279 cerp( 280 cerp(gradCoord6D(seed, x0, y0, z0, w0, u0+1, v0+1, xd, yd, zd, wd, ud-1, vd-1), 281 gradCoord6D(seed, x0+1, y0, z0, w0, u0+1, v0+1, xd-1, yd, zd, wd, ud-1, vd-1), xd), 282 cerp(gradCoord6D(seed, x0, y0+1, z0, w0, u0+1, v0+1, xd, yd-1, zd, wd, ud-1, vd-1), 283 gradCoord6D(seed, x0+1, y0+1, z0, w0, u0+1, v0+1, xd-1, yd-1, zd, wd, ud-1, vd-1), xd), 284 yd), 285 cerp( 286 cerp(gradCoord6D(seed, x0, y0, z0+1, w0, u0+1, v0+1, xd, yd, zd-1, wd, ud-1, vd-1), 287 gradCoord6D(seed, x0+1, y0, z0+1, w0, u0+1, v0+1, xd-1, yd, zd-1, wd, ud-1, vd-1), xd), 288 cerp(gradCoord6D(seed, x0, y0+1, z0+1, w0, u0+1, v0+1, xd, yd-1, zd-1, wd, ud-1, vd-1), 289 gradCoord6D(seed, x0+1, y0+1, z0+1, w0, u0+1, v0+1, xd-1, yd-1, zd-1, wd, ud-1, vd-1), xd), 290 yd), 291 zd), 292 cerp( 293 cerp( 294 cerp(gradCoord6D(seed, x0, y0, z0, w0+1, u0+1, v0+1, xd, yd, zd, wd-1, ud-1, vd-1), 295 gradCoord6D(seed, x0+1, y0, z0, w0+1, u0+1, v0+1, xd-1, yd, zd, wd-1, ud-1, vd-1), xd), 296 cerp(gradCoord6D(seed, x0, y0+1, z0, w0+1, u0+1, v0+1, xd, yd-1, zd, wd-1, ud-1, vd-1), 297 gradCoord6D(seed, x0+1, y0+1, z0, w0+1, u0+1, v0+1, xd-1, yd-1, zd, wd-1, ud-1, vd-1), xd), 298 yd), 299 cerp( 300 cerp(gradCoord6D(seed, x0, y0, z0+1, w0+1, u0+1, v0+1, xd, yd, zd-1, wd-1, ud-1, vd-1), 301 gradCoord6D(seed, x0+1, y0, z0+1, w0+1, u0+1, v0+1, xd-1, yd, zd-1, wd-1, ud-1, vd-1), xd), 302 cerp(gradCoord6D(seed, x0, y0+1, z0+1, w0+1, u0+1, v0+1, xd, yd-1, zd-1, wd-1, ud-1, vd-1), 303 gradCoord6D(seed, x0+1, y0+1, z0+1, w0+1, u0+1, v0+1, xd-1, yd-1, zd-1, wd-1, ud-1, vd-1), xd), 304 yd), 305 zd), 306 wd), 307 ud), 308 vd) * 1.875); 309// if(res < -1 || res > 1) System.out.println(res); 310// return res; 311 } 312}