improve elevation interp (TEMP DISABLE CARVING)

This commit is contained in:
dfsek 2021-01-14 18:39:14 -07:00
parent cbc2885c16
commit c1fdfa94f1
7 changed files with 65 additions and 94 deletions

View File

@ -2515,7 +2515,8 @@ public class FastNoiseLite implements NoiseSampler {
Perlin, Perlin,
ValueCubic, ValueCubic,
Value, Value,
WhiteNoise WhiteNoise,
Constant
} }

View File

@ -1,25 +1,31 @@
package com.dfsek.terra.biome; package com.dfsek.terra.biome;
import com.dfsek.tectonic.exception.ConfigException; 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.math.vector.Vector2;
import com.dfsek.terra.api.platform.TerraPlugin; import com.dfsek.terra.api.platform.TerraPlugin;
import com.dfsek.terra.api.world.biome.TerraBiome; import com.dfsek.terra.api.world.biome.TerraBiome;
import com.dfsek.terra.biome.pipeline.BiomeHolder; import com.dfsek.terra.biome.pipeline.BiomeHolder;
import com.dfsek.terra.biome.pipeline.BiomePipeline; 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.CacheBuilder;
import com.google.common.cache.CacheLoader; import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache; import com.google.common.cache.LoadingCache;
import net.jafama.FastMath; import net.jafama.FastMath;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.concurrent.ExecutionException;
public class StandardBiomeProvider implements BiomeProvider { public class StandardBiomeProvider implements BiomeProvider {
private final LoadingCache<Vector2, BiomeHolder> holderCache; private final LoadingCache<Vector2, BiomeHolder> holderCache;
private final LoadingCache<Vector2, TerraBiome> biomeCache; private final BiomePipeline pipeline;
private int resolution = 1; 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() holderCache = CacheBuilder.newBuilder()
.maximumSize(main == null ? 32 : main.getTerraConfig().getProviderCache()) .maximumSize(main == null ? 32 : main.getTerraConfig().getProviderCache())
.build( .build(
@ -30,27 +36,16 @@ public class StandardBiomeProvider implements BiomeProvider {
} }
} }
); );
biomeCache = CacheBuilder.newBuilder() this.pipeline = pipeline;
.maximumSize(main == null ? 512 : main.getTerraConfig().getBiomeCache())
.build(
new CacheLoader<Vector2, TerraBiome>() {
@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());
}
}
);
} }
@Override @Override
public TerraBiome getBiome(int x, int z) { 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() { public int getResolution() {
@ -68,16 +63,33 @@ public class StandardBiomeProvider implements BiomeProvider {
public static final class StandardBiomeProviderBuilder implements BiomeProviderBuilder { public static final class StandardBiomeProviderBuilder implements BiomeProviderBuilder {
private final ExceptionalFunction<Long, BiomePipeline> pipelineBuilder; private final ExceptionalFunction<Long, BiomePipeline> pipelineBuilder;
private final TerraPlugin main; private final TerraPlugin main;
private int resolution = 1;
private int noiseAmp = 2;
private NoiseBuilder builder = new NoiseBuilder();
public StandardBiomeProviderBuilder(ExceptionalFunction<Long, BiomePipeline> pipelineBuilder, TerraPlugin main) { public StandardBiomeProviderBuilder(ExceptionalFunction<Long, BiomePipeline> pipelineBuilder, TerraPlugin main) {
this.pipelineBuilder = pipelineBuilder; this.pipelineBuilder = pipelineBuilder;
this.main = main; 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 @Override
public StandardBiomeProvider build(long seed) { public StandardBiomeProvider build(long seed) {
try { 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) { } catch(ConfigException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }

View File

@ -182,10 +182,7 @@ public class ConfigPackTemplate implements ValidatedConfigTemplate {
@Override @Override
public boolean validate() throws ValidationException { public boolean validate() throws ValidationException {
if(!MathUtil.equals(FastMath.log(baseBlend) / FastMath.log(2d), FastMath.round(FastMath.log(baseBlend) / FastMath.log(2d)))) { 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."); throw new ValidationException("Biome 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.");
} }
return true; return true;
} }

View File

@ -36,10 +36,10 @@ public class BiomeProviderBuilderLoader implements TypeLoader<BiomeProvider.Biom
} }
@Override @Override
public BiomeProvider.BiomeProviderBuilder load(Type t, Object c, ConfigLoader loader) { public BiomeProvider.BiomeProviderBuilder load(Type t, Object c, ConfigLoader loader) throws LoadException {
Map<String, Object> map = (Map<String, Object>) c; Map<String, Object> map = (Map<String, Object>) c;
return new StandardBiomeProvider.StandardBiomeProviderBuilder(seed -> { StandardBiomeProvider.StandardBiomeProviderBuilder builder = new StandardBiomeProvider.StandardBiomeProviderBuilder(seed -> {
Map<String, Object> source = (Map<String, Object>) map.get("source"); Map<String, Object> source = (Map<String, Object>) map.get("source");
ProbabilityCollection<TerraBiome> sourceBiomes = (ProbabilityCollection<TerraBiome>) loader.loadType(Types.TERRA_BIOME_PROBABILITY_COLLECTION_TYPE, source.get("biomes")); ProbabilityCollection<TerraBiome> sourceBiomes = (ProbabilityCollection<TerraBiome>) 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)); NoiseSampler sourceNoise = new NoiseBuilderLoader().load(NoiseBuilder.class, source.get("noise"), loader).build(FastMath.toInt(seed));
@ -76,5 +76,13 @@ public class BiomeProviderBuilderLoader implements TypeLoader<BiomeProvider.Biom
Debug.info("Biome Pipeline scale factor: " + pipeline.getSize()); Debug.info("Biome Pipeline scale factor: " + pipeline.getSize());
return pipeline; return pipeline;
}, main); }, main);
if(map.containsKey("resolution")) builder.setResolution(Integer.parseInt(map.get("resolution").toString()));
if(map.containsKey("blend")) {
Map<String, Object> blend = (Map<String, Object>) 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;
} }
} }

View File

@ -35,7 +35,6 @@ public class SamplerCache {
} }
private class Container { private class Container {
private final World world;
private final TerraWorld terraWorld; private final TerraWorld terraWorld;
private final LoadingCache<Long, Sampler> cache; private final LoadingCache<Long, Sampler> cache;
@ -46,10 +45,9 @@ public class SamplerCache {
public Sampler load(@NotNull Long key) { public Sampler load(@NotNull Long key) {
int cx = (int) (key >> 32); int cx = (int) (key >> 32);
int cz = (int) key.longValue(); 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); terraWorld = main.getWorld(world);
} }

View File

@ -6,76 +6,32 @@ import com.dfsek.terra.generation.config.WorldGenerator;
import net.jafama.FastMath; import net.jafama.FastMath;
public class ElevationInterpolator { public class ElevationInterpolator {
private final WorldGenerator[][] gens;
private final double[][] values = new double[18][18]; 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) { public ElevationInterpolator(World world, int chunkX, int chunkZ, BiomeProvider provider, int smooth) {
this.xOrigin = chunkX << 4; int xOrigin = chunkX << 4;
this.zOrigin = chunkZ << 4; int 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;
WorldGenerator[][] gens = new WorldGenerator[18 + 2 * smooth][18 + 2 * smooth];
for(int x = -pow; x < 6 + pow; x++) { // Precompute generators.
for(int z = -pow; z < 6 + pow; z++) { for(int x = -1 - smooth; x <= 16 + smooth; x++) {
gens[x + pow][z + pow] = (WorldGenerator) provider.getBiome(xOrigin + (x * smooth), zOrigin + (z * smooth)).getGenerator(world); 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(int x = -1; x <= 16; x++) {
for(byte z = -1; z <= 16; z++) { for(int z = -1; z <= 16; z++) {
WorldGenerator generator = getGenerator(x, z); double noise = 0;
if(compareGens((x / smooth), (z / smooth), generator) && generator.interpolateElevation()) { for(int xi = -smooth; xi <= smooth; xi++) {
Interpolator interpolator = new Interpolator(biomeAvg(x / smooth, z / smooth), for(int zi = -smooth; zi <= smooth; zi++) {
biomeAvg((x / smooth) + 1, z / smooth), noise += gens[x + 1 + smooth + xi][z + 1 + smooth + zi].getElevation(xOrigin + x, zOrigin + z);
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);
} }
} }
} 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) { public double getElevation(int x, int z) {

View File

@ -10,7 +10,6 @@ import com.dfsek.terra.bukkit.world.BukkitAdapter;
import com.dfsek.terra.bukkit.world.BukkitBiomeGrid; import com.dfsek.terra.bukkit.world.BukkitBiomeGrid;
import com.dfsek.terra.config.lang.LangUtil; import com.dfsek.terra.config.lang.LangUtil;
import com.dfsek.terra.debug.Debug; import com.dfsek.terra.debug.Debug;
import com.dfsek.terra.population.CavePopulator;
import com.dfsek.terra.population.FloraPopulator; import com.dfsek.terra.population.FloraPopulator;
import com.dfsek.terra.population.OrePopulator; import com.dfsek.terra.population.OrePopulator;
import com.dfsek.terra.population.StructurePopulator; import com.dfsek.terra.population.StructurePopulator;
@ -90,7 +89,7 @@ public class BukkitChunkGeneratorWrapper extends ChunkGenerator implements Gener
@Override @Override
public @NotNull List<BlockPopulator> getDefaultPopulators(@NotNull World world) { public @NotNull List<BlockPopulator> 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 @Override