Skip to content

Commit

Permalink
Use larger bounding box for nearby sections in frustum check (Caffein…
Browse files Browse the repository at this point in the history
…eMC#2879)

This fixes some problems where very large block entities in
nearby sections may be incorrectly culled. But it does not
comprehensively fix the problem for all other sections,
since that would require visiting the 27-neighborhood of
every section, which is too slow.
  • Loading branch information
douira authored and ThatMG393 committed Dec 15, 2024
1 parent de43cb9 commit 3154547
Showing 1 changed file with 44 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ public void findVisible(Visitor visitor,
while (queues.flip()) {
processQueue(visitor, viewport, searchDistance, useOcclusionCulling, frame, queues.read(), queues.write());
}

this.addNearbySections(visitor, viewport, searchDistance, frame);
}

private static void processQueue(Visitor visitor,
Expand Down Expand Up @@ -208,13 +210,54 @@ private static int nearestToZero(int min, int max) {
// The bounding box of a chunk section must be large enough to contain all possible geometry within it. Block models
// can extend outside a block volume by +/- 1.0 blocks on all axis. Additionally, we make use of a small epsilon
// to deal with floating point imprecision during a frustum check (see GH#2132).
private static final float CHUNK_SECTION_SIZE = 8.0f /* chunk bounds */ + 1.0f /* maximum model extent */ + 0.125f /* epsilon */;
private static final float CHUNK_SECTION_RADIUS = 8.0f /* chunk bounds */;
private static final float CHUNK_SECTION_SIZE = CHUNK_SECTION_RADIUS + 1.0f /* maximum model extent */ + 0.125f /* epsilon */;

public static boolean isWithinFrustum(Viewport viewport, RenderSection section) {
return viewport.isBoxVisible(section.getCenterX(), section.getCenterY(), section.getCenterZ(),
CHUNK_SECTION_SIZE, CHUNK_SECTION_SIZE, CHUNK_SECTION_SIZE);
}

// this bigger chunk section size is only used for frustum-testing nearby sections with large models
private static final float CHUNK_SECTION_SIZE_NEARBY = CHUNK_SECTION_RADIUS + 2.0f /* bigger model extent */ + 0.125f /* epsilon */;

public static boolean isWithinNearbySectionFrustum(Viewport viewport, RenderSection section) {
return viewport.isBoxVisible(section.getCenterX(), section.getCenterY(), section.getCenterZ(),
CHUNK_SECTION_SIZE_NEARBY, CHUNK_SECTION_SIZE_NEARBY, CHUNK_SECTION_SIZE_NEARBY);
}

// This method visits sections near the origin that are not in the path of the graph traversal
// but have bounding boxes that may intersect with the frustum. It does this additional check
// for all neighboring, even diagonally neighboring, sections around the origin to render them
// if their extended bounding box is visible, and they may render large models that extend
// outside the 16x16x16 base volume of the section.
private void addNearbySections(Visitor visitor, Viewport viewport, float searchDistance, int frame) {
var origin = viewport.getChunkCoord();
var originX = origin.getX();
var originY = origin.getY();
var originZ = origin.getZ();

for (var dx = -1; dx <= 1; dx++) {
for (var dy = -1; dy <= 1; dy++) {
for (var dz = -1; dz <= 1; dz++) {
if (dx == 0 && dy == 0 && dz == 0) {
continue;
}

var section = this.getRenderSection(originX + dx, originY + dy, originZ + dz);

// additionally render not yet visited but visible sections
if (section != null && section.getLastVisibleFrame() != frame && isWithinNearbySectionFrustum(viewport, section)) {
// reset state on first visit, but don't enqueue
section.setLastVisibleFrame(frame);

visitor.visit(section);
}
}
}
}
}

private void init(Visitor visitor,
WriteQueue<RenderSection> queue,
Viewport viewport,
Expand Down

0 comments on commit 3154547

Please sign in to comment.