From 86336eea011fc289a7b81574d6fc97a66b9412e7 Mon Sep 17 00:00:00 2001 From: dfsek Date: Sat, 4 Dec 2021 23:29:38 -0700 Subject: [PATCH] create lazily evaluated carver --- .../generation/NoiseChunkGenerator3D.java | 36 +++--- .../LazilyEvaluatedInterpolator.java | 106 ++++++++++++++++++ 2 files changed, 124 insertions(+), 18 deletions(-) create mode 100644 common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/generation/math/interpolation/LazilyEvaluatedInterpolator.java diff --git a/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/generation/NoiseChunkGenerator3D.java b/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/generation/NoiseChunkGenerator3D.java index 415efbe35..fe5a81e62 100644 --- a/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/generation/NoiseChunkGenerator3D.java +++ b/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/generation/NoiseChunkGenerator3D.java @@ -8,19 +8,18 @@ package com.dfsek.terra.addons.chunkgenerator.generation; -import com.dfsek.terra.addons.chunkgenerator.config.noise.BiomeNoiseProperties; - -import com.dfsek.terra.addons.chunkgenerator.generation.math.samplers.Sampler3D; - import net.jafama.FastMath; import org.jetbrains.annotations.NotNull; import java.util.ArrayList; import java.util.List; -import com.dfsek.terra.addons.chunkgenerator.generation.math.PaletteUtil; -import com.dfsek.terra.addons.chunkgenerator.generation.math.samplers.SamplerProvider; +import com.dfsek.terra.addons.chunkgenerator.config.noise.BiomeNoiseProperties; import com.dfsek.terra.addons.chunkgenerator.config.palette.PaletteInfo; +import com.dfsek.terra.addons.chunkgenerator.generation.math.PaletteUtil; +import com.dfsek.terra.addons.chunkgenerator.generation.math.interpolation.LazilyEvaluatedInterpolator; +import com.dfsek.terra.addons.chunkgenerator.generation.math.samplers.Sampler3D; +import com.dfsek.terra.addons.chunkgenerator.generation.math.samplers.SamplerProvider; import com.dfsek.terra.api.Platform; import com.dfsek.terra.api.block.state.BlockState; import com.dfsek.terra.api.config.ConfigPack; @@ -57,38 +56,39 @@ public class NoiseChunkGenerator3D implements ChunkGenerator { int chunkX) { try(ProfileFrame ignore = platform.getProfiler().profile("chunk_base_3d")) { BiomeProvider grid = world.getBiomeProvider(); - + int xOrig = (chunkX << 4); int zOrig = (chunkZ << 4); - + Sampler3D sampler = samplerCache.getChunk(chunkX, chunkZ, world); - + long seed = world.getSeed(); - + + LazilyEvaluatedInterpolator carver = new LazilyEvaluatedInterpolator(world.getBiomeProvider(), chunkX, chunkZ, + world.getMaxHeight(), world.getMinHeight(), 2, 4, seed); for(int x = 0; x < 16; x++) { for(int z = 0; z < 16; z++) { int paletteLevel = 0; - + int cx = xOrig + x; int cz = zOrig + z; - + Biome biome = grid.getBiome(cx, cz, seed); - BiomeNoiseProperties properties = biome.getContext().get(BiomeNoiseProperties.class); - + PaletteInfo paletteInfo = biome.getContext().get(PaletteInfo.class); - + int sea = paletteInfo.seaLevel(); Palette seaPalette = paletteInfo.ocean(); - + BlockState data; for(int y = world.getMaxHeight() - 1; y >= world.getMinHeight(); y--) { if(sampler.sample(x, y, z) > 0) { - if(properties.carving().noise(seed, cx, y, cz) <= 0) { + if(carver.sample(x, y, z) <= 0) { data = PaletteUtil.getPalette(x, y, z, sampler, paletteInfo).get(paletteLevel, cx, y, cz, seed); chunk.setBlock(x, y, z, data); } - + paletteLevel++; } else if(y <= sea) { chunk.setBlock(x, y, z, seaPalette.get(sea - y, x + xOrig, y, z + zOrig, seed)); diff --git a/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/generation/math/interpolation/LazilyEvaluatedInterpolator.java b/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/generation/math/interpolation/LazilyEvaluatedInterpolator.java new file mode 100644 index 000000000..0247fb43f --- /dev/null +++ b/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/generation/math/interpolation/LazilyEvaluatedInterpolator.java @@ -0,0 +1,106 @@ +package com.dfsek.terra.addons.chunkgenerator.generation.math.interpolation; + +import com.dfsek.terra.addons.chunkgenerator.config.noise.BiomeNoiseProperties; +import com.dfsek.terra.api.noise.NoiseSampler; + +import com.dfsek.terra.api.world.biome.generation.BiomeProvider; + +import net.jafama.FastMath; + +import static com.dfsek.terra.addons.chunkgenerator.generation.math.interpolation.Interpolator.lerp; + + +public class LazilyEvaluatedInterpolator { + private final Double[][][] samples; + + private final NoiseSampler[][] samplers; + + private final int chunkX; + private final int chunkZ; + + private final int horizontalRes; + private final int verticalRes; + + private final BiomeProvider biomeProvider; + + private final long seed; + private final int min; + + public LazilyEvaluatedInterpolator(BiomeProvider biomeProvider, int cx, int cz, int max, int min, int horizontalRes, int verticalRes, long seed) { + int hSamples = FastMath.ceilToInt(16.0/horizontalRes); + int vSamples = FastMath.ceilToInt((double) (max-min) / verticalRes); + samples = new Double[hSamples + 1][vSamples][hSamples + 1]; + samplers = new NoiseSampler[hSamples + 1][hSamples + 1]; + this.chunkX = cx << 4; + this.chunkZ = cz << 4; + this.horizontalRes = horizontalRes; + this.verticalRes = verticalRes; + this.biomeProvider = biomeProvider; + this.seed = seed; + this.min = min; + } + + private double sample(int x, int y, int z, int ox, int oy, int oz) { + Double sample = samples[x][y][z]; + if(sample == null) { + int xi = ox+chunkX; + int zi = oz+chunkZ; + + NoiseSampler sampler = samplers[x][z]; + if(sampler == null) { + sampler = biomeProvider.getBiome(xi, zi, seed).getContext().get(BiomeNoiseProperties.class).carving(); + samplers[x][z] = sampler; + } + + sample = sampler.noise(seed, xi, oy, zi); + samples[x][y][z] = sample; + } + return sample; + } + + public double sample(int x, int y, int z) { + int xIndex = x / horizontalRes; + int yIndex = (y - min) / verticalRes; + int zIndex = z / horizontalRes; + + double sample_0_0_0 = sample(xIndex, yIndex, zIndex, x, y, z); + + boolean yRange = y % verticalRes == 0; + if(x % horizontalRes == 0 && yRange && z % horizontalRes == 0) { // we're at the sampling point + return sample_0_0_0; + } + + double sample_0_0_1 = sample(xIndex, yIndex, zIndex + 1, x, y, z + horizontalRes); + + double sample_1_0_0 = sample(xIndex + 1, yIndex, zIndex, x + horizontalRes, y, z); + double sample_1_0_1 = sample(xIndex + 1, yIndex, zIndex + 1, x + horizontalRes, y, z + horizontalRes); + + double xFrac = (double) (x % horizontalRes) / horizontalRes; + double zFrac = (double) (z % horizontalRes) / horizontalRes; + double lerp_bottom_0 = lerp(zFrac, sample_0_0_0, sample_0_0_1); + double lerp_bottom_1 = lerp(zFrac, sample_1_0_0, sample_1_0_1); + + double lerp_bottom = lerp(xFrac, lerp_bottom_0, lerp_bottom_1); + + if(yRange) { // we can do bilerp + return lerp_bottom; + } + + double yFrac = (double) FastMath.floorMod(y, verticalRes) / verticalRes; + + + double sample_0_1_0 = sample(xIndex, yIndex + 1, zIndex, x, y + verticalRes, z); + double sample_0_1_1 = sample(xIndex, yIndex + 1, zIndex + 1, x, y + verticalRes, z + horizontalRes); + + + double sample_1_1_0 = sample(xIndex + 1, yIndex + 1, zIndex, x + horizontalRes, y + verticalRes, z); + double sample_1_1_1 = sample(xIndex + 1, yIndex + 1, zIndex + 1, x + horizontalRes, y + verticalRes, z + horizontalRes); + + double lerp_top_0 = lerp(zFrac, sample_0_1_0, sample_0_1_1); + double lerp_top_1 = lerp(zFrac, sample_1_1_0, sample_1_1_1); + + double lerp_top = lerp(xFrac, lerp_top_0, lerp_top_1); + + return lerp(yFrac, lerp_bottom, lerp_top); + } +}