mirror of
https://github.com/PolyhedralDev/Terra.git
synced 2026-02-16 10:30:42 +00:00
better biome blending
This commit is contained in:
@@ -55,4 +55,31 @@ public class MathUtil {
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute binary logarithm
|
||||
*
|
||||
* @param bits Input
|
||||
* @return Binary logarithm
|
||||
*/
|
||||
public static int binlog(int bits) {
|
||||
int log = 0;
|
||||
if((bits & 0xffff0000) != 0) {
|
||||
bits >>>= 16;
|
||||
log = 16;
|
||||
}
|
||||
if(bits >= 256) {
|
||||
bits >>>= 8;
|
||||
log += 8;
|
||||
}
|
||||
if(bits >= 16) {
|
||||
bits >>>= 4;
|
||||
log += 4;
|
||||
}
|
||||
if(bits >= 4) {
|
||||
bits >>>= 2;
|
||||
log += 2;
|
||||
}
|
||||
return log + (bits >>> 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ public class ChunkInterpolator3 {
|
||||
private final Generator[][] gens = new Generator[7][7];
|
||||
private final boolean[][] needsBiomeInterp = new boolean[5][5];
|
||||
private final double[][][] noiseStorage = new double[7][7][65];
|
||||
private final int smooth;
|
||||
|
||||
/**
|
||||
* Instantiates a 3D ChunkInterpolator at a pair of chunk coordinates, with a BiomeGrid and FastNoiseLite instance.
|
||||
@@ -23,14 +24,15 @@ public class ChunkInterpolator3 {
|
||||
* @param chunkZ Z coordinate of the chunk.
|
||||
* @param grid BiomeGrid to use for noise fetching.
|
||||
*/
|
||||
public ChunkInterpolator3(World w, int chunkX, int chunkZ, BiomeGrid grid) {
|
||||
public ChunkInterpolator3(World w, int chunkX, int chunkZ, BiomeGrid grid, int smooth) {
|
||||
int xOrigin = chunkX << 4;
|
||||
int zOrigin = chunkZ << 4;
|
||||
this.smooth = smooth;
|
||||
|
||||
|
||||
for(int x = -1; x < 6; x++) {
|
||||
for(int z = -1; z < 6; z++) {
|
||||
gens[x + 1][z + 1] = grid.getBiome(xOrigin + (x << 2), zOrigin + (z << 2), GenerationPhase.BASE).getGenerator();
|
||||
gens[x + 1][z + 1] = grid.getBiome(xOrigin + (x * smooth), zOrigin + (z * smooth), GenerationPhase.BASE).getGenerator();
|
||||
}
|
||||
}
|
||||
for(int x = 0; x < 5; x++) {
|
||||
@@ -42,7 +44,7 @@ public class ChunkInterpolator3 {
|
||||
for(byte x = -1; x < 6; x++) {
|
||||
for(byte z = -1; z < 6; z++) {
|
||||
for(int y = 0; y < 65; y++) {
|
||||
noiseStorage[x + 1][z + 1][y] = gens[x + 1][z + 1].getNoise(w, (x << 2) + xOrigin, y << 2, (z << 2) + zOrigin);
|
||||
noiseStorage[x + 1][z + 1][y] = gens[x + 1][z + 1].getNoise(w, (x * smooth) + xOrigin, y << 2, (z * smooth) + zOrigin);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -64,43 +66,40 @@ public class ChunkInterpolator3 {
|
||||
}
|
||||
}
|
||||
|
||||
private static int reRange(int value, int high) {
|
||||
return FastMath.max(FastMath.min(value, high), 0);
|
||||
}
|
||||
|
||||
private boolean compareGens(int x, int z) {
|
||||
Generator comp = gens[x][z];
|
||||
if(!comp.equals(gens[x+1][z])) return true;
|
||||
if(!comp.equals(gens[x + 1][z])) return true;
|
||||
|
||||
if(!comp.equals(gens[x][z+1])) return true;
|
||||
if(!comp.equals(gens[x][z + 1])) return true;
|
||||
|
||||
if(!comp.equals(gens[x-1][z])) return true;
|
||||
if(!comp.equals(gens[x - 1][z])) return true;
|
||||
|
||||
if(!comp.equals(gens[x][z-1])) return true;
|
||||
if(!comp.equals(gens[x][z - 1])) return true;
|
||||
|
||||
if(!comp.equals(gens[x+1][z+1])) return true;
|
||||
if(!comp.equals(gens[x + 1][z + 1])) return true;
|
||||
|
||||
if(!comp.equals(gens[x-1][z-1])) return true;
|
||||
if(!comp.equals(gens[x - 1][z - 1])) return true;
|
||||
|
||||
if(!comp.equals(gens[x+1][z-1])) return true;
|
||||
if(!comp.equals(gens[x + 1][z - 1])) return true;
|
||||
|
||||
return !comp.equals(gens[x - 1][z + 1]);
|
||||
}
|
||||
|
||||
private double biomeAvg(int x, int y, int z) {
|
||||
if(needsBiomeInterp[x][z]) return (noiseStorage[x + 2][z + 1][y]
|
||||
+ noiseStorage[x][z + 1][y]
|
||||
+ noiseStorage[x + 1][z + 2][y]
|
||||
+ noiseStorage[x + 1][z][y]
|
||||
+ noiseStorage[x][z][y]
|
||||
+ noiseStorage[x + 2][z + 2][y]
|
||||
+ noiseStorage[x + 2][z][y]
|
||||
+ noiseStorage[x][z + 2][y]
|
||||
+ noiseStorage[x + 1][z + 1][y]
|
||||
) / 9D;
|
||||
else {
|
||||
if(gens[x+1][z+1].useMinimalInterpolation()) return noiseStorage[x+1][z+1][y];
|
||||
else return (noiseStorage[x + 2][z + 1][y]
|
||||
+ noiseStorage[x][z + 1][y]
|
||||
+ noiseStorage[x + 1][z + 2][y]
|
||||
+ noiseStorage[x + 1][z][y]
|
||||
+ noiseStorage[x+1][z+1][y]) / 5D;
|
||||
if(needsBiomeInterp[x][z]) {
|
||||
double t = 0d;
|
||||
for(int xi = 0; xi <= 2; xi++) {
|
||||
for(int zi = 0; zi <= 2; zi++) {
|
||||
t += noiseStorage[x + xi][z + zi][y];
|
||||
}
|
||||
}
|
||||
return t / 9d;
|
||||
} else {
|
||||
return noiseStorage[x + 1][z + 1][y];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,10 +111,6 @@ public class ChunkInterpolator3 {
|
||||
* @return double - The interpolated noise at the coordinates.
|
||||
*/
|
||||
public double getNoise(double x, double y, double z) {
|
||||
return interpGrid[reRange(((int) x) / 4, 3)][reRange(((int) y) / 4, 63)][reRange(((int) z) / 4, 3)].trilerp((x % 4) / 4, (y % 4) / 4, (z % 4) / 4);
|
||||
}
|
||||
|
||||
private static int reRange(int value, int high) {
|
||||
return FastMath.max(FastMath.min(value, high), 0);
|
||||
return interpGrid[reRange(((int) x) / smooth, 3)][reRange(((int) y) / 4, 63)][reRange(((int) z) / smooth, 3)].trilerp((x % smooth) / smooth, (y % 4) / 4, (z % smooth) / smooth);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,10 +22,4 @@ public interface Generator {
|
||||
*/
|
||||
Palette<BlockData> getPalette(int y);
|
||||
|
||||
/**
|
||||
* Returns true if the biome should be interpolated just once, false to use advanced interpolation + blending.
|
||||
*
|
||||
* @return Whether biome should use minimal interpolation
|
||||
*/
|
||||
boolean useMinimalInterpolation();
|
||||
}
|
||||
|
||||
@@ -27,8 +27,9 @@ public class GeneratorBuilder {
|
||||
|
||||
private boolean interpolateElevation;
|
||||
|
||||
|
||||
public WorldGenerator build(long seed) {
|
||||
return gens.computeIfAbsent(seed, k -> new WorldGenerator(seed, noiseEquation, elevationEquation, varScope, noiseBuilderMap, palettes, slantPalettes, preventInterpolation, interpolateElevation));
|
||||
return gens.computeIfAbsent(seed, k -> new WorldGenerator(seed, noiseEquation, elevationEquation, varScope, noiseBuilderMap, palettes, slantPalettes, interpolateElevation));
|
||||
}
|
||||
|
||||
public String getNoiseEquation() {
|
||||
|
||||
@@ -4,6 +4,7 @@ import com.dfsek.terra.api.math.interpolation.Interpolator;
|
||||
import com.dfsek.terra.api.world.generation.GenerationPhase;
|
||||
import com.dfsek.terra.biome.grid.master.TerraBiomeGrid;
|
||||
import com.dfsek.terra.generation.config.WorldGenerator;
|
||||
import net.jafama.FastMath;
|
||||
|
||||
public class ElevationInterpolator {
|
||||
private final WorldGenerator[][] gens;
|
||||
@@ -12,17 +13,20 @@ public class ElevationInterpolator {
|
||||
private final int zOrigin;
|
||||
private final TerraBiomeGrid grid;
|
||||
private final int smooth;
|
||||
private final int pow;
|
||||
|
||||
public ElevationInterpolator(int chunkX, int chunkZ, TerraBiomeGrid grid, int smooth) {
|
||||
this.xOrigin = chunkX << 4;
|
||||
this.zOrigin = chunkZ << 4;
|
||||
this.grid = grid;
|
||||
this.smooth = smooth;
|
||||
this.gens = new WorldGenerator[10][10];
|
||||
this.pow = FastMath.log2(smooth);
|
||||
this.gens = new WorldGenerator[6 + 2 * pow][6 + 2 * pow];
|
||||
|
||||
for(int x = -2; x < 8; x++) {
|
||||
for(int z = -2; z < 8; z++) {
|
||||
gens[x + 2][z + 2] = (WorldGenerator) grid.getBiome(xOrigin + (x * smooth), zOrigin + (z * smooth), GenerationPhase.BASE).getGenerator();
|
||||
|
||||
for(int x = -pow; x < 6 + pow; x++) {
|
||||
for(int z = -pow; z < 6 + pow; z++) {
|
||||
gens[x + pow][z + pow] = (WorldGenerator) grid.getBiome(xOrigin + (x * smooth), zOrigin + (z * smooth), GenerationPhase.BASE).getGenerator();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,12 +49,12 @@ public class ElevationInterpolator {
|
||||
}
|
||||
|
||||
private WorldGenerator getStoredGen(int x, int z) {
|
||||
return gens[x + 2][z + 2];
|
||||
return gens[x + pow][z + pow];
|
||||
}
|
||||
|
||||
private boolean compareGens(int x, int z, WorldGenerator comp) {
|
||||
for(int xi = x - 2; xi <= x + 2; xi++) {
|
||||
for(int zi = z - 2; zi <= z + 2; zi++) {
|
||||
for(int xi = x - pow; xi <= x + pow; xi++) {
|
||||
for(int zi = z - pow; zi <= z + pow; zi++) {
|
||||
if(!comp.equals(getStoredGen(xi, zi))) return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,7 +88,7 @@ public class MasterChunkGenerator implements TerraChunkGenerator {
|
||||
try(ProfileFuture ignore = tw.getProfiler().measure("TotalChunkGenTime")) {
|
||||
ChunkInterpolator3 interp;
|
||||
try(ProfileFuture ignored = tw.getProfiler().measure("ChunkBaseGenTime")) {
|
||||
interp = new ChunkInterpolator3(world, chunkX, chunkZ, tw.getGrid());
|
||||
interp = new ChunkInterpolator3(world, chunkX, chunkZ, tw.getGrid(), 16);
|
||||
|
||||
if(!tw.isSafe()) return chunk;
|
||||
int xOrig = (chunkX << 4);
|
||||
@@ -96,7 +96,7 @@ public class MasterChunkGenerator implements TerraChunkGenerator {
|
||||
|
||||
ElevationInterpolator elevationInterpolator;
|
||||
try(ProfileFuture ignored1 = tw.getProfiler().measure("ElevationTime")) {
|
||||
elevationInterpolator = new ElevationInterpolator(chunkX, chunkZ, tw.getGrid(), 8);
|
||||
elevationInterpolator = new ElevationInterpolator(chunkX, chunkZ, tw.getGrid(), 4);
|
||||
}
|
||||
|
||||
Sampler sampler = new Sampler(interp, elevationInterpolator);
|
||||
|
||||
@@ -22,7 +22,6 @@ public class WorldGenerator implements Generator {
|
||||
@SuppressWarnings({"unchecked", "rawtypes", "RedundantSuppression"})
|
||||
private final PaletteHolder slantPalettes;
|
||||
|
||||
private final boolean preventSmooth;
|
||||
private final Expression noiseExp;
|
||||
private final Expression elevationExp;
|
||||
private final Variable xVar;
|
||||
@@ -32,7 +31,7 @@ public class WorldGenerator implements Generator {
|
||||
private final Variable elevationZVar;
|
||||
private final boolean elevationInterpolation;
|
||||
|
||||
public WorldGenerator(long seed, String equation, String elevateEquation, Scope vScope, Map<String, NoiseBuilder> noiseBuilders, PaletteHolder palettes, PaletteHolder slantPalettes, boolean preventSmooth, boolean elevationInterpolation) {
|
||||
public WorldGenerator(long seed, String equation, String elevateEquation, Scope vScope, Map<String, NoiseBuilder> noiseBuilders, PaletteHolder palettes, PaletteHolder slantPalettes, boolean elevationInterpolation) {
|
||||
Parser p = new Parser();
|
||||
p.registerFunction("rand", new RandomFunction());
|
||||
Parser ep = new Parser();
|
||||
@@ -44,8 +43,6 @@ public class WorldGenerator implements Generator {
|
||||
zVar = s.create("z");
|
||||
s.create("seed").setValue(seed);
|
||||
|
||||
this.preventSmooth = preventSmooth;
|
||||
|
||||
this.palettes = palettes;
|
||||
this.slantPalettes = slantPalettes;
|
||||
|
||||
@@ -110,11 +107,6 @@ public class WorldGenerator implements Generator {
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean useMinimalInterpolation() {
|
||||
return preventSmooth;
|
||||
}
|
||||
|
||||
public boolean interpolateElevation() {
|
||||
return elevationInterpolation;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user