mirror of
https://github.com/GTNewHorizons/GTNHLib.git
synced 2026-10-26 14:24:10 +00:00
Add simplex noise utilities (#428)
This commit is contained in:
1 parent
e072b8aae7
commit
766b8f483c
9 files changed
+765
No files matched your search
@@ -1,6 +1,7 @@
|
||||
|
||||
plugins {
|
||||
id("com.gtnewhorizons.gtnhconvention")
|
||||
id("me.champeau.jmh") version "0.7.3"
|
||||
}
|
||||
|
||||
minecraft {
|
||||
@@ -80,3 +81,18 @@ for (jarTask in listOf(tasks.jar, tasks.shadowJar, tasks.sourcesJar)) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
named("jmh") {
|
||||
compileClasspath += sourceSets["patchedMc"].output
|
||||
runtimeClasspath = files(main17.output) + runtimeClasspath + files(sourceSets["patchedMc"].output)
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
add("jmhRuntimeOnly", files(sourceSets["patchedMc"].output))
|
||||
}
|
||||
|
||||
tasks.named<me.champeau.jmh.JMHTask>("jmh") {
|
||||
dependsOn(main17.compileJavaTaskName)
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
package com.gtnewhorizon.gtnhlib.noise;
|
||||
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.openjdk.jmh.annotations.Benchmark;
|
||||
import org.openjdk.jmh.annotations.BenchmarkMode;
|
||||
import org.openjdk.jmh.annotations.Fork;
|
||||
import org.openjdk.jmh.annotations.Measurement;
|
||||
import org.openjdk.jmh.annotations.Mode;
|
||||
import org.openjdk.jmh.annotations.OutputTimeUnit;
|
||||
import org.openjdk.jmh.annotations.Param;
|
||||
import org.openjdk.jmh.annotations.Scope;
|
||||
import org.openjdk.jmh.annotations.Setup;
|
||||
import org.openjdk.jmh.annotations.State;
|
||||
import org.openjdk.jmh.annotations.Warmup;
|
||||
import org.openjdk.jmh.infra.Blackhole;
|
||||
|
||||
@BenchmarkMode(Mode.AverageTime)
|
||||
@OutputTimeUnit(TimeUnit.NANOSECONDS)
|
||||
@State(Scope.Thread)
|
||||
@Warmup(iterations = 3, time = 1, timeUnit = TimeUnit.SECONDS)
|
||||
@Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
|
||||
@Fork(1)
|
||||
public class OctavesSamplerBenchmark {
|
||||
|
||||
static final int GRID = 256;
|
||||
|
||||
@Param({ "4", "8" })
|
||||
public int octaveCount;
|
||||
|
||||
private OctavesSampler sampler;
|
||||
private int counter;
|
||||
private double[] xs, ys, zs, out;
|
||||
|
||||
@Setup
|
||||
public void setup() {
|
||||
sampler = new OctavesSampler(new Random(42), octaveCount);
|
||||
counter = 0;
|
||||
xs = new double[GRID];
|
||||
ys = new double[GRID];
|
||||
zs = new double[GRID];
|
||||
out = new double[GRID];
|
||||
for (int i = 0; i < GRID; i++) {
|
||||
xs[i] = (i & 15) * 0.5;
|
||||
ys[i] = (i >> 4) * 0.5;
|
||||
zs[i] = (i & 31) * 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public void sample2D(Blackhole bh) {
|
||||
bh.consume(sampler.sample(1.5, 2.7));
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public void sample3D(Blackhole bh) {
|
||||
bh.consume(sampler.sample(1.5, 2.7, 3.9));
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public void sample2DGrid(Blackhole bh) {
|
||||
int c = counter++;
|
||||
bh.consume(sampler.sample((c & 255) * 0.5, ((c >> 8) & 255) * 0.5));
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public void sample3DGrid(Blackhole bh) {
|
||||
int c = counter++;
|
||||
bh.consume(sampler.sample((c & 63) * 0.5, ((c >> 6) & 63) * 0.5, ((c >> 12) & 63) * 0.5));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package com.gtnewhorizon.gtnhlib.noise;
|
||||
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.openjdk.jmh.annotations.Benchmark;
|
||||
import org.openjdk.jmh.annotations.BenchmarkMode;
|
||||
import org.openjdk.jmh.annotations.Fork;
|
||||
import org.openjdk.jmh.annotations.Measurement;
|
||||
import org.openjdk.jmh.annotations.Mode;
|
||||
import org.openjdk.jmh.annotations.OutputTimeUnit;
|
||||
import org.openjdk.jmh.annotations.Scope;
|
||||
import org.openjdk.jmh.annotations.Setup;
|
||||
import org.openjdk.jmh.annotations.State;
|
||||
import org.openjdk.jmh.annotations.Warmup;
|
||||
import org.openjdk.jmh.infra.Blackhole;
|
||||
|
||||
@BenchmarkMode(Mode.AverageTime)
|
||||
@OutputTimeUnit(TimeUnit.NANOSECONDS)
|
||||
@State(Scope.Thread)
|
||||
@Warmup(iterations = 3, time = 1, timeUnit = TimeUnit.SECONDS)
|
||||
@Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
|
||||
@Fork(1)
|
||||
public class SimplexSamplerBenchmark {
|
||||
|
||||
private SimplexSampler sampler;
|
||||
private int counter;
|
||||
|
||||
@Setup
|
||||
public void setup() {
|
||||
sampler = new SimplexSampler(new Random(42));
|
||||
counter = 0;
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public void sample2D(Blackhole bh) {
|
||||
bh.consume(sampler.sample(1.5, 2.7));
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public void sample3D(Blackhole bh) {
|
||||
bh.consume(sampler.sample(1.5, 2.7, 3.9));
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public void sample2DGrid(Blackhole bh) {
|
||||
int c = counter++;
|
||||
bh.consume(sampler.sample((c & 255) * 0.5, ((c >> 8) & 255) * 0.5));
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public void sample3DGrid(Blackhole bh) {
|
||||
int c = counter++;
|
||||
bh.consume(sampler.sample((c & 63) * 0.5, ((c >> 6) & 63) * 0.5, ((c >> 12) & 63) * 0.5));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.gtnewhorizon.gtnhlib.noise;
|
||||
|
||||
/// A generic noise sampler, typically used for worldgen.
|
||||
/// The domain of the result MUST BE -1 to 1, but the distribution curve is undefined.
|
||||
/// The coordinates can be any non-NaN/non-infinity value, positive or negative.
|
||||
/// [SimplexSampler] will produce a 'boxy' standard distribution.
|
||||
/// Use a [NormalizedSampler] to convert it into an approximately linear distribution.
|
||||
/// Use a [ScaledSampler] to automatically multiply the passed-in coordinates.
|
||||
/// Use an [OctavesSampler] to layer several simplex samplers on top of each other, to increase the complexity and
|
||||
/// detail of the generated noise.
|
||||
public interface NoiseSampler {
|
||||
|
||||
double sample(double x, double y);
|
||||
|
||||
double sample(double x, double y, double z);
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package com.gtnewhorizon.gtnhlib.noise;
|
||||
|
||||
/// A sampler that remaps the 'boxy' normal distribution of a [SimplexSampler] to an approximately linear distribution.
|
||||
public class NormalizedSampler implements NoiseSampler {
|
||||
|
||||
private static final double REMAP_EXPONENT = 0.65;
|
||||
|
||||
private static final int LUT_SIZE = 1024;
|
||||
|
||||
private static final float[] REMAP_LOOKUP_TABLE;
|
||||
|
||||
static {
|
||||
REMAP_LOOKUP_TABLE = buildLut(REMAP_EXPONENT);
|
||||
}
|
||||
|
||||
private static double clamp(double val, double lo, double hi) {
|
||||
return val < lo ? lo : val > hi ? hi : val;
|
||||
}
|
||||
|
||||
private static float remap(double v) {
|
||||
v = clamp(v, -1.0, 1.0);
|
||||
double t = (v + 1.0) * 0.5 * (LUT_SIZE - 1);
|
||||
int lo = (int) t;
|
||||
int hi = Math.min(lo + 1, LUT_SIZE - 1);
|
||||
float frac = (float) (t - lo);
|
||||
return REMAP_LOOKUP_TABLE[lo] + frac * (REMAP_LOOKUP_TABLE[hi] - REMAP_LOOKUP_TABLE[lo]);
|
||||
}
|
||||
|
||||
private static float[] buildLut(double exponent) {
|
||||
float[] lut = new float[LUT_SIZE];
|
||||
for (int i = 0; i < LUT_SIZE; i++) {
|
||||
double v = i / (double) (LUT_SIZE - 1) * 2.0 - 1.0; // map i → [-1, 1]
|
||||
lut[i] = (float) (Math.signum(v) * Math.pow(Math.abs(v), exponent));
|
||||
}
|
||||
return lut;
|
||||
}
|
||||
|
||||
private final NoiseSampler base;
|
||||
|
||||
public NormalizedSampler(NoiseSampler base) {
|
||||
this.base = base;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double sample(double x, double y) {
|
||||
return remap(base.sample(x, y));
|
||||
}
|
||||
|
||||
@Override
|
||||
public double sample(double x, double y, double z) {
|
||||
return remap(base.sample(x, y, z));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
package com.gtnewhorizon.gtnhlib.noise;
|
||||
|
||||
import java.util.Random;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/// Layers several samplers on top of each other.
|
||||
/// More octaves increase the CPU cost linearly, but increase the complexity and detail of the returned noise.
|
||||
/// Each octave has an increasing scale (smaller features) and a decreasing amplitude (smaller effect).
|
||||
public class OctavesSampler implements NoiseSampler {
|
||||
|
||||
private final @NotNull NoiseSampler @NotNull [] octaves;
|
||||
private final double[] normalizedAmplitudes, scales;
|
||||
|
||||
public OctavesSampler(@Nullable NoiseSampler @NotNull [] samplers, double[] amplitudes, double[] scales) {
|
||||
int samplerCount = 0;
|
||||
|
||||
for (NoiseSampler s : samplers) {
|
||||
if (s != null) samplerCount++;
|
||||
}
|
||||
|
||||
this.octaves = new NoiseSampler[samplerCount];
|
||||
this.normalizedAmplitudes = new double[samplerCount];
|
||||
this.scales = new double[samplerCount];
|
||||
|
||||
double sum = 0;
|
||||
|
||||
for (double amp : amplitudes) {
|
||||
sum += amp;
|
||||
}
|
||||
|
||||
double norm = 1d / sum;
|
||||
|
||||
int samplerCursor = 0;
|
||||
for (int i = 0; i < samplers.length; i++) {
|
||||
if (samplers[i] != null) {
|
||||
this.octaves[samplerCursor] = samplers[i];
|
||||
this.normalizedAmplitudes[samplerCursor] = amplitudes[i] * norm;
|
||||
this.scales[samplerCursor] = scales[i];
|
||||
samplerCursor++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public OctavesSampler(Supplier<NoiseSampler> samplers, int octaves) {
|
||||
this.octaves = new NoiseSampler[octaves];
|
||||
this.normalizedAmplitudes = new double[octaves];
|
||||
this.scales = new double[octaves];
|
||||
|
||||
double sum = 0;
|
||||
|
||||
for (int i = 0; i < octaves; i++) {
|
||||
this.octaves[i] = samplers.get();
|
||||
double amp = 1d / Math.pow(2d, i);
|
||||
this.normalizedAmplitudes[i] = amp;
|
||||
this.scales[i] = Math.pow(2d, i);
|
||||
sum += amp;
|
||||
}
|
||||
|
||||
double norm = 1d / sum;
|
||||
|
||||
for (int i = 0; i < octaves; i++) {
|
||||
this.normalizedAmplitudes[i] *= norm;
|
||||
}
|
||||
}
|
||||
|
||||
public OctavesSampler(Random rng, int octaves) {
|
||||
this(() -> new SimplexSampler(rng), octaves);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double sample(double x, double y) {
|
||||
double value = 0;
|
||||
|
||||
for (int i = 0, len = octaves.length; i < len; i++) {
|
||||
double scale = scales[i];
|
||||
value += octaves[i].sample(x * scale, y * scale) * normalizedAmplitudes[i];
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double sample(double x, double y, double z) {
|
||||
double value = 0;
|
||||
|
||||
for (int i = 0, len = octaves.length; i < len; i++) {
|
||||
double scale = scales[i];
|
||||
value += octaves[i].sample(x * scale, y * scale, z * scale) * normalizedAmplitudes[i];
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,248 @@
|
||||
/*****************************************************************************
|
||||
* J3D.org Copyright (c) 2000 Java Source This source is licensed under the GNU LGPL v2.1 Please read
|
||||
* http://www.gnu.org/copyleft/lgpl.html for more information This software comes with the standard NO WARRANTY
|
||||
* disclaimer for any purpose. Use it at your own risk. If there's a problem you get to fix it.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
package com.gtnewhorizon.gtnhlib.noise;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
/// A 2d or 3d perlin sampler.
|
||||
/// This is largely copied from
|
||||
/// [RWG](https://github.com/GTNewHorizons/Realistic-World-Gen/blob/37046ef9a2f807ae4feb0ad87e7ae65f756839a6/src/main/java/rwg/util/PerlinNoise.java),
|
||||
/// with the irrelevant code stripped out.
|
||||
public class PerlinSampler implements NoiseSampler {
|
||||
|
||||
// Constants for setting up the Perlin-1 noise functions
|
||||
private static final int B = 0x1000;
|
||||
private static final int BM = 0xff;
|
||||
private static final int N = 0x1000;
|
||||
|
||||
/** Default sample size to work with */
|
||||
private static final int DEFAULT_SAMPLE_SIZE = 256;
|
||||
|
||||
/** Permutation array for the improved noise function */
|
||||
private final int[] p_imp;
|
||||
|
||||
/** P array for perline 1 noise */
|
||||
private final int[] p = new int[B + B + 2];
|
||||
|
||||
private final float[] g3 = new float[(B + B + 2) * 3];
|
||||
private final float[] g2 = new float[(B + B + 2) * 2];
|
||||
|
||||
/**
|
||||
* Create a new noise creator with the default seed value
|
||||
*/
|
||||
public PerlinSampler() {
|
||||
this(100);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new noise creator with the given seed value for the randomness
|
||||
*
|
||||
* @param seed The seed value to use
|
||||
*/
|
||||
public PerlinSampler(long seed) {
|
||||
p_imp = new int[DEFAULT_SAMPLE_SIZE << 1];
|
||||
|
||||
int i, j, k;
|
||||
Random rand = new Random(seed);
|
||||
|
||||
// Calculate the table of pseudo-random coefficients.
|
||||
for (i = 0; i < DEFAULT_SAMPLE_SIZE; i++) p_imp[i] = i;
|
||||
|
||||
// generate the pseudo-random permutation table.
|
||||
while (--i > 0) {
|
||||
k = p_imp[i];
|
||||
j = (int) (rand.nextLong() & DEFAULT_SAMPLE_SIZE);
|
||||
p_imp[i] = p_imp[j];
|
||||
p_imp[j] = k;
|
||||
}
|
||||
|
||||
initPerlin1(rand);
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes noise function for three dimensions at the point (x,y,z).
|
||||
*
|
||||
* @param x x dimension parameter
|
||||
* @param y y dimension parameter
|
||||
* @param z z dimension parameter
|
||||
* @return the noise value at the point (x, y, z)
|
||||
*/
|
||||
@Override
|
||||
public double sample(double x, double y, double z) {
|
||||
// Constraint the point to a unit cube
|
||||
double fx = Math.floor(x);
|
||||
double fy = Math.floor(y);
|
||||
double fz = Math.floor(z);
|
||||
int uc_x = (int) fx & 255;
|
||||
int uc_y = (int) fy & 255;
|
||||
int uc_z = (int) fz & 255;
|
||||
|
||||
// Relative location of the point in the unit cube
|
||||
double xo = x - fx;
|
||||
double yo = y - fy;
|
||||
double zo = z - fz;
|
||||
|
||||
// Fade curves for x, y and z
|
||||
double u = fade(xo);
|
||||
double v = fade(yo);
|
||||
double w = fade(zo);
|
||||
|
||||
// Generate a hash for each coordinate to find out where in the cube
|
||||
// it lies.
|
||||
int a = p_imp[uc_x] + uc_y;
|
||||
int aa = p_imp[a] + uc_z;
|
||||
int ab = p_imp[a + 1] + uc_z;
|
||||
|
||||
int b = p_imp[uc_x + 1] + uc_y;
|
||||
int ba = p_imp[b] + uc_z;
|
||||
int bb = p_imp[b + 1] + uc_z;
|
||||
|
||||
// blend results from the 8 corners based on the noise function
|
||||
double c1 = grad(p_imp[aa], xo, yo, zo);
|
||||
double c2 = grad(p_imp[ba], xo - 1, yo, zo);
|
||||
double c3 = grad(p_imp[ab], xo, yo - 1, zo);
|
||||
double c4 = grad(p_imp[bb], xo - 1, yo - 1, zo);
|
||||
double c5 = grad(p_imp[aa + 1], xo, yo, zo - 1);
|
||||
double c6 = grad(p_imp[ba + 1], xo - 1, yo, zo - 1);
|
||||
double c7 = grad(p_imp[ab + 1], xo, yo - 1, zo - 1);
|
||||
double c8 = grad(p_imp[bb + 1], xo - 1, yo - 1, zo - 1);
|
||||
|
||||
return lerp(w, lerp(v, lerp(u, c1, c2), lerp(u, c3, c4)), lerp(v, lerp(u, c5, c6), lerp(u, c7, c8)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create noise in a 2D space using the original Perlin noise algorithm.
|
||||
*
|
||||
* @param x The X coordinate of the location to sample
|
||||
* @param y The Y coordinate of the location to sample
|
||||
* @return A noisy value at the given position
|
||||
*/
|
||||
@Override
|
||||
public double sample(double x, double y) {
|
||||
double t = x + N;
|
||||
t = Math.abs(t);
|
||||
int bx0 = (int) t & BM;
|
||||
int bx1 = bx0 + 1 & BM;
|
||||
double rx0 = t - (int) t;
|
||||
double rx1 = rx0 - 1;
|
||||
|
||||
t = y + N;
|
||||
t = Math.abs(t);
|
||||
int by0 = (int) t & BM;
|
||||
int by1 = by0 + 1 & BM;
|
||||
double ry0 = t - (int) t;
|
||||
double ry1 = ry0 - 1;
|
||||
|
||||
int i = p[bx0];
|
||||
int j = p[bx1];
|
||||
|
||||
int b00 = p[i + by0];
|
||||
int b10 = p[j + by0];
|
||||
int b01 = p[i + by1];
|
||||
int b11 = p[j + by1];
|
||||
|
||||
double sx = sCurve(rx0);
|
||||
double sy = sCurve(ry0);
|
||||
|
||||
double u = rx0 * g2[b00 * 2] + ry0 * g2[b00 * 2 + 1];
|
||||
double v = rx1 * g2[b10 * 2] + ry0 * g2[b10 * 2 + 1];
|
||||
double a = lerp(sx, u, v);
|
||||
|
||||
u = rx0 * g2[b01 * 2] + ry1 * g2[b01 * 2 + 1];
|
||||
v = rx1 * g2[b11 * 2] + ry1 * g2[b11 * 2 + 1];
|
||||
double b = lerp(sx, u, v);
|
||||
|
||||
return lerp(sy, a, b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple lerp function using doubles.
|
||||
*/
|
||||
private double lerp(double t, double a, double b) {
|
||||
return a + t * (b - a);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fade curve calculation which is 6t^5 - 15t^4 + 10t^3. This is the new algorithm, where the old one used to be
|
||||
* 3t^2 - 2t^3.
|
||||
*
|
||||
* @param t The t parameter to calculate the fade for
|
||||
* @return the drop-off amount.
|
||||
*/
|
||||
private double fade(double t) {
|
||||
return t * t * t * (t * (t * 6 - 15) + 10);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the gradient function based on the hash code.
|
||||
*/
|
||||
private double grad(int hash, double x, double y, double z) {
|
||||
// Convert low 4 bits of hash code into 12 gradient directions.
|
||||
int h = hash & 15;
|
||||
double u = h < 8 || h == 12 || h == 13 ? x : y;
|
||||
double v = h < 4 || h == 12 || h == 13 ? y : z;
|
||||
|
||||
return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v);
|
||||
}
|
||||
|
||||
/**
|
||||
* S-curve function for value distribution for Perlin-1 noise function.
|
||||
*/
|
||||
private double sCurve(double t) {
|
||||
return t * t * (3 - 2 * t);
|
||||
}
|
||||
|
||||
/**
|
||||
* 2D-vector normalization function.
|
||||
*/
|
||||
private void normalize2(float[] v, int off) {
|
||||
float s = (float) (1 / Math.sqrt(v[off] * v[off] + v[off + 1] * v[off + 1]));
|
||||
v[off] *= s;
|
||||
v[off + 1] *= s;
|
||||
}
|
||||
|
||||
/**
|
||||
* 3D-vector normalization function.
|
||||
*/
|
||||
private void normalize3(float[] v, int off) {
|
||||
float s = (float) (1 / Math.sqrt(v[off] * v[off] + v[off + 1] * v[off + 1] + v[off + 2] * v[off + 2]));
|
||||
v[off] *= s;
|
||||
v[off + 1] *= s;
|
||||
v[off + 2] *= s;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the lookup arrays used by Perlin 1 function.
|
||||
*/
|
||||
private void initPerlin1(Random rand) {
|
||||
int i, j, k;
|
||||
|
||||
for (i = 0; i < B; i++) {
|
||||
p[i] = i;
|
||||
|
||||
for (j = 0; j < 2; j++) g2[i * 2 + j] = (float) (rand.nextDouble() * Integer.MAX_VALUE % (B + B) - B) / B;
|
||||
normalize2(g2, i * 2);
|
||||
|
||||
for (j = 0; j < 3; j++) g3[i * 3 + j] = (float) (rand.nextDouble() * Integer.MAX_VALUE % (B + B) - B) / B;
|
||||
normalize3(g3, i * 3);
|
||||
}
|
||||
|
||||
while (--i > 0) {
|
||||
k = p[i];
|
||||
j = (int) (rand.nextDouble() * Integer.MAX_VALUE % B);
|
||||
p[i] = p[j];
|
||||
p[j] = k;
|
||||
}
|
||||
|
||||
for (i = 0; i < B + 2; i++) {
|
||||
p[B + i] = p[i];
|
||||
for (j = 0; j < 2; j++) g2[(B + i) * 2 + j] = g2[i * 2 + j];
|
||||
for (j = 0; j < 3; j++) g3[(B + i) * 3 + j] = g3[i * 3 + j];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.gtnewhorizon.gtnhlib.noise;
|
||||
|
||||
/// Scales another sampler by a certain amount in each axis.
|
||||
/// Effects are the opposite of what you'd expect - scaling by 2 in an axis shrinks the noise's feature size by half
|
||||
/// along that axis.
|
||||
/// This does not affect the noise's output domain.
|
||||
public class ScaledSampler implements NoiseSampler {
|
||||
|
||||
private final NoiseSampler base;
|
||||
private final double scaleX;
|
||||
private final double scaleY;
|
||||
private final double scaleZ;
|
||||
|
||||
public ScaledSampler(NoiseSampler base, double scaleX, double scaleY, double scaleZ) {
|
||||
this.base = base;
|
||||
this.scaleX = scaleX;
|
||||
this.scaleY = scaleY;
|
||||
this.scaleZ = scaleZ;
|
||||
}
|
||||
|
||||
public ScaledSampler(NoiseSampler base, double scale) {
|
||||
this(base, scale, scale, scale);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double sample(double x, double y) {
|
||||
return base.sample(x * scaleX, y * scaleY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double sample(double x, double y, double z) {
|
||||
return base.sample(x * scaleX, y * scaleY, z * scaleZ);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,174 @@
|
||||
package com.gtnewhorizon.gtnhlib.noise;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
import net.minecraft.util.MathHelper;
|
||||
|
||||
/// A standard simplex noise sampler.
|
||||
public class SimplexSampler implements NoiseSampler {
|
||||
|
||||
protected static final int[][] GRADIENTS = new int[][] { { 1, 1, 0 }, { -1, 1, 0 }, { 1, -1, 0 }, { -1, -1, 0 },
|
||||
{ 1, 0, 1 }, { -1, 0, 1 }, { 1, 0, -1 }, { -1, 0, -1 }, { 0, 1, 1 }, { 0, -1, 1 }, { 0, 1, -1 },
|
||||
{ 0, -1, -1 }, { 1, 1, 0 }, { 0, -1, 1 }, { -1, 1, 0 }, { 0, -1, -1 }, };
|
||||
private static final double SQRT_3 = Math.sqrt(3.0D);
|
||||
private static final double SKEW_FACTOR_2D = 0.5D * (SQRT_3 - 1.0D);
|
||||
private static final double UNSKEW_FACTOR_2D = (3.0D - SQRT_3) / 6.0D;
|
||||
private final int[] permutations = new int[512];
|
||||
public final double originX;
|
||||
public final double originY;
|
||||
public final double originZ;
|
||||
|
||||
public SimplexSampler(Random random) {
|
||||
this.originX = random.nextDouble() * 256.0D;
|
||||
this.originY = random.nextDouble() * 256.0D;
|
||||
this.originZ = random.nextDouble() * 256.0D;
|
||||
|
||||
for (int i = 0; i < 256; i++) {
|
||||
this.permutations[i] = i;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 256; ++i) {
|
||||
int k = random.nextInt(256 - i);
|
||||
int l = this.permutations[i];
|
||||
this.permutations[i] = this.permutations[k + i];
|
||||
this.permutations[k + i] = l;
|
||||
}
|
||||
}
|
||||
|
||||
private int getGradient(int hash) {
|
||||
return this.permutations[hash & 255];
|
||||
}
|
||||
|
||||
protected static double dot(int[] gArr, double x, double y, double z) {
|
||||
return (double) gArr[0] * x + (double) gArr[1] * y + (double) gArr[2] * z;
|
||||
}
|
||||
|
||||
private double grad(int hash, double x, double y, double z, double distance) {
|
||||
double d = distance - x * x - y * y - z * z;
|
||||
double f;
|
||||
if (d < 0.0D) {
|
||||
f = 0.0D;
|
||||
} else {
|
||||
d *= d;
|
||||
f = d * d * dot(GRADIENTS[hash], x, y, z);
|
||||
}
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double sample(double x, double y) {
|
||||
double d = (x + y) * SKEW_FACTOR_2D;
|
||||
int i = MathHelper.floor_double(x + d);
|
||||
int j = MathHelper.floor_double(y + d);
|
||||
double e = (double) (i + j) * UNSKEW_FACTOR_2D;
|
||||
double f = (double) i - e;
|
||||
double g = (double) j - e;
|
||||
double h = x - f;
|
||||
double k = y - g;
|
||||
byte n = (byte) (h > k ? 1 : 0);
|
||||
byte o = (byte) (h > k ? 0 : 1);
|
||||
|
||||
double p = h - (double) n + UNSKEW_FACTOR_2D;
|
||||
double q = k - (double) o + UNSKEW_FACTOR_2D;
|
||||
double r = h - 1.0D + 2.0D * UNSKEW_FACTOR_2D;
|
||||
double s = k - 1.0D + 2.0D * UNSKEW_FACTOR_2D;
|
||||
int t = i & 255;
|
||||
int u = j & 255;
|
||||
int v = this.getGradient(t + this.getGradient(u)) % 12;
|
||||
int w = this.getGradient(t + n + this.getGradient(u + o)) % 12;
|
||||
int z = this.getGradient(t + 1 + this.getGradient(u + 1)) % 12;
|
||||
double aa = this.grad(v, h, k, 0.0D, 0.5D);
|
||||
double ab = this.grad(w, p, q, 0.0D, 0.5D);
|
||||
double ac = this.grad(z, r, s, 0.0D, 0.5D);
|
||||
return 70.0D * (aa + ab + ac);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double sample(double x, double y, double z) {
|
||||
double e = (x + y + z) * 0.3333333333333333D;
|
||||
int i = MathHelper.floor_double(x + e);
|
||||
int j = MathHelper.floor_double(y + e);
|
||||
int k = MathHelper.floor_double(z + e);
|
||||
double g = (double) (i + j + k) * 0.16666666666666666D;
|
||||
double h = (double) i - g;
|
||||
double l = (double) j - g;
|
||||
double m = (double) k - g;
|
||||
double n = x - h;
|
||||
double o = y - l;
|
||||
double p = z - m;
|
||||
byte w;
|
||||
byte aa;
|
||||
byte ab;
|
||||
byte ac;
|
||||
byte ad;
|
||||
byte bc;
|
||||
if (n >= o) {
|
||||
if (o >= p) {
|
||||
w = 1;
|
||||
aa = 0;
|
||||
ab = 0;
|
||||
ac = 1;
|
||||
ad = 1;
|
||||
bc = 0;
|
||||
} else if (n >= p) {
|
||||
w = 1;
|
||||
aa = 0;
|
||||
ab = 0;
|
||||
ac = 1;
|
||||
ad = 0;
|
||||
bc = 1;
|
||||
} else {
|
||||
w = 0;
|
||||
aa = 0;
|
||||
ab = 1;
|
||||
ac = 1;
|
||||
ad = 0;
|
||||
bc = 1;
|
||||
}
|
||||
} else if (o < p) {
|
||||
w = 0;
|
||||
aa = 0;
|
||||
ab = 1;
|
||||
ac = 0;
|
||||
ad = 1;
|
||||
bc = 1;
|
||||
} else if (n < p) {
|
||||
w = 0;
|
||||
aa = 1;
|
||||
ab = 0;
|
||||
ac = 0;
|
||||
ad = 1;
|
||||
bc = 1;
|
||||
} else {
|
||||
w = 0;
|
||||
aa = 1;
|
||||
ab = 0;
|
||||
ac = 1;
|
||||
ad = 1;
|
||||
bc = 0;
|
||||
}
|
||||
|
||||
double bd = n - (double) w + 0.16666666666666666D;
|
||||
double be = o - (double) aa + 0.16666666666666666D;
|
||||
double bf = p - (double) ab + 0.16666666666666666D;
|
||||
double bg = n - (double) ac + 0.3333333333333333D;
|
||||
double bh = o - (double) ad + 0.3333333333333333D;
|
||||
double bi = p - (double) bc + 0.3333333333333333D;
|
||||
double bj = n - 1.0D + 0.5D;
|
||||
double bk = o - 1.0D + 0.5D;
|
||||
double bl = p - 1.0D + 0.5D;
|
||||
int bm = i & 255;
|
||||
int bn = j & 255;
|
||||
int bo = k & 255;
|
||||
int bp = this.getGradient(bm + this.getGradient(bn + this.getGradient(bo))) % 12;
|
||||
int bq = this.getGradient(bm + w + this.getGradient(bn + aa + this.getGradient(bo + ab))) % 12;
|
||||
int br = this.getGradient(bm + ac + this.getGradient(bn + ad + this.getGradient(bo + bc))) % 12;
|
||||
int bs = this.getGradient(bm + 1 + this.getGradient(bn + 1 + this.getGradient(bo + 1))) % 12;
|
||||
double bt = this.grad(bp, n, o, p, 0.6D);
|
||||
double bu = this.grad(bq, bd, be, bf, 0.6D);
|
||||
double bv = this.grad(br, bg, bh, bi, 0.6D);
|
||||
double bw = this.grad(bs, bj, bk, bl, 0.6D);
|
||||
return 32.0D * (bt + bu + bv + bw);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user