Skip to content

Commit 7e7917c

Browse files
committed
fast section sorting to fix remaining inter-section intra-region sorting issues stemming from bfs traversal with frustum not producing fully correct results
1 parent 66681e9 commit 7e7917c

File tree

2 files changed

+55
-7
lines changed

2 files changed

+55
-7
lines changed

common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/lists/ChunkRenderList.java

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
package net.caffeinemc.mods.sodium.client.render.chunk.lists;
22

3+
import net.caffeinemc.mods.sodium.client.render.chunk.LocalSectionIndex;
34
import net.caffeinemc.mods.sodium.client.render.chunk.RenderSection;
45
import net.caffeinemc.mods.sodium.client.render.chunk.RenderSectionFlags;
6+
import net.caffeinemc.mods.sodium.client.render.chunk.region.RenderRegion;
7+
import net.caffeinemc.mods.sodium.client.render.viewport.CameraTransform;
8+
import net.caffeinemc.mods.sodium.client.util.iterator.ByteArrayIterator;
59
import net.caffeinemc.mods.sodium.client.util.iterator.ByteIterator;
610
import net.caffeinemc.mods.sodium.client.util.iterator.ReversibleByteArrayIterator;
7-
import net.caffeinemc.mods.sodium.client.util.iterator.ByteArrayIterator;
8-
import net.caffeinemc.mods.sodium.client.render.chunk.region.RenderRegion;
11+
import net.minecraft.util.Mth;
912
import org.jetbrains.annotations.Nullable;
1013

1114
public class ChunkRenderList {
@@ -37,6 +40,39 @@ public void reset(int frame) {
3740
this.lastVisibleFrame = frame;
3841
}
3942

43+
// clamping the relative camera position to the region bounds means there can only be very few different distances
44+
private static final int SORTING_HISTOGRAM_SIZE = RenderRegion.REGION_WIDTH + RenderRegion.REGION_HEIGHT + RenderRegion.REGION_LENGTH - 2;
45+
46+
public void sortSections(CameraTransform transform, int[] sortItems) {
47+
var cameraX = Mth.clamp((transform.intX >> 4) - this.region.getChunkX(), 0, RenderRegion.REGION_WIDTH - 1);
48+
var cameraY = Mth.clamp((transform.intY >> 4) - this.region.getChunkY(), 0, RenderRegion.REGION_HEIGHT - 1);
49+
var cameraZ = Mth.clamp((transform.intZ >> 4) - this.region.getChunkZ(), 0, RenderRegion.REGION_LENGTH - 1);
50+
51+
int[] histogram = new int[SORTING_HISTOGRAM_SIZE];
52+
53+
for (int i = 0; i < this.sectionsWithGeometryCount; i++) {
54+
var index = this.sectionsWithGeometry[i] & 0xFF; // makes sure the byte -> int conversion is unsigned
55+
var x = Math.abs(LocalSectionIndex.unpackX(index) - cameraX);
56+
var y = Math.abs(LocalSectionIndex.unpackY(index) - cameraY);
57+
var z = Math.abs(LocalSectionIndex.unpackZ(index) - cameraZ);
58+
59+
var distance = x + y + z;
60+
histogram[distance]++;
61+
sortItems[i] = distance << 8 | index;
62+
}
63+
64+
// prefix sum to calculate indexes
65+
for (int i = 1; i < SORTING_HISTOGRAM_SIZE; i++) {
66+
histogram[i] += histogram[i - 1];
67+
}
68+
69+
for (int i = 0; i < this.sectionsWithGeometryCount; i++) {
70+
var item = sortItems[i];
71+
var distance = item >>> 8;
72+
this.sectionsWithGeometry[--histogram[distance]] = (byte) item;
73+
}
74+
}
75+
4076
public void add(RenderSection render) {
4177
if (this.size >= RenderRegion.REGION_SIZE) {
4278
throw new ArrayIndexOutOfBoundsException("Render list is full");

common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/lists/VisibleChunkCollector.java

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package net.caffeinemc.mods.sodium.client.render.chunk.lists;
22

3+
import it.unimi.dsi.fastutil.ints.IntArrays;
34
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
45
import net.caffeinemc.mods.sodium.client.render.chunk.ChunkUpdateType;
56
import net.caffeinemc.mods.sodium.client.render.chunk.RenderSection;
@@ -62,6 +63,8 @@ private void addToRebuildLists(RenderSection section) {
6263
}
6364
}
6465

66+
private static int[] sortItems = new int[RenderRegion.REGION_SIZE];
67+
6568
public SortedRenderLists createRenderLists(Viewport viewport) {
6669
// sort the regions by distance to fix rare region ordering bugs
6770
var transform = viewport.getTransform();
@@ -70,20 +73,29 @@ public SortedRenderLists createRenderLists(Viewport viewport) {
7073
var cameraZ = transform.intZ >> (4 + RenderRegion.REGION_LENGTH_SH);
7174
var size = this.sortedRenderLists.size();
7275

73-
var items = new int[size];
76+
if (sortItems.length < size) {
77+
sortItems = new int[size];
78+
}
79+
7480
for (var i = 0; i < size; i++) {
7581
var region = this.sortedRenderLists.get(i).getRegion();
7682
var x = Math.abs(region.getX() - cameraX);
7783
var y = Math.abs(region.getY() - cameraY);
7884
var z = Math.abs(region.getZ() - cameraZ);
79-
items[i] = (x + y + z) << 16 | i;
85+
sortItems[i] = (x + y + z) << 16 | i;
8086
}
8187

82-
Arrays.sort(items);
88+
IntArrays.unstableSort(sortItems, 0, size);
8389

8490
var sorted = new ObjectArrayList<ChunkRenderList>(size);
85-
for (var key : items) {
86-
sorted.add(this.sortedRenderLists.get(key & 0xFFFF));
91+
for (var i = 0; i < size; i++) {
92+
var key = sortItems[i];
93+
var renderList = this.sortedRenderLists.get(key & 0xFFFF);
94+
sorted.add(renderList);
95+
}
96+
97+
for (var list : sorted) {
98+
list.sortSections(transform, sortItems);
8799
}
88100

89101
return new SortedRenderLists(sorted);

0 commit comments

Comments
 (0)