mirror of
https://github.com/PolyhedralDev/Terra.git
synced 2026-02-16 10:30:42 +00:00
Implement cubic spline sampler
This commit is contained in:
@@ -14,6 +14,7 @@ import java.util.Map;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import com.dfsek.terra.addons.manifest.api.AddonInitializer;
|
||||
import com.dfsek.terra.addons.noise.config.CubicSplinePointTemplate;
|
||||
import com.dfsek.terra.addons.noise.config.DimensionApplicableNoiseSampler;
|
||||
import com.dfsek.terra.addons.noise.config.templates.BinaryArithmeticTemplate;
|
||||
import com.dfsek.terra.addons.noise.config.templates.DomainWarpTemplate;
|
||||
@@ -32,12 +33,14 @@ import com.dfsek.terra.addons.noise.config.templates.noise.fractal.BrownianMotio
|
||||
import com.dfsek.terra.addons.noise.config.templates.noise.fractal.PingPongTemplate;
|
||||
import com.dfsek.terra.addons.noise.config.templates.noise.fractal.RidgedFractalTemplate;
|
||||
import com.dfsek.terra.addons.noise.config.templates.normalizer.ClampNormalizerTemplate;
|
||||
import com.dfsek.terra.addons.noise.config.templates.normalizer.CubicSplineNormalizerTemplate;
|
||||
import com.dfsek.terra.addons.noise.config.templates.normalizer.ExpressionNormalizerTemplate;
|
||||
import com.dfsek.terra.addons.noise.config.templates.normalizer.LinearNormalizerTemplate;
|
||||
import com.dfsek.terra.addons.noise.config.templates.normalizer.NormalNormalizerTemplate;
|
||||
import com.dfsek.terra.addons.noise.config.templates.normalizer.PosterizationNormalizerTemplate;
|
||||
import com.dfsek.terra.addons.noise.config.templates.normalizer.ProbabilityNormalizerTemplate;
|
||||
import com.dfsek.terra.addons.noise.config.templates.normalizer.ScaleNormalizerTemplate;
|
||||
import com.dfsek.terra.addons.noise.math.CubicSpline;
|
||||
import com.dfsek.terra.addons.noise.samplers.arithmetic.AdditionSampler;
|
||||
import com.dfsek.terra.addons.noise.samplers.arithmetic.DivisionSampler;
|
||||
import com.dfsek.terra.addons.noise.samplers.arithmetic.MaxSampler;
|
||||
@@ -90,7 +93,8 @@ public class NoiseAddon implements AddonInitializer {
|
||||
.applyLoader(DistanceSampler.DistanceFunction.class,
|
||||
(type, o, loader, depthTracker) -> DistanceSampler.DistanceFunction.valueOf((String) o))
|
||||
.applyLoader(DimensionApplicableNoiseSampler.class, DimensionApplicableNoiseSampler::new)
|
||||
.applyLoader(FunctionTemplate.class, FunctionTemplate::new);
|
||||
.applyLoader(FunctionTemplate.class, FunctionTemplate::new)
|
||||
.applyLoader(CubicSpline.Point.class, CubicSplinePointTemplate::new);
|
||||
|
||||
noiseRegistry.register(addon.key("LINEAR"), LinearNormalizerTemplate::new);
|
||||
noiseRegistry.register(addon.key("NORMAL"), NormalNormalizerTemplate::new);
|
||||
@@ -98,6 +102,7 @@ public class NoiseAddon implements AddonInitializer {
|
||||
noiseRegistry.register(addon.key("PROBABILITY"), ProbabilityNormalizerTemplate::new);
|
||||
noiseRegistry.register(addon.key("SCALE"), ScaleNormalizerTemplate::new);
|
||||
noiseRegistry.register(addon.key("POSTERIZATION"), PosterizationNormalizerTemplate::new);
|
||||
noiseRegistry.register(addon.key("CUBIC_SPLINE"), CubicSplineNormalizerTemplate::new);
|
||||
|
||||
noiseRegistry.register(addon.key("IMAGE"), ImageSamplerTemplate::new);
|
||||
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.dfsek.terra.addons.noise.config;
|
||||
|
||||
import com.dfsek.tectonic.api.config.template.annotations.Value;
|
||||
import com.dfsek.tectonic.api.config.template.object.ObjectTemplate;
|
||||
|
||||
import com.dfsek.terra.addons.noise.math.CubicSpline.Point;
|
||||
import com.dfsek.terra.api.config.meta.Meta;
|
||||
|
||||
|
||||
public class CubicSplinePointTemplate implements ObjectTemplate<Point> {
|
||||
|
||||
@Value("from")
|
||||
private @Meta double from;
|
||||
|
||||
@Value("to")
|
||||
private @Meta double to;
|
||||
|
||||
@Value("gradient")
|
||||
private @Meta double gradient;
|
||||
|
||||
@Override
|
||||
public Point get() {
|
||||
return new Point(from, to, gradient);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package com.dfsek.terra.addons.noise.config.templates.normalizer;
|
||||
|
||||
import com.dfsek.tectonic.api.config.template.annotations.Value;
|
||||
|
||||
import com.dfsek.terra.addons.noise.math.CubicSpline;
|
||||
import com.dfsek.terra.addons.noise.math.CubicSpline.Point;
|
||||
import com.dfsek.terra.addons.noise.normalizer.CubicSplineNoiseSampler;
|
||||
import com.dfsek.terra.api.config.meta.Meta;
|
||||
import com.dfsek.terra.api.noise.NoiseSampler;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
public class CubicSplineNormalizerTemplate extends NormalizerTemplate<CubicSplineNoiseSampler> {
|
||||
|
||||
@Value("points")
|
||||
private @Meta List<@Meta Point> points;
|
||||
|
||||
@Override
|
||||
public NoiseSampler get() {
|
||||
return new CubicSplineNoiseSampler(function, new CubicSpline(points));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
package com.dfsek.terra.addons.noise.math;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
public class CubicSpline {
|
||||
|
||||
private final double[] fromValues;
|
||||
private final double[] toValues;
|
||||
private final double[] gradients;
|
||||
|
||||
public CubicSpline(List<Point> points) {
|
||||
Collections.sort(points);
|
||||
|
||||
this.fromValues = new double[points.size()];
|
||||
this.toValues = new double[points.size()];
|
||||
this.gradients = new double[points.size()];
|
||||
|
||||
for(int i = 0; i < points.size(); i++) {
|
||||
fromValues[i] = points.get(i).from;
|
||||
toValues[i] = points.get(i).to;
|
||||
gradients[i] = points.get(i).gradient;
|
||||
}
|
||||
}
|
||||
|
||||
public double apply(double in) {
|
||||
return calculate(in, fromValues, toValues, gradients);
|
||||
}
|
||||
|
||||
public static double calculate(double in, double[] fromValues, double[] toValues, double[] gradients) {
|
||||
int pointIdx = floorBinarySearch(in, fromValues) - 1;
|
||||
|
||||
int pointIdxLast = fromValues.length - 1;
|
||||
|
||||
if (pointIdx < 0) { // If to left of first point return linear function intersecting said point using point's gradient
|
||||
return gradients[0] * (in - fromValues[0]) + toValues[0];
|
||||
} else if (pointIdx == pointIdxLast) { // Do same if to right of last point
|
||||
return gradients[pointIdxLast] * (in - fromValues[pointIdxLast]) + toValues[pointIdxLast];
|
||||
} else {
|
||||
double fromLeft = fromValues[pointIdx];
|
||||
double fromRight = fromValues[pointIdx + 1];
|
||||
|
||||
double toLeft = toValues[pointIdx];
|
||||
double toRight = toValues[pointIdx + 1];
|
||||
|
||||
double gradientLeft = gradients[pointIdx];
|
||||
double gradientRight = gradients[pointIdx + 1];
|
||||
|
||||
double fromDelta = fromRight - fromLeft;
|
||||
double toDelta = toRight - toLeft;
|
||||
|
||||
double t = (in - fromLeft) / fromDelta;
|
||||
|
||||
return lerp(t, toLeft, toRight) + t * (1.0F - t) * lerp(t, gradientLeft * fromDelta - toDelta, -gradientRight * fromDelta + toDelta);
|
||||
}
|
||||
}
|
||||
|
||||
private static int floorBinarySearch(double targetValue, double[] values) {
|
||||
int left = 0;
|
||||
int right = values.length;
|
||||
int idx = right - left;
|
||||
while (idx > 0) {
|
||||
int halfDelta = idx / 2;
|
||||
int mid = left + halfDelta;
|
||||
if (targetValue < values[mid]) {
|
||||
idx = halfDelta;
|
||||
} else {
|
||||
left = mid + 1;
|
||||
idx -= halfDelta + 1;
|
||||
}
|
||||
}
|
||||
return left;
|
||||
}
|
||||
|
||||
private static double lerp(double t, double a, double b) {
|
||||
return a + t * (b - a);
|
||||
}
|
||||
|
||||
public record Point(double from, double to, double gradient) implements Comparable<Point> {
|
||||
|
||||
@Override
|
||||
public int compareTo(@NotNull CubicSpline.Point o) {
|
||||
return Double.compare(from, o.from);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.dfsek.terra.addons.noise.normalizer;
|
||||
|
||||
import com.dfsek.terra.addons.noise.math.CubicSpline;
|
||||
import com.dfsek.terra.api.noise.NoiseSampler;
|
||||
|
||||
|
||||
public class CubicSplineNoiseSampler extends Normalizer {
|
||||
|
||||
private final CubicSpline spline;
|
||||
|
||||
public CubicSplineNoiseSampler(NoiseSampler sampler, CubicSpline spline) {
|
||||
super(sampler);
|
||||
this.spline = spline;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double normalize(double in) {
|
||||
return spline.apply(in);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user