Skip to content

Commit

Permalink
fast section sorting to fix remaining inter-section intra-region sort…
Browse files Browse the repository at this point in the history
…ing issues stemming from bfs traversal with frustum not producing fully correct results
  • Loading branch information
douira committed Oct 3, 2024
1 parent 67ca404 commit 6771c61
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 7 deletions.
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
package net.caffeinemc.mods.sodium.client.render.chunk.lists;

import net.caffeinemc.mods.sodium.client.render.chunk.LocalSectionIndex;
import net.caffeinemc.mods.sodium.client.render.chunk.RenderSection;
import net.caffeinemc.mods.sodium.client.render.chunk.RenderSectionFlags;
import net.caffeinemc.mods.sodium.client.render.chunk.region.RenderRegion;
import net.caffeinemc.mods.sodium.client.render.viewport.CameraTransform;
import net.caffeinemc.mods.sodium.client.util.iterator.ByteArrayIterator;
import net.caffeinemc.mods.sodium.client.util.iterator.ByteIterator;
import net.caffeinemc.mods.sodium.client.util.iterator.ReversibleByteArrayIterator;
import net.caffeinemc.mods.sodium.client.util.iterator.ByteArrayIterator;
import net.caffeinemc.mods.sodium.client.render.chunk.region.RenderRegion;
import net.minecraft.util.Mth;
import org.jetbrains.annotations.Nullable;

public class ChunkRenderList {
Expand Down Expand Up @@ -37,6 +40,39 @@ public void reset(int frame) {
this.lastVisibleFrame = frame;
}

// clamping the relative camera position to the region bounds means there can only be very few different distances
private static final int SORTING_HISTOGRAM_SIZE = RenderRegion.REGION_WIDTH + RenderRegion.REGION_HEIGHT + RenderRegion.REGION_LENGTH - 2;

public void sortSections(CameraTransform transform, int[] sortItems) {
var cameraX = Mth.clamp((transform.intX >> 4) - this.region.getChunkX(), 0, RenderRegion.REGION_WIDTH - 1);
var cameraY = Mth.clamp((transform.intY >> 4) - this.region.getChunkY(), 0, RenderRegion.REGION_HEIGHT - 1);
var cameraZ = Mth.clamp((transform.intZ >> 4) - this.region.getChunkZ(), 0, RenderRegion.REGION_LENGTH - 1);

int[] histogram = new int[SORTING_HISTOGRAM_SIZE];

for (int i = 0; i < this.sectionsWithGeometryCount; i++) {
var index = this.sectionsWithGeometry[i] & 0xFF; // makes sure the byte -> int conversion is unsigned
var x = Math.abs(LocalSectionIndex.unpackX(index) - cameraX);
var y = Math.abs(LocalSectionIndex.unpackY(index) - cameraY);
var z = Math.abs(LocalSectionIndex.unpackZ(index) - cameraZ);

var distance = x + y + z;
histogram[distance]++;
sortItems[i] = distance << 8 | index;
}

// prefix sum to calculate indexes
for (int i = 1; i < SORTING_HISTOGRAM_SIZE; i++) {
histogram[i] += histogram[i - 1];
}

for (int i = 0; i < this.sectionsWithGeometryCount; i++) {
var item = sortItems[i];
var distance = item >>> 8;
this.sectionsWithGeometry[--histogram[distance]] = (byte) item;
}
}

public void add(RenderSection render) {
if (this.size >= RenderRegion.REGION_SIZE) {
throw new ArrayIndexOutOfBoundsException("Render list is full");
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package net.caffeinemc.mods.sodium.client.render.chunk.lists;

import it.unimi.dsi.fastutil.ints.IntArrays;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import net.caffeinemc.mods.sodium.client.render.chunk.ChunkUpdateType;
import net.caffeinemc.mods.sodium.client.render.chunk.RenderSection;
Expand Down Expand Up @@ -62,6 +63,8 @@ private void addToRebuildLists(RenderSection section) {
}
}

private static int[] sortItems = new int[RenderRegion.REGION_SIZE];

public SortedRenderLists createRenderLists(Viewport viewport) {
// sort the regions by distance to fix rare region ordering bugs
var transform = viewport.getTransform();
Expand All @@ -70,20 +73,29 @@ public SortedRenderLists createRenderLists(Viewport viewport) {
var cameraZ = transform.intZ >> (4 + RenderRegion.REGION_LENGTH_SH);
var size = this.sortedRenderLists.size();

var items = new int[size];
if (sortItems.length < size) {
sortItems = new int[size];
}

for (var i = 0; i < size; i++) {
var region = this.sortedRenderLists.get(i).getRegion();
var x = Math.abs(region.getX() - cameraX);
var y = Math.abs(region.getY() - cameraY);
var z = Math.abs(region.getZ() - cameraZ);
items[i] = (x + y + z) << 16 | i;
sortItems[i] = (x + y + z) << 16 | i;
}

Arrays.sort(items);
IntArrays.unstableSort(sortItems, 0, size);

var sorted = new ObjectArrayList<ChunkRenderList>(size);
for (var key : items) {
sorted.add(this.sortedRenderLists.get(key & 0xFFFF));
for (var i = 0; i < size; i++) {
var key = sortItems[i];
var renderList = this.sortedRenderLists.get(key & 0xFFFF);
sorted.add(renderList);
}

for (var list : sorted) {
list.sortSections(transform, sortItems);
}

return new SortedRenderLists(sorted);
Expand Down

0 comments on commit 6771c61

Please sign in to comment.