Terrain 3D Carving (noise) for overhangs & cliffs. Also performance stuf

This commit is contained in:
Daniel Mills 2020-01-13 02:10:11 -05:00
parent 9aac129aad
commit a3eb0bb9fc
13 changed files with 468 additions and 86 deletions

View File

@ -9,8 +9,8 @@ public class Settings
public static class PerformanceSettings
{
public PerformanceMode performanceMode = PerformanceMode.DOUBLE_CPU;
public boolean decoratePhysics = false;
public PerformanceMode performanceMode = PerformanceMode.HALF_CPU;
public boolean fastDecoration = true;
public int threadPriority = Thread.MIN_PRIORITY;
public int compilerPriority = Thread.MIN_PRIORITY;
public int threadCount = 1;
@ -24,9 +24,10 @@ public class Settings
{
public double horizontalZoom = 1; // 0.525
public double heightFracture = 155;
public double beachScale = 76;
public double landScale = 0.325;
public double landChance = 0.67;
public double roughness = 1.333;
public double landChance = 0.62;
public double roughness = 1;
public double heightMultiplier = 0.806;
public double heightExponentBase = 1;
public double heightExponentMultiplier = 1.41;
@ -39,5 +40,8 @@ public class Settings
public double biomeScale = 2;
public boolean flatBedrock = false;
public boolean genObjects = true;
public int minCarvingHeight = 75;
public int maxCarvingHeight = 175;
public double carvingChance = 0.6;
}
}

View File

@ -14,9 +14,11 @@ import ninja.bytecode.iris.generator.genobject.GenObjectDecorator;
import ninja.bytecode.iris.generator.genobject.GenObjectGroup;
import ninja.bytecode.iris.generator.layer.GenLayerBase;
import ninja.bytecode.iris.generator.layer.GenLayerBiome;
import ninja.bytecode.iris.generator.layer.GenLayerCarving;
import ninja.bytecode.iris.generator.layer.GenLayerCaves;
import ninja.bytecode.iris.generator.layer.GenLayerLayeredNoise;
import ninja.bytecode.iris.generator.layer.GenLayerRidge;
import ninja.bytecode.iris.generator.layer.GenLayerSnow;
import ninja.bytecode.iris.pack.IrisBiome;
import ninja.bytecode.iris.pack.IrisDimension;
import ninja.bytecode.iris.util.AtomicChunkData;
@ -59,6 +61,8 @@ public class IrisGenerator extends ParallelChunkGenerator
private GenLayerRidge glRidge;
private GenLayerBiome glBiome;
private GenLayerCaves glCaves;
private GenLayerCarving glCarving;
private GenLayerSnow glSnow;
private RNG rTerrain;
private IrisDimension dim;
private World world;
@ -110,6 +114,8 @@ public class IrisGenerator extends ParallelChunkGenerator
glRidge = new GenLayerRidge(this, world, random, rTerrain.nextParallelRNG(3));
glBiome = new GenLayerBiome(this, world, random, rTerrain.nextParallelRNG(4), dim.getBiomes());
glCaves = new GenLayerCaves(this, world, random, rTerrain.nextParallelRNG(-1));
glCarving = new GenLayerCarving(this, world, random, rTerrain.nextParallelRNG(-2));
glSnow = new GenLayerSnow(this, world, random, rTerrain.nextParallelRNG(5));
}
@Override
@ -145,7 +151,7 @@ public class IrisGenerator extends ParallelChunkGenerator
int max = Math.max(height, seaLevel);
IrisBiome override = null;
if(height > 61 && height < 65 + (glLNoise.getHeight(wz, wx) * 24D))
if(height > 61 && height < 65 + (glLNoise.getHeight(wz, wx) * Iris.settings.gen.beachScale))
{
override = biome("Beach");
}
@ -187,6 +193,31 @@ public class IrisGenerator extends ParallelChunkGenerator
if(i == height - 1)
{
mb = biome.getSurface(wx, wz, rTerrain);
if(biome.getSnow() > 0)
{
double level = glSnow.getHeight(wx, wz) * biome.getSnow();
int blocks = (int) level;
level -= blocks;
int layers = (int) (level * 7D);
int snowHeight = blocks + (layers > 0 ? 1 : 0);
for(int j = 0; j < snowHeight; j++)
{
if(j == snowHeight - 1)
{
setBlock(x, i + j + 1, z, Material.SNOW, (byte) layers);
}
else
{
setBlock(x, i + j + 1, z, Material.SNOW_BLOCK);
}
}
}
else
{
MB mbx = biome.getScatterChanceSingle();
if(!mbx.material.equals(Material.AIR))
@ -195,6 +226,7 @@ public class IrisGenerator extends ParallelChunkGenerator
highest = i > highest ? i : highest;
}
}
}
if(i == 0)
{
@ -211,6 +243,7 @@ public class IrisGenerator extends ParallelChunkGenerator
}
glCaves.genCaves(wxx, wzx, x, z, height, this);
glCarving.genCarves(wxx, wzx, x, z, height, this, biome);
plan.setRealHeight(x, z, highest);
return biome.getRealBiome();
}
@ -247,7 +280,9 @@ public class IrisGenerator extends ParallelChunkGenerator
private double getBiomedHeight(int x, int z, ChunkPlan plan)
{
return plan.getHeight(x, z, () ->
double xh = plan.getHeight(x, z);
if(xh == -1)
{
int wx = (int) Math.round((double) x * Iris.settings.gen.horizontalZoom);
int wz = (int) Math.round((double) z * Iris.settings.gen.horizontalZoom);
@ -255,8 +290,11 @@ public class IrisGenerator extends ParallelChunkGenerator
double h = Iris.settings.gen.baseHeight + biome.getHeight();
h += (glBase.getHeight(wx, wz) * 0.5) - (0.33 * 0.5);
plan.setHeight(x, z, h);
return h;
});
}
return xh;
}
public World getWorld()
@ -273,4 +311,14 @@ public class IrisGenerator extends ParallelChunkGenerator
{
this.schematicCache = schematicCache;
}
public RNG getRTerrain()
{
return rTerrain;
}
public GenLayerBase getGlBase()
{
return glBase;
}
}

