From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Martijn Muijsers Date: Wed, 30 Nov 2022 19:49:14 +0100 Subject: [PATCH] Optimize noise generation License: MIT (https://opensource.org/licenses/MIT) Gale - https://galemc.org This patch is based on the following mixins: * "com/ishland/c2me/opts/math/mixin/MixinOctavePerlinNoiseSampler.java" * "com/ishland/c2me/opts/math/mixin/MixinPerlinNoiseSampler.java" By: ishland As part of: C2ME (https://github.com/RelativityMC/C2ME-fabric) Licensed under: MIT (https://opensource.org/licenses/MIT) diff --git a/net/minecraft/world/level/levelgen/synth/ImprovedNoise.java b/net/minecraft/world/level/levelgen/synth/ImprovedNoise.java index fb11a2eea540d55e50eab59f9857ca5d99f556f8..dcc1a3f8b611c9f103b848db90b077b984b60ada 100644 --- a/net/minecraft/world/level/levelgen/synth/ImprovedNoise.java +++ b/net/minecraft/world/level/levelgen/synth/ImprovedNoise.java @@ -11,6 +11,27 @@ public final class ImprovedNoise { public final double yo; public final double zo; + // Gale start - C2ME - optimize noise generation + private static final double[] FLAT_SIMPLEX_GRAD = new double[]{ + 1, 1, 0, 0, + -1, 1, 0, 0, + 1, -1, 0, 0, + -1, -1, 0, 0, + 1, 0, 1, 0, + -1, 0, 1, 0, + 1, 0, -1, 0, + -1, 0, -1, 0, + 0, 1, 1, 0, + 0, -1, 1, 0, + 0, 1, -1, 0, + 0, -1, -1, 0, + 1, 1, 0, 0, + 0, -1, 1, 0, + -1, 1, 0, 0, + 0, -1, -1, 0, + }; + // Gale end - C2ME - optimize noise generation + public ImprovedNoise(RandomSource random) { this.xo = random.nextDouble() * 256.0; this.yo = random.nextDouble() * 256.0; @@ -38,9 +59,11 @@ public final class ImprovedNoise { double d = x + this.xo; double d1 = y + this.yo; double d2 = z + this.zo; - int floor = Mth.floor(d); - int floor1 = Mth.floor(d1); - int floor2 = Mth.floor(d2); + // Gale start - C2ME - optimize noise generation - optimize: remove frequent type conversions + double floor = Math.floor(d); + double floor1 = Math.floor(d1); + double floor2 = Math.floor(d2); + // Gale end - C2ME - optimize noise generation - optimize: remove frequent type conversions double d3 = d - floor; double d4 = d1 - floor1; double d5 = d2 - floor2; @@ -53,25 +76,27 @@ public final class ImprovedNoise { d6 = d4; } - d7 = Mth.floor(d6 / yScale + 1.0E-7F) * yScale; + d7 = Math.floor(d6 / yScale + 1.0E-7F) * yScale; // Gale - C2ME - optimize noise generation - optimize: remove frequent type conversions } else { d7 = 0.0; } - return this.sampleAndLerp(floor, floor1, floor2, d3, d4 - d7, d5, d4); + return this.sampleAndLerp((int) floor, (int) floor1, (int) floor2, d3, d4 - d7, d5, d4); // Gale - C2ME - optimize noise generation - optimize: remove frequent type conversions } public double noiseWithDerivative(double x, double y, double z, double[] values) { double d = x + this.xo; double d1 = y + this.yo; double d2 = z + this.zo; - int floor = Mth.floor(d); - int floor1 = Mth.floor(d1); - int floor2 = Mth.floor(d2); + // Gale start - C2ME - optimize noise generation - optimize: remove frequent type conversions + double floor = Math.floor(d); + double floor1 = Math.floor(d1); + double floor2 = Math.floor(d2); + // Gale end - C2ME - optimize noise generation - optimize: remove frequent type conversions double d3 = d - floor; double d4 = d1 - floor1; double d5 = d2 - floor2; - return this.sampleWithDerivative(floor, floor1, floor2, d3, d4, d5, values); + return this.sampleWithDerivative((int) floor, (int) floor1, (int) floor2, d3, d4, d5, values); // Gale - C2ME - optimize noise generation - optimize: remove frequent type conversions } private static double gradDot(int gradIndex, double xFactor, double yFactor, double zFactor) { @@ -83,24 +108,69 @@ public final class ImprovedNoise { } private double sampleAndLerp(int gridX, int gridY, int gridZ, double deltaX, double weirdDeltaY, double deltaZ, double deltaY) { - int i = this.p(gridX); - int i1 = this.p(gridX + 1); - int i2 = this.p(i + gridY); - int i3 = this.p(i + gridY + 1); - int i4 = this.p(i1 + gridY); - int i5 = this.p(i1 + gridY + 1); - double d = gradDot(this.p(i2 + gridZ), deltaX, weirdDeltaY, deltaZ); - double d1 = gradDot(this.p(i4 + gridZ), deltaX - 1.0, weirdDeltaY, deltaZ); - double d2 = gradDot(this.p(i3 + gridZ), deltaX, weirdDeltaY - 1.0, deltaZ); - double d3 = gradDot(this.p(i5 + gridZ), deltaX - 1.0, weirdDeltaY - 1.0, deltaZ); - double d4 = gradDot(this.p(i2 + gridZ + 1), deltaX, weirdDeltaY, deltaZ - 1.0); - double d5 = gradDot(this.p(i4 + gridZ + 1), deltaX - 1.0, weirdDeltaY, deltaZ - 1.0); - double d6 = gradDot(this.p(i3 + gridZ + 1), deltaX, weirdDeltaY - 1.0, deltaZ - 1.0); - double d7 = gradDot(this.p(i5 + gridZ + 1), deltaX - 1.0, weirdDeltaY - 1.0, deltaZ - 1.0); - double d8 = Mth.smoothstep(deltaX); - double d9 = Mth.smoothstep(deltaY); - double d10 = Mth.smoothstep(deltaZ); - return Mth.lerp3(d8, d9, d10, d, d1, d2, d3, d4, d5, d6, d7); + // Gale start - C2ME - optimize noise generation - inline math & small optimization: remove frequent type conversions and redundant ops + final int var0 = gridX & 0xFF; + final int var1 = (gridX + 1) & 0xFF; + final int var2 = this.p[var0] & 0xFF; + final int var3 = this.p[var1] & 0xFF; + final int var4 = (var2 + gridY) & 0xFF; + final int var5 = (var3 + gridY) & 0xFF; + final int var6 = (var2 + gridY + 1) & 0xFF; + final int var7 = (var3 + gridY + 1) & 0xFF; + final int var8 = this.p[var4] & 0xFF; + final int var9 = this.p[var5] & 0xFF; + final int var10 = this.p[var6] & 0xFF; + final int var11 = this.p[var7] & 0xFF; + + final int var12 = (var8 + gridZ) & 0xFF; + final int var13 = (var9 + gridZ) & 0xFF; + final int var14 = (var10 + gridZ) & 0xFF; + final int var15 = (var11 + gridZ) & 0xFF; + final int var16 = (var8 + gridZ + 1) & 0xFF; + final int var17 = (var9 + gridZ + 1) & 0xFF; + final int var18 = (var10 + gridZ + 1) & 0xFF; + final int var19 = (var11 + gridZ + 1) & 0xFF; + final int var20 = (this.p[var12] & 15) << 2; + final int var21 = (this.p[var13] & 15) << 2; + final int var22 = (this.p[var14] & 15) << 2; + final int var23 = (this.p[var15] & 15) << 2; + final int var24 = (this.p[var16] & 15) << 2; + final int var25 = (this.p[var17] & 15) << 2; + final int var26 = (this.p[var18] & 15) << 2; + final int var27 = (this.p[var19] & 15) << 2; + final double var60 = deltaX - 1.0; + final double var61 = weirdDeltaY - 1.0; + final double var62 = deltaZ - 1.0; + final double var87 = FLAT_SIMPLEX_GRAD[(var20) | 0] * deltaX + FLAT_SIMPLEX_GRAD[(var20) | 1] * weirdDeltaY + FLAT_SIMPLEX_GRAD[(var20) | 2] * deltaZ; + final double var88 = FLAT_SIMPLEX_GRAD[(var21) | 0] * var60 + FLAT_SIMPLEX_GRAD[(var21) | 1] * weirdDeltaY + FLAT_SIMPLEX_GRAD[(var21) | 2] * deltaZ; + final double var89 = FLAT_SIMPLEX_GRAD[(var22) | 0] * deltaX + FLAT_SIMPLEX_GRAD[(var22) | 1] * var61 + FLAT_SIMPLEX_GRAD[(var22) | 2] * deltaZ; + final double var90 = FLAT_SIMPLEX_GRAD[(var23) | 0] * var60 + FLAT_SIMPLEX_GRAD[(var23) | 1] * var61 + FLAT_SIMPLEX_GRAD[(var23) | 2] * deltaZ; + final double var91 = FLAT_SIMPLEX_GRAD[(var24) | 0] * deltaX + FLAT_SIMPLEX_GRAD[(var24) | 1] * weirdDeltaY + FLAT_SIMPLEX_GRAD[(var24) | 2] * var62; + final double var92 = FLAT_SIMPLEX_GRAD[(var25) | 0] * var60 + FLAT_SIMPLEX_GRAD[(var25) | 1] * weirdDeltaY + FLAT_SIMPLEX_GRAD[(var25) | 2] * var62; + final double var93 = FLAT_SIMPLEX_GRAD[(var26) | 0] * deltaX + FLAT_SIMPLEX_GRAD[(var26) | 1] * var61 + FLAT_SIMPLEX_GRAD[(var26) | 2] * var62; + final double var94 = FLAT_SIMPLEX_GRAD[(var27) | 0] * var60 + FLAT_SIMPLEX_GRAD[(var27) | 1] * var61 + FLAT_SIMPLEX_GRAD[(var27) | 2] * var62; + + final double var95 = deltaX * 6.0 - 15.0; + final double var96 = deltaY * 6.0 - 15.0; + final double var97 = deltaZ * 6.0 - 15.0; + final double var98 = deltaX * var95 + 10.0; + final double var99 = deltaY * var96 + 10.0; + final double var100 = deltaZ * var97 + 10.0; + final double var101 = deltaX * deltaX * deltaX * var98; + final double var102 = deltaY * deltaY * deltaY * var99; + final double var103 = deltaZ * deltaZ * deltaZ * var100; + + final double var113 = var87 + var101 * (var88 - var87); + final double var114 = var93 + var101 * (var94 - var93); + final double var115 = var91 + var101 * (var92 - var91); + final double var116 = var89 + var101 * (var90 - var89); + final double var117 = var114 - var115; + final double var118 = var102 * (var116 - var113); + final double var119 = var102 * var117; + final double var120 = var113 + var118; + final double var121 = var115 + var119; + return var120 + (var103 * (var121 - var120)); + // Gale end - C2ME - optimize noise generation - inline math & small optimization: remove frequent type conversions and redundant ops } private double sampleWithDerivative(int gridX, int gridY, int gridZ, double deltaX, double deltaY, double deltaZ, double[] noiseValues) { diff --git a/net/minecraft/world/level/levelgen/synth/PerlinNoise.java b/net/minecraft/world/level/levelgen/synth/PerlinNoise.java index da3c26fbad32d75d71f7e59c8c3341316a754756..797368070540d78981cfeef82f9820ae6ef4b676 100644 --- a/net/minecraft/world/level/levelgen/synth/PerlinNoise.java +++ b/net/minecraft/world/level/levelgen/synth/PerlinNoise.java @@ -26,6 +26,10 @@ public class PerlinNoise { private final double lowestFreqValueFactor; private final double lowestFreqInputFactor; private final double maxValue; + // Gale start - C2ME - optimize noise generation + private final int octaveSamplersCount; + private final double [] amplitudesArray; + // Gale end - C2ME - optimize noise generation @Deprecated public static PerlinNoise createLegacyForBlendedNoise(RandomSource random, IntStream octaves) { @@ -127,6 +131,10 @@ public class PerlinNoise { this.lowestFreqInputFactor = Math.pow(2.0, -i); this.lowestFreqValueFactor = Math.pow(2.0, size - 1) / (Math.pow(2.0, size) - 1.0); this.maxValue = this.edgeValue(2.0); + // Gale start - C2ME - optimize noise generation + this.octaveSamplersCount = this.noiseLevels.length; + this.amplitudesArray = this.amplitudes.toDoubleArray(); + // Gale end - C2ME - optimize noise generation } protected double maxValue() { @@ -138,7 +146,27 @@ public class PerlinNoise { } public double getValue(double x, double y, double z) { - return this.getValue(x, y, z, 0.0, 0.0, false); + // Gale start - C2ME - optimize noise generation - optimize for common cases + double d = 0.0; + double e = this.lowestFreqInputFactor; + double f = this.lowestFreqValueFactor; + + for (int i = 0; i < this.octaveSamplersCount; ++i) { + ImprovedNoise perlinNoiseSampler = this.noiseLevels[i]; + if (perlinNoiseSampler != null) { + @SuppressWarnings("deprecation") + double g = perlinNoiseSampler.noise( + wrap(x * e), wrap(y * e), wrap(z * e), 0.0, 0.0 + ); + d += this.amplitudesArray[i] * g * f; + } + + e *= 2.0; + f /= 2.0; + } + + return d; + // Gale end - C2ME - optimize noise generation - optimize for common cases } @Deprecated @@ -187,7 +215,7 @@ public class PerlinNoise { } public static double wrap(double value) { - return value - Mth.lfloor(value / 3.3554432E7 + 0.5) * 3.3554432E7; + return value - Math.floor(value / 3.3554432E7 + 0.5) * 3.3554432E7; // Gale - C2ME - optimize noise generation } protected int firstOctave() {