001package squidpony.squidmath; 002 003import static squidpony.squidmath.ValueNoise.valueNoise; 004 005/** 006 * An unusual continuous noise generator that tends to produce organic-looking forms, currently supporting 2D, 3D, 4D 007 * and 6D. Produces noise values from -1.0 inclusive to 1.0 exclusive. Typically needs fewer octaves than the Simplex 008 * option in FastNoise to produce roughly comparable quality, but it also has about a third the speed. A useful property 009 * of FoamNoise is how its visual "character" doesn't change much as dimensions are added; whereas 6D simplex noise 010 * tends to separate into "surflets" separated by spans of 0, and higher dimensions of simplex only have larger such 011 * spans, FoamNoise seems to stay approximately as coherent in 2D, 3D, and 4D. Verifying this claim about FoamNoise is 012 * not easy, but it makes sense intuitively because of how this generator works. Simplex noise in N dimensions relies on 013 * a lattice of N-simplices (such as triangles in 2D or tetrahedra in 3D) and evaluates the noise at a point by hashing 014 * each of the N+1 vertices, looking up a gradient vector for each vertex from a pre-calculated array, and combining the 015 * gradient vectors based on proximity of the evaluated point to each vertex. FoamNoise in N dimensions is not nearly as 016 * complex; it relies on making N+1 averaged calls to N-dimensional value noise, each call using a rotated (and 017 * potentially skewed) set of axes, with each call's result also affecting the inputs to the next call (domain warping). 018 * Value noise uses a cubic lattice or its hypercube equivalent in higher dimensions, which seems to be more "stable" as 019 * dimensionality increases, and the number of value noise calls increases at the same rate as simplex noise adds 020 * gradient vectors. Averaging more calls causes the distribution of the noise to gradually approach Gaussian (biased 021 * toward results in the center of the range), but adjustments this does at the end counteract this well enough. 022 * <br> 023 * It's encouraged to experiment with the lacunarity parameter in {@link Noise.Layered3D} and similar classes if you use 024 * one of those variants, which also probably needs adjustments to frequency. Changing lacunarity wit multiple octaves 025 * can be useful to edit how tightly the noise clumps together. FoamNoise tends to look about the same with 3 octaves as 026 * it does with 4 octaves; for perceived quality, the returns seem to diminish quickly from added octaves. This isn't 027 * accurate for all frequencies, so you should definitely run through your options for what kinds of noise look good for 028 * a particular scenario. Mixing Simplex and Foam noise can produce a good water effect when applied to grid cells. 029 * <br> 030 * <a href="https://i.imgur.com/WpUz1xP.png">2D FoamNoise, one octave</a>, 031 * <a href="https://i.imgur.com/CDXcQRW.png">2D FoamNoise, one octave colorized</a>, 032 * <a href="https://i.imgur.com/XYUN8y4.png">2D FoamNoise, two octaves colorized</a> (note fewer peaks and valleys), 033 * <a href="https://i.imgur.com/cSiXzgW.gifv">3D FoamNoise animated over time, one octave colorized</a>, 034 * <a href="https://i.imgur.com/a2xO1Tb.gifv">3D FoamNoise animated over time, two octaves colorized</a>, 035 * <a href="https://i.imgur.com/MMnPn8C.gifv">4D FoamNoise animated over time, one octave colorized</a>, 036 * <a href="https://i.imgur.com/0ZHicDs.gifv">4D FoamNoise animated over time, two octaves colorized</a>, 037 * <a href="https://i.imgur.com/pjuFork.gifv">6D FoamNoise animated over time, one octave colorized</a>, 038 * <a href="https://i.imgur.com/CvWFFyI.gifv">6D FoamNoise animated over time, two octaves colorized</a>, 039 * <a href="https://i.imgur.com/ktCTiIK.jpg">World map made using FoamNoise</a>. 040 */ 041public class FoamNoise implements Noise.Noise2D, Noise.Noise3D, Noise.Noise4D, Noise.Noise6D { 042 public static final FoamNoise instance = new FoamNoise(); 043 044 public int seed = 0xD1CEBEEF; 045 public FoamNoise() { 046 } 047 048 public FoamNoise(int seed) { 049 this.seed = seed; 050 } 051 052 public FoamNoise(long seed) { 053 this.seed = (int) (seed ^ seed >>> 32); 054 } 055 056 public static double foamNoise(final double x, final double y, int seed) { 057 final double p0 = x; 058 final double p1 = x * -0.5 + y * 0.8660254037844386; 059 final double p2 = x * -0.5 + y * -0.8660254037844387; 060 061 double xin = p1; 062 double yin = p2; 063 //double xin = x * 0.540302 + y * 0.841471; // sin and cos of 1 064 //double yin = x * -0.841471 + y * 0.540302; 065 final double a = valueNoise(seed, xin, yin); 066 seed += 0x9E3779BD; 067 seed = (seed ^ seed >>> 12) * 0xDAB; 068 seed ^= seed >>> 14; 069 xin = p2; 070 yin = p0; 071 //xin = x * -0.989992 + y * 0.141120; // sin and cos of 3 072 //yin = x * -0.141120 + y * -0.989992; 073 final double b = valueNoise(seed, xin + a, yin); 074 seed += 0x9E3779BD; 075 seed = (seed ^ seed >>> 12) * 0xDAB; 076 seed ^= seed >>> 14; 077 xin = p0; 078 yin = p1; 079 //xin = x * 0.283662 + y * -0.958924; // sin and cos of 5 080 //yin = x * 0.958924 + y * 0.283662; 081 final double c = valueNoise(seed, xin + b, yin); 082 final double result = a * 0.3125 + (b + c) * 0.34375; 083// return result * result * (6.0 - 4.0 * result) - 1.0; 084 return (result <= 0.5) 085 ? (result * result * 4.0) - 1.0 086 : 1.0 - ((result - 1.0) * (result - 1.0) * 4.0); 087 } 088 089 /* 090x * -0.185127 + y * -0.791704 + z * -0.582180; 091x * -0.776796 + y * 0.628752 + z * -0.035464; 092x * 0.822283 + y * 0.467437 + z * -0.324582; 093 094x * 0.139640 + y * -0.304485 + z * 0.942226; 095x * -0.776796 + y * 0.628752 + z * -0.035464; 096x * 0.822283 + y * 0.467437 + z * -0.324582; 097 098x * 0.139640 + y * -0.304485 + z * 0.942226; 099x * -0.185127 + y * -0.791704 + z * -0.582180; 100x * 0.822283 + y * 0.467437 + z * -0.324582; 101 102x * 0.139640 + y * -0.304485 + z * 0.942226; 103x * -0.185127 + y * -0.791704 + z * -0.582180; 104x * -0.776796 + y * 0.628752 + z * -0.035464; 105 */ 106 107 108 public static double foamNoise(final double x, final double y, final double z, int seed) { 109 final double p0 = x; 110 final double p1 = x * -0.3333333333333333 + y * 0.9428090415820634; 111 final double p2 = x * -0.3333333333333333 + y * -0.4714045207910317 + z * 0.816496580927726; 112 final double p3 = x * -0.3333333333333333 + y * -0.4714045207910317 + z * -0.816496580927726; 113 114 //final double p0 = (x + y + z);// * 0.5; 115 //final double p1 = x - (y + z);// * 0.25; 116 //final double p2 = y - (x + z);// * 0.25; 117 //final double p3 = z - (x + y);// * 0.25; 118////rotated version of above points on a tetrahedron; the ones below are "more correct" but more complex (and slower?) 119// final double p0 = x * 0.139640 + y * -0.304485 + z * 0.942226; 120// final double p1 = x * -0.185127 + y * -0.791704 + z * -0.582180; 121// final double p2 = x * -0.776796 + y * 0.628752 + z * -0.035464; 122// final double p3 = x * 0.822283 + y * 0.467437 + z * -0.324582; 123 double xin = p1; 124 double yin = p2; 125 double zin = p3; 126 final double a = valueNoise(seed, xin, yin, zin); 127 //seed = (seed ^ 0x9E3779BD) * 0xDAB; 128 seed += 0x9E3779BD; 129 seed = (seed ^ seed >>> 12) * 0xDAB; 130 seed ^= seed >>> 14; 131 xin = p0; 132 yin = p2; 133 zin = p3; 134 final double b = valueNoise(seed, xin + a, yin, zin); 135 //seed = (seed ^ 0x9E3779BD) * 0xDAB; 136 seed += 0x9E3779BD; 137 seed = (seed ^ seed >>> 12) * 0xDAB; 138 seed ^= seed >>> 14; 139 xin = p0; 140 yin = p1; 141 zin = p3; 142 final double c = valueNoise(seed, xin + b, yin, zin); 143 //seed = (seed ^ 0x9E3779BD) * 0xDAB; 144 seed += 0x9E3779BD; 145 seed = (seed ^ seed >>> 12) * 0xDAB; 146 seed ^= seed >>> 14; 147 xin = p0; 148 yin = p1; 149 zin = p2; 150 final double d = valueNoise(seed, xin + c, yin, zin); 151 152 final double result = (a + b + c + d) * 0.25; 153// return (result * result * (6.0 - 4.0 * result) - 1.0); 154 return (result <= 0.5) 155 ? Math.pow(result * 2, 3.0) - 1.0 156 : Math.pow((result - 1) * 2, 3.0) + 1.0; 157 } 158 159 public static double foamNoise(final double x, final double y, final double z, final double w, int seed) { 160 final double p0 = x; 161 final double p1 = x * -0.25 + y * 0.9682458365518543; 162 final double p2 = x * -0.25 + y * -0.3227486121839514 + z * 0.9128709291752769; 163 final double p3 = x * -0.25 + y * -0.3227486121839514 + z * -0.45643546458763834 + w * 0.7905694150420949; 164 final double p4 = x * -0.25 + y * -0.3227486121839514 + z * -0.45643546458763834 + w * -0.7905694150420947; 165////orthogonal 5-cell, like a right triangle; probably incorrect 166 //final double p0 = (x + y + z + w); 167 //final double p1 = x - (y + z + w); 168 //final double p2 = y - (x + z + w); 169 //final double p3 = z - (x + y + w); 170 //final double p4 = w - (x + y + z); 171////rotated version of above points on a 5-cell; the ones below are "more correct" but more complex (and slower?) 172// final double p0 = x * 0.139640 + y * -0.304485 + z * 0.942226; 173// final double p1 = x * -0.185127 + y * -0.791704 + z * -0.582180; 174// final double p2 = x * -0.776796 + y * 0.628752 + z * -0.035464; 175// final double p3 = x * 0.822283 + y * 0.467437 + z * -0.324582; 176 double xin = p1; 177 double yin = p2; 178 double zin = p3; 179 double win = p4; 180 final double a = valueNoise(seed, xin, yin, zin, win); 181 //seed = (seed ^ 0x9E3779BD) * 0xDAB; 182 seed += 0x9E3779BD; 183 seed = (seed ^ seed >>> 12) * 0xDAB; 184 seed ^= seed >>> 14; 185 xin = p0; 186 yin = p2; 187 zin = p3; 188 win = p4; 189 final double b = valueNoise(seed, xin + a, yin, zin, win); 190 //seed = (seed ^ 0x9E3779BD) * 0xDAB; 191 seed += 0x9E3779BD; 192 seed = (seed ^ seed >>> 12) * 0xDAB; 193 seed ^= seed >>> 14; 194 xin = p0; 195 yin = p1; 196 zin = p3; 197 win = p4; 198 final double c = valueNoise(seed, xin + b, yin, zin, win); 199 //seed = (seed ^ 0x9E3779BD) * 0xDAB; 200 seed += 0x9E3779BD; 201 seed = (seed ^ seed >>> 12) * 0xDAB; 202 seed ^= seed >>> 14; 203 xin = p0; 204 yin = p1; 205 zin = p2; 206 win = p4; 207 final double d = valueNoise(seed, xin + c, yin, zin, win); 208 seed += 0x9E3779BD; 209 seed = (seed ^ seed >>> 12) * 0xDAB; 210 seed ^= seed >>> 14; 211 xin = p0; 212 yin = p1; 213 zin = p2; 214 win = p3; 215 final double e = valueNoise(seed, xin + d, yin, zin, win); 216 217 final double result = (a + b + c + d + e) * 0.2; 218 return (result <= 0.5) 219 ? Math.pow(result * 2, 4.0) - 1.0 220 : 1.0 - Math.pow((result - 1) * 2, 4.0); 221 222// return (result * result * (6.0 - 4.0 * result) - 1.0); 223 } 224 public static double foamNoise(final double x, final double y, final double z, 225 final double w, final double u, final double v, int seed) { 226 final double p0 = x; 227 final double p1 = x * -0.16666666666666666 + y * 0.9860132971832694; 228 final double p2 = x * -0.16666666666666666 + y * -0.19720265943665383 + z * 0.9660917830792959; 229 final double p3 = x * -0.16666666666666666 + y * -0.19720265943665383 + z * -0.24152294576982394 + w * 0.9354143466934853; 230 final double p4 = x * -0.16666666666666666 + y * -0.19720265943665383 + z * -0.24152294576982394 + w * -0.31180478223116176 + u * 0.8819171036881969; 231 final double p5 = x * -0.16666666666666666 + y * -0.19720265943665383 + z * -0.24152294576982394 + w * -0.31180478223116176 + u * -0.4409585518440984 + v * 0.7637626158259734; 232 final double p6 = x * -0.16666666666666666 + y * -0.19720265943665383 + z * -0.24152294576982394 + w * -0.31180478223116176 + u * -0.4409585518440984 + v * -0.7637626158259732; 233 double xin = p1; 234 double yin = p2; 235 double zin = p3; 236 double win = p4; 237 double uin = p5; 238 double vin = p6; 239 final double a = valueNoise(seed, xin, yin, zin, win, uin, vin); 240 seed += 0x9E3779BD; 241 seed = (seed ^ seed >>> 12) * 0xDAB; 242 seed ^= seed >>> 14; 243 xin = p0; 244 yin = p2; 245 zin = p3; 246 win = p4; 247 uin = p5; 248 vin = p6; 249 final double b = valueNoise(seed, xin + a, yin, zin, win, uin, vin); 250 seed += 0x9E3779BD; 251 seed = (seed ^ seed >>> 12) * 0xDAB; 252 seed ^= seed >>> 14; 253 xin = p0; 254 yin = p1; 255 zin = p3; 256 win = p4; 257 uin = p5; 258 vin = p6; 259 final double c = valueNoise(seed, xin + b, yin, zin, win, uin, vin); 260 seed += 0x9E3779BD; 261 seed = (seed ^ seed >>> 12) * 0xDAB; 262 seed ^= seed >>> 14; 263 xin = p0; 264 yin = p1; 265 zin = p2; 266 win = p4; 267 uin = p5; 268 vin = p6; 269 final double d = valueNoise(seed, xin + c, yin, zin, win, uin, vin); 270 seed += 0x9E3779BD; 271 seed = (seed ^ seed >>> 12) * 0xDAB; 272 seed ^= seed >>> 14; 273 xin = p0; 274 yin = p1; 275 zin = p2; 276 win = p3; 277 uin = p5; 278 vin = p6; 279 final double e = valueNoise(seed, xin + d, yin, zin, win, uin, vin); 280 seed += 0x9E3779BD; 281 seed = (seed ^ seed >>> 12) * 0xDAB; 282 seed ^= seed >>> 14; 283 xin = p0; 284 yin = p1; 285 zin = p2; 286 win = p3; 287 uin = p4; 288 vin = p6; 289 final double f = valueNoise(seed, xin + e, yin, zin, win, uin, vin); 290 seed += 0x9E3779BD; 291 seed = (seed ^ seed >>> 12) * 0xDAB; 292 seed ^= seed >>> 14; 293 xin = p0; 294 yin = p1; 295 zin = p2; 296 win = p3; 297 uin = p4; 298 vin = p5; 299 final double g = valueNoise(seed, xin + f, yin, zin, win, uin, vin); 300 301 final double result = (a + b + c + d + e + f + g) * 0.14285714285714285; 302 return (result <= 0.5) 303 ? Math.pow(result * 2, 6.0) - 1.0 304 : 1.0 - Math.pow((result - 1) * 2, 6.0); 305 } 306 307 @Override 308 public double getNoise(double x, double y) { 309 return foamNoise(x, y, seed); 310 } 311 @Override 312 public double getNoiseWithSeed(double x, double y, long seed) { 313 return foamNoise(x, y, (int) (seed ^ seed >>> 32)); 314 } 315 @Override 316 public double getNoise(double x, double y, double z) { 317 return foamNoise(x, y, z, seed); 318 } 319 @Override 320 public double getNoiseWithSeed(double x, double y, double z, long seed) { 321 return foamNoise(x, y, z, (int) (seed ^ seed >>> 32)); 322 } 323 @Override 324 public double getNoise(double x, double y, double z, double w) { 325 return foamNoise(x, y, z, w, seed); 326 } 327 @Override 328 public double getNoiseWithSeed(double x, double y, double z, double w, long seed) { 329 return foamNoise(x, y, z, w, (int) (seed ^ seed >>> 32)); 330 } 331 @Override 332 public double getNoise(double x, double y, double z, double w, double u, double v) { 333 return foamNoise(x, y, z, w, u, v, seed); 334 } 335 @Override 336 public double getNoiseWithSeed(double x, double y, double z, double w, double u, double v, long seed) { 337 return foamNoise(x, y, z, w, u, v, (int) (seed ^ seed >>> 32)); 338 } 339}