From c1fdfa94f170151a6f6108a7ac536fade687556b Mon Sep 17 00:00:00 2001 From: dfsek Date: Thu, 14 Jan 2021 18:39:14 -0700 Subject: [PATCH] improve elevation interp (TEMP DISABLE CARVING) --- .../math/noise/samplers/FastNoiseLite.java | 3 +- .../terra/biome/StandardBiomeProvider.java | 56 ++++++++------ .../terra/config/base/ConfigPackTemplate.java | 5 +- .../biome/BiomeProviderBuilderLoader.java | 12 ++- .../terra/generation/math/SamplerCache.java | 4 +- .../interpolation/ElevationInterpolator.java | 76 ++++--------------- .../BukkitChunkGeneratorWrapper.java | 3 +- 7 files changed, 65 insertions(+), 94 deletions(-) diff --git a/common/src/main/java/com/dfsek/terra/api/math/noise/samplers/FastNoiseLite.java b/common/src/main/java/com/dfsek/terra/api/math/noise/samplers/FastNoiseLite.java index 5ffa366d9..9e4d69aa3 100644 --- a/common/src/main/java/com/dfsek/terra/api/math/noise/samplers/FastNoiseLite.java +++ b/common/src/main/java/com/dfsek/terra/api/math/noise/samplers/FastNoiseLite.java @@ -2515,7 +2515,8 @@ public class FastNoiseLite implements NoiseSampler { Perlin, ValueCubic, Value, - WhiteNoise + WhiteNoise, + Constant } diff --git a/common/src/main/java/com/dfsek/terra/biome/StandardBiomeProvider.java b/common/src/main/java/com/dfsek/terra/biome/StandardBiomeProvider.java index 64a5bd482..ea11efa6e 100644 --- a/common/src/main/java/com/dfsek/terra/biome/StandardBiomeProvider.java +++ b/common/src/main/java/com/dfsek/terra/biome/StandardBiomeProvider.java @@ -1,25 +1,31 @@ package com.dfsek.terra.biome; import com.dfsek.tectonic.exception.ConfigException; +import com.dfsek.terra.api.math.noise.samplers.NoiseSampler; import com.dfsek.terra.api.math.vector.Vector2; import com.dfsek.terra.api.platform.TerraPlugin; import com.dfsek.terra.api.world.biome.TerraBiome; import com.dfsek.terra.biome.pipeline.BiomeHolder; import com.dfsek.terra.biome.pipeline.BiomePipeline; +import com.dfsek.terra.generation.config.NoiseBuilder; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; import net.jafama.FastMath; import org.jetbrains.annotations.NotNull; -import java.util.concurrent.ExecutionException; - public class StandardBiomeProvider implements BiomeProvider { private final LoadingCache holderCache; - private final LoadingCache biomeCache; + private final BiomePipeline pipeline; private int resolution = 1; + private final NoiseSampler xSampler; + private final NoiseSampler zSampler; + private final int noiseAmp; - protected StandardBiomeProvider(BiomePipeline pipeline, TerraPlugin main) { + protected StandardBiomeProvider(BiomePipeline pipeline, TerraPlugin main, NoiseSampler xSampler, NoiseSampler zSampler, int noiseAmp) { + this.xSampler = xSampler; + this.zSampler = zSampler; + this.noiseAmp = noiseAmp; holderCache = CacheBuilder.newBuilder() .maximumSize(main == null ? 32 : main.getTerraConfig().getProviderCache()) .build( @@ -30,27 +36,16 @@ public class StandardBiomeProvider implements BiomeProvider { } } ); - biomeCache = CacheBuilder.newBuilder() - .maximumSize(main == null ? 512 : main.getTerraConfig().getBiomeCache()) - .build( - new CacheLoader() { - @Override - public TerraBiome load(@NotNull Vector2 key) throws ExecutionException { - int x = FastMath.floorToInt(key.getX()); - int z = FastMath.floorToInt(key.getZ()); - x /= resolution; - z /= resolution; - int fdX = FastMath.floorDiv(x, pipeline.getSize()); - int fdZ = FastMath.floorDiv(z, pipeline.getSize()); - return holderCache.get(new Vector2(fdX, fdZ)).getBiome(x - fdX * pipeline.getSize(), z - fdZ * pipeline.getSize()); - } - } - ); + this.pipeline = pipeline; } @Override public TerraBiome getBiome(int x, int z) { - return biomeCache.getUnchecked(new Vector2(x, z)); + x = FastMath.floorToInt(FastMath.floorDiv(x, resolution) + xSampler.getNoise(x, z) * noiseAmp); + z = FastMath.floorToInt(FastMath.floorDiv(z, resolution) + zSampler.getNoise(x, z) * noiseAmp); + int fdX = FastMath.floorDiv(x, pipeline.getSize()); + int fdZ = FastMath.floorDiv(z, pipeline.getSize()); + return holderCache.getUnchecked(new Vector2(fdX, fdZ)).getBiome(x - fdX * pipeline.getSize(), z - fdZ * pipeline.getSize()); } public int getResolution() { @@ -68,16 +63,33 @@ public class StandardBiomeProvider implements BiomeProvider { public static final class StandardBiomeProviderBuilder implements BiomeProviderBuilder { private final ExceptionalFunction pipelineBuilder; private final TerraPlugin main; + private int resolution = 1; + private int noiseAmp = 2; + private NoiseBuilder builder = new NoiseBuilder(); public StandardBiomeProviderBuilder(ExceptionalFunction pipelineBuilder, TerraPlugin main) { this.pipelineBuilder = pipelineBuilder; this.main = main; } + public void setResolution(int resolution) { + this.resolution = resolution; + } + + public void setBuilder(NoiseBuilder builder) { + this.builder = builder; + } + + public void setNoiseAmp(int noiseAmp) { + this.noiseAmp = noiseAmp; + } + @Override public StandardBiomeProvider build(long seed) { try { - return new StandardBiomeProvider(pipelineBuilder.apply(seed), main); + StandardBiomeProvider provider = new StandardBiomeProvider(pipelineBuilder.apply(seed), main, builder.build((int) seed), builder.build((int) (seed + 1)), noiseAmp); + provider.setResolution(resolution); + return provider; } catch(ConfigException e) { throw new RuntimeException(e); } diff --git a/common/src/main/java/com/dfsek/terra/config/base/ConfigPackTemplate.java b/common/src/main/java/com/dfsek/terra/config/base/ConfigPackTemplate.java index ab63afadc..16095467f 100644 --- a/common/src/main/java/com/dfsek/terra/config/base/ConfigPackTemplate.java +++ b/common/src/main/java/com/dfsek/terra/config/base/ConfigPackTemplate.java @@ -182,10 +182,7 @@ public class ConfigPackTemplate implements ValidatedConfigTemplate { @Override public boolean validate() throws ValidationException { if(!MathUtil.equals(FastMath.log(baseBlend) / FastMath.log(2d), FastMath.round(FastMath.log(baseBlend) / FastMath.log(2d)))) { - throw new ValidationException("TerraBiome base blend value \"" + baseBlend + "\" is not a power of 2."); - } - if(!MathUtil.equals(FastMath.log(elevationBlend) / FastMath.log(2d), FastMath.round(FastMath.log(elevationBlend) / FastMath.log(2d)))) { - throw new ValidationException("TerraBiome elevation blend value \"" + baseBlend + "\" is not a power of 2."); + throw new ValidationException("Biome base blend value \"" + baseBlend + "\" is not a power of 2."); } return true; } diff --git a/common/src/main/java/com/dfsek/terra/config/loaders/config/biome/BiomeProviderBuilderLoader.java b/common/src/main/java/com/dfsek/terra/config/loaders/config/biome/BiomeProviderBuilderLoader.java index 3a5aeaecb..56abb90d6 100644 --- a/common/src/main/java/com/dfsek/terra/config/loaders/config/biome/BiomeProviderBuilderLoader.java +++ b/common/src/main/java/com/dfsek/terra/config/loaders/config/biome/BiomeProviderBuilderLoader.java @@ -36,10 +36,10 @@ public class BiomeProviderBuilderLoader implements TypeLoader map = (Map) c; - return new StandardBiomeProvider.StandardBiomeProviderBuilder(seed -> { + StandardBiomeProvider.StandardBiomeProviderBuilder builder = new StandardBiomeProvider.StandardBiomeProviderBuilder(seed -> { Map source = (Map) map.get("source"); ProbabilityCollection sourceBiomes = (ProbabilityCollection) loader.loadType(Types.TERRA_BIOME_PROBABILITY_COLLECTION_TYPE, source.get("biomes")); NoiseSampler sourceNoise = new NoiseBuilderLoader().load(NoiseBuilder.class, source.get("noise"), loader).build(FastMath.toInt(seed)); @@ -76,5 +76,13 @@ public class BiomeProviderBuilderLoader implements TypeLoader blend = (Map) map.get("blend"); + if(blend.containsKey("amplitude")) builder.setNoiseAmp(Integer.parseInt(blend.get("amplitude").toString())); + if(blend.containsKey("noise")) + builder.setBuilder(new NoiseBuilderLoader().load(NoiseBuilder.class, blend.get("noise"), loader)); + } + return builder; } } diff --git a/common/src/main/java/com/dfsek/terra/generation/math/SamplerCache.java b/common/src/main/java/com/dfsek/terra/generation/math/SamplerCache.java index 9c7d5f4a2..10d72e027 100644 --- a/common/src/main/java/com/dfsek/terra/generation/math/SamplerCache.java +++ b/common/src/main/java/com/dfsek/terra/generation/math/SamplerCache.java @@ -35,7 +35,6 @@ public class SamplerCache { } private class Container { - private final World world; private final TerraWorld terraWorld; private final LoadingCache cache; @@ -46,10 +45,9 @@ public class SamplerCache { public Sampler load(@NotNull Long key) { int cx = (int) (key >> 32); int cz = (int) key.longValue(); - return new Sampler(cx, cz, terraWorld.getBiomeProvider(), world, terraWorld.getConfig().getTemplate().getBaseBlend(), terraWorld.getConfig().getTemplate().getElevationBlend()); + return new Sampler(cx, cz, terraWorld.getBiomeProvider(), world, terraWorld.getConfig().getTemplate().getElevationBlend(), terraWorld.getConfig().getTemplate().getBaseBlend()); } }); - this.world = world; terraWorld = main.getWorld(world); } diff --git a/common/src/main/java/com/dfsek/terra/generation/math/interpolation/ElevationInterpolator.java b/common/src/main/java/com/dfsek/terra/generation/math/interpolation/ElevationInterpolator.java index a56f9a429..62b92a6ae 100644 --- a/common/src/main/java/com/dfsek/terra/generation/math/interpolation/ElevationInterpolator.java +++ b/common/src/main/java/com/dfsek/terra/generation/math/interpolation/ElevationInterpolator.java @@ -6,78 +6,34 @@ import com.dfsek.terra.generation.config.WorldGenerator; import net.jafama.FastMath; public class ElevationInterpolator { - private final WorldGenerator[][] gens; private final double[][] values = new double[18][18]; - private final int xOrigin; - private final int zOrigin; - private final BiomeProvider provider; - private final int smooth; - private final int pow; - private final World world; public ElevationInterpolator(World world, int chunkX, int chunkZ, BiomeProvider provider, int smooth) { - this.xOrigin = chunkX << 4; - this.zOrigin = chunkZ << 4; - this.provider = provider; - this.smooth = smooth; - this.pow = FastMath.log2(smooth); - this.gens = new WorldGenerator[6 + 2 * pow][6 + 2 * pow]; - this.world = world; + int xOrigin = chunkX << 4; + int zOrigin = chunkZ << 4; + WorldGenerator[][] gens = new WorldGenerator[18 + 2 * smooth][18 + 2 * smooth]; - for(int x = -pow; x < 6 + pow; x++) { - for(int z = -pow; z < 6 + pow; z++) { - gens[x + pow][z + pow] = (WorldGenerator) provider.getBiome(xOrigin + (x * smooth), zOrigin + (z * smooth)).getGenerator(world); + // Precompute generators. + for(int x = -1 - smooth; x <= 16 + smooth; x++) { + for(int z = -1 - smooth; z <= 16 + smooth; z++) { + gens[x + 1 + smooth][z + 1 + smooth] = (WorldGenerator) provider.getBiome(xOrigin + x, zOrigin + z).getGenerator(world); } } - for(byte x = -1; x <= 16; x++) { - for(byte z = -1; z <= 16; z++) { - WorldGenerator generator = getGenerator(x, z); - if(compareGens((x / smooth), (z / smooth), generator) && generator.interpolateElevation()) { - Interpolator interpolator = new Interpolator(biomeAvg(x / smooth, z / smooth), - biomeAvg((x / smooth) + 1, z / smooth), - biomeAvg(x / smooth, (z / smooth) + 1), - biomeAvg((x / smooth) + 1, (z / smooth) + 1)); - values[x + 1][z + 1] = interpolator.bilerp((double) (x % smooth) / smooth, (double) (z % smooth) / smooth); - } else values[x + 1][z + 1] = elevate(generator, xOrigin + x, zOrigin + z); + for(int x = -1; x <= 16; x++) { + for(int z = -1; z <= 16; z++) { + double noise = 0; + for(int xi = -smooth; xi <= smooth; xi++) { + for(int zi = -smooth; zi <= smooth; zi++) { + noise += gens[x + 1 + smooth + xi][z + 1 + smooth + zi].getElevation(xOrigin + x, zOrigin + z); + } + } + values[x + 1][z + 1] = noise / FastMath.pow2(smooth * 2 + 1); } } } - private WorldGenerator getGenerator(int x, int z) { - return (WorldGenerator) provider.getBiome(xOrigin + x, zOrigin + z).getGenerator(world); - } - - private WorldGenerator getStoredGen(int x, int z) { - return gens[x + pow][z + pow]; - } - - private boolean compareGens(int x, int z, WorldGenerator comp) { - 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; - } - } - return false; - } - - private double biomeAvg(int x, int z) { - return (elevate(getStoredGen(x + 1, z), (x * smooth) + smooth + xOrigin, (z * smooth) + zOrigin) - + elevate(getStoredGen(x - 1, z), (x * smooth) - smooth + xOrigin, (z * smooth) + zOrigin) - + elevate(getStoredGen(x, z + 1), (x * smooth) + xOrigin, (z * smooth) + smooth + zOrigin) - + elevate(getStoredGen(x, z - 1), (x * smooth) + xOrigin, (z * smooth) - smooth + zOrigin) - + elevate(getStoredGen(x, z), (x * smooth) + xOrigin, (z * smooth) + zOrigin) - + elevate(getStoredGen(x - 1, z - 1), (x * smooth) - smooth + xOrigin, (z * smooth) - smooth + zOrigin) - + elevate(getStoredGen(x - 1, z + 1), (x * smooth) - smooth + xOrigin, (z * smooth) + smooth + zOrigin) - + elevate(getStoredGen(x + 1, z - 1), (x * smooth) + smooth + xOrigin, (z * smooth) - smooth + zOrigin) - + elevate(getStoredGen(x + 1, z + 1), (x * smooth) + smooth + xOrigin, (z * smooth) + smooth + zOrigin)) / 9D; - } - - private double elevate(WorldGenerator g, int x, int z) { - return g.getElevation(x, z); - } - public double getElevation(int x, int z) { return values[x + 1][z + 1]; } diff --git a/platforms/bukkit/src/main/java/com/dfsek/terra/bukkit/generator/BukkitChunkGeneratorWrapper.java b/platforms/bukkit/src/main/java/com/dfsek/terra/bukkit/generator/BukkitChunkGeneratorWrapper.java index 673ad3ed2..909466ac4 100644 --- a/platforms/bukkit/src/main/java/com/dfsek/terra/bukkit/generator/BukkitChunkGeneratorWrapper.java +++ b/platforms/bukkit/src/main/java/com/dfsek/terra/bukkit/generator/BukkitChunkGeneratorWrapper.java @@ -10,7 +10,6 @@ import com.dfsek.terra.bukkit.world.BukkitAdapter; import com.dfsek.terra.bukkit.world.BukkitBiomeGrid; import com.dfsek.terra.config.lang.LangUtil; import com.dfsek.terra.debug.Debug; -import com.dfsek.terra.population.CavePopulator; import com.dfsek.terra.population.FloraPopulator; import com.dfsek.terra.population.OrePopulator; import com.dfsek.terra.population.StructurePopulator; @@ -90,7 +89,7 @@ public class BukkitChunkGeneratorWrapper extends ChunkGenerator implements Gener @Override public @NotNull List getDefaultPopulators(@NotNull World world) { - return Stream.of(new CavePopulator(main), new StructurePopulator(main), popMan).map(BukkitPopulatorWrapper::new).collect(Collectors.toList()); + return Stream.of(new StructurePopulator(main), popMan).map(BukkitPopulatorWrapper::new).collect(Collectors.toList()); } @Override