From 559a1b8d81aa2793655da2a402c9a56709432aa9 Mon Sep 17 00:00:00 2001 From: paulevsGitch Date: Mon, 28 Dec 2020 11:21:32 +0300 Subject: [PATCH] SDF islands --- .../common/NoiseChunkGeneratorMixin.java | 40 ++----- .../java/ru/betterend/noise/VoronoiNoise.java | 106 ++++++++++++------ .../world/generator/IslandLayer.java | 93 +++++++++++++++ .../world/generator/TerrainGenerator.java | 25 +++++ 4 files changed, 197 insertions(+), 67 deletions(-) create mode 100644 src/main/java/ru/betterend/world/generator/IslandLayer.java create mode 100644 src/main/java/ru/betterend/world/generator/TerrainGenerator.java diff --git a/src/main/java/ru/betterend/mixin/common/NoiseChunkGeneratorMixin.java b/src/main/java/ru/betterend/mixin/common/NoiseChunkGeneratorMixin.java index 2397aa91..15c45d0e 100644 --- a/src/main/java/ru/betterend/mixin/common/NoiseChunkGeneratorMixin.java +++ b/src/main/java/ru/betterend/mixin/common/NoiseChunkGeneratorMixin.java @@ -1,6 +1,5 @@ package ru.betterend.mixin.common; -import java.util.Arrays; import java.util.function.Supplier; import org.spongepowered.asm.mixin.Final; @@ -9,10 +8,11 @@ import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import net.minecraft.world.biome.source.BiomeSource; import net.minecraft.world.gen.chunk.ChunkGeneratorSettings; import net.minecraft.world.gen.chunk.NoiseChunkGenerator; +import ru.betterend.world.generator.TerrainGenerator; @Mixin(NoiseChunkGenerator.class) public abstract class NoiseChunkGeneratorMixin { @@ -20,41 +20,15 @@ public abstract class NoiseChunkGeneratorMixin { @Shadow protected Supplier settings; - @Final - @Shadow - private int noiseSizeY; - - /*@Inject(method = "sampleNoise", at = @At("HEAD"), cancellable = true) - private void beSampleEndNoise(int x, int y, int z, double horizontalScale, double verticalScale, double horizontalStretch, double verticalStretch, CallbackInfoReturnable info) { - if (settings.get().equals(ChunkGeneratorSettings.END)) { - double value = ((x + y + z) & 1) == 0 ? 1 : -1; - info.setReturnValue(value); - info.cancel(); - } - }*/ + @Inject(method = "(Lnet/minecraft/world/biome/source/BiomeSource;Lnet/minecraft/world/biome/source/BiomeSource;JLjava/util/function/Supplier;)V", at = @At("TAIL")) + private void beOnInit(BiomeSource populationSource, BiomeSource biomeSource, long seed, Supplier settings, CallbackInfo info) { + TerrainGenerator.initNoise(seed); + } @Inject(method = "sampleNoiseColumn([DII)V", at = @At("HEAD"), cancellable = true, allow = 2) private void beSampleNoiseColumn(double[] buffer, int x, int z, CallbackInfo info) { if (settings.get().equals(ChunkGeneratorSettings.END)) { - //System.out.println("Replace!"); - //Arrays.fill(buffer, -100); - //Arrays.fill(buffer, 0, buffer.length >> 1, 100); - //info.cancel(); - - float center = buffer.length * 0.5F; - /*float sin = (float) (Math.sin(x * 0.1) * Math.sin(z * 0.1)) * center * 0.5F; - int min = (int) (center - sin); - int max = (int) (center + sin); - if (max > min) { - Arrays.fill(buffer, min, max, 1); - }*/ - - float sin = (float) (Math.sin(x * 0.5) * Math.sin(z * 0.5)) * center * 0.5F; - for (int y = 0; y < buffer.length; y++) { - float value = (y - center); - buffer[y] = sin * 0.01F - Math.abs(value) * 0.01F; - } - + TerrainGenerator.fillTerrainDensity(buffer, x, z); info.cancel(); } } diff --git a/src/main/java/ru/betterend/noise/VoronoiNoise.java b/src/main/java/ru/betterend/noise/VoronoiNoise.java index 9a601f44..cddc7b4d 100644 --- a/src/main/java/ru/betterend/noise/VoronoiNoise.java +++ b/src/main/java/ru/betterend/noise/VoronoiNoise.java @@ -2,19 +2,19 @@ package ru.betterend.noise; import java.util.Random; -import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.BlockPos; import ru.betterend.util.MHelper; public class VoronoiNoise { private static final Random RANDOM = new Random(); final int seed; - final double scale; - final double separation; + + public VoronoiNoise() { + this(0); + } - public VoronoiNoise(int seed, double side, double separation) { + public VoronoiNoise(int seed) { this.seed = seed; - this.scale = 1.0 / side; - this.separation = MathHelper.clamp(separation, 0, 1); } private int getSeed(int x, int y, int z) { @@ -22,38 +22,76 @@ public class VoronoiNoise { h = (h ^ (h >> 13)) * 1274126177; return h ^ (h >> 16); } - - public double sample(float x, float y, float z) { - return sample(MHelper.floor(x), MHelper.floor(y), MHelper.floor(z)); - } - public double sample(int x, int y, int z) { - double posX = x * scale; - double posY = y * scale; - double posZ = z * scale; - int posXI = MHelper.floor(posX); - int posYI = MHelper.floor(posY); - int posZI = MHelper.floor(posZ); - double distance = Double.MAX_VALUE; - for (int px = -1; px < 2; px++) { - double pointX = posXI + px; - for (int py = -1; py < 2; py++) { - double pointY = posYI + py; - for (int pz = -1; pz < 2; pz++) { - double pointZ = posZI + pz; - RANDOM.setSeed(getSeed(posXI + px, posYI + py, posZI + pz)); - - double posXN = pointX + RANDOM.nextDouble() * separation; - double posYN = pointY + RANDOM.nextDouble() * separation; - double posZN = pointZ + RANDOM.nextDouble() * separation; - - double dist2 = MHelper.lengthSqr(posXN - posX, posYN - posY, posZN - posZ); - if (dist2 < distance) { - distance = dist2; + public double sample(double x, double y, double z) { + int ix = MHelper.floor(x); + int iy = MHelper.floor(y); + int iz = MHelper.floor(z); + + float px = (float) (x - ix); + float py = (float) (y - iy); + float pz = (float) (z - iz); + + float d = 10; + + for (int pox = -1; pox < 2; pox++) { + for (int poy = -1; poy < 2; poy++) { + for (int poz = -1; poz < 2; poz++) { + RANDOM.setSeed(getSeed(pox + ix, poy + iy, poz + iz)); + float pointX = pox + RANDOM.nextFloat(); + float pointY = poy + RANDOM.nextFloat(); + float pointZ = poz + RANDOM.nextFloat(); + float d2 = MHelper.lengthSqr(pointX - px, pointY - py, pointZ - pz); + if (d2 < d) { + d = d2; } } } } - return distance; + + return Math.sqrt(d); + } + + public BlockPos[] getPos(double x, double y, double z, double scale) { + int ix = MHelper.floor(x); + int iy = MHelper.floor(y); + int iz = MHelper.floor(z); + + float px = (float) (x - ix); + float py = (float) (y - iy); + float pz = (float) (z - iz); + + float d = 10; + float selX = 0; + float selY = 0; + float selZ = 0; + float selXPre = 0; + float selYPre = 0; + float selZPre = 0; + + for (int pox = -1; pox < 2; pox++) { + for (int poy = -1; poy < 2; poy++) { + for (int poz = -1; poz < 2; poz++) { + RANDOM.setSeed(getSeed(pox + ix, poy + iy, poz + iz)); + float pointX = pox + RANDOM.nextFloat(); + float pointY = poy + RANDOM.nextFloat(); + float pointZ = poz + RANDOM.nextFloat(); + float d2 = MHelper.lengthSqr(pointX - px, pointY - py, pointZ - pz); + if (d2 < d) { + d = d2; + selXPre = selX; + selYPre = selY; + selZPre = selZ; + selX = pointX; + selY = pointY; + selZ = pointZ; + } + } + } + } + + BlockPos p1 = new BlockPos((ix + (double) selX) * scale, (iy + (double) selY) * scale, (iz + (double) selZ) * scale); + BlockPos p2 = new BlockPos((ix + (double) selXPre) * scale, (iy + (double) selYPre) * scale, (iz + (double) selZPre) * scale); + return new BlockPos[] {p1, p2}; } } diff --git a/src/main/java/ru/betterend/world/generator/IslandLayer.java b/src/main/java/ru/betterend/world/generator/IslandLayer.java new file mode 100644 index 00000000..426c50ca --- /dev/null +++ b/src/main/java/ru/betterend/world/generator/IslandLayer.java @@ -0,0 +1,93 @@ +package ru.betterend.world.generator; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Random; + +import com.google.common.collect.Maps; + +import net.minecraft.util.math.BlockPos; +import ru.betterend.util.MHelper; +import ru.betterend.util.sdf.SDF; +import ru.betterend.util.sdf.primitive.SDFCapedCone; + +public class IslandLayer { + private static final List POSITIONS = new ArrayList(9); + private static final Random RANDOM = new Random(); + + private final Map islands = Maps.newHashMap(); + private final double distance; + private final int seed; + private final int minY; + private final int maxY; + + public IslandLayer(int seed, double distance, int minY, int maxY) { + this.distance = distance; + this.seed = seed; + this.minY = minY; + this.maxY = maxY; + } + + private int getSeed(int x, int y, int z) { + int h = seed + x * 374761393 + y * 668265263 + z; + h = (h ^ (h >> 13)) * 1274126177; + return h ^ (h >> 16); + } + + private void updatePositions(double x, double y, double z) { + POSITIONS.clear(); + + int ix = MHelper.floor(x / distance); + int iy = MHelper.floor(y / distance); + int iz = MHelper.floor(z / distance); + + for (int pox = -1; pox < 2; pox++) { + int px = pox + ix; + for (int poy = -1; poy < 2; poy++) { + int py = poy + iy; + for (int poz = -1; poz < 2; poz++) { + int pz = poz + iz; + RANDOM.setSeed(getSeed(px, py, pz)); + double posX = (px + RANDOM.nextFloat()) * distance; + double posY = (py + RANDOM.nextFloat()) * distance; + double posZ = (pz + RANDOM.nextFloat()) * distance; + POSITIONS.add(new BlockPos(posX, posY, posZ)); + } + } + } + } + + private SDF getIsland(BlockPos pos) { + SDF island = islands.get(pos); + if (island == null) { + island = new SDFCapedCone().setHeight(10).setRadius1(0).setRadius2(30); + islands.put(pos, island); + } + return island; + } + + private float getRelativeDistance(SDF sdf, BlockPos center, double px, double py, double pz) { + float x = (float) (px - center.getX()); + float y = (float) (py - center.getY()); + float z = (float) (pz - center.getZ()); + return sdf.getDistance(x, y, z); + } + + private float calculateSDF(double x, double y, double z) { + float distance = 10; + for (BlockPos pos: POSITIONS) { + if (pos.getY() > minY && pos.getY() < maxY) { + SDF island = getIsland(pos); + float dist = getRelativeDistance(island, pos, x, y, z); + distance = MHelper.min(distance, dist); + } + } + return distance; + } + + public float getDensity(double x, double y, double z) { + updatePositions(x, y, z); + return -calculateSDF(x, y, z); + } +} diff --git a/src/main/java/ru/betterend/world/generator/TerrainGenerator.java b/src/main/java/ru/betterend/world/generator/TerrainGenerator.java new file mode 100644 index 00000000..d5553a45 --- /dev/null +++ b/src/main/java/ru/betterend/world/generator/TerrainGenerator.java @@ -0,0 +1,25 @@ +package ru.betterend.world.generator; + +import java.util.Random; + +public class TerrainGenerator { + private static final double SCALE_XZ = 8.0; + private static final double SCALE_Y = 4.0; + + private static IslandLayer layer; + + public static void initNoise(long seed) { + Random random = new Random(seed); + layer = new IslandLayer(random.nextInt(), 100, 40, 90); + } + + public static void fillTerrainDensity(double[] buffer, int x, int z) { + double px = (double) x * SCALE_XZ; + double pz = (double) z * SCALE_XZ; + for (int y = 0; y < buffer.length; y++) { + double py = (double) y * SCALE_Y; + float dist = layer.getDensity(px, py, pz); + buffer[y] = dist; + } + } +}