Skip to content

Commit

Permalink
add region sorting to fix translucency sorting issues,
Browse files Browse the repository at this point in the history
tree traversal only does correct in-region sorting, not between regions
  • Loading branch information
douira committed Dec 31, 2024
1 parent b8ad5ef commit 29caa4b
Show file tree
Hide file tree
Showing 6 changed files with 89 additions and 48 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -423,7 +423,7 @@ private void processRenderListUpdate(Viewport viewport) {
this.renderableSectionTree.prepareForTraversal();
this.renderableSectionTree.traverse(visitor, viewport, searchDistance);

this.renderLists = visitor.createRenderLists();
this.renderLists = visitor.createRenderLists(viewport);
this.frustumTaskLists = visitor.getPendingTaskLists();
this.globalTaskLists = null;
this.renderTree = null;
Expand All @@ -432,7 +432,7 @@ private void processRenderListUpdate(Viewport viewport) {

var visibleCollector = new VisibleChunkCollectorAsync(this.regions, this.frame);
bestTree.traverse(visibleCollector, viewport, this.getSearchDistance());
this.renderLists = visibleCollector.createRenderLists();
this.renderLists = visibleCollector.createRenderLists(viewport);

var end = System.nanoTime();
var time = end - start;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ public FallbackVisibleChunkCollector(Viewport viewport, float buildDistance, Lon
this.renderListCollector = new VisibleChunkCollectorAsync(regions, frame);
}

public SortedRenderLists createRenderLists() {
return this.renderListCollector.createRenderLists();
public SortedRenderLists createRenderLists(Viewport viewport) {
return this.renderListCollector.createRenderLists(viewport);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
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.region.RenderRegion;
import net.caffeinemc.mods.sodium.client.render.viewport.Viewport;

public interface RenderListProvider {
ObjectArrayList<ChunkRenderList> getUnsortedRenderLists();

int[] getCachedSortItems();

void setCachedSortItems(int[] sortItems);

default SortedRenderLists createRenderLists(Viewport viewport) {
// sort the regions by distance to fix rare region ordering bugs
var sectionPos = viewport.getChunkCoord();
var cameraX = sectionPos.getX() >> RenderRegion.REGION_WIDTH_SH;
var cameraY = sectionPos.getY() >> RenderRegion.REGION_HEIGHT_SH;
var cameraZ = sectionPos.getZ() >> RenderRegion.REGION_LENGTH_SH;

var unsortedRenderLists = this.getUnsortedRenderLists();
var size = unsortedRenderLists.size();

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

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

IntArrays.unstableSort(sortItems, 0, size);

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

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

return new SortedRenderLists(sorted);
}
}
Original file line number Diff line number Diff line change
@@ -1,22 +1,15 @@
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.LocalSectionIndex;
import net.caffeinemc.mods.sodium.client.render.chunk.occlusion.SectionTree;
import net.caffeinemc.mods.sodium.client.render.chunk.region.RenderRegion;
import net.caffeinemc.mods.sodium.client.render.chunk.region.RenderRegionManager;
import net.caffeinemc.mods.sodium.client.render.viewport.Viewport;

import java.util.ArrayDeque;
import java.util.EnumMap;
import java.util.Map;
import java.util.Queue;

/**
* The async visible chunk collector is passed into a section tree to collect visible chunks.
*/
public class VisibleChunkCollectorAsync implements SectionTree.VisibleSectionVisitor {
public class VisibleChunkCollectorAsync implements SectionTree.VisibleSectionVisitor, RenderListProvider {
private final RenderRegionManager regions;
private final int frame;

Expand Down Expand Up @@ -55,7 +48,20 @@ public void visit(int x, int y, int z) {
renderList.add(sectionIndex);
}

public SortedRenderLists createRenderLists() {
return new SortedRenderLists(this.sortedRenderLists);
private static int[] sortItems = new int[RenderRegion.REGION_SIZE];

@Override
public ObjectArrayList<ChunkRenderList> getUnsortedRenderLists() {
return this.sortedRenderLists;
}

@Override
public int[] getCachedSortItems() {
return sortItems;
}

@Override
public void setCachedSortItems(int[] sortItems) {
VisibleChunkCollectorAsync.sortItems = sortItems;
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
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.RenderSection;
import net.caffeinemc.mods.sodium.client.render.chunk.RenderSectionFlags;
Expand All @@ -13,7 +12,7 @@
/**
* The sync visible chunk collector is passed into the graph search occlusion culler to collect visible chunks.
*/
public class VisibleChunkCollectorSync extends SectionTree {
public class VisibleChunkCollectorSync extends SectionTree implements RenderListProvider {
private final ObjectArrayList<ChunkRenderList> sortedRenderLists;

public VisibleChunkCollectorSync(Viewport viewport, float buildDistance, int frame, CullType cullType, Level level) {
Expand Down Expand Up @@ -44,39 +43,18 @@ public void visit(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 sectionPos = viewport.getChunkCoord();
var cameraX = sectionPos.getX() >> RenderRegion.REGION_WIDTH_SH;
var cameraY = sectionPos.getY() >> RenderRegion.REGION_HEIGHT_SH;
var cameraZ = sectionPos.getZ() >> RenderRegion.REGION_LENGTH_SH;
var size = this.sortedRenderLists.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);
sortItems[i] = (x + y + z) << 16 | i;
}

IntArrays.unstableSort(sortItems, 0, size);

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

for (var list : sorted) {
list.sortSections(sectionPos, sortItems);
}
@Override
public int[] getCachedSortItems() {
return sortItems;
}

return new SortedRenderLists(sorted);
@Override
public void setCachedSortItems(int[] sortItems) {
VisibleChunkCollectorSync.sortItems = sortItems;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
import net.caffeinemc.mods.sodium.client.render.viewport.Viewport;
import org.joml.FrustumIntersection;

/**
* A traversable tree is a tree of sections that can be traversed with a distance limit and a frustum. It traverses the sections in visual front-to-back order, so that they can be directly put into a render list. Note however that ordering regions by adding them to the list the first time one of their sections is visited does not yield the correct order. This is because the sections are traversed in visual order, not ordered by distance from the camera.
*/
public class TraversableTree extends Tree {
private static final int INSIDE_FRUSTUM = 0b01;
private static final int INSIDE_DISTANCE = 0b10;
Expand Down

0 comments on commit 29caa4b

Please sign in to comment.