View File

@ -14,6 +14,7 @@ import org.bukkit.Material;
import org.bukkit.util.BlockVector;
import org.bukkit.util.Vector;
import mortar.compute.math.M;
import ninja.bytecode.iris.Iris;
import ninja.bytecode.iris.generator.placer.NMSPlacer;
import ninja.bytecode.iris.util.Direction;
@ -24,6 +25,7 @@ import ninja.bytecode.shuriken.collections.GList;
import ninja.bytecode.shuriken.collections.GMap;
import ninja.bytecode.shuriken.io.CustomOutputStream;
import ninja.bytecode.shuriken.logging.L;
import ninja.bytecode.shuriken.math.RNG;
public class GenObject
{
@ -49,7 +51,7 @@ public class GenObject
centeredHeight = false;
}
public void computeMountShift()
public void recalculateMountShift()
{
int ly = Integer.MAX_VALUE;
@ -259,7 +261,7 @@ public class GenObject
if(mount == null)
{
computeMountShift();
recalculateMountShift();
}
start.subtract(mount);
@ -337,6 +339,11 @@ public class GenObject
return name;
}
public void setName(String name)
{
this.name = name;
}
public void rotate(Direction from, Direction to)
{
GMap<BlockVector, MB> g = s.copy();
@ -386,4 +393,85 @@ public class GenObject
L.ex(e);
}
}
public void applySnowFilter(int factor)
{
int minX = 0;
int maxX = 0;
int minY = 0;
int maxY = 0;
int minZ = 0;
int maxZ = 0;
boolean added = false;
for(BlockVector i : getSchematic().k())
{
if(i.getBlockX() > maxX)
{
maxX = i.getBlockX();
}
if(i.getBlockY() > maxY)
{
maxY = i.getBlockY();
}
if(i.getBlockZ() > maxZ)
{
maxZ = i.getBlockZ();
}
if(i.getBlockX() < minX)
{
minX = i.getBlockX();
}
if(i.getBlockY() < minY)
{
minY = i.getBlockY();
}
if(i.getBlockZ() < minZ)
{
minZ = i.getBlockZ();
}
}
for(int i = minX; i <= maxX; i++)
{
for(int j = minZ; j <= maxZ; j++)
{
BlockVector highest = null;
for(BlockVector k : getSchematic().k())
{
if(k.getBlockX() == i && k.getBlockZ() == j)
{
if(highest == null)
{
highest = k;
}
else if(highest.getBlockY() < k.getBlockY())
{
highest = k;
}
}
}
if(highest != null)
{
BlockVector mbv = highest.clone().add(new Vector(0, 1, 0)).toBlockVector();
added = true;
getSchematic().put(mbv, MB.of(Material.SNOW, RNG.r.nextInt((int) M.clip(factor, 0, 8))));
}
}
}
if(added)
{
h++;
recalculateMountShift();
}
}
}

