Last active
April 29, 2019 22:08
-
-
Save Barteks2x/41e6d542cc32e286bbd938361d49083c to your computer and use it in GitHub Desktop.
Mixed gradient-value noise that generates it's values based on Minecraft biome data.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package io.github.opencubicchunks.cubicchunks.cubicgen.noise; | |
import com.flowpowered.noise.Utils; | |
import com.flowpowered.noise.module.Module; | |
import io.github.opencubicchunks.cubicchunks.cubicgen.math.Vec2d; | |
import net.minecraft.util.math.MathHelper; | |
public class BiomeControlledGradValPerlinNoise extends Module { | |
private static final int X_NOISE_GEN = 1619; | |
private static final int Y_NOISE_GEN = 31337; | |
private static final int Z_NOISE_GEN = 6971; | |
private static final int SEED_NOISE_GEN = 1013; | |
private static final int SHIFT_NOISE_GEN = 8; | |
private final double maxVal; | |
private int octaves; | |
private double fx; | |
private double fy; | |
private double fz; | |
private double valleyDepthFactor; | |
private final double scale; | |
private final double offset; | |
private final double fxi; | |
private final double fyi; | |
private final double fzi; | |
private final int seed; | |
private BiomeDataProvider data; | |
/** | |
* Generates a gradient-coherent-noise value from the coordinates of a three-dimensional input value. | |
* | |
* @param x The @a x coordinate of the input value. | |
* @param y The @a y coordinate of the input value. | |
* @param z The @a z coordinate of the input value. | |
* @param seed The random number seed. | |
* @param valleyDepthFactor | |
* @return The generated gradient-coherent-noise value. | |
* <p/> | |
* The return value ranges from 0 to 1. | |
* <p/> | |
* For an explanation of the difference between <i>gradient</i> noise and <i>value</i> noise, see the comments for the GradientNoise3D() function. | |
*/ | |
public static void gradientCoherentNoise3D(double x, double y, double z, | |
double freqInvX, double freqInvY, double freqInvZ, | |
int seed, BiomeDataProvider data, double valleyDepthFactor, | |
Vec2d output) { | |
// Create a unit-length cube aligned along an integer boundary. This cube | |
// surrounds the input point. | |
int x0 = ((x > 0.0) ? (int) x : (int) x - 1); | |
int x1 = x0 + 1; | |
int y0 = ((y > 0.0) ? (int) y : (int) y - 1); | |
int y1 = y0 + 1; | |
int z0 = ((z > 0.0) ? (int) z : (int) z - 1); | |
int z1 = z0 + 1; | |
// world coordinates for biome data | |
int wx0 = MathHelper.floor(x0 * freqInvX); | |
int wy0 = MathHelper.floor(y0 * freqInvY); | |
int wz0 = MathHelper.floor(z0 * freqInvZ); | |
int wx1 = MathHelper.floor(x1 * freqInvX); | |
int wy1 = MathHelper.floor(y1 * freqInvY); | |
int wz1 = MathHelper.floor(z1 * freqInvZ); | |
// Map the difference between the coordinates of the input value and the | |
// coordinates of the cube's outer-lower-left vertex onto an S-curve. | |
double xs = Utils.sCurve5(x - (double) x0); | |
double ys = Utils.sCurve5(y - (double) y0); | |
double zs = Utils.sCurve5(z - (double) z0); | |
// Now calculate the noise values at each vertex of the cube. To generate | |
// the coherent-noise value at the input point, interpolate these eight | |
// noise values using the S-curve value as the interpolant (trilinear | |
// interpolation.) | |
Vec2d n0 = new Vec2d(0, 0); | |
Vec2d n1 = new Vec2d(0, 0); | |
Vec2d ix0 = new Vec2d(0, 0); | |
Vec2d ix1 = new Vec2d(0, 0); | |
Vec2d iy0 = new Vec2d(0, 0); | |
Vec2d iy1 = new Vec2d(0, 0); | |
gradvalBiomeNoise3D(x, y, z, x0, y0, z0, wx0, wy0, wz0, seed, data, n0); | |
gradvalBiomeNoise3D(x, y, z, x1, y0, z0, wx1, wy0, wz0, seed, data, n1); | |
linearInterp(n0, n1, xs, ix0); | |
gradvalBiomeNoise3D(x, y, z, x0, y1, z0, wx0, wy1, wz0, seed, data, n0); | |
gradvalBiomeNoise3D(x, y, z, x1, y1, z0, wx1, wy1, wz0, seed, data, n1); | |
linearInterp(n0, n1, xs, ix1); | |
linearInterp(ix0, ix1, ys, iy0); | |
gradvalBiomeNoise3D(x, y, z, x0, y0, z1, wx0, wy0, wz1, seed, data, n0); | |
gradvalBiomeNoise3D(x, y, z, x1, y0, z1, wx1, wy0, wz1, seed, data, n1); | |
linearInterp(n0, n1, xs, ix0); | |
gradvalBiomeNoise3D(x, y, z, x0, y1, z1, wx0, wy1, wz1, seed, data, n0); | |
gradvalBiomeNoise3D(x, y, z, x1, y1, z1, wx1, wy1, wz1, seed, data, n1); | |
linearInterp(n0, n1, xs, ix1); | |
linearInterp(ix0, ix1, ys, iy1); | |
linearInterp(iy0, iy1, zs, output); | |
} | |
private static void linearInterp(Vec2d x0, Vec2d x1, double a, Vec2d out) { | |
out.x = Utils.linearInterp(x0.x, x1.x, a); | |
out.y = Utils.linearInterp(x0.y, x1.y, a); | |
} | |
/** | |
* Generates mixed gradient and value noise using biome data basis for given coordinates, | |
* specified as pair of integer and fractional parts. | |
* <p> | |
* The difference between fx and ix must be less than or equal to one. | |
* The difference between @a fy and @a iy must be less than or equal to one. | |
* The difference between @a fz and @a iz must be less than or equal to one. | |
* <p/> | |
* The noise gen | |
* <p/> | |
* The gradient part ranges from -1 to 1 multiplied by biome factor. | |
* The value part is biome offset. | |
* <p/> | |
* This function generates a gradient-noise value by performing the following steps: - It first calculates a random normalized vector based on the nearby integer value passed to this function. - | |
* It then calculates a new value by adding this vector to the nearby integer value passed to this function. - It then calculates the dot product of the above-generated value and the | |
* floating-point input value passed to this function. | |
* <p/> | |
* A noise function differs from a random-number generator because it always returns the same output value if the same input value is passed to it. | |
* | |
* @param fx The floating-point @a x coordinate of the input value. | |
* @param fy The floating-point @a y coordinate of the input value. | |
* @param fz The floating-point @a z coordinate of the input value. | |
* @param ix The integer @a x coordinate of a nearby value. | |
* @param iy The integer @a y coordinate of a nearby value. | |
* @param iz The integer @a z coordinate of a nearby value. | |
* @param wx World x coordinate for biome data | |
* @param wy World y coordinate for biome data | |
* @param wz World z coordinate for biome data | |
* @param seed The random number seed. | |
* @param data Source of biome data | |
* @param output The output value. x is gradient component, y is value component | |
*/ | |
public static void gradvalBiomeNoise3D(double fx, double fy, double fz, | |
int ix, int iy, int iz, | |
int wx, int wy, int wz, | |
int seed, BiomeDataProvider data, Vec2d output) { | |
data.prepare(wx, wy, wz); | |
double factor = data.variation() * 2; // * 2 because RANDOM_VECTORS is halved as an optimization | |
// Randomly generate a gradient vector given the integer coordinates of the | |
// input value. This implementation generates a random number and uses it | |
// as an index into a normalized-vector lookup table. | |
int vectorIndex = (X_NOISE_GEN * ix + Y_NOISE_GEN * iy + Z_NOISE_GEN * iz + SEED_NOISE_GEN * seed); | |
vectorIndex ^= (vectorIndex >> SHIFT_NOISE_GEN); | |
vectorIndex &= 0xff; | |
double xvGradient = Utils.RANDOM_VECTORS[(vectorIndex << 2)] * factor; | |
double yvGradient = Utils.RANDOM_VECTORS[(vectorIndex << 2) + 1] * factor; | |
double zvGradient = Utils.RANDOM_VECTORS[(vectorIndex << 2) + 2] * factor; | |
// Set up us another vector equal to the distance between the two vectors | |
// passed to this function. | |
double xvPoint = (fx - ix); | |
double yvPoint = (fy - iy); | |
double zvPoint = (fz - iz); | |
// Now compute the dot product of the gradient vector with the distance | |
// vector. The resulting value is gradient noise. Apply a scaling and | |
// offset value so that this noise value ranges from 0 to 1. | |
output.x = (xvGradient * xvPoint) + (yvGradient * yvPoint) + (zvGradient * zvPoint); | |
output.y = data.offset(); | |
} | |
public BiomeControlledGradValPerlinNoise(BiomeDataProvider data, int octaves, long seed, | |
boolean normalized, double minNorm, double maxNorm, | |
double fx, double fy, double fz, double valleyDepthFactor) { | |
super(0); | |
this.data = data; | |
this.fx = fx; | |
this.fy = fy; | |
this.fz = fz; | |
fxi = 1.0/fx; | |
fyi = 1.0/fy; | |
fzi = 1.0/fz; | |
maxVal = (Math.pow(0.5, octaves) - 1) / (0.5 - 1); | |
scale = normalized ? (1.0/maxVal) * (maxNorm - minNorm) / 2 : 1; | |
offset = normalized ? (maxNorm + minNorm) / 2 : 0; | |
this.octaves = octaves; | |
this.valleyDepthFactor = valleyDepthFactor; | |
this.seed = (int) (seed ^ (seed >>> 32)); | |
} | |
@Override | |
public int getSourceModuleCount() { | |
return 0; | |
} | |
@Override | |
public double getValue(double x, double y, double z) { | |
double x1 = x; | |
double y1 = y; | |
double z1 = z; | |
double fxi = this.fxi; | |
double fyi = this.fyi; | |
double fzi = this.fzi; | |
double curPersistence = 1.0; | |
int seed; | |
x1 *= fx; | |
y1 *= fy; | |
z1 *= fz; | |
Vec2d out = new Vec2d(0, 0); | |
Vec2d temp = new Vec2d(0, 0); | |
for (int curOctave = 0; curOctave < octaves; curOctave++) { | |
// Get the coherent-noise value from the input value and add it to the | |
// final result. | |
seed = this.seed + curOctave; | |
BiomeControlledGradValPerlinNoise.gradientCoherentNoise3D( | |
x1, y1, z1, fxi, fyi, fzi, | |
seed, data, valleyDepthFactor, temp); | |
out.add(temp.mul(curPersistence)); | |
// Prepare the next octave. | |
x1 *= 2; | |
y1 *= 2; | |
z1 *= 2; | |
fxi *= 0.5; | |
fyi *= 0.5; | |
fzi *= 0.5; | |
curPersistence *= 0.5; | |
} | |
out.mul(scale).add(offset); | |
if (y < out.y) { | |
out.x *= valleyDepthFactor; | |
} | |
return out.x + out.y; | |
} | |
public interface BiomeDataProvider { | |
void prepare(int x, int y, int z); | |
double variation(); | |
double offset(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment