mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2026-10-19 06:54:45 +00:00
Merged river lookup batching
- Post processing reuses river-weight samples across neighboring columns
This commit is contained in:
@@ -54,43 +54,44 @@ public class IrisPostModifier extends EngineAssignedModifier<NativeBlockState> {
|
||||
int depth = output.getDepth();
|
||||
int planeWidth = width + 2;
|
||||
int[] heights = heightPlane(x, z, width, depth, planeWidth);
|
||||
boolean[] rivers = riverPlane(getComplex().getRiverCarveWeightStream(), x, z, width, depth);
|
||||
IrisDimension dimension = getDimension();
|
||||
boolean walls = dimension.isPostProcessingWalls();
|
||||
boolean slabs = dimension.isPostProcessingSlabs();
|
||||
for (int i = 0; i < width; i++) {
|
||||
for (int j = 0; j < depth; j++) {
|
||||
post(i, j, sync, i + x, j + z, context, heights, planeWidth, walls, slabs);
|
||||
post(i, j, sync, i + x, j + z, context, heights, rivers, planeWidth, walls, slabs);
|
||||
}
|
||||
}
|
||||
|
||||
getEngine().getMetrics().getPost().put(p.getMilliseconds());
|
||||
}
|
||||
|
||||
static boolean[] riverPlane(ProceduralStream<Double> carveWeights, int x, int z, int width, int depth) {
|
||||
int planeWidth = width + 2;
|
||||
boolean[] rivers = new boolean[planeWidth * (depth + 2)];
|
||||
for (int j = -1; j <= depth; j++) {
|
||||
boolean edge = j == -1 || j == depth;
|
||||
int from = edge ? 0 : -1;
|
||||
int to = edge ? width - 1 : width;
|
||||
int row = (j + 1) * planeWidth;
|
||||
for (int i = from; i <= to; i++) {
|
||||
rivers[row + i + 1] = carveWeights.get(x + i, z + j) > 0D;
|
||||
}
|
||||
}
|
||||
return rivers;
|
||||
}
|
||||
|
||||
static boolean skipsHydrologyColumn(boolean[] rivers, int center, int planeWidth) {
|
||||
return rivers[center] || rivers[center + 1] || rivers[center - 1]
|
||||
|| rivers[center + planeWidth] || rivers[center - planeWidth];
|
||||
}
|
||||
|
||||
/**
|
||||
* Every column reads its own height plus its four neighbours, so adjacent columns would otherwise
|
||||
* resolve the same height stream entry up to five times. Resolve the padded plane once instead. The
|
||||
* four diagonal corners are never read, so they are left unresolved.
|
||||
*/
|
||||
private boolean riverColumn(int x, int z) {
|
||||
ProceduralStream<Double> carveWeights = getComplex().getRiverCarveWeightStream();
|
||||
return skipsHydrologyColumn(new double[] {
|
||||
carveWeights.get(x, z),
|
||||
carveWeights.get(x + 1, z),
|
||||
carveWeights.get(x - 1, z),
|
||||
carveWeights.get(x, z + 1),
|
||||
carveWeights.get(x, z - 1)
|
||||
});
|
||||
}
|
||||
|
||||
static boolean skipsHydrologyColumn(double[] carveWeights) {
|
||||
for (double weight : carveWeights) {
|
||||
if (weight > 0D) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private int[] heightPlane(int x, int z, int width, int depth, int planeWidth) {
|
||||
int[] heights = new int[planeWidth * (depth + 2)];
|
||||
EngineMantle mantle = getEngine().getMantle();
|
||||
@@ -109,7 +110,7 @@ public class IrisPostModifier extends EngineAssignedModifier<NativeBlockState> {
|
||||
return heights;
|
||||
}
|
||||
|
||||
private void post(int currentPostX, int currentPostZ, Hunk<NativeBlockState> currentData, int x, int z, ChunkContext context, int[] heights, int planeWidth, boolean walls, boolean slabs) {
|
||||
private void post(int currentPostX, int currentPostZ, Hunk<NativeBlockState> currentData, int x, int z, ChunkContext context, int[] heights, boolean[] rivers, int planeWidth, boolean walls, boolean slabs) {
|
||||
// x/z are world coordinates, the hunk is indexed relative to this chunk origin.
|
||||
int originX = x - currentPostX;
|
||||
int originZ = z - currentPostZ;
|
||||
@@ -120,7 +121,7 @@ public class IrisPostModifier extends EngineAssignedModifier<NativeBlockState> {
|
||||
int hc = heights[center - 1];
|
||||
int hd = heights[center - planeWidth];
|
||||
int fluidHeight = (int) Math.round(getComplex().getRiverWaterSurfaceStream().get(x, z));
|
||||
boolean river = riverColumn(x, z);
|
||||
boolean river = skipsHydrologyColumn(rivers, center, planeWidth);
|
||||
|
||||
// Floating Nibs
|
||||
int g = 0;
|
||||
|
||||
+71
-4
@@ -1,20 +1,87 @@
|
||||
package art.arcane.iris.generation.stage;
|
||||
|
||||
import art.arcane.volmlib.util.stream.ProceduralStream;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class IrisPostModifierHydrologyTest {
|
||||
@Test
|
||||
public void columnsTouchingARiverFootprintSkipThePostPasses() {
|
||||
assertTrue(IrisPostModifier.skipsHydrologyColumn(new double[] {1D, 0D, 0D, 0D, 0D}));
|
||||
assertTrue(IrisPostModifier.skipsHydrologyColumn(new double[] {0D, 0D, 0.5D, 0D, 0D}));
|
||||
assertTrue(IrisPostModifier.skipsHydrologyColumn(new double[] {0D, 0D, 0D, 0D, 0.75D}));
|
||||
for (int index : new int[] {4, 3, 5, 1, 7}) {
|
||||
boolean[] rivers = new boolean[9];
|
||||
rivers[index] = true;
|
||||
assertTrue(IrisPostModifier.skipsHydrologyColumn(rivers, 4, 3));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void columnsAwayFromRiversKeepThePostPasses() {
|
||||
assertFalse(IrisPostModifier.skipsHydrologyColumn(new double[] {0D, 0D, 0D, 0D, 0D}));
|
||||
boolean[] rivers = new boolean[9];
|
||||
rivers[0] = true;
|
||||
rivers[2] = true;
|
||||
rivers[6] = true;
|
||||
rivers[8] = true;
|
||||
assertFalse(IrisPostModifier.skipsHydrologyColumn(rivers, 4, 3));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void paddedPlaneSamplesEachRequiredCoordinateOnce() {
|
||||
Map<Long, Integer> samples = new HashMap<>();
|
||||
ProceduralStream<Double> stream = ProceduralStream.ofDouble((x, z) -> {
|
||||
long key = ((long) (int) x << 32) | ((int) z & 0xffffffffL);
|
||||
samples.merge(key, 1, Integer::sum);
|
||||
return weight((int) x, (int) z);
|
||||
});
|
||||
boolean[] rivers = IrisPostModifier.riverPlane(stream, -32, 48, 16, 16);
|
||||
assertEquals(320, samples.size());
|
||||
for (int count : samples.values()) {
|
||||
assertEquals(1, count);
|
||||
}
|
||||
assertPlaneMatchesPointSampling(rivers, -32, 48, 16, 16);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void rectangularPlanesPreservePositiveWeightRules() {
|
||||
ProceduralStream<Double> stream = ProceduralStream.ofDouble((x, z) -> weight((int) x, (int) z));
|
||||
for (int width : new int[] {1, 3, 16}) {
|
||||
for (int depth : new int[] {1, 5, 16}) {
|
||||
boolean[] rivers = IrisPostModifier.riverPlane(stream, -19, -37, width, depth);
|
||||
assertPlaneMatchesPointSampling(rivers, -19, -37, width, depth);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void assertPlaneMatchesPointSampling(boolean[] rivers, int x, int z, int width, int depth) {
|
||||
int planeWidth = width + 2;
|
||||
for (int localX = 0; localX < width; localX++) {
|
||||
for (int localZ = 0; localZ < depth; localZ++) {
|
||||
int worldX = x + localX;
|
||||
int worldZ = z + localZ;
|
||||
boolean expected = weight(worldX, worldZ) > 0D || weight(worldX + 1, worldZ) > 0D
|
||||
|| weight(worldX - 1, worldZ) > 0D || weight(worldX, worldZ + 1) > 0D
|
||||
|| weight(worldX, worldZ - 1) > 0D;
|
||||
assertEquals(expected, IrisPostModifier.skipsHydrologyColumn(rivers,
|
||||
(localZ + 1) * planeWidth + localX + 1, planeWidth));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static double weight(int x, int z) {
|
||||
return switch (Math.floorMod(x * 31 + z * 17, 8)) {
|
||||
case 0 -> Double.NaN;
|
||||
case 1 -> -1D;
|
||||
case 2 -> 0D;
|
||||
case 3 -> -0D;
|
||||
case 4 -> Double.MIN_VALUE;
|
||||
case 5 -> 1D;
|
||||
case 6 -> Double.POSITIVE_INFINITY;
|
||||
default -> Double.NEGATIVE_INFINITY;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -91,9 +91,9 @@ public class IrisPostModifierSlabSupportTest {
|
||||
heights[2 * PLANE_WIDTH + 3] = SURFACE + 1;
|
||||
|
||||
Method post = IrisPostModifier.class.getDeclaredMethod("post", int.class, int.class, Hunk.class,
|
||||
int.class, int.class, ChunkContext.class, int[].class, int.class, boolean.class, boolean.class);
|
||||
int.class, int.class, ChunkContext.class, int[].class, boolean[].class, int.class, boolean.class, boolean.class);
|
||||
post.setAccessible(true);
|
||||
post.invoke(modifier, 1, 1, output, 1, 1, context, heights, PLANE_WIDTH, false, true);
|
||||
post.invoke(modifier, 1, 1, output, 1, 1, context, heights, new boolean[heights.length], PLANE_WIDTH, false, true);
|
||||
return output.get(1, SURFACE + 1, 1);
|
||||
}
|
||||
|
||||
|
||||
+3
-2
@@ -123,9 +123,10 @@ public class IrisPostModifierWallShoreTest {
|
||||
heights[5] = SURFACE - 4;
|
||||
|
||||
Method post = IrisPostModifier.class.getDeclaredMethod("post", int.class, int.class, Hunk.class,
|
||||
int.class, int.class, ChunkContext.class, int[].class, int.class, boolean.class, boolean.class);
|
||||
int.class, int.class, ChunkContext.class, int[].class, boolean[].class, int.class, boolean.class, boolean.class);
|
||||
post.setAccessible(true);
|
||||
post.invoke(modifier, 0, 0, data, 0, 0, context, heights, PLANE_WIDTH, walls, false);
|
||||
boolean[] rivers = IrisPostModifier.riverPlane(carveWeights, 0, 0, PLANE_WIDTH - 2, PLANE_WIDTH - 2);
|
||||
post.invoke(modifier, 0, 0, data, 0, 0, context, heights, rivers, PLANE_WIDTH, walls, false);
|
||||
return data.get(0, SURFACE, 0);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user