View File

@ -15,6 +15,7 @@ import ninja.bytecode.iris.Iris;
import ninja.bytecode.iris.controller.PackController;
import ninja.bytecode.iris.controller.TimingsController;
import ninja.bytecode.iris.generator.IrisGenerator;
import ninja.bytecode.iris.generator.placer.BukkitPlacer;
import ninja.bytecode.iris.generator.placer.NMSPlacer;
import ninja.bytecode.iris.pack.IrisBiome;
import ninja.bytecode.iris.util.IPlacer;
@ -26,16 +27,17 @@ import ninja.bytecode.shuriken.math.M;
public class GenObjectDecorator extends BlockPopulator
{
private GMap<String, GenObjectGroup> snowCache;
private GMap<Biome, IrisBiome> biomeMap;
private GMap<Biome, GMap<GenObjectGroup, Double>> populationCache;
private IPlacer cascadingPlacer;
private IPlacer placer;
private ChronoLatch cl = new ChronoLatch(1000);
private ChronoLatch cl = new ChronoLatch(250);
public GenObjectDecorator(IrisGenerator generator)
{
biomeMap = new GMap<>();
populationCache = new GMap<>();
snowCache = new GMap<>();
for(IrisBiome i : generator.getLoadedBiomes())
{
@ -48,6 +50,21 @@ public class GenObjectDecorator extends BlockPopulator
try
{
GenObjectGroup g = Iris.getController(PackController.class).getGenObjectGroups().get(j);
if(i.isSnowy())
{
String v = g.getName() + "-" + i.getSnow();
if(!snowCache.containsKey(v))
{
GenObjectGroup gog = g.copy("-snowy-" + i.getSnow());
gog.applySnowFilter((int) (i.getSnow() * 4));
snowCache.put(v, gog);
}
g = snowCache.get(v);
}
gc.put(g, i.getSchematicGroups().get(j));
}
@ -67,6 +84,8 @@ public class GenObjectDecorator extends BlockPopulator
@Override
public void populate(World world, Random rnotusingyou, Chunk source)
{
try
{
Random random = new Random(((source.getX() - 32) * (source.getZ() + 54)) + world.getSeed());
Iris.getController(TimingsController.class).started("decor");
@ -104,6 +123,12 @@ public class GenObjectDecorator extends BlockPopulator
Iris.getController(TimingsController.class).stopped("decor");
}
catch(Throwable e)
{
}
}
private void populate(World world, Random random, Chunk source, Biome biome, IrisBiome ibiome, GMap<GenObjectGroup, Double> objects)
{
for(GenObjectGroup i : objects.k())
@ -120,12 +145,20 @@ public class GenObjectDecorator extends BlockPopulator
continue;
}
if(cascadingPlacer == null)
if(placer == null)
{
cascadingPlacer = new NMSPlacer(world);
if(Iris.settings.performance.fastDecoration)
{
placer = new NMSPlacer(world);
}
i.getSchematics().get(random.nextInt(i.getSchematics().size())).place(x, b.getY(), z, cascadingPlacer);
else
{
placer = new BukkitPlacer(world, false);
}
}
i.getSchematics().get(random.nextInt(i.getSchematics().size())).place(x, b.getY(), z, placer);
}
}

View File

@ -32,6 +32,33 @@ public class GenObjectGroup
this.noCascade = false;
}
public void applySnowFilter(int factor)
{
L.i(ChatColor.AQUA + "Applying Snow Filter to " + ChatColor.WHITE + getName());
for(GenObject i : schematics)
{
i.applySnowFilter(factor);
}
}
public GenObjectGroup copy(String suffix)
{
GenObjectGroup gog = new GenObjectGroup(name + suffix);
gog.schematics = new GList<>();
gog.flags = flags.copy();
gog.priority = priority;
gog.noCascade = noCascade;
for(GenObject i : schematics)
{
GenObject g = i.copy();
g.setName(i.getName() + suffix);
gog.schematics.add(g);
}
return gog;
}
public String getName()
{
return name;
@ -135,7 +162,8 @@ public class GenObjectGroup
{
GenObject cp = i.copy();
gg.queue(() -> {
gg.queue(() ->
{
GenObject f = cp;
f.rotate(Direction.N, j);
rr.lock();
@ -151,8 +179,9 @@ public class GenObjectGroup
for(GenObject i : getSchematics())
{
gg.queue(() -> {
i.computeMountShift();
gg.queue(() ->
{
i.recalculateMountShift();
for(String j : flags)
{

View File

@ -29,7 +29,7 @@ public class GenLayerBase extends GenLayer
.scale(10);
hfracture = new CNG(rng.nextParallelRNG(6), 1, 2)
.scale(0.0124);
gen = new CNG(rng.nextParallelRNG(7), 0.19D, 8)
gen = new CNG(rng.nextParallelRNG(7), 0.19D, 7)
.scale(0.012)
.amp(0.5)
.freq(1.1)

View File

@ -25,7 +25,6 @@ public class GenLayerBiome extends GenLayer
private MaxingGenerator roads;
private Function<CNG, CNG> factory;
private CNG pathCheck;
private CNG riverCheck;
private CNG fracture;
private CNG island;
@ -36,7 +35,6 @@ public class GenLayerBiome extends GenLayer
island = new CNG(rng.nextParallelRNG(10334), 1D, 3).scale(0.003 * Iris.settings.gen.landScale).fractureWith(new CNG(rng.nextParallelRNG(34), 1D, 12).scale(0.6), 180);
fracture = new CNG(rng.nextParallelRNG(28), 1D, 24).scale(0.0021).fractureWith(new CNG(rng.nextParallelRNG(34), 1D, 12).scale(0.01), 12250);
factory = (g) -> g.fractureWith(new CNG(rng.nextParallelRNG(29), 1D, 4).scale(0.02), 56);
riverCheck = new CNG(rng.nextParallelRNG(30), 1D, 2).scale(0.00096);
pathCheck = new CNG(rng.nextParallelRNG(31), 1D, 1).scale(0.00096);
roads = new MaxingGenerator(rng.nextParallelRNG(32), 5, 0.00055, 8, factory);
//@done
@ -83,14 +81,6 @@ public class GenLayerBiome extends GenLayer
else if(land > landChance + 0.0175)
{
if(riverCheck.noise(x, z) > 0.75)
{
if(getRegionGenerator(x, z).hasBorder(3, 3 + Math.pow(riverCheck.noise(x, z), 1.25) * 16, x, z))
{
return iris.biome("River");
}
}
cbi = getRegionGenerator(x, z).getChoice(x, z);
if(pathCheck.noise(x, z) > 0.33)

View File

@ -0,0 +1,133 @@
package ninja.bytecode.iris.generator.layer;
import java.util.Random;
import org.bukkit.Material;
import org.bukkit.World;
import ninja.bytecode.iris.Iris;
import ninja.bytecode.iris.generator.IrisGenerator;
import ninja.bytecode.iris.pack.IrisBiome;
import ninja.bytecode.iris.util.GenLayer;
import ninja.bytecode.iris.util.IrisInterpolation;
import ninja.bytecode.iris.util.MB;
import ninja.bytecode.shuriken.math.CNG;
import ninja.bytecode.shuriken.math.M;
import ninja.bytecode.shuriken.math.RNG;
public class GenLayerCarving extends GenLayer
{
public CNG carver;
public CNG clipper;
public GenLayerCarving(IrisGenerator iris, World world, Random random, RNG rng)
{
super(iris, world, random, rng);
//@builder
carver = new CNG(rng.nextParallelRNG(116), 1D, 3)
.scale(0.0135)
.amp(0.5)
.freq(1.1)
.fractureWith(new CNG(rng.nextParallelRNG(18), 1, 3)
.scale(0.018)
.child(new CNG(rng.nextParallelRNG(19), 0.745, 2)
.scale(0.1))
.fractureWith(new CNG(rng.nextParallelRNG(20), 1, 3)
.scale(0.15), 24), 44);
clipper = new CNG(rng.nextParallelRNG(117), 1D, 1)
.scale(0.005)
.amp(0.5)
.freq(1.1)
.fractureWith(new CNG(rng.nextParallelRNG(18), 1, 3)
.scale(0.018)
.child(new CNG(rng.nextParallelRNG(19), 0.745, 2)
.scale(0.1))
.fractureWith(new CNG(rng.nextParallelRNG(20), 1, 3)
.scale(0.15), 24), 44);
//@done
}
public double getHill(double height)
{
double min = Iris.settings.gen.minCarvingHeight;
double max = Iris.settings.gen.maxCarvingHeight;
double mid = IrisInterpolation.lerp(min, max, 0.5);
if(height >= min && height <= mid)
{
return IrisInterpolation.lerpBezier(0, 1, M.lerpInverse(min, mid, height));
}
else if(height >= mid && height <= max)
{
return IrisInterpolation.lerpBezier(1, 0, M.lerpInverse(mid, max, height));
}
return 0;
}
public void genCarves(double wxx, double wzx, int x, int z, int s, IrisGenerator g, IrisBiome biome)
{
if(s < Iris.settings.gen.minCarvingHeight)
{
return;
}
int hit = 0;
int carved = 0;
for(int i = Math.min(Iris.settings.gen.maxCarvingHeight, s); i > Iris.settings.gen.minCarvingHeight; i--)
{
if(clipper.noise(wzx, i, wxx) < Iris.settings.gen.carvingChance)
{
double hill = getHill(i);
if(hill < 0.065)
{
continue;
}
if(carver.noise(wxx, i, wzx) < IrisInterpolation.lerpBezier(0.01, 0.465, hill))
{
carved++;
g.setBlock(x, i, z, Material.AIR);
}
}
}
if(carved > 4)
{
for(int i = Iris.settings.gen.maxCarvingHeight; i > Iris.settings.gen.minCarvingHeight; i--)
{
Material m = g.getType(x, i, z);
if(!m.equals(Material.AIR))
{
hit++;
if(hit == 1)
{
MB mb = biome.getSurface(wxx, wzx, g.getRTerrain());
g.setBlock(x, i, z, mb.material, mb.data);
}
else if(hit > 1 && hit < g.getGlBase().scatterInt(x, i, z, 4) + 3)
{
MB mb = biome.getDirtRNG();
g.setBlock(x, i, z, mb.material, mb.data);
}
}
else
{
hit = 0;
}
}
}
}
@Override
public double generateLayer(double gnoise, double dx, double dz)
{
return gnoise;
}
}

View File

@ -18,12 +18,12 @@ public class GenLayerLayeredNoise extends GenLayer
{
//@builder
super(iris, world, random, rng);
fract = new CNG(rng.nextParallelRNG(16), 1D, 9).scale(0.0181);
gen = new CNG(rng.nextParallelRNG(17), 0.19D, 16)
fract = new CNG(rng.nextParallelRNG(16), 1D, 3).scale(0.0181);
gen = new CNG(rng.nextParallelRNG(17), 0.19D, 6)
.scale(0.012)
.amp(0.5)
.freq(1.1)
.fractureWith(new CNG(rng.nextParallelRNG(18), 1, 6)
.fractureWith(new CNG(rng.nextParallelRNG(18), 1, 3)
.scale(0.018)
.child(new CNG(rng.nextParallelRNG(19), 0.745, 2)
.scale(0.1))

View File

@ -0,0 +1,42 @@
package ninja.bytecode.iris.generator.layer;
import java.util.Random;
import org.bukkit.World;
import ninja.bytecode.iris.generator.IrisGenerator;
import ninja.bytecode.iris.util.GenLayer;
import ninja.bytecode.shuriken.math.CNG;
import ninja.bytecode.shuriken.math.RNG;
public class GenLayerSnow extends GenLayer
{
private CNG gen;
public GenLayerSnow(IrisGenerator iris, World world, Random random, RNG rng)
{
//@builder
super(iris, world, random, rng);
gen = new CNG(rng.nextParallelRNG(117), 1D, 16)
.scale(0.059)
.amp(0.5)
.freq(1.1)
.fractureWith(new CNG(rng.nextParallelRNG(18), 1, 6)
.scale(0.018)
.child(new CNG(rng.nextParallelRNG(19), 0.745, 2)
.scale(0.1))
.fractureWith(new CNG(rng.nextParallelRNG(20), 1, 3)
.scale(0.15), 24), 44);
}
public double getHeight(double x, double z)
{
return gen.noise(x, z);
}
@Override
public double generateLayer(double gnoise, double dx, double dz)
{
return getHeight(dx, dz);
}
}

View File

@ -12,6 +12,7 @@ import mortar.api.world.MaterialBlock;
import ninja.bytecode.iris.util.MB;
import ninja.bytecode.iris.util.Placer;
import ninja.bytecode.shuriken.collections.GSet;
import ninja.bytecode.shuriken.execution.J;
public class NMSPlacer extends Placer
{
@ -49,10 +50,15 @@ public class NMSPlacer extends Placer
{
for(Chunk i : c)
{
for(Player j : NMP.CHUNK.nearbyPlayers(i))
NMP.host.relight(i);
J.a(() ->
{
NMP.CHUNK.refresh(j, i);
for(Player j : i.getWorld().getPlayers())
{
NMP.CHUNK.refreshIgnorePosition(j, i);
}
});
}
c.clear();

View File

@ -63,6 +63,7 @@ public class IrisBiome
private boolean scatterSurface;
private boolean core;
private boolean simplexScatter;
private double snow;
private String region;
private GMap<String, Double> schematicGroups;
private PolygonGenerator.EnumPolygonGenerator<MB> poly;
@ -162,6 +163,7 @@ public class IrisBiome
realBiome = Biome.valueOf(o.getString("derivative").toUpperCase().replaceAll(" ", "_"));
J.attempt(() -> region = o.getString("region"));
J.attempt(() -> height = o.getDouble("height"));
J.attempt(() -> snow = o.getDouble("snow"));
J.attempt(() -> surface = mbListFromJSON(o.getJSONArray("surface")));
J.attempt(() -> dirt = mbListFromJSON(o.getJSONArray("dirt")));
J.attempt(() -> scatterChance = scatterFromJSON(o.getJSONArray("scatter")));
@ -185,6 +187,7 @@ public class IrisBiome
J.attempt(() -> j.put("region", region));
J.attempt(() -> j.put("derivative", realBiome.name().toLowerCase().replaceAll("_", " ")));
J.attempt(() -> j.put("height", height));
J.attempt(() -> j.put("snow", snow));
J.attempt(() -> j.put("surface", mbListToJSON(surface)));
J.attempt(() -> j.put("dirt", mbListToJSON(dirt)));
J.attempt(() -> j.put("scatter", scatterToJson(scatterChance)));
@ -483,4 +486,14 @@ public class IrisBiome
{
return region;
}
public boolean isSnowy()
{
return getSnow() > 0;
}
public double getSnow()
{
return snow;
}
}

View File

@ -1,7 +1,5 @@
package ninja.bytecode.iris.util;
import java.util.function.Supplier;
import ninja.bytecode.iris.pack.IrisBiome;
import ninja.bytecode.shuriken.collections.GMap;
@ -28,7 +26,7 @@ public class ChunkPlan
biomeCache.put(new ChunkedVector(x, z), cng);
}
public double getHeight(int x, int z, Supplier<Double> realHeight)
public double getHeight(int x, int z)
{
ChunkedVector c = new ChunkedVector(x, z);
if(hasHeight(c))
@ -36,9 +34,7 @@ public class ChunkPlan
return heightCache.get(c);
}
double m = realHeight.get();
setHeight(c, m);
return m;
return -1;
}
public int getRealHeight(int x, int z)