mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2026-04-03 06:16:19 +00:00
Noise Pass
This commit is contained in:
@@ -100,8 +100,8 @@ public class IrisNoiseGenerator {
|
||||
|
||||
for (IrisNoiseGenerator i : fracture) {
|
||||
if (i.isEnabled()) {
|
||||
x += i.getNoise(superSeed + seed + g, xv, zv, data) - (opacity / 2D);
|
||||
z -= i.getNoise(superSeed + seed + g, zv, xv, data) - (opacity / 2D);
|
||||
x += i.getNoise(superSeed + seed + g, xv, zv, data) - (i.getOpacity() / 2D);
|
||||
z += i.getNoise(superSeed + seed + g, zv, xv, data) - (i.getOpacity() / 2D);
|
||||
}
|
||||
g += 819;
|
||||
}
|
||||
|
||||
@@ -143,6 +143,21 @@ public enum NoiseStyle {
|
||||
@Desc("Cellular noise creates the same noise level for cells, changes noise level on cell borders.")
|
||||
CELLULAR_HERMITE(rng -> new CNG(rng, NoiseType.CELLULAR_HERMITE, 1D, 1)),
|
||||
|
||||
@Desc("Hexagonal cells with stable per-cell values.")
|
||||
HEXAGON(rng -> new CNG(rng, NoiseType.HEXAGON, 1D, 1).scale(1)),
|
||||
|
||||
@Desc("Hex James substitution pattern with 3 large and 3 small recursive hex children plus gaps.")
|
||||
HEX_JAMES(rng -> new CNG(rng, NoiseType.HEX_JAMES, 1D, 1).scale(1)),
|
||||
|
||||
@Desc("Interlocked solid hex cells with per-cell values from a smooth simplex heatmap.")
|
||||
HEX_SIMPLEX(rng -> new CNG(rng, NoiseType.HEX_SIMPLEX, 1D, 1).scale(1)),
|
||||
|
||||
@Desc("Randomized finite-depth Sierpinski-style hex recursion with per-level random 3-large/3-small James substitution.")
|
||||
HEX_RANDOM_SIZE(rng -> new CNG(rng, NoiseType.HEX_RANDOM_SIZE, 1D, 1).scale(1)),
|
||||
|
||||
@Desc("Sierpinski triangle mask blended with simplex heat.")
|
||||
SIERPINSKI_TRIANGLE(rng -> new CNG(rng, NoiseType.SIERPINSKI_TRIANGLE, 1D, 1).scale(1)),
|
||||
|
||||
@Desc("Classic German Engineering")
|
||||
NOWHERE(rng -> CNG.signaturePerlin(rng).scale(0.776).bake()),
|
||||
|
||||
@@ -152,6 +167,21 @@ public enum NoiseStyle {
|
||||
@Desc("Classic German Engineering")
|
||||
NOWHERE_CLOVER(rng -> CNG.signaturePerlin(rng, NoiseType.CLOVER).scale(1).bake()),
|
||||
|
||||
@Desc("Classic German Engineering")
|
||||
NOWHERE_HEXAGON(rng -> CNG.signaturePerlin(rng, NoiseType.HEXAGON).scale(1).bake()),
|
||||
|
||||
@Desc("Classic German Engineering")
|
||||
NOWHERE_HEX_JAMES(rng -> CNG.signaturePerlin(rng, NoiseType.HEX_JAMES).scale(1).bake()),
|
||||
|
||||
@Desc("Classic German Engineering")
|
||||
NOWHERE_HEX_SIMPLEX(rng -> CNG.signaturePerlin(rng, NoiseType.HEX_SIMPLEX).scale(1).bake()),
|
||||
|
||||
@Desc("Classic German Engineering")
|
||||
NOWHERE_HEX_RANDOM_SIZE(rng -> CNG.signaturePerlin(rng, NoiseType.HEX_RANDOM_SIZE).scale(1).bake()),
|
||||
|
||||
@Desc("Classic German Engineering")
|
||||
NOWHERE_SIERPINSKI_TRIANGLE(rng -> CNG.signaturePerlin(rng, NoiseType.SIERPINSKI_TRIANGLE).scale(1).bake()),
|
||||
|
||||
@Desc("Classic German Engineering")
|
||||
NOWHERE_SIMPLEX(rng -> CNG.signaturePerlin(rng, NoiseType.SIMPLEX).scale(1).bake()),
|
||||
|
||||
@@ -242,6 +272,21 @@ public enum NoiseStyle {
|
||||
@Desc("FBM Fractal Iris Noise. Single octave.")
|
||||
FRACTAL_FBM_IRIS_THICK(rng -> CNG.signatureThick(rng, NoiseType.FRACTAL_FBM_SIMPLEX)),
|
||||
|
||||
@Desc("Fractal hexagonal cell noise.")
|
||||
FRACTAL_HEXAGON(rng -> new CNG(rng, NoiseType.HEXAGON, 1D, 4).scale(1)),
|
||||
|
||||
@Desc("Fractal Hex James substitution pattern with recursive 3-large/3-small child hexes and gaps.")
|
||||
FRACTAL_HEX_JAMES(rng -> new CNG(rng, NoiseType.HEX_JAMES, 1D, 4).scale(1)),
|
||||
|
||||
@Desc("Interlocked solid hex cells with per-cell fractal simplex heatmap values.")
|
||||
FRACTAL_HEX_SIMPLEX(rng -> new CNG(rng, NoiseType.HEX_SIMPLEX, 1D, 4).scale(1)),
|
||||
|
||||
@Desc("Fractal hexagonal gradient noise with randomized local hex sizes and blended random/simplex heatmaps.")
|
||||
FRACTAL_HEX_RANDOM_SIZE(rng -> new CNG(rng, NoiseType.HEX_RANDOM_SIZE, 1D, 4).scale(1)),
|
||||
|
||||
@Desc("Fractal Sierpinski triangle mask blended with simplex heat.")
|
||||
FRACTAL_SIERPINSKI_TRIANGLE(rng -> new CNG(rng, NoiseType.SIERPINSKI_TRIANGLE, 1D, 4).scale(1)),
|
||||
|
||||
@Desc("Rigid Multi Fractal Simplex Noise. Single octave.")
|
||||
FRACTAL_RM_SIMPLEX(rng -> new CNG(rng, NoiseType.FRACTAL_RIGID_MULTI_SIMPLEX, 1D, 1)),
|
||||
|
||||
@@ -407,6 +452,54 @@ public enum NoiseStyle {
|
||||
@Desc("Cubic Noise")
|
||||
CUBIC_IRIS_THICK(rng -> CNG.signatureThick(rng, NoiseType.CUBIC).scale(256)),
|
||||
|
||||
@Desc("Hexagonal cell noise distorted using Iris styled wispy noise.")
|
||||
HEXAGON_IRIS(rng -> CNG.signature(rng, NoiseType.HEXAGON).scale(1)),
|
||||
|
||||
@Desc("Hexagonal cell noise distorted using Iris styled wispy noise.")
|
||||
HEXAGON_IRIS_DOUBLE(rng -> CNG.signatureDouble(rng, NoiseType.HEXAGON).scale(1)),
|
||||
|
||||
@Desc("Hexagonal cell noise distorted using Iris styled wispy noise.")
|
||||
HEXAGON_IRIS_THICK(rng -> CNG.signatureThick(rng, NoiseType.HEXAGON).scale(1)),
|
||||
|
||||
@Desc("Hexagonal cell noise distorted using Iris styled wispy noise.")
|
||||
HEXAGON_IRIS_HALF(rng -> CNG.signatureHalf(rng, NoiseType.HEXAGON).scale(1)),
|
||||
|
||||
@Desc("Hex James substitution pattern distorted using Iris styled wispy noise.")
|
||||
HEX_JAMES_IRIS(rng -> CNG.signature(rng, NoiseType.HEX_JAMES).scale(1)),
|
||||
|
||||
@Desc("Hex James substitution pattern distorted using Iris styled wispy noise.")
|
||||
HEX_JAMES_IRIS_DOUBLE(rng -> CNG.signatureDouble(rng, NoiseType.HEX_JAMES).scale(1)),
|
||||
|
||||
@Desc("Hex James substitution pattern distorted using Iris styled wispy noise.")
|
||||
HEX_JAMES_IRIS_THICK(rng -> CNG.signatureThick(rng, NoiseType.HEX_JAMES).scale(1)),
|
||||
|
||||
@Desc("Hex James substitution pattern distorted using Iris styled wispy noise.")
|
||||
HEX_JAMES_IRIS_HALF(rng -> CNG.signatureHalf(rng, NoiseType.HEX_JAMES).scale(1)),
|
||||
|
||||
@Desc("Interlocked solid hex-cell simplex heatmap distorted using Iris styled wispy noise.")
|
||||
HEX_SIMPLEX_IRIS(rng -> CNG.signature(rng, NoiseType.HEX_SIMPLEX).scale(1)),
|
||||
|
||||
@Desc("Interlocked solid hex-cell simplex heatmap distorted using Iris styled wispy noise.")
|
||||
HEX_SIMPLEX_IRIS_DOUBLE(rng -> CNG.signatureDouble(rng, NoiseType.HEX_SIMPLEX).scale(1)),
|
||||
|
||||
@Desc("Interlocked solid hex-cell simplex heatmap distorted using Iris styled wispy noise.")
|
||||
HEX_SIMPLEX_IRIS_THICK(rng -> CNG.signatureThick(rng, NoiseType.HEX_SIMPLEX).scale(1)),
|
||||
|
||||
@Desc("Interlocked solid hex-cell simplex heatmap distorted using Iris styled wispy noise.")
|
||||
HEX_SIMPLEX_IRIS_HALF(rng -> CNG.signatureHalf(rng, NoiseType.HEX_SIMPLEX).scale(1)),
|
||||
|
||||
@Desc("Hexagonal random-size gradient noise and distorted using Iris styled wispy noise.")
|
||||
HEX_RANDOM_SIZE_IRIS(rng -> CNG.signature(rng, NoiseType.HEX_RANDOM_SIZE).scale(1)),
|
||||
|
||||
@Desc("Hexagonal random-size gradient noise and distorted using Iris styled wispy noise.")
|
||||
HEX_RANDOM_SIZE_IRIS_DOUBLE(rng -> CNG.signatureDouble(rng, NoiseType.HEX_RANDOM_SIZE).scale(1)),
|
||||
|
||||
@Desc("Hexagonal random-size gradient noise and distorted using Iris styled wispy noise.")
|
||||
HEX_RANDOM_SIZE_IRIS_THICK(rng -> CNG.signatureThick(rng, NoiseType.HEX_RANDOM_SIZE).scale(1)),
|
||||
|
||||
@Desc("Hexagonal random-size gradient noise and distorted using Iris styled wispy noise.")
|
||||
HEX_RANDOM_SIZE_IRIS_HALF(rng -> CNG.signatureHalf(rng, NoiseType.HEX_RANDOM_SIZE).scale(1)),
|
||||
|
||||
@Desc("Cellular noise creates the same noise level for cells, changes noise level on cell borders. Cells are distorted using Iris styled wispy noise.")
|
||||
CELLULAR_IRIS(rng -> CNG.signature(rng, NoiseType.CELLULAR)),
|
||||
|
||||
|
||||
@@ -462,10 +462,22 @@ public class CNG {
|
||||
return generator.noise(x * scale, y * scale, z * scale) * opacity;
|
||||
}
|
||||
|
||||
double f = fracture.noise(dim) * fscale;
|
||||
double x = dim.length > 0 ? dim[0] + f : 0D;
|
||||
double y = dim.length > 1 ? dim[1] - f : 0D;
|
||||
double z = dim.length > 2 ? dim[2] - f : 0D;
|
||||
double x = dim.length > 0 ? dim[0] : 0D;
|
||||
double y = dim.length > 1 ? dim[1] : 0D;
|
||||
double z = dim.length > 2 ? dim[2] : 0D;
|
||||
|
||||
if (dim.length > 0) {
|
||||
x += (fracture.noise(dim) - 0.5) * fscale;
|
||||
}
|
||||
|
||||
if (dim.length > 1) {
|
||||
y += (fracture.noise(dim[1], dim[0]) - 0.5) * fscale;
|
||||
}
|
||||
|
||||
if (dim.length > 2) {
|
||||
z += (fracture.noise(dim[2], dim[0], dim[1]) - 0.5) * fscale;
|
||||
}
|
||||
|
||||
return generator.noise(x * scale, y * scale, z * scale) * opacity;
|
||||
}
|
||||
|
||||
|
||||
@@ -87,10 +87,20 @@ public class CloverNoise implements NoiseGenerator {
|
||||
return input;
|
||||
}
|
||||
|
||||
private long mix(long input) {
|
||||
input = (input ^ (input >>> 33)) * 0xff51afd7ed558ccdL;
|
||||
input = (input ^ (input >>> 33)) * 0xc4ceb9fe1a85ec53L;
|
||||
return input ^ (input >>> 33);
|
||||
}
|
||||
|
||||
private double hash(Vector2 position) {
|
||||
long hash = doHash(seed, (long) Math.floor(position.getX()));
|
||||
hash = doHash(hash, (long) Math.floor(position.getY()));
|
||||
hash = doHash(hash, hash * (long) Math.floor(position.getX() + position.getY()));
|
||||
long x = (long) Math.floor(position.getX());
|
||||
long y = (long) Math.floor(position.getY());
|
||||
long hash = seed;
|
||||
hash ^= mix(x + 0x9E3779B97F4A7C15L);
|
||||
hash ^= mix(y + 0xC2B2AE3D27D4EB4FL);
|
||||
hash = mix(hash);
|
||||
hash &= (HASH_M - 1);
|
||||
if (hash < 0) {
|
||||
hash += HASH_M;
|
||||
}
|
||||
@@ -392,11 +402,22 @@ public class CloverNoise implements NoiseGenerator {
|
||||
return input;
|
||||
}
|
||||
|
||||
private long mix(long input) {
|
||||
input = (input ^ (input >>> 33)) * 0xff51afd7ed558ccdL;
|
||||
input = (input ^ (input >>> 33)) * 0xc4ceb9fe1a85ec53L;
|
||||
return input ^ (input >>> 33);
|
||||
}
|
||||
|
||||
private double hash(Vector3 position) {
|
||||
long hash = doHash(seed, (long) Math.floor(position.getX()));
|
||||
hash = doHash(hash, (long) Math.floor(position.getY()));
|
||||
hash = doHash(hash, (long) Math.floor(position.getZ()));
|
||||
hash = doHash(hash, hash * (long) Math.floor(position.getX() + position.getY() + position.getZ()));
|
||||
long x = (long) Math.floor(position.getX());
|
||||
long y = (long) Math.floor(position.getY());
|
||||
long z = (long) Math.floor(position.getZ());
|
||||
long hash = seed;
|
||||
hash ^= mix(x + 0x9E3779B97F4A7C15L);
|
||||
hash ^= mix(y + 0xC2B2AE3D27D4EB4FL);
|
||||
hash ^= mix(z + 0x165667B19E3779F9L);
|
||||
hash = mix(hash);
|
||||
hash &= (HASH_M - 1);
|
||||
if (hash < 0) {
|
||||
hash += HASH_M;
|
||||
}
|
||||
@@ -1043,4 +1064,4 @@ public class CloverNoise implements NoiseGenerator {
|
||||
return new Vector3(y * c.z - z * c.y, z * c.x - x * c.z, x * c.y - y * c.x);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,8 +37,8 @@ public class FastNoiseDouble {
|
||||
private final static double F3 = 1.0 / 3.0;
|
||||
private final static double G3 = 1.0 / 6.0;
|
||||
private final static double G33 = G3 * 3 - 1;
|
||||
private final static double F2 = 1.0 / 2.0;
|
||||
private final static double G2 = 1.0 / 4.0;
|
||||
private final static double F2 = 0.5 * (Math.sqrt(3.0) - 1.0);
|
||||
private final static double G2 = (3.0 - Math.sqrt(3.0)) / 6.0;
|
||||
private static final byte[] SIMPLEX_4D = {0, 1, 2, 3, 0, 1, 3, 2, 0, 0, 0, 0, 0, 2, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 2, 1, 3, 0, 0, 0, 0, 0, 3, 1, 2, 0, 3, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 3, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 3, 0, 0, 0, 0, 1, 3, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 0, 1, 2, 3, 1, 0, 1, 0, 2, 3, 1, 0, 3, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 3, 1, 0, 0, 0, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 1, 2, 3, 0, 2, 1, 0, 0, 0, 0, 3, 1, 2, 0, 2, 1, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 1, 0, 2, 0, 0, 0, 0, 3, 2, 0, 1, 3, 2, 1, 0
|
||||
};
|
||||
private final static double F4 = (2.23606797 - 1.0) / 4.0;
|
||||
@@ -1132,8 +1132,8 @@ public class FastNoiseDouble {
|
||||
|
||||
double x1 = x0 - i1 + G2;
|
||||
double y1 = y0 - j1 + G2;
|
||||
double x2 = x0 - 1 + F2;
|
||||
double y2 = y0 - 1 + F2;
|
||||
double x2 = x0 - 1 + (2 * G2);
|
||||
double y2 = y0 - 1 + (2 * G2);
|
||||
|
||||
double n0, n1, n2;
|
||||
|
||||
@@ -1986,4 +1986,4 @@ public class FastNoiseDouble {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,288 @@
|
||||
package art.arcane.iris.util.project.noise;
|
||||
|
||||
import art.arcane.volmlib.util.math.RNG;
|
||||
|
||||
public class HexJamesNoise implements NoiseGenerator, OctaveNoise {
|
||||
private static final double SQRT_3_OVER_3 = Math.sqrt(3.0) / 3.0;
|
||||
private static final double TWO_OVER_THREE = 2.0 / 3.0;
|
||||
private static final double SQRT_3 = Math.sqrt(3.0);
|
||||
private static final double THREE_OVER_TWO = 1.5D;
|
||||
private static final double ONE_THIRD = 1D / 3D;
|
||||
private static final double TWO_THIRDS = 2D / 3D;
|
||||
private static final int MAX_DEPTH = 7;
|
||||
private static final double HEAT_SCALE = 0.31D;
|
||||
private static final double LARGE_CONTINUE = 0.26D;
|
||||
private static final double SMALL_CONTINUE = 0.79D;
|
||||
private static final double CENTER_CONTINUE = 0.58D;
|
||||
private static final long CONST_X = 0x9E3779B97F4A7C15L;
|
||||
private static final long CONST_Z = 0xC2B2AE3D27D4EB4FL;
|
||||
private static final long[][] CHILD_DIRECTIONS = new long[][]{
|
||||
{1L, 0L},
|
||||
{1L, -1L},
|
||||
{0L, -1L},
|
||||
{-1L, 0L},
|
||||
{-1L, 1L},
|
||||
{0L, 1L}
|
||||
};
|
||||
private final long seed;
|
||||
private final SimplexNoise heatSimplex;
|
||||
private int octaves;
|
||||
|
||||
public HexJamesNoise(long seed) {
|
||||
RNG rng = new RNG(seed);
|
||||
this.seed = rng.lmax();
|
||||
this.heatSimplex = new SimplexNoise(rng.nextParallelRNG(877L).lmax());
|
||||
this.octaves = 1;
|
||||
}
|
||||
|
||||
private double clip(double value) {
|
||||
if (value < 0D) {
|
||||
return 0D;
|
||||
}
|
||||
|
||||
if (value > 1D) {
|
||||
return 1D;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
private long mix(long input) {
|
||||
input = (input ^ (input >>> 33)) * 0xff51afd7ed558ccdL;
|
||||
input = (input ^ (input >>> 33)) * 0xc4ceb9fe1a85ec53L;
|
||||
return input ^ (input >>> 33);
|
||||
}
|
||||
|
||||
private double hashToUnit(long value) {
|
||||
long normalized = mix(value) & Long.MAX_VALUE;
|
||||
return normalized / (double) Long.MAX_VALUE;
|
||||
}
|
||||
|
||||
private double random01(long nodeHash, int salt) {
|
||||
long mixed = nodeHash ^ (CONST_X * (salt + 1L)) ^ (CONST_Z * (salt + 7L));
|
||||
return hashToUnit(mixed);
|
||||
}
|
||||
|
||||
private long nextNodeHash(long nodeHash, int childIndex, int level) {
|
||||
long mixed = nodeHash ^ (CONST_X * (childIndex + 11L)) ^ (CONST_Z * (level + 1L));
|
||||
return mix(mixed);
|
||||
}
|
||||
|
||||
private long[] roundAxial(double q, double r) {
|
||||
double cubeX = q;
|
||||
double cubeZ = r;
|
||||
double cubeY = -cubeX - cubeZ;
|
||||
long roundedX = Math.round(cubeX);
|
||||
long roundedY = Math.round(cubeY);
|
||||
long roundedZ = Math.round(cubeZ);
|
||||
double xDiff = Math.abs(roundedX - cubeX);
|
||||
double yDiff = Math.abs(roundedY - cubeY);
|
||||
double zDiff = Math.abs(roundedZ - cubeZ);
|
||||
|
||||
if (xDiff > yDiff && xDiff > zDiff) {
|
||||
roundedX = -roundedY - roundedZ;
|
||||
} else if (yDiff > zDiff) {
|
||||
roundedY = -roundedX - roundedZ;
|
||||
} else {
|
||||
roundedZ = -roundedX - roundedY;
|
||||
}
|
||||
|
||||
return new long[]{roundedX, roundedZ};
|
||||
}
|
||||
|
||||
private double hexDistance(double q, double r, double centerQ, double centerR) {
|
||||
double deltaQ = q - centerQ;
|
||||
double deltaR = r - centerR;
|
||||
double deltaY = -deltaQ - deltaR;
|
||||
return Math.max(Math.abs(deltaQ), Math.max(Math.abs(deltaR), Math.abs(deltaY)));
|
||||
}
|
||||
|
||||
private double axialX(double q, double r) {
|
||||
return SQRT_3 * (q + (r * 0.5D));
|
||||
}
|
||||
|
||||
private double axialZ(double r) {
|
||||
return THREE_OVER_TWO * r;
|
||||
}
|
||||
|
||||
private double simplexField(double x, double z, double scale) {
|
||||
if (octaves <= 1) {
|
||||
return heatSimplex.noise(x * scale, z * scale);
|
||||
}
|
||||
|
||||
double frequency = 1D;
|
||||
double amplitude = 1D;
|
||||
double total = 0D;
|
||||
double max = 0D;
|
||||
|
||||
for (int i = 0; i < octaves; i++) {
|
||||
total += heatSimplex.noise((x * scale) * frequency, (z * scale) * frequency) * amplitude;
|
||||
max += amplitude;
|
||||
frequency *= 2D;
|
||||
amplitude *= 0.5D;
|
||||
}
|
||||
|
||||
if (max == 0D) {
|
||||
return 0.5D;
|
||||
}
|
||||
|
||||
return clip(total / max);
|
||||
}
|
||||
|
||||
private double cellHeat(double centerQ, double centerR, long nodeHash, int level) {
|
||||
double x = axialX(centerQ, centerR);
|
||||
double z = axialZ(centerR);
|
||||
double scale = HEAT_SCALE * (1D + (level * 0.24D));
|
||||
double simplexValue = simplexField(x, z, scale);
|
||||
double randomValue = random01(nodeHash, 31 + level);
|
||||
return clip((simplexValue * 0.82D) + (randomValue * 0.18D));
|
||||
}
|
||||
|
||||
private int rotationForNode(long nodeHash) {
|
||||
int rotation = (int) Math.floor(random01(nodeHash, 3) * 6D);
|
||||
if (rotation < 0) {
|
||||
rotation = 0;
|
||||
}
|
||||
|
||||
if (rotation > 5) {
|
||||
rotation = 5;
|
||||
}
|
||||
|
||||
return rotation;
|
||||
}
|
||||
|
||||
private int parityForNode(long nodeHash) {
|
||||
return random01(nodeHash, 5) >= 0.5D ? 1 : 0;
|
||||
}
|
||||
|
||||
private int ringIndexForDirection(int direction, int rotation) {
|
||||
int ring = direction - rotation;
|
||||
|
||||
while (ring < 0) {
|
||||
ring += 6;
|
||||
}
|
||||
|
||||
while (ring >= 6) {
|
||||
ring -= 6;
|
||||
}
|
||||
|
||||
return ring;
|
||||
}
|
||||
|
||||
private int pickChildIndex(double localQ, double localR, double[] centersQ, double[] centersR) {
|
||||
int bestIndex = -1;
|
||||
double bestDistance = Double.POSITIVE_INFINITY;
|
||||
|
||||
centersQ[0] = 0D;
|
||||
centersR[0] = 0D;
|
||||
double centerDistance = hexDistance(localQ, localR, 0D, 0D) / ONE_THIRD;
|
||||
|
||||
if (centerDistance <= 1D && centerDistance < bestDistance) {
|
||||
bestDistance = centerDistance;
|
||||
bestIndex = 0;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 6; i++) {
|
||||
int index = i + 1;
|
||||
double centerQ = CHILD_DIRECTIONS[i][0] * TWO_THIRDS;
|
||||
double centerR = CHILD_DIRECTIONS[i][1] * TWO_THIRDS;
|
||||
centersQ[index] = centerQ;
|
||||
centersR[index] = centerR;
|
||||
double distance = hexDistance(localQ, localR, centerQ, centerR) / ONE_THIRD;
|
||||
|
||||
if (distance <= 1D && distance < bestDistance) {
|
||||
bestDistance = distance;
|
||||
bestIndex = index;
|
||||
}
|
||||
}
|
||||
|
||||
return bestIndex;
|
||||
}
|
||||
|
||||
private boolean shouldContinue(int level, int childIndex, long nodeHash) {
|
||||
if (level >= MAX_DEPTH - 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
double gate;
|
||||
|
||||
if (childIndex == 0) {
|
||||
gate = CENTER_CONTINUE;
|
||||
} else {
|
||||
int rotation = rotationForNode(nodeHash);
|
||||
int parity = parityForNode(nodeHash);
|
||||
int ringIndex = ringIndexForDirection(childIndex - 1, rotation);
|
||||
boolean large = (ringIndex % 2) == parity;
|
||||
gate = large ? LARGE_CONTINUE : SMALL_CONTINUE;
|
||||
}
|
||||
|
||||
double randomValue = random01(nodeHash, 97 + level);
|
||||
return randomValue <= gate;
|
||||
}
|
||||
|
||||
private double sample(double x, double z) {
|
||||
double qWorld = (SQRT_3_OVER_3 * x) - (z / 3.0);
|
||||
double rWorld = TWO_OVER_THREE * z;
|
||||
long[] rounded = roundAxial(qWorld, rWorld);
|
||||
double centerQ = rounded[0];
|
||||
double centerR = rounded[1];
|
||||
double radius = 0.5D;
|
||||
double localQ = (qWorld - centerQ) / radius;
|
||||
double localR = (rWorld - centerR) / radius;
|
||||
long nodeHash = mix(seed ^ (rounded[0] * CONST_X) ^ (rounded[1] * CONST_Z));
|
||||
double heat = cellHeat(centerQ, centerR, nodeHash, 0);
|
||||
|
||||
for (int level = 0; level < MAX_DEPTH; level++) {
|
||||
double[] centersQ = new double[7];
|
||||
double[] centersR = new double[7];
|
||||
int childIndex = pickChildIndex(localQ, localR, centersQ, centersR);
|
||||
|
||||
if (childIndex < 0) {
|
||||
return heat;
|
||||
}
|
||||
|
||||
double childCenterQ = centersQ[childIndex];
|
||||
double childCenterR = centersR[childIndex];
|
||||
centerQ += childCenterQ * radius;
|
||||
centerR += childCenterR * radius;
|
||||
radius *= ONE_THIRD;
|
||||
localQ = (localQ - childCenterQ) / ONE_THIRD;
|
||||
localR = (localR - childCenterR) / ONE_THIRD;
|
||||
nodeHash = nextNodeHash(nodeHash, childIndex, level);
|
||||
heat = cellHeat(centerQ, centerR, nodeHash, level + 1);
|
||||
|
||||
if (!shouldContinue(level, childIndex, nodeHash)) {
|
||||
return heat;
|
||||
}
|
||||
}
|
||||
|
||||
return heat;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double noise(double x) {
|
||||
return sample(x, 0D);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double noise(double x, double z) {
|
||||
return sample(x, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double noise(double x, double y, double z) {
|
||||
if (z == 0D) {
|
||||
return sample(x, y);
|
||||
}
|
||||
|
||||
double a = sample(x, z);
|
||||
double b = sample(y, x);
|
||||
double c = sample(z, y);
|
||||
return (a + b + c) / 3D;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOctaves(int o) {
|
||||
this.octaves = Math.max(1, o);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,253 @@
|
||||
package art.arcane.iris.util.project.noise;
|
||||
|
||||
import art.arcane.volmlib.util.math.RNG;
|
||||
|
||||
public class HexRandomSizeNoise implements NoiseGenerator, OctaveNoise {
|
||||
private static final double SQRT_3_OVER_3 = Math.sqrt(3.0) / 3.0;
|
||||
private static final double TWO_OVER_THREE = 2.0 / 3.0;
|
||||
private static final double SQRT_3 = Math.sqrt(3.0);
|
||||
private static final double THREE_OVER_TWO = 1.5D;
|
||||
private static final double ONE_THIRD = 1D / 3D;
|
||||
private static final double TWO_THIRDS = 2D / 3D;
|
||||
private static final int MAX_DEPTH = 8;
|
||||
private static final double HEAT_SCALE = 0.24D;
|
||||
private static final double STRUCTURE_SCALE = 0.36D;
|
||||
private static final double SUBDIVIDE_BASE_THRESHOLD = 0.22D;
|
||||
private static final double SUBDIVIDE_LEVEL_STEP = 0.11D;
|
||||
private static final long CONST_X = 0x9E3779B97F4A7C15L;
|
||||
private static final long CONST_Z = 0xC2B2AE3D27D4EB4FL;
|
||||
private static final long[][] CHILD_DIRECTIONS = new long[][]{
|
||||
{1L, 0L},
|
||||
{1L, -1L},
|
||||
{0L, -1L},
|
||||
{-1L, 0L},
|
||||
{-1L, 1L},
|
||||
{0L, 1L}
|
||||
};
|
||||
private final long seed;
|
||||
private final SimplexNoise heatSimplex;
|
||||
private final SimplexNoise structureSimplex;
|
||||
private int octaves;
|
||||
|
||||
public HexRandomSizeNoise(long seed) {
|
||||
RNG rng = new RNG(seed);
|
||||
this.seed = rng.lmax();
|
||||
this.heatSimplex = new SimplexNoise(rng.nextParallelRNG(221L).lmax());
|
||||
this.structureSimplex = new SimplexNoise(rng.nextParallelRNG(442L).lmax());
|
||||
this.octaves = 1;
|
||||
}
|
||||
|
||||
private double clip(double value) {
|
||||
if (value < 0D) {
|
||||
return 0D;
|
||||
}
|
||||
|
||||
if (value > 1D) {
|
||||
return 1D;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
private long mix(long input) {
|
||||
input = (input ^ (input >>> 33)) * 0xff51afd7ed558ccdL;
|
||||
input = (input ^ (input >>> 33)) * 0xc4ceb9fe1a85ec53L;
|
||||
return input ^ (input >>> 33);
|
||||
}
|
||||
|
||||
private double hashToUnit(long value) {
|
||||
long normalized = mix(value) & Long.MAX_VALUE;
|
||||
return normalized / (double) Long.MAX_VALUE;
|
||||
}
|
||||
|
||||
private double random01(long nodeHash, int salt) {
|
||||
long mixed = nodeHash ^ (CONST_X * (salt + 1L)) ^ (CONST_Z * (salt + 31L));
|
||||
return hashToUnit(mixed);
|
||||
}
|
||||
|
||||
private long nextNodeHash(long nodeHash, int childIndex, int level) {
|
||||
long mixed = nodeHash ^ (CONST_Z * (childIndex + 1L)) ^ (CONST_X * (level + 1L));
|
||||
return mix(mixed);
|
||||
}
|
||||
|
||||
private long[] roundAxial(double q, double r) {
|
||||
double cubeX = q;
|
||||
double cubeZ = r;
|
||||
double cubeY = -cubeX - cubeZ;
|
||||
long roundedX = Math.round(cubeX);
|
||||
long roundedY = Math.round(cubeY);
|
||||
long roundedZ = Math.round(cubeZ);
|
||||
double xDiff = Math.abs(roundedX - cubeX);
|
||||
double yDiff = Math.abs(roundedY - cubeY);
|
||||
double zDiff = Math.abs(roundedZ - cubeZ);
|
||||
|
||||
if (xDiff > yDiff && xDiff > zDiff) {
|
||||
roundedX = -roundedY - roundedZ;
|
||||
} else if (yDiff > zDiff) {
|
||||
roundedY = -roundedX - roundedZ;
|
||||
} else {
|
||||
roundedZ = -roundedX - roundedY;
|
||||
}
|
||||
|
||||
return new long[]{roundedX, roundedZ};
|
||||
}
|
||||
|
||||
private double hexDistance(double q, double r, double centerQ, double centerR) {
|
||||
double deltaQ = q - centerQ;
|
||||
double deltaR = r - centerR;
|
||||
double deltaY = -deltaQ - deltaR;
|
||||
return Math.max(Math.abs(deltaQ), Math.max(Math.abs(deltaR), Math.abs(deltaY)));
|
||||
}
|
||||
|
||||
private double axialX(double q, double r) {
|
||||
return SQRT_3 * (q + (r * 0.5D));
|
||||
}
|
||||
|
||||
private double axialZ(double r) {
|
||||
return THREE_OVER_TWO * r;
|
||||
}
|
||||
|
||||
private double simplexField(SimplexNoise simplex, double x, double z, double scale) {
|
||||
if (octaves <= 1) {
|
||||
return simplex.noise(x * scale, z * scale);
|
||||
}
|
||||
|
||||
double frequency = 1D;
|
||||
double amplitude = 1D;
|
||||
double total = 0D;
|
||||
double max = 0D;
|
||||
|
||||
for (int i = 0; i < octaves; i++) {
|
||||
total += simplex.noise((x * scale) * frequency, (z * scale) * frequency) * amplitude;
|
||||
max += amplitude;
|
||||
frequency *= 2D;
|
||||
amplitude *= 0.5D;
|
||||
}
|
||||
|
||||
if (max == 0D) {
|
||||
return 0.5D;
|
||||
}
|
||||
|
||||
return clip(total / max);
|
||||
}
|
||||
|
||||
private double cellHeat(double centerQ, double centerR, long nodeHash, int level) {
|
||||
double x = axialX(centerQ, centerR);
|
||||
double z = axialZ(centerR);
|
||||
double scale = HEAT_SCALE * (1D + (level * 0.2D));
|
||||
double simplexValue = simplexField(heatSimplex, x, z, scale);
|
||||
double randomValue = random01(nodeHash, 11 + level);
|
||||
return clip((simplexValue * 0.74D) + (randomValue * 0.26D));
|
||||
}
|
||||
|
||||
private boolean shouldSubdivide(double centerQ, double centerR, long nodeHash, int level) {
|
||||
if (level >= MAX_DEPTH - 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
double x = axialX(centerQ, centerR);
|
||||
double z = axialZ(centerR);
|
||||
double scale = STRUCTURE_SCALE * (1D + (level * 0.31D));
|
||||
double simplexValue = simplexField(structureSimplex, x, z, scale);
|
||||
double randomValue = random01(nodeHash, 71 + level);
|
||||
double score = clip((simplexValue * 0.68D) + (randomValue * 0.32D));
|
||||
double threshold = SUBDIVIDE_BASE_THRESHOLD + (level * SUBDIVIDE_LEVEL_STEP);
|
||||
return score > threshold;
|
||||
}
|
||||
|
||||
private int pickChildIndex(double localQ, double localR, double[] centersQ, double[] centersR) {
|
||||
int bestIndex = -1;
|
||||
double bestDistance = Double.POSITIVE_INFINITY;
|
||||
|
||||
centersQ[0] = 0D;
|
||||
centersR[0] = 0D;
|
||||
double centerDistance = hexDistance(localQ, localR, 0D, 0D) / ONE_THIRD;
|
||||
|
||||
if (centerDistance <= 1D && centerDistance < bestDistance) {
|
||||
bestDistance = centerDistance;
|
||||
bestIndex = 0;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 6; i++) {
|
||||
int index = i + 1;
|
||||
double centerQ = CHILD_DIRECTIONS[i][0] * TWO_THIRDS;
|
||||
double centerR = CHILD_DIRECTIONS[i][1] * TWO_THIRDS;
|
||||
centersQ[index] = centerQ;
|
||||
centersR[index] = centerR;
|
||||
double distance = hexDistance(localQ, localR, centerQ, centerR) / ONE_THIRD;
|
||||
|
||||
if (distance <= 1D && distance < bestDistance) {
|
||||
bestDistance = distance;
|
||||
bestIndex = index;
|
||||
}
|
||||
}
|
||||
|
||||
return bestIndex;
|
||||
}
|
||||
|
||||
private double sample(double x, double z) {
|
||||
double qWorld = (SQRT_3_OVER_3 * x) - (z / 3.0);
|
||||
double rWorld = TWO_OVER_THREE * z;
|
||||
long[] rounded = roundAxial(qWorld, rWorld);
|
||||
double centerQ = rounded[0];
|
||||
double centerR = rounded[1];
|
||||
double radius = 0.5D;
|
||||
double localQ = (qWorld - centerQ) / radius;
|
||||
double localR = (rWorld - centerR) / radius;
|
||||
long nodeHash = mix(seed ^ (rounded[0] * CONST_X) ^ (rounded[1] * CONST_Z));
|
||||
double heat = cellHeat(centerQ, centerR, nodeHash, 0);
|
||||
|
||||
for (int level = 0; level < MAX_DEPTH; level++) {
|
||||
if (!shouldSubdivide(centerQ, centerR, nodeHash, level)) {
|
||||
return heat;
|
||||
}
|
||||
|
||||
double[] centersQ = new double[7];
|
||||
double[] centersR = new double[7];
|
||||
int childIndex = pickChildIndex(localQ, localR, centersQ, centersR);
|
||||
|
||||
if (childIndex < 0) {
|
||||
return heat;
|
||||
}
|
||||
|
||||
double childCenterQ = centersQ[childIndex];
|
||||
double childCenterR = centersR[childIndex];
|
||||
centerQ += childCenterQ * radius;
|
||||
centerR += childCenterR * radius;
|
||||
radius *= ONE_THIRD;
|
||||
localQ = (localQ - childCenterQ) / ONE_THIRD;
|
||||
localR = (localR - childCenterR) / ONE_THIRD;
|
||||
nodeHash = nextNodeHash(nodeHash, childIndex, level);
|
||||
heat = cellHeat(centerQ, centerR, nodeHash, level + 1);
|
||||
}
|
||||
|
||||
return heat;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double noise(double x) {
|
||||
return sample(x, 0D);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double noise(double x, double z) {
|
||||
return sample(x, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double noise(double x, double y, double z) {
|
||||
if (z == 0D) {
|
||||
return sample(x, y);
|
||||
}
|
||||
|
||||
double a = sample(x, z);
|
||||
double b = sample(y, x);
|
||||
double c = sample(z, y);
|
||||
return (a + b + c) / 3D;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOctaves(int o) {
|
||||
this.octaves = Math.max(1, o);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
package art.arcane.iris.util.project.noise;
|
||||
|
||||
import art.arcane.volmlib.util.math.RNG;
|
||||
|
||||
public class HexSimplexNoise implements NoiseGenerator, OctaveNoise {
|
||||
private static final double SQRT_3_OVER_3 = Math.sqrt(3.0) / 3.0;
|
||||
private static final double TWO_OVER_THREE = 2.0 / 3.0;
|
||||
private static final double SQRT_3 = Math.sqrt(3.0);
|
||||
private static final double THREE_OVER_TWO = 1.5D;
|
||||
private static final double CELL_HEAT_SCALE = 2.7D;
|
||||
private final SimplexNoise cellHeatSimplex;
|
||||
private int octaves;
|
||||
|
||||
public HexSimplexNoise(long seed) {
|
||||
RNG rng = new RNG(seed);
|
||||
this.cellHeatSimplex = new SimplexNoise(rng.nextParallelRNG(811L).lmax());
|
||||
this.octaves = 1;
|
||||
}
|
||||
|
||||
private double clip(double value) {
|
||||
if (value < 0D) {
|
||||
return 0D;
|
||||
}
|
||||
|
||||
if (value > 1D) {
|
||||
return 1D;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
private long[] roundAxial(double q, double r) {
|
||||
double cubeX = q;
|
||||
double cubeZ = r;
|
||||
double cubeY = -cubeX - cubeZ;
|
||||
long roundedX = Math.round(cubeX);
|
||||
long roundedY = Math.round(cubeY);
|
||||
long roundedZ = Math.round(cubeZ);
|
||||
double xDiff = Math.abs(roundedX - cubeX);
|
||||
double yDiff = Math.abs(roundedY - cubeY);
|
||||
double zDiff = Math.abs(roundedZ - cubeZ);
|
||||
|
||||
if (xDiff > yDiff && xDiff > zDiff) {
|
||||
roundedX = -roundedY - roundedZ;
|
||||
} else if (yDiff > zDiff) {
|
||||
roundedY = -roundedX - roundedZ;
|
||||
} else {
|
||||
roundedZ = -roundedX - roundedY;
|
||||
}
|
||||
|
||||
return new long[]{roundedX, roundedZ};
|
||||
}
|
||||
|
||||
private double axialX(long q, long r) {
|
||||
return SQRT_3 * (q + (r * 0.5D));
|
||||
}
|
||||
|
||||
private double axialZ(long r) {
|
||||
return THREE_OVER_TWO * r;
|
||||
}
|
||||
|
||||
private double cellHeat(long q, long r, double frequency) {
|
||||
double x = axialX(q, r);
|
||||
double z = axialZ(r);
|
||||
return cellHeatSimplex.noise((x * CELL_HEAT_SCALE) * frequency, (z * CELL_HEAT_SCALE) * frequency);
|
||||
}
|
||||
|
||||
private double sampleCell(long q, long r) {
|
||||
if (octaves <= 1) {
|
||||
return cellHeat(q, r, 1D);
|
||||
}
|
||||
|
||||
double frequency = 1D;
|
||||
double amplitude = 1D;
|
||||
double total = 0D;
|
||||
double max = 0D;
|
||||
|
||||
for (int i = 0; i < octaves; i++) {
|
||||
total += cellHeat(q, r, frequency) * amplitude;
|
||||
max += amplitude;
|
||||
frequency *= 2D;
|
||||
amplitude *= 0.5D;
|
||||
}
|
||||
|
||||
if (max == 0D) {
|
||||
return 0.5D;
|
||||
}
|
||||
|
||||
return clip(total / max);
|
||||
}
|
||||
|
||||
private double sample(double x, double z) {
|
||||
double q = (SQRT_3_OVER_3 * x) - (z / 3.0);
|
||||
double r = TWO_OVER_THREE * z;
|
||||
long[] rounded = roundAxial(q, r);
|
||||
return sampleCell(rounded[0], rounded[1]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double noise(double x) {
|
||||
return sample(x, 0D);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double noise(double x, double z) {
|
||||
return sample(x, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double noise(double x, double y, double z) {
|
||||
if (z == 0D) {
|
||||
return sample(x, y);
|
||||
}
|
||||
|
||||
double a = sample(x, z);
|
||||
double b = sample(y, x);
|
||||
double c = sample(z, y);
|
||||
return (a + b + c) / 3D;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOctaves(int o) {
|
||||
this.octaves = Math.max(1, o);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
package art.arcane.iris.util.project.noise;
|
||||
|
||||
import art.arcane.volmlib.util.math.RNG;
|
||||
|
||||
public class HexagonNoise implements NoiseGenerator {
|
||||
private static final double SQRT_3_OVER_3 = Math.sqrt(3.0) / 3.0;
|
||||
private static final double TWO_OVER_THREE = 2.0 / 3.0;
|
||||
private static final long CONST_X = 0x9E3779B97F4A7C15L;
|
||||
private static final long CONST_Z = 0xC2B2AE3D27D4EB4FL;
|
||||
private final long seed;
|
||||
|
||||
public HexagonNoise(long seed) {
|
||||
this.seed = new RNG(seed).lmax();
|
||||
}
|
||||
|
||||
private long mix(long input) {
|
||||
input = (input ^ (input >>> 33)) * 0xff51afd7ed558ccdL;
|
||||
input = (input ^ (input >>> 33)) * 0xc4ceb9fe1a85ec53L;
|
||||
return input ^ (input >>> 33);
|
||||
}
|
||||
|
||||
private long hash(long q, long r) {
|
||||
long hash = seed;
|
||||
hash ^= mix(q + CONST_X);
|
||||
hash ^= mix(r + CONST_Z);
|
||||
return mix(hash);
|
||||
}
|
||||
|
||||
private long[] roundAxial(double q, double r) {
|
||||
double cubeX = q;
|
||||
double cubeZ = r;
|
||||
double cubeY = -cubeX - cubeZ;
|
||||
|
||||
long rx = Math.round(cubeX);
|
||||
long ry = Math.round(cubeY);
|
||||
long rz = Math.round(cubeZ);
|
||||
|
||||
double xDiff = Math.abs(rx - cubeX);
|
||||
double yDiff = Math.abs(ry - cubeY);
|
||||
double zDiff = Math.abs(rz - cubeZ);
|
||||
|
||||
if (xDiff > yDiff && xDiff > zDiff) {
|
||||
rx = -ry - rz;
|
||||
} else if (yDiff > zDiff) {
|
||||
ry = -rx - rz;
|
||||
} else {
|
||||
rz = -rx - ry;
|
||||
}
|
||||
|
||||
return new long[]{rx, rz};
|
||||
}
|
||||
|
||||
private double sampleCell(double x, double z) {
|
||||
double q = (SQRT_3_OVER_3 * x) - (z / 3.0);
|
||||
double r = TWO_OVER_THREE * z;
|
||||
long[] axial = roundAxial(q, r);
|
||||
long hashed = hash(axial[0], axial[1]);
|
||||
long normalized = hashed & Long.MAX_VALUE;
|
||||
return normalized / (double) Long.MAX_VALUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double noise(double x) {
|
||||
return sampleCell(x, 0D);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double noise(double x, double z) {
|
||||
return sampleCell(x, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double noise(double x, double y, double z) {
|
||||
if (z == 0D) {
|
||||
return sampleCell(x, y);
|
||||
}
|
||||
|
||||
double a = sampleCell(x, z);
|
||||
double b = sampleCell(y, x);
|
||||
double c = sampleCell(z, y);
|
||||
return (a + b + c) / 3D;
|
||||
}
|
||||
}
|
||||
@@ -68,6 +68,26 @@ public enum NoiseType {
|
||||
CLOVER_HERMITE_STARCAST_6((s) -> new InterpolatedNoise(s, CLOVER, InterpolationMethod.HERMITE_STARCAST_6)),
|
||||
CLOVER_HERMITE_STARCAST_9((s) -> new InterpolatedNoise(s, CLOVER, InterpolationMethod.HERMITE_STARCAST_9)),
|
||||
CLOVER_HERMITE_STARCAST_12((s) -> new InterpolatedNoise(s, CLOVER, InterpolationMethod.HERMITE_STARCAST_12)),
|
||||
HEXAGON(HexagonNoise::new),
|
||||
HEXAGON_BILINEAR((s) -> new InterpolatedNoise(s, HEXAGON, InterpolationMethod.BILINEAR)),
|
||||
HEXAGON_BICUBIC((s) -> new InterpolatedNoise(s, HEXAGON, InterpolationMethod.BICUBIC)),
|
||||
HEXAGON_HERMITE((s) -> new InterpolatedNoise(s, HEXAGON, InterpolationMethod.HERMITE)),
|
||||
HEX_JAMES(HexJamesNoise::new),
|
||||
HEX_JAMES_BILINEAR((s) -> new InterpolatedNoise(s, HEX_JAMES, InterpolationMethod.BILINEAR)),
|
||||
HEX_JAMES_BICUBIC((s) -> new InterpolatedNoise(s, HEX_JAMES, InterpolationMethod.BICUBIC)),
|
||||
HEX_JAMES_HERMITE((s) -> new InterpolatedNoise(s, HEX_JAMES, InterpolationMethod.HERMITE)),
|
||||
HEX_SIMPLEX(HexSimplexNoise::new),
|
||||
HEX_SIMPLEX_BILINEAR((s) -> new InterpolatedNoise(s, HEX_SIMPLEX, InterpolationMethod.BILINEAR)),
|
||||
HEX_SIMPLEX_BICUBIC((s) -> new InterpolatedNoise(s, HEX_SIMPLEX, InterpolationMethod.BICUBIC)),
|
||||
HEX_SIMPLEX_HERMITE((s) -> new InterpolatedNoise(s, HEX_SIMPLEX, InterpolationMethod.HERMITE)),
|
||||
HEX_RANDOM_SIZE(HexRandomSizeNoise::new),
|
||||
HEX_RANDOM_SIZE_BILINEAR((s) -> new InterpolatedNoise(s, HEX_RANDOM_SIZE, InterpolationMethod.BILINEAR)),
|
||||
HEX_RANDOM_SIZE_BICUBIC((s) -> new InterpolatedNoise(s, HEX_RANDOM_SIZE, InterpolationMethod.BICUBIC)),
|
||||
HEX_RANDOM_SIZE_HERMITE((s) -> new InterpolatedNoise(s, HEX_RANDOM_SIZE, InterpolationMethod.HERMITE)),
|
||||
SIERPINSKI_TRIANGLE(SierpinskiTriangleNoise::new),
|
||||
SIERPINSKI_TRIANGLE_BILINEAR((s) -> new InterpolatedNoise(s, SIERPINSKI_TRIANGLE, InterpolationMethod.BILINEAR)),
|
||||
SIERPINSKI_TRIANGLE_BICUBIC((s) -> new InterpolatedNoise(s, SIERPINSKI_TRIANGLE, InterpolationMethod.BICUBIC)),
|
||||
SIERPINSKI_TRIANGLE_HERMITE((s) -> new InterpolatedNoise(s, SIERPINSKI_TRIANGLE, InterpolationMethod.HERMITE)),
|
||||
VASCULAR(VascularNoise::new);
|
||||
|
||||
private final NoiseFactory f;
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
package art.arcane.iris.util.project.noise;
|
||||
|
||||
import art.arcane.volmlib.util.math.RNG;
|
||||
|
||||
public class SierpinskiTriangleNoise implements NoiseGenerator, OctaveNoise {
|
||||
private static final double TRI_SCALE = 0.18D;
|
||||
private static final double TRI_PROJECTION = 0.8660254037844386D;
|
||||
private static final double HEAT_SCALE = 0.33D;
|
||||
private final SimplexNoise heatSimplex;
|
||||
private int octaves;
|
||||
|
||||
public SierpinskiTriangleNoise(long seed) {
|
||||
RNG rng = new RNG(seed);
|
||||
this.heatSimplex = new SimplexNoise(rng.nextParallelRNG(177L).lmax());
|
||||
this.octaves = 1;
|
||||
}
|
||||
|
||||
private double clip(double value) {
|
||||
if (value < 0D) {
|
||||
return 0D;
|
||||
}
|
||||
|
||||
if (value > 1D) {
|
||||
return 1D;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
private double heat(double x, double z) {
|
||||
if (octaves <= 1) {
|
||||
return heatSimplex.noise(x * HEAT_SCALE, z * HEAT_SCALE);
|
||||
}
|
||||
|
||||
double frequency = 1D;
|
||||
double amplitude = 1D;
|
||||
double total = 0D;
|
||||
double max = 0D;
|
||||
|
||||
for (int i = 0; i < octaves; i++) {
|
||||
total += heatSimplex.noise((x * HEAT_SCALE) * frequency, (z * HEAT_SCALE) * frequency) * amplitude;
|
||||
max += amplitude;
|
||||
frequency *= 2D;
|
||||
amplitude *= 0.5D;
|
||||
}
|
||||
|
||||
if (max == 0D) {
|
||||
return 0.5D;
|
||||
}
|
||||
|
||||
return clip(total / max);
|
||||
}
|
||||
|
||||
private double mask(double x, double z) {
|
||||
double sx = (x * TRI_SCALE) + ((z * TRI_SCALE) * 0.5D);
|
||||
double sz = (z * TRI_SCALE) * TRI_PROJECTION;
|
||||
long ix = (long) Math.floor(Math.abs(sx));
|
||||
long iz = (long) Math.floor(Math.abs(sz));
|
||||
return ((ix & iz) == 0L) ? 1D : 0D;
|
||||
}
|
||||
|
||||
private double sample(double x, double z) {
|
||||
double m = mask(x, z);
|
||||
double h = heat(x, z);
|
||||
if (m >= 0.5D) {
|
||||
return clip((h * 0.65D) + 0.35D);
|
||||
}
|
||||
|
||||
return clip(h * 0.12D);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double noise(double x) {
|
||||
return sample(x, 0D);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double noise(double x, double z) {
|
||||
return sample(x, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double noise(double x, double y, double z) {
|
||||
if (z == 0D) {
|
||||
return sample(x, y);
|
||||
}
|
||||
|
||||
double a = sample(x, z);
|
||||
double b = sample(y, x);
|
||||
double c = sample(z, y);
|
||||
return (a + b + c) / 3D;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOctaves(int o) {
|
||||
this.octaves = Math.max(1, o);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user