User defined noise functions

This commit is contained in:
dfsek
2020-11-16 11:15:50 -07:00
parent 9125590a02
commit 022c95a862
12 changed files with 300 additions and 56 deletions

View File

@@ -1,35 +1,65 @@
package com.dfsek.terra.generation;
import com.dfsek.terra.config.genconfig.noise.NoiseConfig;
import com.dfsek.terra.math.NoiseFunction;
import com.dfsek.terra.math.NoiseFunction2;
import org.polydev.gaea.math.FastNoiseLite;
import com.dfsek.terra.math.NoiseFunction3;
import org.bukkit.World;
import parsii.eval.Expression;
import parsii.eval.Parser;
import parsii.eval.Scope;
import parsii.eval.Variable;
import parsii.tokenizer.ParseException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class ElevationEquation {
private static final Object noiseLock = new Object();
private final Expression delegate;
private final Scope s = new Scope();
private final NoiseFunction2 n2 = new NoiseFunction2();
private final Variable xVar = s.getVariable("x");
private final Variable zVar = s.getVariable("z");
public ElevationEquation(String equation) throws ParseException {
private final List<NoiseFunction> noiseFunctions = new ArrayList<>();
private boolean set = true;
public ElevationEquation(String equation, Map<String, NoiseConfig> noiseBuilders) throws ParseException {
Parser p = new Parser();
p.registerFunction("noise2", n2);
for(Map.Entry<String, NoiseConfig> e : noiseBuilders.entrySet()) {
switch(e.getValue().getDimensions()) {
case 2:
NoiseFunction2 function2 = new NoiseFunction2(e.getValue().getBuilder());
noiseFunctions.add(function2);
p.registerFunction(e.getKey(), function2);
break;
case 3:
NoiseFunction3 function3 = new NoiseFunction3(e.getValue().getBuilder());
noiseFunctions.add(function3);
p.registerFunction(e.getKey(), function3);
break;
}
}
delegate = p.parse(equation, s);
}
public double getNoise(double x, double z, FastNoiseLite noiseLite) {
public double getNoise(double x, double z, World w) {
synchronized(noiseLock) {
xVar.setValue(x);
zVar.setValue(z);
n2.setNoise(noiseLite);
setNoise(w.getSeed());
return delegate.evaluate();
}
}
private void setNoise(long seed) {
if(set) {
set = false;
for(NoiseFunction n : noiseFunctions) {
n.setNoise(seed);
}
}
}
}

View File

@@ -3,21 +3,18 @@ package com.dfsek.terra.generation;
import com.dfsek.terra.biome.grid.TerraBiomeGrid;
import org.bukkit.World;
import org.polydev.gaea.generation.GenerationPhase;
import org.polydev.gaea.math.FastNoiseLite;
import org.polydev.gaea.math.Interpolator;
public class ElevationInterpolator {
private final UserDefinedGenerator[][] gens = new UserDefinedGenerator[10][10];
private final double[][] values = new double[18][18];
private final FastNoiseLite noise;
private final int xOrigin;
private final int zOrigin;
private final TerraBiomeGrid grid;
public ElevationInterpolator(World w, int chunkX, int chunkZ, TerraBiomeGrid grid, FastNoiseLite noise) {
public ElevationInterpolator(World w, int chunkX, int chunkZ, TerraBiomeGrid grid) {
this.xOrigin = chunkX << 4;
this.zOrigin = chunkZ << 4;
this.noise = noise;
this.grid = grid;
for(int x = -2; x < 8; x++) {
@@ -30,13 +27,13 @@ public class ElevationInterpolator {
for(byte z = -1; z <= 16; z++) {
UserDefinedGenerator generator = getGenerator(x, z);
if(compareGens((x / 4), (z / 4)) && generator.interpolateElevation()) {
Interpolator interpolator = new Interpolator(biomeAvg(x / 4, z / 4),
biomeAvg((x / 4) + 1, z / 4),
biomeAvg(x / 4, (z / 4) + 1),
biomeAvg((x / 4) + 1, (z / 4) + 1),
Interpolator interpolator = new Interpolator(biomeAvg(x / 4, z / 4, w),
biomeAvg((x / 4) + 1, z / 4, w),
biomeAvg(x / 4, (z / 4) + 1, w),
biomeAvg((x / 4) + 1, (z / 4) + 1, w),
Interpolator.Type.LINEAR);
values[x + 1][z + 1] = interpolator.bilerp((double) (x % 4) / 4, (double) (z % 4) / 4);
} else values[x + 1][z + 1] = elevate(generator, xOrigin + x, zOrigin + z);
} else values[x + 1][z + 1] = elevate(generator, xOrigin + x, zOrigin + z, w);
}
}
}
@@ -60,20 +57,20 @@ public class ElevationInterpolator {
return false;
}
private double biomeAvg(int x, int z) {
return (elevate(getStoredGen(x + 1, z), x * 4 + 4 + xOrigin, z * 4 + zOrigin)
+ elevate(getStoredGen(x - 1, z), x * 4 - 4 + xOrigin, z * 4 + zOrigin)
+ elevate(getStoredGen(x, z + 1), x * 4 + xOrigin, z * 4 + 4 + zOrigin)
+ elevate(getStoredGen(x, z - 1), x * 4 + xOrigin, z * 4 - 4 + zOrigin)
+ elevate(getStoredGen(x, z), x * 4 + xOrigin, z * 4 + zOrigin)
+ elevate(getStoredGen(x - 1, z - 1), x * 4 + xOrigin, z * 4 + zOrigin)
+ elevate(getStoredGen(x - 1, z + 1), x * 4 + xOrigin, z * 4 + zOrigin)
+ elevate(getStoredGen(x + 1, z - 1), x * 4 + xOrigin, z * 4 + zOrigin)
+ elevate(getStoredGen(x + 1, z + 1), x * 4 + xOrigin, z * 4 + zOrigin)) / 9D;
private double biomeAvg(int x, int z, World w) {
return (elevate(getStoredGen(x + 1, z), x * 4 + 4 + xOrigin, z * 4 + zOrigin, w)
+ elevate(getStoredGen(x - 1, z), x * 4 - 4 + xOrigin, z * 4 + zOrigin, w)
+ elevate(getStoredGen(x, z + 1), x * 4 + xOrigin, z * 4 + 4 + zOrigin, w)
+ elevate(getStoredGen(x, z - 1), x * 4 + xOrigin, z * 4 - 4 + zOrigin, w)
+ elevate(getStoredGen(x, z), x * 4 + xOrigin, z * 4 + zOrigin, w)
+ elevate(getStoredGen(x - 1, z - 1), x * 4 + xOrigin, z * 4 + zOrigin, w)
+ elevate(getStoredGen(x - 1, z + 1), x * 4 + xOrigin, z * 4 + zOrigin, w)
+ elevate(getStoredGen(x + 1, z - 1), x * 4 + xOrigin, z * 4 + zOrigin, w)
+ elevate(getStoredGen(x + 1, z + 1), x * 4 + xOrigin, z * 4 + zOrigin, w)) / 9D;
}
private double elevate(UserDefinedGenerator g, int x, int z) {
if(g.getElevationEquation() != null) return g.getElevationEquation().getNoise(x, z, noise);
private double elevate(UserDefinedGenerator g, int x, int z, World w) {
if(g.getElevationEquation() != null) return g.getElevationEquation().getNoise(x, z, w);
return 0;
}

View File

@@ -151,7 +151,7 @@ public class TerraChunkGenerator extends GaeaChunkGenerator {
ElevationInterpolator elevationInterpolator;
try(ProfileFuture ignore = TerraProfiler.fromWorld(world).measure("ElevationTime")) {
elevationInterpolator = new ElevationInterpolator(world, chunkX, chunkZ, tw.getGrid(), getNoiseGenerator());
elevationInterpolator = new ElevationInterpolator(world, chunkX, chunkZ, tw.getGrid());
}
for(byte x = 0; x < 16; x++) {
@@ -203,12 +203,12 @@ public class TerraChunkGenerator extends GaeaChunkGenerator {
@Override
public int getNoiseOctaves(World world) {
return configPack.octaves;
return 1;
}
@Override
public double getNoiseFrequency(World world) {
return configPack.frequency;
return 0.02;
}
@Override

View File

@@ -1,6 +1,8 @@
package com.dfsek.terra.generation;
import com.dfsek.terra.Debug;
import com.dfsek.terra.config.genconfig.noise.NoiseConfig;
import com.dfsek.terra.math.NoiseFunction;
import com.dfsek.terra.math.NoiseFunction2;
import com.dfsek.terra.math.NoiseFunction3;
import com.dfsek.terra.util.DataUtil;
@@ -17,6 +19,8 @@ import parsii.eval.Scope;
import parsii.eval.Variable;
import parsii.tokenizer.ParseException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@@ -31,21 +35,35 @@ public class UserDefinedGenerator extends Generator {
private final Palette<BlockData>[] palettes = new Palette[256];
@SuppressWarnings({"unchecked", "rawtypes", "RedundantSuppression"})
private final Palette<BlockData>[] slantPalettes = new Palette[256];
private final NoiseFunction2 n2 = new NoiseFunction2();
private final NoiseFunction3 n3 = new NoiseFunction3();
private final ElevationEquation elevationEquation;
private final boolean preventSmooth;
private boolean elevationInterpolation;
private final List<NoiseFunction> noiseFunctions = new ArrayList<>();
private boolean set = true;
public UserDefinedGenerator(String equation, @Nullable String elevateEquation, Map<String, Double> userVariables, Map<Integer, Palette<BlockData>> paletteMap, Map<Integer, Palette<BlockData>> slantPaletteMap, boolean preventSmooth)
public UserDefinedGenerator(String equation, @Nullable String elevateEquation, Map<String, Double> userVariables, Map<Integer, Palette<BlockData>> paletteMap, Map<Integer, Palette<BlockData>> slantPaletteMap, Map<String, NoiseConfig> noiseBuilders, boolean preventSmooth)
throws ParseException {
for(Map.Entry<String, Double> entry : userVariables.entrySet()) {
s.getVariable(entry.getKey()).setValue(entry.getValue()); // Define all user variables.
}
Parser p = new Parser();
p.registerFunction("noise2", n2);
p.registerFunction("noise3", n3);
for(Map.Entry<String, NoiseConfig> e : noiseBuilders.entrySet()) {
switch(e.getValue().getDimensions()) {
case 2:
NoiseFunction2 function2 = new NoiseFunction2(e.getValue().getBuilder());
noiseFunctions.add(function2);
p.registerFunction(e.getKey(), function2);
break;
case 3:
NoiseFunction3 function3 = new NoiseFunction3(e.getValue().getBuilder());
noiseFunctions.add(function3);
p.registerFunction(e.getKey(), function3);
break;
}
}
for(int y = 0; y < 256; y++) {
Palette<BlockData> d = DataUtil.BLANK_PALETTE;
for(Map.Entry<Integer, Palette<BlockData>> e : paletteMap.entrySet()) {
@@ -66,12 +84,21 @@ public class UserDefinedGenerator extends Generator {
}
if(elevateEquation != null) {
Debug.info("Using elevation equation");
this.elevationEquation = new ElevationEquation(elevateEquation);
this.elevationEquation = new ElevationEquation(elevateEquation, noiseBuilders);
} else this.elevationEquation = null;
this.noiseExp = p.parse(equation, s);
this.preventSmooth = preventSmooth;
}
private void setNoise(long seed) {
if(set) {
set = false;
for(NoiseFunction n : noiseFunctions) {
n.setNoise(seed);
}
}
}
/**
* Gets the 2D noise at a pair of coordinates using the provided FastNoiseLite instance.
*
@@ -86,8 +113,7 @@ public class UserDefinedGenerator extends Generator {
xVar.setValue(x);
yVar.setValue(0);
zVar.setValue(z);
n2.setNoise(gen);
n3.setNoise(gen);
setNoise(w.getSeed());
return noiseExp.evaluate();
}
}
@@ -107,8 +133,7 @@ public class UserDefinedGenerator extends Generator {
xVar.setValue(x);
yVar.setValue(y);
zVar.setValue(z);
n2.setNoise(gen);
n3.setNoise(gen);
setNoise(w.getSeed());
return noiseExp.evaluate();
}
}

View File

@@ -0,0 +1,109 @@
package com.dfsek.terra.generation.config;
import org.polydev.gaea.math.FastNoiseLite;
public class NoiseBuilder {
private FastNoiseLite.NoiseType type = FastNoiseLite.NoiseType.OpenSimplex2;
private int octaves = 1;
private FastNoiseLite.FractalType fractalType = FastNoiseLite.FractalType.None;
private double frequency = 0.02D;
private double fractalGain = 0.5D;
private double fractalLacunarity = 2.0D;
private double pingPong = 2.0D;
private double weightedStrength = 0.0D;
private FastNoiseLite.CellularDistanceFunction cellularDistanceFunction = FastNoiseLite.CellularDistanceFunction.EuclideanSq;
private FastNoiseLite.CellularReturnType cellularReturnType = FastNoiseLite.CellularReturnType.Distance;
private double cellularJitter = 1.0D;
private FastNoiseLite.DomainWarpType domainWarpType = FastNoiseLite.DomainWarpType.OpenSimplex2;
private double domainWarpAmp = 1.0D;
private FastNoiseLite.RotationType3D rotationType3D = FastNoiseLite.RotationType3D.None;
public FastNoiseLite build(int seed) {
FastNoiseLite noise = new FastNoiseLite(seed);
if(!fractalType.equals(FastNoiseLite.FractalType.None)) {
noise.setFractalType(fractalType);
noise.setFractalOctaves(octaves);
noise.setFractalGain(fractalGain);
noise.setFractalLacunarity(fractalLacunarity);
if(fractalType.equals(FastNoiseLite.FractalType.PingPong)) noise.setFractalPingPongStrength(pingPong);
noise.setFractalWeightedStrength(weightedStrength);
}
if(type.equals(FastNoiseLite.NoiseType.Cellular)) {
noise.setCellularDistanceFunction(cellularDistanceFunction);
noise.setCellularReturnType(cellularReturnType);
noise.setCellularJitter(cellularJitter);
}
noise.setDomainWarpType(domainWarpType);
noise.setDomainWarpAmp(domainWarpAmp);
noise.setRotationType3D(rotationType3D);
noise.setFrequency(frequency);
return noise;
}
public void setFrequency(double frequency) {
this.frequency = frequency;
}
public void setFractalGain(double fractalGain) {
this.fractalGain = fractalGain;
}
public void setFractalLacunarity(double fractalLacunarity) {
this.fractalLacunarity = fractalLacunarity;
}
public void setFractalType(FastNoiseLite.FractalType fractalType) {
this.fractalType = fractalType;
}
public void setOctaves(int octaves) {
this.octaves = octaves;
}
public void setPingPong(double pingPong) {
this.pingPong = pingPong;
}
public void setWeightedStrength(double weightedStrength) {
this.weightedStrength = weightedStrength;
}
public FastNoiseLite.NoiseType getType() {
return type;
}
public void setType(FastNoiseLite.NoiseType type) {
this.type = type;
}
public void setCellularDistanceFunction(FastNoiseLite.CellularDistanceFunction cellularDistanceFunction) {
this.cellularDistanceFunction = cellularDistanceFunction;
}
public void setCellularReturnType(FastNoiseLite.CellularReturnType cellularReturnType) {
this.cellularReturnType = cellularReturnType;
}
public void setCellularJitter(double cellularJitter) {
this.cellularJitter = cellularJitter;
}
public void setDomainWarpAmp(double domainWarpAmp) {
this.domainWarpAmp = domainWarpAmp;
}
public void setDomainWarpType(FastNoiseLite.DomainWarpType domainWarpType) {
this.domainWarpType = domainWarpType;
}
public void setRotationType3D(FastNoiseLite.RotationType3D rotationType3D) {
this.rotationType3D = rotationType3D;
}
}