Add opt-in rendering for loaded chunk edges#3713
Conversation
|
By the way, I just noticed that some other PRs got marked as AI generated recently, and I realized that my Summary/Background/Details style at the top most likely matches ChatGPT exactly, ha. Just leaving a quick note in case anyone thinks this was AI-generated. I'm just rather finicky about how I format my PRs so that they're legible, heh. Anyway, the actual code for the logic in here is all manually written based off my standalone EdgeChunkFix mod. I figured that forcing a standalone mixin into the LevelRenderer's cullTerrain method would have made this incompatible with Sodium anyway, so doing this directly was definitely easier. Feel free to let me know if you need any changes! |
|
How does this handle chunk meshing since it requires the data of neighboring chunks to correctly function? We copy a margin around each section since that context is needed for meshing, so if we don't have that data, I don't see how meshing could be deterministic or even possible to do correctly in the first place. Does this end up meshing chunks on the borders of the world twice? |
27f88ca to
32e6062
Compare
| this.refreshReadyChunks(); | ||
| } | ||
|
|
||
| public void refreshReadyChunks() { |
There was a problem hiding this comment.
what is the cost of this method and how often is it called?
There was a problem hiding this comment.
pushed a rework for this now. it’s not just a boolean anymore, it’s Off / Performance / Immediate.
for the correctness part, chunks meshed with missing neighbors are treated as temporary. the tracker stores which neighbors were missing when the chunk became ready. when chunk status changes, the changed chunk + its 3x3 around it are checked again. if a missing neighbor arrives, or the missing-neighbor mask changes, that chunk gets queued unload+load so it gets rebuilt with the real neighbor data. so it shouldn’t keep using the first “missing neighbor = air” mesh forever.
for refreshReadyChunks, yeah that’s the expensive path since it scans the tracked chunk map. normal chunk status updates use local 3x3 updates. the full refresh is for bigger state changes like option changes, view/load-distance changes, Performance mode turning edge rendering off when chunks start changing again, and turning it back on after the quiet period.
the modes are:
Off = current behavior
Performance = waits until chunk loading has been quiet for a bit before rendering these edge chunks
Immediate = renders them as soon as the center chunk is complete, so it can do more rebuilds while chunks are still loading


Summary
This adds an opt-in
Render Loaded Chunk Edgesperformance option with three modes:Off: keeps Sodium's current full-neighborhood readiness behavior.Performance: renders eligible loaded edge chunks only after chunk loading has been quiet for a short cooldown.Immediate: renders eligible loaded edge chunks as soon as the center chunk has complete data and all known neighbors are complete.The goal is to reduce visible holes at loaded chunk borders when the client already has the center chunk's block and light data, while keeping the conservative behavior as the default.
Background
This came out of a small standalone Fabric mod called EdgeChunkFix, which explored the same visual problem in the vanilla renderer. At loaded chunk borders, the client can sometimes select a block and know its state, but terrain rendering still leaves that block invisible because the renderer is stricter than the client-side world data.
That standalone mod is useful for vanilla-style rendering, but it is not compatible with Sodium because both alter terrain renderer behavior around
LevelRenderer.cullTerrain. Integrating a Sodium-specific version here avoids that mod compatibility trap and makes the improvement available directly to Sodium users who choose to enable it.This PR intentionally does not port the vanilla lighting workaround from that mod. It only adjusts Sodium's chunk readiness rule for the opt-in case.
Before / After
Before, client-known edge terrain can be selectable while the terrain itself is missing:
After, the already-known edge terrain renders:
Details
Sodium currently merges readiness across the 3x3 chunk neighborhood. If any neighboring chunk is absent, the merged status becomes empty, which can keep an otherwise complete center chunk out of the renderer.
With loaded-edge rendering enabled by mode:
FLAG_HAS_BLOCK_DATA | FLAG_HAS_LIGHT_DATAThis means a mesh built while a neighbor was missing is not treated as final. Once the neighboring data arrives, the stored mask changes and the affected render chunk is rebuilt using the new neighbor data.
refreshReadyChunks()is the expensive path because it scans the tracked chunk map. It is used for global state changes such as option changes, view/load-distance context changes, andPerformancemode entering or leaving its delayed edge-rendering state. Normal chunk status updates use local 3x3 updates unlessPerformancemode was actively rendering provisional edges and needs to globally disable them again after new chunk activity resumes.Disabling the option restores the previous full-neighborhood readiness behavior.
Validation
./gradlew :fabric:build --no-daemonon Minecraft 1.21.11/Fabric.