mirror of
https://github.com/PolyhedralDev/Terra.git
synced 2025-07-04 00:45:57 +00:00
Merge branch 'dev/fractal-gavoro-pseudoerosion' into ver/6.5.0
This commit is contained in:
commit
b14b355c6f
@ -36,6 +36,7 @@ import com.dfsek.terra.api.addon.BaseAddon;
|
|||||||
import com.dfsek.terra.api.event.events.config.pack.ConfigPackPreLoadEvent;
|
import com.dfsek.terra.api.event.events.config.pack.ConfigPackPreLoadEvent;
|
||||||
import com.dfsek.terra.api.event.functional.FunctionalEventHandler;
|
import com.dfsek.terra.api.event.functional.FunctionalEventHandler;
|
||||||
import com.dfsek.terra.api.inject.annotations.Inject;
|
import com.dfsek.terra.api.inject.annotations.Inject;
|
||||||
|
import com.dfsek.terra.api.noise.DerivativeNoiseSampler;
|
||||||
import com.dfsek.terra.api.noise.NoiseSampler;
|
import com.dfsek.terra.api.noise.NoiseSampler;
|
||||||
import com.dfsek.terra.api.registry.CheckedRegistry;
|
import com.dfsek.terra.api.registry.CheckedRegistry;
|
||||||
import com.dfsek.terra.api.util.reflection.TypeKey;
|
import com.dfsek.terra.api.util.reflection.TypeKey;
|
||||||
@ -71,7 +72,8 @@ public class NoiseAddon implements AddonInitializer {
|
|||||||
(type, o, loader, depthTracker) -> DistanceSampler.DistanceFunction.valueOf((String) o))
|
(type, o, loader, depthTracker) -> DistanceSampler.DistanceFunction.valueOf((String) o))
|
||||||
.applyLoader(DimensionApplicableNoiseSampler.class, DimensionApplicableNoiseSampler::new)
|
.applyLoader(DimensionApplicableNoiseSampler.class, DimensionApplicableNoiseSampler::new)
|
||||||
.applyLoader(FunctionTemplate.class, FunctionTemplate::new)
|
.applyLoader(FunctionTemplate.class, FunctionTemplate::new)
|
||||||
.applyLoader(CubicSpline.Point.class, CubicSplinePointTemplate::new);
|
.applyLoader(CubicSpline.Point.class, CubicSplinePointTemplate::new)
|
||||||
|
.applyLoader(DerivativeNoiseSampler.class, DerivativeNoiseSamplerTemplate::new);
|
||||||
|
|
||||||
noiseRegistry.register(addon.key("LINEAR"), LinearNormalizerTemplate::new);
|
noiseRegistry.register(addon.key("LINEAR"), LinearNormalizerTemplate::new);
|
||||||
noiseRegistry.register(addon.key("NORMAL"), NormalNormalizerTemplate::new);
|
noiseRegistry.register(addon.key("NORMAL"), NormalNormalizerTemplate::new);
|
||||||
@ -94,7 +96,8 @@ public class NoiseAddon implements AddonInitializer {
|
|||||||
noiseRegistry.register(addon.key("PERLIN"), () -> new SimpleNoiseTemplate(PerlinSampler::new));
|
noiseRegistry.register(addon.key("PERLIN"), () -> new SimpleNoiseTemplate(PerlinSampler::new));
|
||||||
noiseRegistry.register(addon.key("SIMPLEX"), () -> new SimpleNoiseTemplate(SimplexSampler::new));
|
noiseRegistry.register(addon.key("SIMPLEX"), () -> new SimpleNoiseTemplate(SimplexSampler::new));
|
||||||
noiseRegistry.register(addon.key("GABOR"), GaborNoiseTemplate::new);
|
noiseRegistry.register(addon.key("GABOR"), GaborNoiseTemplate::new);
|
||||||
|
noiseRegistry.register(addon.key("PSEUDOEROSION"), PseudoErosionTemplate::new);
|
||||||
|
noiseRegistry.register(addon.key("DERIVATIVE"), DerivativeFractalTemplate::new);
|
||||||
|
|
||||||
noiseRegistry.register(addon.key("VALUE"), () -> new SimpleNoiseTemplate(ValueSampler::new));
|
noiseRegistry.register(addon.key("VALUE"), () -> new SimpleNoiseTemplate(ValueSampler::new));
|
||||||
noiseRegistry.register(addon.key("VALUE_CUBIC"), () -> new SimpleNoiseTemplate(ValueCubicSampler::new));
|
noiseRegistry.register(addon.key("VALUE_CUBIC"), () -> new SimpleNoiseTemplate(ValueCubicSampler::new));
|
||||||
|
@ -0,0 +1,25 @@
|
|||||||
|
package com.dfsek.terra.addons.noise.config.templates;
|
||||||
|
|
||||||
|
import com.dfsek.tectonic.api.config.template.annotations.Value;
|
||||||
|
import com.dfsek.tectonic.api.exception.ValidationException;
|
||||||
|
|
||||||
|
import com.dfsek.terra.api.noise.DerivativeNoiseSampler;
|
||||||
|
import com.dfsek.terra.api.noise.NoiseSampler;
|
||||||
|
|
||||||
|
|
||||||
|
public class DerivativeNoiseSamplerTemplate extends SamplerTemplate<DerivativeNoiseSampler> {
|
||||||
|
|
||||||
|
@Value(".")
|
||||||
|
private NoiseSampler sampler;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean validate() throws ValidationException {
|
||||||
|
if (!DerivativeNoiseSampler.isDifferentiable(sampler)) throw new ValidationException("Provided sampler does not support calculating a derivative");
|
||||||
|
return super.validate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DerivativeNoiseSampler get() {
|
||||||
|
return (DerivativeNoiseSampler) sampler;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
package com.dfsek.terra.addons.noise.config.templates.noise;
|
||||||
|
|
||||||
|
import com.dfsek.tectonic.api.config.template.annotations.Default;
|
||||||
|
import com.dfsek.tectonic.api.config.template.annotations.Value;
|
||||||
|
|
||||||
|
import com.dfsek.terra.addons.noise.config.templates.SamplerTemplate;
|
||||||
|
import com.dfsek.terra.addons.noise.samplers.noise.simplex.DerivativeFractal;
|
||||||
|
|
||||||
|
|
||||||
|
public class DerivativeFractalTemplate extends SamplerTemplate<DerivativeFractal> {
|
||||||
|
|
||||||
|
@Value("octaves")
|
||||||
|
@Default
|
||||||
|
private int octaves = 3;
|
||||||
|
|
||||||
|
@Value("gain")
|
||||||
|
@Default
|
||||||
|
private double gain = 0.5;
|
||||||
|
|
||||||
|
@Value("lacunarity")
|
||||||
|
@Default
|
||||||
|
private double lacunarity = 2.0;
|
||||||
|
|
||||||
|
@Value("frequency")
|
||||||
|
@Default
|
||||||
|
private double frequency = 0.02;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DerivativeFractal get() {
|
||||||
|
return new DerivativeFractal(octaves, gain, lacunarity, frequency);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,70 @@
|
|||||||
|
package com.dfsek.terra.addons.noise.config.templates.noise;
|
||||||
|
|
||||||
|
import com.dfsek.tectonic.api.config.template.annotations.Default;
|
||||||
|
import com.dfsek.tectonic.api.config.template.annotations.Value;
|
||||||
|
|
||||||
|
import com.dfsek.terra.addons.noise.config.templates.SamplerTemplate;
|
||||||
|
import com.dfsek.terra.addons.noise.samplers.noise.simplex.PseudoErosion;
|
||||||
|
import com.dfsek.terra.api.noise.DerivativeNoiseSampler;
|
||||||
|
|
||||||
|
|
||||||
|
public class PseudoErosionTemplate extends SamplerTemplate<PseudoErosion> {
|
||||||
|
|
||||||
|
@Value("octaves")
|
||||||
|
@Default
|
||||||
|
private int octaves = 4;
|
||||||
|
|
||||||
|
@Value("lacunarity")
|
||||||
|
@Default
|
||||||
|
private double lacunarity = 2.0;
|
||||||
|
|
||||||
|
@Value("gain")
|
||||||
|
@Default
|
||||||
|
private double gain = 0.5;
|
||||||
|
|
||||||
|
@Value("slope-strength")
|
||||||
|
@Default
|
||||||
|
private double slopeStrength = 1.0;
|
||||||
|
|
||||||
|
@Value("branch-strength")
|
||||||
|
@Default
|
||||||
|
private double branchStrength = 1.0;
|
||||||
|
|
||||||
|
@Value("strength")
|
||||||
|
@Default
|
||||||
|
private double strength = 0.04;
|
||||||
|
|
||||||
|
@Value("erosion-frequency")
|
||||||
|
@Default
|
||||||
|
private double erosionFrequency = 0.02;
|
||||||
|
|
||||||
|
@Value("sampler")
|
||||||
|
private DerivativeNoiseSampler heightSampler;
|
||||||
|
|
||||||
|
@Value("slope-mask.enable")
|
||||||
|
@Default
|
||||||
|
private boolean slopeMask = true;
|
||||||
|
|
||||||
|
@Value("slope-mask.none")
|
||||||
|
@Default
|
||||||
|
private double slopeMaskNone = -0.5;
|
||||||
|
|
||||||
|
@Value("slope-mask.full")
|
||||||
|
@Default
|
||||||
|
private double slopeMaskFull = 1;
|
||||||
|
|
||||||
|
@Value("jitter")
|
||||||
|
@Default
|
||||||
|
private double jitterModifier = 1;
|
||||||
|
|
||||||
|
@Value("average-impulses")
|
||||||
|
@Default
|
||||||
|
private boolean averageErosionImpulses = true;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PseudoErosion get() {
|
||||||
|
return new PseudoErosion(octaves, gain, lacunarity,
|
||||||
|
slopeStrength, branchStrength, strength,
|
||||||
|
erosionFrequency, heightSampler, slopeMask, slopeMaskFull, slopeMaskNone, jitterModifier, averageErosionImpulses);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,109 @@
|
|||||||
|
package com.dfsek.terra.addons.noise.samplers.noise.simplex;
|
||||||
|
|
||||||
|
import com.dfsek.terra.api.noise.DerivativeNoiseSampler;
|
||||||
|
|
||||||
|
import static com.dfsek.terra.addons.noise.samplers.noise.simplex.PseudoErosion.dot;
|
||||||
|
import static com.dfsek.terra.addons.noise.samplers.noise.simplex.PseudoErosion.hash;
|
||||||
|
import static com.dfsek.terra.addons.noise.samplers.noise.simplex.PseudoErosion.hashX;
|
||||||
|
import static com.dfsek.terra.addons.noise.samplers.noise.simplex.PseudoErosion.hashY;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Temporary sampler that provides derivatives to test pseudoerosion, should be replaced with
|
||||||
|
* derivative versions of existing samplers
|
||||||
|
*/
|
||||||
|
public class DerivativeFractal implements DerivativeNoiseSampler {
|
||||||
|
|
||||||
|
private final int heightOctaves;
|
||||||
|
private final double heightGain;
|
||||||
|
private final double heightLacunarity;
|
||||||
|
private final double frequency;
|
||||||
|
|
||||||
|
public DerivativeFractal(int octaves, double gain, double lacunarity, double frequency) {
|
||||||
|
this.heightOctaves = octaves;
|
||||||
|
this.heightGain = gain;
|
||||||
|
this.heightLacunarity = lacunarity;
|
||||||
|
this.frequency = frequency;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static float[] baseNoise(float px, float py) {
|
||||||
|
float ix = (float)Math.floor(px);
|
||||||
|
float iy = (float)Math.floor(py);
|
||||||
|
float fx = px - ix;
|
||||||
|
float fy = py - iy;
|
||||||
|
|
||||||
|
float ux = fx * fx * fx * (fx * (fx * 6.0f - 15.0f) + 10.0f);
|
||||||
|
float uy = fy * fy * fy * (fy * (fy * 6.0f - 15.0f) + 10.0f);
|
||||||
|
float dux = fx * fx * 30.0f * (fx * (fx - 2.0f) + 1.0f);
|
||||||
|
float duy = fy * fy * 30.0f * (fy * (fy - 2.0f) + 1.0f);
|
||||||
|
|
||||||
|
float gan = hash(ix, iy);
|
||||||
|
float gax = hashX(gan);
|
||||||
|
float gay = hashY(gan);
|
||||||
|
|
||||||
|
float gbn = hash(ix + 1, iy);
|
||||||
|
float gbx = hashX(gbn);
|
||||||
|
float gby = hashY(gbn);
|
||||||
|
|
||||||
|
float gcn = hash(ix, iy + 1);
|
||||||
|
float gcx = hashX(gcn);
|
||||||
|
float gcy = hashY(gcn);
|
||||||
|
|
||||||
|
float gdn = hash(ix + 1, iy + 1);
|
||||||
|
float gdx = hashX(gdn);
|
||||||
|
float gdy = hashY(gdn);
|
||||||
|
|
||||||
|
float va = dot(gax, gay, fx, fy);
|
||||||
|
float vb = dot(gbx, gby, fx - 1, fy);
|
||||||
|
float vc = dot(gcx, gcy, fx, fy - 1);
|
||||||
|
float vd = dot(gdx, gdy, fx - 1, fy - 1);
|
||||||
|
|
||||||
|
float u2x = gax + (gbx - gax) * ux + (gcx - gax) * uy + (gax - gbx - gcx + gdx) * ux * uy + dux * (uy * (va - vb - vc + vd) + vb - va);
|
||||||
|
float u2y = gay + (gby - gay) * ux + (gcy - gay) * uy + (gay - gby - gcy + gdy) * ux * uy + duy * (ux * (va - vb - vc + vd) + vc - va);
|
||||||
|
|
||||||
|
return new float[] { va + ux * (vb - va) + uy * (vc - va) + ux * uy * (va - vb - vc + vd), u2x, u2y };
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isDifferentiable() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double[] noised(long seed, double x, double y) {
|
||||||
|
x *= frequency;
|
||||||
|
y *= frequency;
|
||||||
|
double[] out = { 0.0f, 0.0f, 0.0f };
|
||||||
|
float heightFreq = 1.0f;
|
||||||
|
float heightAmp = 1f;
|
||||||
|
float cumAmp = 0.0f;
|
||||||
|
for (int i = 0; i < heightOctaves; i++) {
|
||||||
|
float[] noise = baseNoise((float) (x * heightFreq), (float) (y * heightFreq));
|
||||||
|
out[0] += noise[0] * heightAmp;
|
||||||
|
out[1] += noise[1] * heightAmp * heightFreq;
|
||||||
|
out[2] += noise[2] * heightAmp * heightFreq;
|
||||||
|
cumAmp += heightAmp;
|
||||||
|
heightAmp *= heightGain;
|
||||||
|
heightFreq *= heightLacunarity;
|
||||||
|
}
|
||||||
|
out[0] /= cumAmp;
|
||||||
|
out[1] /= cumAmp;
|
||||||
|
out[2] /= cumAmp;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double[] noised(long seed, double x, double y, double z) {
|
||||||
|
return noised(seed, x, z);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double noise(long seed, double x, double y) {
|
||||||
|
return noised(seed, x, y)[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double noise(long seed, double x, double y, double z) {
|
||||||
|
return noised(seed, x, y, z)[0];
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,187 @@
|
|||||||
|
package com.dfsek.terra.addons.noise.samplers.noise.simplex;
|
||||||
|
|
||||||
|
|
||||||
|
import com.dfsek.terra.api.noise.DerivativeNoiseSampler;
|
||||||
|
import com.dfsek.terra.api.noise.NoiseSampler;
|
||||||
|
import com.dfsek.terra.api.util.MathUtil;
|
||||||
|
|
||||||
|
|
||||||
|
public class PseudoErosion implements NoiseSampler {
|
||||||
|
public static final float TAU = (float) (2.0 * Math.PI);
|
||||||
|
private static final float HASH_X = 0.3183099f;
|
||||||
|
private static final float HASH_Y = 0.3678794f;
|
||||||
|
private final int octaves;
|
||||||
|
public final double gain;
|
||||||
|
public final double lacunarity;
|
||||||
|
public final double slopeStrength;
|
||||||
|
public final double branchStrength;
|
||||||
|
public final double erosionStrength;
|
||||||
|
private final double erosionFrequency;
|
||||||
|
private final DerivativeNoiseSampler sampler;
|
||||||
|
private final boolean slopeMask;
|
||||||
|
private final double slopeMaskFullSq;
|
||||||
|
private final double slopeMaskNoneSq;
|
||||||
|
private final double jitter;
|
||||||
|
private final double maxCellDistSq;
|
||||||
|
private final double maxCellDistSqRecip;
|
||||||
|
private final boolean averageErosionImpulses;
|
||||||
|
|
||||||
|
public PseudoErosion(int octaves, double gain, double lacunarity, double slopeStrength, double branchStrength, double erosionStrength, double erosionFrequency, DerivativeNoiseSampler sampler,
|
||||||
|
boolean slopeMask, double slopeMaskFull, double slopeMaskNone, double jitterModifier,
|
||||||
|
boolean averageErosionImpulses) {
|
||||||
|
this.octaves = octaves;
|
||||||
|
this.gain = gain;
|
||||||
|
this.lacunarity = lacunarity;
|
||||||
|
this.slopeStrength = slopeStrength;
|
||||||
|
this.branchStrength = branchStrength;
|
||||||
|
this.erosionStrength = erosionStrength;
|
||||||
|
this.erosionFrequency = erosionFrequency;
|
||||||
|
this.sampler = sampler;
|
||||||
|
this.slopeMask = slopeMask;
|
||||||
|
// Square these values and maintain sign since they're compared to a
|
||||||
|
// squared value, otherwise a sqrt would need to be used
|
||||||
|
this.slopeMaskFullSq = slopeMaskFull * slopeMaskFull * Math.signum(slopeMaskFull);
|
||||||
|
this.slopeMaskNoneSq = slopeMaskNone * slopeMaskNone * Math.signum((slopeMaskNone));
|
||||||
|
this.jitter = 0.43701595 * jitterModifier;
|
||||||
|
this.averageErosionImpulses = averageErosionImpulses;
|
||||||
|
this.maxCellDistSq = 1 + jitter * jitter;
|
||||||
|
this.maxCellDistSqRecip = 1 / maxCellDistSq;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float hash(float x, float y) {
|
||||||
|
float xx = x * HASH_X + HASH_Y;
|
||||||
|
float yy = y * HASH_Y + HASH_X;
|
||||||
|
|
||||||
|
// Swapped the components here
|
||||||
|
return 16 * (xx * yy * (xx + yy));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float hashX(float n) {
|
||||||
|
// Swapped the components here
|
||||||
|
float nx = HASH_X * n;
|
||||||
|
return -1.0f + 2.0f * fract(nx);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float hashY(float n) {
|
||||||
|
float ny = HASH_Y * n;
|
||||||
|
return -1.0f + 2.0f * fract(ny);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float fract(float x) {
|
||||||
|
return (x - (float)Math.floor(x));
|
||||||
|
}
|
||||||
|
|
||||||
|
public float[] erosion(float x, float y, float dirX, float dirY) {
|
||||||
|
int gridX = Math.round(x);
|
||||||
|
int gridY = Math.round(y);
|
||||||
|
float noise = 0.0f;
|
||||||
|
float dirOutX = 0.0f;
|
||||||
|
float dirOutY = 0.0f;
|
||||||
|
float cumAmp = 0.0f;
|
||||||
|
|
||||||
|
for (int cellX = gridX - 1; cellX <= gridX + 1; cellX++) {
|
||||||
|
for (int cellY = gridY - 1; cellY <= gridY + 1; cellY++) {
|
||||||
|
// TODO - Make seed affect hashing
|
||||||
|
float cellHash = hash(cellX, cellY);
|
||||||
|
float cellOffsetX = (float) (hashX(cellHash) * jitter);
|
||||||
|
float cellOffsetY = (float) (hashY(cellHash) * jitter);
|
||||||
|
float cellOriginDeltaX = (x - cellX) + cellOffsetX;
|
||||||
|
float cellOriginDeltaY = (y - cellY) + cellOffsetY;
|
||||||
|
float cellOriginDistSq = cellOriginDeltaX * cellOriginDeltaX + cellOriginDeltaY * cellOriginDeltaY;
|
||||||
|
if (cellOriginDistSq > maxCellDistSq) continue; // Skip calculating cells too far away
|
||||||
|
float ampTmp = (float) ((cellOriginDistSq * maxCellDistSqRecip) - 1); float amp = ampTmp * ampTmp; // Decrease cell amplitude further away
|
||||||
|
cumAmp += amp;
|
||||||
|
float directionalStrength = dot(cellOriginDeltaX, cellOriginDeltaY, dirX, dirY) * TAU;
|
||||||
|
noise += (float) (MathUtil.cos(directionalStrength) * amp);
|
||||||
|
float sinAngle = (float) MathUtil.sin(directionalStrength) * amp;
|
||||||
|
dirOutX -= sinAngle * (cellOriginDeltaX + dirX);
|
||||||
|
dirOutY -= sinAngle * (cellOriginDeltaY + dirY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (averageErosionImpulses && cumAmp != 0) {
|
||||||
|
noise /= cumAmp;
|
||||||
|
dirOutX /= cumAmp;
|
||||||
|
dirOutY /= cumAmp;
|
||||||
|
}
|
||||||
|
return new float[] {noise, dirOutX, dirOutY};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double exp(double val) {
|
||||||
|
final long tmp = (long) (1512775 * val + 1072632447);
|
||||||
|
return Double.longBitsToDouble(tmp << 32);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float smoothstep(float edge0, float edge1, float x) {
|
||||||
|
// Scale, bias and saturate x to 0..1 range
|
||||||
|
x = clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
|
||||||
|
// Evaluate polynomial
|
||||||
|
return x * x * (3 - 2 * x);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float clamp(float x, float minVal, float maxVal) {
|
||||||
|
return Math.max(minVal, Math.min(maxVal, x));
|
||||||
|
}
|
||||||
|
|
||||||
|
public float heightMap(long seed, float x, float y) {
|
||||||
|
double[] sample = sampler.noised(seed, x, y);
|
||||||
|
float height = (float) sample[0];
|
||||||
|
float heightDirX = (float) sample[1];
|
||||||
|
float heightDirY = (float) sample[2];
|
||||||
|
|
||||||
|
// Take the curl of the normal to get the gradient facing down the slope
|
||||||
|
float baseDirX = heightDirY * (float) slopeStrength;
|
||||||
|
float baseDirY = -heightDirX * (float) slopeStrength;
|
||||||
|
|
||||||
|
float erosion = 0.0f;
|
||||||
|
float dirX = 0.0f;
|
||||||
|
float dirY = 0.0f;
|
||||||
|
float amp = 1.0f;
|
||||||
|
float cumAmp = 0.0f;
|
||||||
|
float freq = 1.0f;
|
||||||
|
|
||||||
|
// Stack erosion octaves
|
||||||
|
for (int i = 0; i < octaves; i++) {
|
||||||
|
float[] erosionResult = erosion(
|
||||||
|
x * freq * (float) erosionFrequency,
|
||||||
|
y * freq * (float) erosionFrequency,
|
||||||
|
baseDirX + dirY * (float) branchStrength,
|
||||||
|
baseDirY - dirX * (float) branchStrength);
|
||||||
|
erosion += erosionResult[0] * amp;
|
||||||
|
dirX += erosionResult[1] * amp * freq;
|
||||||
|
dirY += erosionResult[2] * amp * freq;
|
||||||
|
cumAmp += amp;
|
||||||
|
amp *= gain;
|
||||||
|
freq *= lacunarity;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO - Test different output ranges, see how they affect visuals
|
||||||
|
// Normalize erosion noise
|
||||||
|
erosion /= cumAmp;
|
||||||
|
// [-1, 1] -> [0, 1]
|
||||||
|
erosion = erosion * 0.5F + 0.5F;
|
||||||
|
|
||||||
|
// Without masking, erosion noise in areas with small gradients tend to produce mounds,
|
||||||
|
// this reduces erosion amplitude towards smaller gradients to avoid this
|
||||||
|
if (slopeMask) {
|
||||||
|
float dirMagSq = dot(baseDirX, baseDirY, baseDirX, baseDirY);
|
||||||
|
float flatness = smoothstep((float) slopeMaskNoneSq, (float) slopeMaskFullSq, dirMagSq);
|
||||||
|
erosion *= flatness;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (float) (height + erosion * erosionStrength);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float dot(float x1, float y1, float x2, float y2) {
|
||||||
|
return x1 * x2 + y1 * y2;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double noise(long seed, double x, double y) {
|
||||||
|
return heightMap(seed, (float) x, (float) y);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double noise(long seed, double x, double y, double z) {
|
||||||
|
return noise(seed, x, z);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,41 @@
|
|||||||
|
package com.dfsek.terra.api.noise;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A NoiseSampler which additionally may provide a 1st directional derivative
|
||||||
|
*/
|
||||||
|
public interface DerivativeNoiseSampler extends NoiseSampler {
|
||||||
|
|
||||||
|
static boolean isDifferentiable(NoiseSampler sampler) {
|
||||||
|
if (sampler instanceof DerivativeNoiseSampler dSampler) {
|
||||||
|
return dSampler.isDifferentiable();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Samplers may or may not be able to provide a derivative depending on what
|
||||||
|
* inputs they take, this method signals whether this is the case.
|
||||||
|
*
|
||||||
|
* @return If the noise sampler provides a derivative or not
|
||||||
|
*/
|
||||||
|
boolean isDifferentiable();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Derivative return version of standard 2D noise evaluation
|
||||||
|
* @param seed
|
||||||
|
* @param x
|
||||||
|
* @param y
|
||||||
|
* @return 3 element array, in index order: noise value, partial x derivative, partial y derivative
|
||||||
|
*/
|
||||||
|
double[] noised(long seed, double x, double y);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Derivative return version of standard 3D noise evaluation
|
||||||
|
* @param seed
|
||||||
|
* @param x
|
||||||
|
* @param y
|
||||||
|
* @param z
|
||||||
|
* @return 4 element array, in index order: noise value, partial x derivative, partial y derivative, partial z derivative
|
||||||
|
*/
|
||||||
|
double[] noised(long seed, double x, double y, double z);
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user