Added diverse noise styles

- Dune and Strata add dunes and layered bands
- Wood and Marble add warped grain and mineral veins
- Gabor and Scales add oriented waves and overlapping scallops
- Chladni and Kaleidoscope add nodal lines and mirrored motifs
- Menger Sponge and Circuit add recursive voids and connected traces
- New styles use the shared scale and full seeds
- Tests cover tile seams, volume variation, bounds, and octaves
This commit is contained in:
Brian Neumann-Fopiano committed 2026-09-05 19:33:53 -04:00
1 parent 645edcff5c
commit 14cfe3ed68
22 files changed
+1183 -3

No files matched your search

@@ -553,6 +553,36 @@ public enum NoiseStyle {
@Desc("Seeded spiral arms form swirling eddies in 2D and winding funnels in 3D.")
VORTEX(rng -> new CNG(rng, NoiseType.VORTEX, 1D, 1), NoiseType.VORTEX),
@Desc("Seeded crescent dunes with asymmetric slopes and smooth height-dependent drift.")
DUNE(rng -> new CNG(rng, NoiseType.DUNE, 1D, 1), NoiseType.DUNE),
@Desc("Folded sedimentary bands with varying thickness through the volume.")
STRATA(rng -> new CNG(rng, NoiseType.STRATA, 1D, 1), NoiseType.STRATA),
@Desc("Distorted growth rings and knot-like forms with variation through height.")
WOOD(rng -> new CNG(rng, NoiseType.WOOD, 1D, 1), NoiseType.WOOD),
@Desc("Seeded oriented wave packets form a sparse directional ripple texture.")
GABOR(rng -> new CNG(rng, NoiseType.GABOR, 1D, 1), NoiseType.GABOR),
@Desc("Turbulent stone veins separate broad smooth regions.")
MARBLE(rng -> new CNG(rng, NoiseType.MARBLE, 1D, 1), NoiseType.MARBLE),
@Desc("Overlapping scalloped scales form a seeded tiled surface.")
SCALES(rng -> new CNG(rng, NoiseType.SCALES, 1D, 1), NoiseType.SCALES),
@Desc("Standing-wave nodes form plate-like figures that change through height.")
CHLADNI(rng -> new CNG(rng, NoiseType.CHLADNI, 1D, 1), NoiseType.CHLADNI),
@Desc("Mirrored wedge motifs repeat at a local scale with seeded variation.")
KALEIDOSCOPE(rng -> new CNG(rng, NoiseType.KALEIDOSCOPE, 1D, 1), NoiseType.KALEIDOSCOPE),
@Desc("Recursive cubic voids form a three-dimensional sponge with square-hole slices.")
MENGER_SPONGE(rng -> new CNG(rng, NoiseType.MENGER_SPONGE, 1D, 1), NoiseType.MENGER_SPONGE),
@Desc("Orthogonal tracks and ring pads form connected circuits that shift through height.")
CIRCUIT(rng -> new CNG(rng, NoiseType.CIRCUIT, 1D, 1), NoiseType.CIRCUIT),
;
private final CNGFactory f;
@@ -0,0 +1,34 @@
package art.arcane.iris.util.project.noise;
public final class ChladniNoise extends PatternNoise {
private final int firstMode;
private final int secondMode;
private final double phase;
private final double width;
public ChladniNoise(long seed) {
long hash = mix(seed);
firstMode = 2 + (int) (hash & 1L);
secondMode = firstMode + 1 + (int) ((hash >>> 1) & 1L);
phase = (hash >>> 11) * 0x1.0p-52D;
width = 0.22D + ((hash >>> 3) & 255L) * (0.12D / 255D);
}
@Override
protected double sample(double x, double y, double z) {
double u = (x + phase) * Math.PI;
double v = (z + phase) * Math.PI;
double first = Math.cos(firstMode * u) * Math.cos(secondMode * v);
double second = Math.cos(secondMode * u) * Math.cos(firstMode * v);
double field = first * Math.cos(y * Math.PI * 0.5D)
- second * Math.cos(y * Math.PI * 0.75D);
double node = Math.max(0D, 1D - Math.abs(field) / width);
return node * node * (3D - 2D * node);
}
private static long mix(long value) {
value = (value ^ (value >>> 30)) * 0xBF58476D1CE4E5B9L;
value = (value ^ (value >>> 27)) * 0x94D049BB133111EBL;
return value ^ (value >>> 31);
}
}
@@ -0,0 +1,73 @@
package art.arcane.iris.util.project.noise;
public final class CircuitNoise extends PatternNoise {
private final long seed;
private final double phaseX;
private final double phaseZ;
public CircuitNoise(long seed) {
this.seed = seed;
phaseX = (mix(seed) >>> 11) * 0x1.0p-53;
phaseZ = (mix(seed + 0x9E3779B97F4A7C15L) >>> 11) * 0x1.0p-53;
}
@Override
protected double sample(double x, double y, double z) {
x += phaseX;
z += phaseZ;
if (y != 0D) {
x += y * 0.13D + 0.17D * Math.sin(y * Math.PI * 0.5D);
z += 0.11D * Math.sin(y * Math.PI * 0.75D);
}
long cellX = (long) Math.floor(x);
long cellZ = (long) Math.floor(z);
x -= cellX;
z -= cellZ;
long hash = mix(seed ^ cellX * 0x9E3779B97F4A7C15L ^ cellZ * 0xD1B54A32D192ED03L);
double distance;
double padDistance;
if ((hash & 3L) == 0L) {
distance = Math.min(Math.abs(x - 0.5D), Math.abs(z - 0.5D));
double dx = x - 0.5D;
double dz = z - 0.5D;
padDistance = Math.sqrt(dx * dx + dz * dz);
} else {
if ((hash & 1L) != 0L) {
x = 1D - x;
}
distance = Math.sqrt(Math.min(routeDistanceSquared(x, z), routeDistanceSquared(1D - x, 1D - z)));
double dx = x - 0.75D;
double dz = z - 0.25D;
double oppositeX = x - 0.25D;
double oppositeZ = z - 0.75D;
padDistance = Math.sqrt(Math.min(dx * dx + dz * dz, oppositeX * oppositeX + oppositeZ * oppositeZ));
}
double trace = smooth(1D - distance / 0.045D);
double pad = smooth(1D - Math.abs(padDistance - 0.085D) / 0.03D);
return Math.max(trace, pad) * smooth(padDistance / 0.045D);
}
private static double routeDistanceSquared(double x, double z) {
double top = segmentDistanceSquared(x - 0.5D, z, 0D, 0.25D);
double bend = segmentDistanceSquared(z - 0.25D, x, 0.5D, 0.75D);
double middle = segmentDistanceSquared(x - 0.75D, z, 0.25D, 0.5D);
double right = segmentDistanceSquared(z - 0.5D, x, 0.75D, 1D);
return Math.min(Math.min(top, bend), Math.min(middle, right));
}
private static double segmentDistanceSquared(double perpendicular, double along, double start, double end) {
double excess = Math.max(start - along, Math.max(along - end, 0D));
return perpendicular * perpendicular + excess * excess;
}
private static double smooth(double value) {
double bounded = Math.clamp(value, 0D, 1D);
return bounded * bounded * (3D - 2D * bounded);
}
private static long mix(long value) {
value = (value ^ (value >>> 30)) * 0xBF58476D1CE4E5B9L;
value = (value ^ (value >>> 27)) * 0x94D049BB133111EBL;
return value ^ (value >>> 31);
}
}
@@ -0,0 +1,61 @@
package art.arcane.iris.util.project.noise;
public final class DuneNoise extends PatternNoise {
private static final double TAU = Math.PI * 2D;
private final long seed;
private final double cosine;
private final double sine;
private final double phase;
public DuneNoise(long seed) {
this.seed = seed;
phase = unit(mix(seed)) * TAU;
cosine = Math.cos(phase);
sine = Math.sin(phase);
}
@Override
protected double sample(double x, double y, double z) {
double wind = x * cosine + z * sine + y * 0.17D;
double across = z * cosine - x * sine + 0.12D * Math.sin(y * 0.7D + phase);
long cellWind = (long) Math.floor(wind);
long cellAcross = (long) Math.floor(across);
double dune = 0D;
for (int offsetWind = -1; offsetWind <= 1; offsetWind++) {
long gridWind = cellWind + offsetWind;
for (int offsetAcross = -1; offsetAcross <= 1; offsetAcross++) {
long gridAcross = cellAcross + offsetAcross;
long hash = mix(seed ^ gridWind * 0x9E3779B97F4A7C15L ^ gridAcross * 0xD1B54A32D192ED03L);
double centerWind = gridWind + 0.2D + (hash & 65535L) * (0.6D / 65535D);
double centerAcross = gridAcross + 0.2D + ((hash >>> 16) & 65535L) * (0.6D / 65535D);
double width = 0.32D + ((hash >>> 32) & 255L) * (0.16D / 255D);
double transverse = (across - centerAcross) / width;
double transverseSquared = transverse * transverse;
if (transverseSquared >= 1D) {
continue;
}
double crest = centerWind + 0.43D * transverseSquared;
double offset = wind - crest;
double windward = 0.52D + ((hash >>> 40) & 255L) * (0.14D / 255D);
double leeward = 0.1D + ((hash >>> 48) & 255L) * (0.035D / 255D);
double slope = Math.max(0D, 1D - Math.abs(offset) / (offset < 0D ? windward : leeward));
double horns = 1D - transverseSquared * transverseSquared;
double height = 0.62D + (hash >>> 56) * (0.38D / 255D);
dune = Math.max(dune, height * horns * horns * slope * slope * (3D - 2D * slope));
}
}
double ripples = 0.04D + 0.035D * Math.cos(wind * TAU * 2D + 0.5D * Math.sin(across * 1.7D + phase));
return ripples + (1D - ripples) * dune;
}
private static long mix(long value) {
value = (value ^ (value >>> 30)) * 0xBF58476D1CE4E5B9L;
value = (value ^ (value >>> 27)) * 0x94D049BB133111EBL;
return value ^ (value >>> 31);
}
private static double unit(long value) {
return (value >>> 11) * 0x1.0p-53D;
}
}
@@ -0,0 +1,72 @@
package art.arcane.iris.util.project.noise;
import java.util.SplittableRandom;
public final class GaborNoise extends PatternNoise {
private static final double TAU = Math.PI * 2D;
private static final double RADIUS_SQUARED = 0.95D * 0.95D;
private static final double SPREAD = 0.6D / 65535D;
private final long seed;
private final double directionX;
private final double directionY;
private final double directionZ;
public GaborNoise(long seed) {
this.seed = seed;
SplittableRandom random = new SplittableRandom(seed);
double angle = random.nextDouble(TAU);
double elevation = random.nextDouble(-0.55D, 0.55D);
double horizontal = Math.sqrt(1D - elevation * elevation);
directionX = Math.cos(angle) * horizontal;
directionY = elevation;
directionZ = Math.sin(angle) * horizontal;
}
@Override
protected double sample(double x, double y, double z) {
long cellX = (long) Math.floor(x);
long cellY = (long) Math.floor(y);
long cellZ = (long) Math.floor(z);
double sum = 0D;
double weights = 0.12D;
for (int offsetY = -1; offsetY <= 1; offsetY++) {
long pointY = cellY + offsetY;
long hashY = pointY * 0xC2B2AE3D27D4EB4FL;
for (int offsetZ = -1; offsetZ <= 1; offsetZ++) {
long pointZ = cellZ + offsetZ;
long hashYZ = hashY ^ pointZ * 0x165667B19E3779F9L;
for (int offsetX = -1; offsetX <= 1; offsetX++) {
long pointX = cellX + offsetX;
long hash = mix(seed ^ pointX * 0x9E3779B97F4A7C15L ^ hashYZ);
if ((hash & 3L) == 0L) {
continue;
}
double dx = x - (pointX + 0.2D + (hash & 65535L) * SPREAD);
double dy = y - (pointY + 0.2D + ((hash >>> 16) & 65535L) * SPREAD);
double dz = z - (pointZ + 0.2D + ((hash >>> 32) & 65535L) * SPREAD);
double distanceSquared = dx * dx + dy * dy + dz * dz;
if (distanceSquared >= RADIUS_SQUARED) {
continue;
}
double envelope = 1D - distanceSquared / RADIUS_SQUARED;
double weight = envelope * envelope * envelope;
long wave = mix(hash);
double waveX = directionX + ((wave & 1023L) / 1023D - 0.5D) * 0.35D;
double waveY = directionY + (((wave >>> 10) & 1023L) / 1023D - 0.5D) * 0.35D;
double waveZ = directionZ + (((wave >>> 20) & 1023L) / 1023D - 0.5D) * 0.35D;
double phase = (wave >>> 32) * (TAU / 4294967296D);
sum += weight * Math.cos(TAU * 3D * (waveX * dx + waveY * dy + waveZ * dz) + phase);
weights += weight;
}
}
}
return 0.5D + 0.5D * sum / weights;
}
private static long mix(long value) {
value = (value ^ (value >>> 30)) * 0xBF58476D1CE4E5B9L;
value = (value ^ (value >>> 27)) * 0x94D049BB133111EBL;
return value ^ (value >>> 31);
}
}
@@ -0,0 +1,43 @@
package art.arcane.iris.util.project.noise;
public final class KaleidoscopeNoise extends PatternNoise {
private static final double TAU = Math.PI * 2D;
private final long seed;
public KaleidoscopeNoise(long seed) {
this.seed = seed;
}
@Override
protected double sample(double x, double y, double z) {
z += 0.5D;
long cellX = (long) Math.floor(x);
long cellZ = (long) Math.floor(z);
double dx = x - cellX - 0.5D;
double dz = z - cellZ - 0.5D;
double radiusSquared = dx * dx + dz * dz;
if (radiusSquared >= 0.25D) {
return 0D;
}
long hash = mix(seed ^ cellX * 0x9E3779B97F4A7C15L ^ cellZ * 0xD1B54A32D192ED03L);
int wedges = 4 + (int) (hash & 3L);
double phase = (hash >>> 11) * 0x1.0p-53D * TAU;
double sector = TAU / wedges;
double angle = Math.atan2(dz, dx) + phase + y * 0.35D;
angle = Math.abs(angle - Math.floor(angle / sector + 0.5D) * sector);
double radius = Math.sqrt(radiusSquared);
double u = radius * Math.cos(angle);
double v = radius * Math.sin(angle);
double motif = 0.5D + 0.5D * Math.cos(16D * u + 2.5D * Math.cos(18D * v + phase + y));
double envelope = 1D - radiusSquared * 4D;
return motif * envelope * envelope;
}
private static long mix(long value) {
value = (value ^ (value >>> 30)) * 0xBF58476D1CE4E5B9L;
value = (value ^ (value >>> 27)) * 0x94D049BB133111EBL;
return value ^ (value >>> 31);
}
}
@@ -0,0 +1,36 @@
package art.arcane.iris.util.project.noise;
import java.util.SplittableRandom;
public final class MarbleNoise extends PatternNoise {
private static final double TAU = Math.PI * 2D;
private final FastNoiseDouble distortion;
private final double directionX;
private final double directionY;
private final double directionZ;
private final double phase;
public MarbleNoise(long seed) {
SplittableRandom random = new SplittableRandom(seed);
distortion = new FastNoiseDouble(random.nextLong());
distortion.setFrequency(1D);
double angle = random.nextDouble(TAU);
directionX = Math.cos(angle);
directionY = random.nextDouble(0.25D, 0.65D);
directionZ = Math.sin(angle);
phase = random.nextDouble(TAU);
}
@Override
protected double sample(double x, double y, double z) {
double broad = distortion.GetSimplex(x * 0.45D, y * 0.45D, z * 0.45D);
double detail = distortion.GetSimplex(x * 1.3D + 17.3D, y * 1.3D - 11.7D, z * 1.3D + 5.9D);
double warp = broad * 1.1D + detail * 0.2D;
double position = x * directionX + y * directionY + z * directionZ;
double ridge = Math.sin(TAU * (position + warp) + phase);
double vein = 1D / (1D + 90D * ridge * ridge);
double stone = 0.85D + 0.15D * broad;
return Math.clamp(0.1D + 0.84D * stone * (1D - vein), 0D, 1D);
}
}
@@ -0,0 +1,48 @@
package art.arcane.iris.util.project.noise;
public final class MengerSpongeNoise extends PatternNoise {
private static final int DEPTH = 3;
private final double phaseX;
private final double phaseY;
private final double phaseZ;
public MengerSpongeNoise(long seed) {
long hash = mix(seed);
phaseX = (hash & 0x1FFFFFL) * 0x1.0p-21D;
phaseY = ((hash >>> 21) & 0x1FFFFFL) * (0x1.0p-21D / 3D);
phaseZ = (hash >>> 42) * 0x1.0p-22D;
}
@Override
protected double sample(double x, double y, double z) {
x += phaseX;
y += phaseY;
z += phaseZ;
x -= Math.floor(x);
y -= Math.floor(y);
z -= Math.floor(z);
for (int level = 0; level < DEPTH; level++) {
x *= 3D;
y *= 3D;
z *= 3D;
int cellX = (int) x;
int cellY = (int) y;
int cellZ = (int) z;
int middleAxes = (cellX == 1 ? 1 : 0) + (cellY == 1 ? 1 : 0) + (cellZ == 1 ? 1 : 0);
if (middleAxes >= 2) {
return 0D;
}
x -= cellX;
y -= cellY;
z -= cellZ;
}
return 1D;
}
private static long mix(long value) {
value = (value ^ (value >>> 30)) * 0xBF58476D1CE4E5B9L;
value = (value ^ (value >>> 27)) * 0x94D049BB133111EBL;
return value ^ (value >>> 31);
}
}
@@ -92,7 +92,17 @@ public enum NoiseType {
QUASICRYSTAL(QuasicrystalNoise::new, 1D / 64D),
TRUCHET(TruchetNoise::new, 1D / 64D),
CRATER(CraterNoise::new, 1D / 64D),
VORTEX(VortexNoise::new, 1D / 64D);
VORTEX(VortexNoise::new, 1D / 64D),
DUNE(DuneNoise::new, 1D / 64D),
STRATA(StrataNoise::new, 1D / 64D),
WOOD(WoodNoise::new, 1D / 64D),
GABOR(GaborNoise::new, 1D / 64D),
MARBLE(MarbleNoise::new, 1D / 64D),
SCALES(ScalesNoise::new, 1D / 64D),
CHLADNI(ChladniNoise::new, 1D / 64D),
KALEIDOSCOPE(KaleidoscopeNoise::new, 1D / 64D),
MENGER_SPONGE(MengerSpongeNoise::new, 1D / 64D),
CIRCUIT(CircuitNoise::new, 1D / 64D);
private final NoiseFactory f;
private final double coordinateScale;
@@ -0,0 +1,61 @@
package art.arcane.iris.util.project.noise;
public final class ScalesNoise extends PatternNoise {
private static final double TAU = Math.PI * 2D;
private static final double RADIUS = 0.5D;
private static final double ROW_HEIGHT = 0.5D;
private static final double GROOVE_WIDTH = 0.055D;
private final long seed;
private final double phaseX;
private final double phaseZ;
public ScalesNoise(long seed) {
this.seed = seed;
phaseX = (mix(seed) >>> 11) * 0x1.0p-53D;
phaseZ = (mix(seed + 0x9E3779B97F4A7C15L) >>> 11) * 0x1.0p-53D;
}
@Override
protected double sample(double x, double y, double z) {
x += phaseX + Math.sin(y * TAU * 0.5D) * 0.22D + y * 0.15D;
z += phaseZ + Math.sin(y * TAU * 0.25D) * 0.12D + y * 0.2D;
long row = (long) Math.floor(z / ROW_HEIGHT);
double groove = 0D;
double shade = 0D;
for (int offsetZ = -1; offsetZ <= 1; offsetZ++) {
long pointZ = row + offsetZ;
double shift = (pointZ & 1L) * 0.5D;
long column = (long) Math.floor(x - shift);
double dz = z - pointZ * ROW_HEIGHT;
for (int offsetX = -1; offsetX <= 1; offsetX++) {
long pointX = column + offsetX;
double dx = x - (pointX + shift);
double radiusSquared = dx * dx + dz * dz;
double distance;
if (dz >= 0D) {
distance = Math.abs(Math.sqrt(radiusSquared) - RADIUS);
} else {
double endpoint = Math.abs(dx) - RADIUS;
distance = Math.sqrt(endpoint * endpoint + dz * dz);
}
double rim = Math.max(0D, 1D - distance / GROOVE_WIDTH);
if (rim > 0D || radiusSquared < RADIUS * RADIUS && dz > 0D) {
long hash = mix(seed ^ pointX * 0x9E3779B97F4A7C15L ^ pointZ * 0xC2B2AE3D27D4EB4FL);
double variation = 0.75D + (hash >>> 11) * 0x1.0p-53D * 0.25D;
groove = Math.max(groove, rim * rim * (3D - 2D * rim) * variation);
double inside = Math.max(0D, 1D - radiusSquared / (RADIUS * RADIUS));
double rise = Math.clamp(dz / 0.12D, 0D, 1D);
shade = Math.max(shade, inside * rise * rise * (3D - 2D * rise) * variation);
}
}
}
return 0.72D + 0.22D * shade - 0.65D * groove;
}
private static long mix(long value) {
value = (value ^ (value >>> 30)) * 0xBF58476D1CE4E5B9L;
value = (value ^ (value >>> 27)) * 0x94D049BB133111EBL;
return value ^ (value >>> 31);
}
}
@@ -0,0 +1,37 @@
package art.arcane.iris.util.project.noise;
import java.util.SplittableRandom;
public final class StrataNoise extends PatternNoise {
private static final double TAU = Math.PI * 2D;
private final double cosine;
private final double sine;
private final double phaseA;
private final double phaseB;
private final double phaseC;
public StrataNoise(long seed) {
SplittableRandom random = new SplittableRandom(seed);
double angle = random.nextDouble(TAU);
cosine = Math.cos(angle);
sine = Math.sin(angle);
phaseA = random.nextDouble(TAU);
phaseB = random.nextDouble(TAU);
phaseC = random.nextDouble(TAU);
}
@Override
protected double sample(double x, double y, double z) {
double along = x * cosine + z * sine;
double across = z * cosine - x * sine;
double fold = 1.1D * Math.sin(along * 1.1D + phaseA)
+ 0.35D * Math.sin(along * 2.7D + across * 0.8D + phaseB + y * 0.4D)
+ 0.2D * Math.sin(across * 1.7D + y * 0.9D + phaseC);
double layer = TAU * (across + y * 0.75D + fold);
double thickness = layer + 0.55D * Math.sin(layer * 0.25D + phaseB);
double broadBand = 0.5D + 0.5D * Math.sin(thickness);
double lamina = 0.5D + 0.5D * Math.sin(thickness * 3D + phaseC);
return 0.82D * broadBand + 0.18D * lamina;
}
}
@@ -0,0 +1,56 @@
package art.arcane.iris.util.project.noise;
public final class WoodNoise extends PatternNoise {
private static final double TAU = Math.PI * 2D;
private final long seed;
private final double cosine;
private final double sine;
private final double phase;
public WoodNoise(long seed) {
this.seed = seed;
phase = (mix(seed) >>> 11) * 0x1.0p-53D * TAU;
cosine = Math.cos(phase);
sine = Math.sin(phase);
}
@Override
protected double sample(double x, double y, double z) {
double along = (z * cosine - x * sine) * 0.45D + y * 0.17D;
double across = x * cosine + z * sine + y * 0.07D + 0.11D * Math.sin(along * 0.85D + phase);
double grainPhase = across * TAU * 3D + 0.18D * Math.sin(along * 2.1D + phase);
double value = 0.12D * (0.5D + 0.5D * Math.sin(grainPhase));
double weightSum = 0.12D;
long cellAcross = (long) Math.floor(across);
long cellAlong = (long) Math.floor(along);
for (int offsetAcross = -1; offsetAcross <= 1; offsetAcross++) {
long gridAcross = cellAcross + offsetAcross;
for (int offsetAlong = -1; offsetAlong <= 1; offsetAlong++) {
long gridAlong = cellAlong + offsetAlong;
long hash = mix(seed ^ gridAcross * 0x9E3779B97F4A7C15L ^ gridAlong * 0xD1B54A32D192ED03L);
double deltaAcross = across - (gridAcross + 0.3D + (hash & 65535L) * (0.4D / 65535D));
double deltaAlong = along - (gridAlong + 0.3D + ((hash >>> 16) & 65535L) * (0.4D / 65535D));
double radius = 0.5D + ((hash >>> 32) & 255L) * (0.12D / 255D);
double distanceSquared = deltaAcross * deltaAcross + deltaAlong * deltaAlong;
double envelope = 1D - distanceSquared / (radius * radius);
if (envelope <= 0D) {
continue;
}
double rings = Math.sqrt(distanceSquared + 0.0004D) * TAU * 5D;
double ringPhase = ((hash >>> 40) & 65535L) * (TAU / 65535D);
double knot = 0.5D + 0.5D * Math.sin(rings + ringPhase);
double weight = 3D * envelope * envelope;
value += knot * weight;
weightSum += weight;
}
}
return value / weightSum;
}
private static long mix(long value) {
value = (value ^ (value >>> 30)) * 0xBF58476D1CE4E5B9L;
value = (value ^ (value >>> 27)) * 0x94D049BB133111EBL;
return value ^ (value >>> 31);
}
}