mirror of
https://github.com/PolyhedralDev/Terra.git
synced 2025-07-03 08:25:31 +00:00
customizable palette noise
This commit is contained in:
parent
462b6f4198
commit
18d7408f53
@ -1,12 +1,11 @@
|
||||
package com.dfsek.terra.api.math;
|
||||
|
||||
import com.dfsek.terra.api.math.noise.samplers.NoiseSampler;
|
||||
import com.dfsek.terra.api.world.biome.NormalizationUtil;
|
||||
import net.jafama.FastMath;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public class ProbabilityCollection<E> {
|
||||
@ -25,19 +24,19 @@ public class ProbabilityCollection<E> {
|
||||
return this;
|
||||
}
|
||||
|
||||
public E get() {
|
||||
if(array.length == 0) return null;
|
||||
return (E) array[ThreadLocalRandom.current().nextInt(array.length)];
|
||||
}
|
||||
|
||||
public E get(Random r) {
|
||||
if(array.length == 0) return null;
|
||||
return (E) array[r.nextInt(array.length)];
|
||||
}
|
||||
|
||||
private static double getNoise(double x, double z, NoiseSampler sampler) {
|
||||
double n = sampler.getNoise(x, z);
|
||||
return FastMath.min(FastMath.max(n, -1), 1);
|
||||
}
|
||||
|
||||
public E get(NoiseSampler n, double x, double z) {
|
||||
if(array.length == 0) return null;
|
||||
return (E) array[NormalizationUtil.normalize(n.getNoise(x, z), array.length, 1)];
|
||||
return (E) array[FastMath.min(FastMath.floorToInt(((getNoise(x, z, n) + 1D) / 2D) * array.length), array.length - 1)];
|
||||
}
|
||||
|
||||
public int getTotalProbability() {
|
||||
|
@ -1615,25 +1615,32 @@ public class FastNoiseLite implements NoiseSampler {
|
||||
return lerp(xf0, xf1, ys) * 1.4247691104677813f;
|
||||
}
|
||||
|
||||
private int doubleCast2Int(double f) {
|
||||
int i = Float.floatToRawIntBits((float) f);
|
||||
|
||||
return i ^ (i >> 16);
|
||||
private static long hash(long in) {
|
||||
in = (in + 0x7ed55d16) + (in << 12);
|
||||
in = (in ^ 0xc761c23c) ^ (in >> 19);
|
||||
in = (in + 0x165667b1) + (in << 5);
|
||||
in = (in + 0xd3a2646c) ^ (in << 9);
|
||||
in = (in + 0xfd7046c5) + (in << 3);
|
||||
in = (in ^ 0xb55a4f09) ^ (in >> 16);
|
||||
return in;
|
||||
}
|
||||
|
||||
private double singleWhiteNoise(int seed, double x, double y, double z) {
|
||||
int xi = doubleCast2Int(x);
|
||||
int yi = doubleCast2Int(y);
|
||||
int zi = doubleCast2Int(z);
|
||||
|
||||
return valCoord(seed, xi, yi, zi);
|
||||
long hashX = hash(Double.doubleToRawLongBits(x) ^ seed);
|
||||
long hashZ = hash(Double.doubleToRawLongBits(y) ^ seed);
|
||||
long hash = (((hashX ^ (hashX >>> 32)) + ((hashZ ^ (hashZ >>> 32)) << 32)) ^ seed) + Double.doubleToRawLongBits(z);
|
||||
long base = ((hash(hash)) & 0x000fffffffffffffL)
|
||||
+ (0b01111111111L << 52); // Sign and exponent
|
||||
return (Double.longBitsToDouble(base) - 1.5) * 2;
|
||||
}
|
||||
|
||||
private double singleWhiteNoise(int seed, double x, double y) {
|
||||
int xi = doubleCast2Int(x);
|
||||
int yi = doubleCast2Int(y);
|
||||
|
||||
return valCoord(seed, xi, yi);
|
||||
long hashX = hash(Double.doubleToRawLongBits(x) ^ seed);
|
||||
long hashZ = hash(Double.doubleToRawLongBits(y) ^ seed);
|
||||
long hash = ((hashX ^ (hashX >>> 32)) + ((hashZ ^ (hashZ >>> 32)) << 32)) ^ seed;
|
||||
long base = (hash(hash) & 0x000fffffffffffffL)
|
||||
+ (0b01111111111L << 52); // Sign and exponent
|
||||
return (Double.longBitsToDouble(base) - 1.5) * 2;
|
||||
}
|
||||
|
||||
// Simplex/OpenSimplex2 Noise
|
||||
|
@ -4,10 +4,10 @@ import com.dfsek.terra.api.math.noise.samplers.NoiseSampler;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class SimplexPalette<E> extends Palette<E> {
|
||||
public class NoisePalette<E> extends Palette<E> {
|
||||
private final NoiseSampler r;
|
||||
|
||||
public SimplexPalette(NoiseSampler r) {
|
||||
public NoisePalette(NoiseSampler r) {
|
||||
this.r = r;
|
||||
}
|
||||
|
@ -15,28 +15,28 @@ public class TreeGeometry {
|
||||
}
|
||||
|
||||
public static Vector3 getPerpendicular(Vector3 v) {
|
||||
return v.getZ() < v.getX() ? new Vector3(v.getY(), - v.getX(), 0) : new Vector3(0, - v.getZ(), v.getY());
|
||||
return v.getZ() < v.getX() ? new Vector3(v.getY(), -v.getX(), 0) : new Vector3(0, -v.getZ(), v.getY());
|
||||
}
|
||||
|
||||
public FractalTree getTree() {
|
||||
return tree;
|
||||
}
|
||||
|
||||
public void generateSphere(Location l, BlockData m, int radius, boolean overwrite) {
|
||||
generateSphere(l, new ProbabilityCollection<BlockData>().add(m, 1), radius, overwrite);
|
||||
public void generateSphere(Location l, BlockData m, int radius, boolean overwrite, Random r) {
|
||||
generateSphere(l, new ProbabilityCollection<BlockData>().add(m, 1), radius, overwrite, r);
|
||||
}
|
||||
|
||||
public void generateCylinder(Location l, BlockData m, int radius, int height, boolean overwrite) {
|
||||
generateCylinder(l, new ProbabilityCollection<BlockData>().add(m, 1), radius, height, overwrite);
|
||||
public void generateCylinder(Location l, BlockData m, int radius, int height, boolean overwrite, Random r) {
|
||||
generateCylinder(l, new ProbabilityCollection<BlockData>().add(m, 1), radius, height, overwrite, r);
|
||||
}
|
||||
|
||||
public void generateSphere(Location l, ProbabilityCollection<BlockData> m, int radius, boolean overwrite) {
|
||||
for(int x = - radius; x <= radius; x++) {
|
||||
for(int y = - radius; y <= radius; y++) {
|
||||
for(int z = - radius; z <= radius; z++) {
|
||||
public void generateSphere(Location l, ProbabilityCollection<BlockData> m, int radius, boolean overwrite, Random r) {
|
||||
for(int x = -radius; x <= radius; x++) {
|
||||
for(int y = -radius; y <= radius; y++) {
|
||||
for(int z = -radius; z <= radius; z++) {
|
||||
Vector3 position = l.toVector().clone().add(new Vector3(x, y, z));
|
||||
if(l.toVector().distance(position) <= radius + 0.5 && (overwrite || position.toLocation(l.getWorld()).getBlock().isEmpty()))
|
||||
tree.setBlock(position.toLocation(l.getWorld()), m.get());
|
||||
tree.setBlock(position.toLocation(l.getWorld()), m.get(r));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -48,19 +48,19 @@ public class TreeGeometry {
|
||||
for(int z = -radius; z <= radius; z++) {
|
||||
Vector3 position = l.toVector().clone().add(new Vector3(x, y, z));
|
||||
if(r.nextInt(100) < sponginess && l.toVector().distance(position) <= radius + 0.5 && (overwrite || position.toLocation(l.getWorld()).getBlock().isEmpty()))
|
||||
tree.setBlock(position.toLocation(l.getWorld()), m.get());
|
||||
tree.setBlock(position.toLocation(l.getWorld()), m.get(r));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void generateCylinder(Location l, ProbabilityCollection<BlockData> m, int radius, int height, boolean overwrite) {
|
||||
for(int x = - radius; x <= radius; x++) {
|
||||
public void generateCylinder(Location l, ProbabilityCollection<BlockData> m, int radius, int height, boolean overwrite, Random r) {
|
||||
for(int x = -radius; x <= radius; x++) {
|
||||
for(int y = 0; y <= height; y++) {
|
||||
for(int z = - radius; z <= radius; z++) {
|
||||
for(int z = -radius; z <= radius; z++) {
|
||||
Vector3 position = l.toVector().clone().add(new Vector3(x, 0, z));
|
||||
if(l.toVector().distance(position) <= radius + 0.5 && (overwrite || position.toLocation(l.getWorld()).getBlock().isEmpty()))
|
||||
tree.setBlock(position.toLocation(l.getWorld()), m.get());
|
||||
tree.setBlock(position.toLocation(l.getWorld()), m.get(r));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -41,13 +41,13 @@ public class OakTree extends FractalTree {
|
||||
BlockData wood = getMain().getWorldHandle().createBlockData("minecraft:oak_wood");
|
||||
BlockData leaves = getMain().getWorldHandle().createBlockData("minecraft:oak_leave");
|
||||
if(recursions > 1) {
|
||||
geo.generateSphere(l1, leaves, 1 + r.nextInt(2) + (3 - recursions), false);
|
||||
geo.generateSphere(l1, leaves, 1 + r.nextInt(2) + (3 - recursions), false, r);
|
||||
if(recursions > 2) return;
|
||||
}
|
||||
if(diff.getY() < 0) diff.rotateAroundAxis(TreeGeometry.getPerpendicular(diff.clone()).normalize(), FastMath.PI);
|
||||
int d = (int) diff.length();
|
||||
for(int i = 0; i < d; i++) {
|
||||
geo.generateSphere(l1.clone().add(diff.clone().multiply((double) i / d)), wood, FastMath.max((int) d1, 0), true);
|
||||
geo.generateSphere(l1.clone().add(diff.clone().multiply((double) i / d)), wood, FastMath.max((int) d1, 0), true, r);
|
||||
}
|
||||
double runningAngle = (double) 45 / (recursions + 1);
|
||||
growBranch(l1.clone().add(diff), diff.clone().multiply(0.75).rotateAroundX(FastMath.toRadians(runningAngle + getNoise(r))).rotateAroundZ(FastMath.toRadians(getNoise(r))),
|
||||
|
@ -50,13 +50,13 @@ public class ShatteredTree extends FractalTree {
|
||||
|
||||
private void growBranch(Location l1, Vector3 diff, double d1, int recursions, Random r) {
|
||||
if(recursions > 2) {
|
||||
geo.generateSphere(l1, leaves, 1 + r.nextInt(2), false);
|
||||
geo.generateSphere(l1, leaves, 1 + r.nextInt(2), false, r);
|
||||
return;
|
||||
}
|
||||
if(diff.getY() < 0) diff.rotateAroundAxis(TreeGeometry.getPerpendicular(diff.clone()).normalize(), FastMath.PI);
|
||||
int d = (int) diff.length();
|
||||
for(int i = 0; i < d; i++) {
|
||||
geo.generateSphere(l1.clone().add(diff.clone().multiply((double) i / d)), bark, FastMath.max((int) d1, 0), true);
|
||||
geo.generateSphere(l1.clone().add(diff.clone().multiply((double) i / d)), bark, FastMath.max((int) d1, 0), true, r);
|
||||
}
|
||||
double runningAngle = (double) 45 / (recursions + 1);
|
||||
growBranch(l1.clone().add(diff), diff.clone().multiply(0.9).rotateAroundX(FastMath.toRadians(runningAngle + getNoise(r))).rotateAroundZ(FastMath.toRadians(getNoise(r))),
|
||||
|
@ -50,13 +50,13 @@ public class SmallShatteredTree extends FractalTree {
|
||||
|
||||
private void growBranch(Location l1, Vector3 diff, double d1, int recursions, Random r) {
|
||||
if(recursions > 2) {
|
||||
geo.generateSphere(l1, leaves, 1 + r.nextInt(2) + (3 - recursions), false);
|
||||
geo.generateSphere(l1, leaves, 1 + r.nextInt(2) + (3 - recursions), false, r);
|
||||
return;
|
||||
}
|
||||
if(diff.getY() < 0) diff.rotateAroundAxis(TreeGeometry.getPerpendicular(diff.clone()).normalize(), FastMath.PI);
|
||||
int d = (int) diff.length();
|
||||
for(int i = 0; i < d; i++) {
|
||||
geo.generateSphere(l1.clone().add(diff.clone().multiply((double) i / d)), bark, FastMath.max((int) d1, 0), true);
|
||||
geo.generateSphere(l1.clone().add(diff.clone().multiply((double) i / d)), bark, FastMath.max((int) d1, 0), true, r);
|
||||
}
|
||||
double runningAngle = (double) 45 / (recursions + 1);
|
||||
growBranch(l1.clone().add(diff), diff.clone().multiply(0.7).rotateAroundX(FastMath.toRadians(runningAngle + getNoise(r))).rotateAroundZ(FastMath.toRadians(getNoise(r))),
|
||||
|
@ -33,19 +33,19 @@ public class SpruceTree extends FractalTree {
|
||||
*/
|
||||
@Override
|
||||
public void grow(Location origin, Random random) {
|
||||
growTrunk(origin.clone(), new Vector3(0, 16 + random.nextInt(5), 0));
|
||||
growTrunk(origin.clone(), new Vector3(0, 16 + random.nextInt(5), 0), random);
|
||||
}
|
||||
|
||||
private void growTrunk(Location l1, Vector3 diff) {
|
||||
private void growTrunk(Location l1, Vector3 diff, Random r) {
|
||||
if(diff.getY() < 0) diff.rotateAroundAxis(TreeGeometry.getPerpendicular(diff.clone()).normalize(), FastMath.PI);
|
||||
int d = (int) diff.length();
|
||||
int rad = 7;
|
||||
BlockData wood = getMain().getWorldHandle().createBlockData("minecraft:spruce_wood");
|
||||
BlockData leaves = getMain().getWorldHandle().createBlockData("minecraft:spruce_leave");
|
||||
for(int i = 0; i < d; i++) {
|
||||
geo.generateSphere(l1.clone().add(diff.clone().multiply((double) i / d)), wood, (int) ((i > d * 0.65) ? 0.5 : 1.5), true);
|
||||
geo.generateSphere(l1.clone().add(diff.clone().multiply((double) i / d)), wood, (int) ((i > d * 0.65) ? 0.5 : 1.5), true, r);
|
||||
if(i > 3)
|
||||
geo.generateCylinder(l1.clone().add(diff.clone().multiply((double) i / d)), leaves, (int) (((6 - (i % 4))) * (1.25 - ((double) i / d))), 1, false);
|
||||
geo.generateCylinder(l1.clone().add(diff.clone().multiply((double) i / d)), leaves, (int) (((6 - (i % 4))) * (1.25 - ((double) i / d))), 1, false, r);
|
||||
}
|
||||
setBlock(l1.clone().add(diff), leaves);
|
||||
setBlock(l1.clone().add(diff).add(0, 1, 0), leaves);
|
||||
|
@ -1,25 +1,16 @@
|
||||
package com.dfsek.terra.config.factories;
|
||||
|
||||
import com.dfsek.terra.api.math.noise.samplers.FastNoiseLite;
|
||||
import com.dfsek.terra.api.platform.TerraPlugin;
|
||||
import com.dfsek.terra.api.platform.block.BlockData;
|
||||
import com.dfsek.terra.api.util.FastRandom;
|
||||
import com.dfsek.terra.api.world.palette.NoisePalette;
|
||||
import com.dfsek.terra.api.world.palette.Palette;
|
||||
import com.dfsek.terra.api.world.palette.RandomPalette;
|
||||
import com.dfsek.terra.api.world.palette.SimplexPalette;
|
||||
import com.dfsek.terra.biome.palette.PaletteLayer;
|
||||
import com.dfsek.terra.config.templates.PaletteTemplate;
|
||||
|
||||
public class PaletteFactory implements TerraFactory<PaletteTemplate, Palette<BlockData>> {
|
||||
@Override
|
||||
public Palette<BlockData> build(PaletteTemplate config, TerraPlugin main) {
|
||||
Palette<BlockData> palette;
|
||||
if(config.isSimplex()) {
|
||||
FastNoiseLite noise = new FastNoiseLite((int) config.getSeed());
|
||||
noise.setFrequency(config.getFrequency());
|
||||
palette = new SimplexPalette<>(noise);
|
||||
} else palette = new RandomPalette<>(new FastRandom(config.getSeed()));
|
||||
|
||||
Palette<BlockData> palette = new NoisePalette<>(config.getNoise().build(2403));
|
||||
for(PaletteLayer layer : config.getPalette()) {
|
||||
palette.add(layer.getLayer(), layer.getSize());
|
||||
}
|
||||
|
@ -3,12 +3,19 @@ package com.dfsek.terra.config.templates;
|
||||
import com.dfsek.tectonic.annotations.Abstractable;
|
||||
import com.dfsek.tectonic.annotations.Default;
|
||||
import com.dfsek.tectonic.annotations.Value;
|
||||
import com.dfsek.terra.api.math.noise.samplers.FastNoiseLite;
|
||||
import com.dfsek.terra.biome.palette.PaletteLayer;
|
||||
import com.dfsek.terra.generation.config.NoiseBuilder;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@SuppressWarnings({"FieldMayBeFinal", "unused"})
|
||||
public class PaletteTemplate extends AbstractableTemplate {
|
||||
@Value("noise")
|
||||
@Abstractable
|
||||
@Default
|
||||
private NoiseBuilder noise = new NoiseBuilder();
|
||||
|
||||
@Value("id")
|
||||
private String id;
|
||||
|
||||
@ -16,38 +23,19 @@ public class PaletteTemplate extends AbstractableTemplate {
|
||||
@Abstractable
|
||||
private List<PaletteLayer> palette;
|
||||
|
||||
@Value("simplex")
|
||||
@Abstractable
|
||||
@Default
|
||||
private boolean simplex = false;
|
||||
|
||||
@Value("frequency")
|
||||
@Abstractable
|
||||
@Default
|
||||
private double frequency = 0.02D;
|
||||
|
||||
@Value("seed")
|
||||
@Abstractable
|
||||
@Default
|
||||
private long seed = 0;
|
||||
public PaletteTemplate() {
|
||||
noise.setType(FastNoiseLite.NoiseType.WhiteNoise);
|
||||
}
|
||||
|
||||
public String getID() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public double getFrequency() {
|
||||
return frequency;
|
||||
}
|
||||
|
||||
public long getSeed() {
|
||||
return seed;
|
||||
}
|
||||
|
||||
public List<PaletteLayer> getPalette() {
|
||||
return palette;
|
||||
}
|
||||
|
||||
public boolean isSimplex() {
|
||||
return simplex;
|
||||
public NoiseBuilder getNoise() {
|
||||
return noise;
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import com.dfsek.tectonic.config.ConfigTemplate;
|
||||
import com.dfsek.terra.api.math.noise.samplers.FastNoiseLite;
|
||||
import com.dfsek.terra.api.math.noise.samplers.NoiseSampler;
|
||||
|
||||
@SuppressWarnings("FieldMayBeFinal")
|
||||
public class NoiseBuilder implements ConfigTemplate {
|
||||
@Value("type")
|
||||
@Default
|
||||
@ -39,7 +40,7 @@ public class NoiseBuilder implements ConfigTemplate {
|
||||
@Default
|
||||
private double weightedStrength = 0.0D;
|
||||
|
||||
@Value("offset")
|
||||
@Value("salt")
|
||||
@Default
|
||||
private int seedOffset = 0;
|
||||
|
||||
@ -71,6 +72,10 @@ public class NoiseBuilder implements ConfigTemplate {
|
||||
@Default
|
||||
private int dimensions = 2;
|
||||
|
||||
@Value("cellular.lookup")
|
||||
@Default
|
||||
private NoiseBuilder lookup = new NoiseBuilder();
|
||||
|
||||
public NoiseSampler build(int seed) {
|
||||
FastNoiseLite noise = new FastNoiseLite(seed + seedOffset);
|
||||
if(!fractalType.equals(FastNoiseLite.FractalType.None)) {
|
||||
@ -85,6 +90,7 @@ public class NoiseBuilder implements ConfigTemplate {
|
||||
noise.setCellularDistanceFunction(cellularDistanceFunction);
|
||||
noise.setCellularReturnType(cellularReturnType);
|
||||
noise.setCellularJitter(cellularJitter);
|
||||
noise.setCellularNoiseLookup(lookup.build(seed));
|
||||
}
|
||||
|
||||
noise.setNoiseType(type);
|
||||
|
Loading…
x
Reference in New Issue
Block a user