Try fixing LOD flashing/stuck low details

This commit is contained in:
James Seibel
2026-04-21 07:48:07 -05:00
parent ae16ed2341
commit 5dcda31990
@@ -245,7 +245,7 @@ public class LodQuadTree extends QuadTree<LodRenderSection> implements IDebugRen
//===================//
//region
// remove out of bounds sections
// remove out of bound sections
this.setCenterBlockPos(playerPos, (renderSection) ->
{
if (renderSection != null)
@@ -481,7 +481,29 @@ public class LodQuadTree extends QuadTree<LodRenderSection> implements IDebugRen
//=========================//
//region
private void recursivelyUpdateRenderSectionNode(
@NotNull
private QuadNode<LodRenderSection> tryAddNodeToTree(
@NotNull QuadNode<LodRenderSection> rootNode,
@Nullable QuadNode<LodRenderSection> quadNode,
long sectionPos // section pos is needed here since the quad node may be null
)
{
// create the node
if (quadNode == null)
{
rootNode.setValue(sectionPos, new LodRenderSection(sectionPos, this, this.level, this.fullDataSourceProvider));
quadNode = rootNode.getNode(sectionPos);
}
if (quadNode == null)
{
LodUtil.assertNotReach("Unable to add node with pos ["+DhSectionPos.toString(sectionPos)+"] to tree root ["+rootNode+"].");
}
return quadNode;
}
/** @return true if the node at this position has uploaded its render data */
private boolean recursivelyUpdateRenderSectionNode(
@NotNull DhBlockPos2D playerPos,
@NotNull QuadNode<LodRenderSection> rootNode,
@Nullable QuadNode<LodRenderSection> parentNode,
@@ -495,16 +517,17 @@ public class LodQuadTree extends QuadTree<LodRenderSection> implements IDebugRen
//=====================//
//region
// create the node
if (quadNode == null)
{
rootNode.setValue(sectionPos, new LodRenderSection(sectionPos, this, this.level, this.fullDataSourceProvider));
quadNode = rootNode.getNode(sectionPos);
}
if (quadNode == null)
{
LodUtil.assertNotReach("Unable to add node with pos ["+DhSectionPos.toString(sectionPos)+"] to tree root ["+rootNode+"].");
}
quadNode = this.tryAddNodeToTree(rootNode, quadNode, sectionPos);
//// Skip sections that are out-of-bounds.
//// If not done some sections will appear and/or generate
//// outside the desired render distance
//if (!this.isSectionPosInBounds(quadNode.sectionPos))
//{
// return true;
//}
// make sure the render section is created (shouldn't be necessary, but just in case)
LodRenderSection renderSection = quadNode.value;
@@ -538,13 +561,13 @@ public class LodQuadTree extends QuadTree<LodRenderSection> implements IDebugRen
if (DhSectionPos.getDetailLevel(quadNode.sectionPos) > expectedDetailLevel)
{
this.onDetailLevelTooHigh(playerPos, rootNode, quadNode);
return this.onDetailLevelTooLow(playerPos, rootNode, quadNode);
}
// the (expectedDetailLevel-1) fixes corners being cut out due to distance calculations using the LOD center
else if (DhSectionPos.getDetailLevel(quadNode.sectionPos) == expectedDetailLevel
|| DhSectionPos.getDetailLevel(quadNode.sectionPos) == expectedDetailLevel - 1)
{
this.onDesiredDetailLevel(quadNode, parentNode);
return this.onDesiredDetailLevel(quadNode, parentNode);
}
else
{
@@ -553,74 +576,91 @@ public class LodQuadTree extends QuadTree<LodRenderSection> implements IDebugRen
//endregion
}
private void onDetailLevelTooHigh(
/** @return true if the node at this position has uploaded its render data */
private boolean onDetailLevelTooLow(
@NotNull DhBlockPos2D playerPos,
@NotNull QuadNode<LodRenderSection> rootNode, @NotNull QuadNode<LodRenderSection> quadNode)
@NotNull QuadNode<LodRenderSection> rootNode,
@NotNull QuadNode<LodRenderSection> quadNode)
{
// recursively update each child node
boolean allChildNodesCanRender = true;
int childNodeRenderCount = 0;
for (int i = 0; i < 4; i++)
{
QuadNode<LodRenderSection> childNode = quadNode.getChildByIndex(i);
long childPos = DhSectionPos.getChildByIndex(quadNode.sectionPos, i);
this.recursivelyUpdateRenderSectionNode(
QuadNode<LodRenderSection> childNode = quadNode.getChildByIndex(i);
boolean childCanRender = this.recursivelyUpdateRenderSectionNode(
playerPos,
rootNode, quadNode, childNode, childPos);
childNode = quadNode.getChildByIndex(i); // needs to be gotten again in case a new node was added to the tree (this will often happen when moving into new areas where the children were deleted)
// nodes shouldn't be null, but just in case
if (childNode != null
&& childNode.value != null
&& !childNode.value.gpuUploadComplete())
if (childCanRender)
{
// the node is present but not uploaded yet
allChildNodesCanRender = false;
// node can be rendered
childNodeRenderCount++;
}
}
if (allChildNodesCanRender)
if (childNodeRenderCount >= 4)
{
// all child nodes can render, this node isn't needed
this.tickNodeHolder.addDisableNode(quadNode);
/*
DEBUG_RENDERER.makeParticle(
new AbstractDebugWireframeRenderer.BoxParticle(
new AbstractDebugWireframeRenderer.Box(
quadNode.sectionPos
, -64, 80,
0.0f,
Color.BLUE),
0.25, 0f
));
*/
// all children can render,
// the area will be filled when rendering
return true;
}
else
{
// not all child positions are loaded yet, this one should be rendered instead
this.tickNodeHolder.addEnableNode(quadNode);
boolean nodeCanRender = quadNode.value != null
&& quadNode.value.gpuUploadComplete();
if (nodeCanRender)
{
// not all child positions are loaded yet, this one should be rendered instead
this.tickNodeHolder.addEnableNode(quadNode);
}
else
{
this.tickNodeHolder.addDisableNode(quadNode);
}
return nodeCanRender;
}
}
private void onDesiredDetailLevel(
@NotNull QuadNode<LodRenderSection> quadNode, @Nullable QuadNode<LodRenderSection> parentNode)
/** @return true if the node at this position has uploaded its render data */
private boolean onDesiredDetailLevel(
@NotNull QuadNode<LodRenderSection> quadNode,
@Nullable QuadNode<LodRenderSection> parentNode)
{
boolean allAdjNodesCanRender = true;
// if the parent node is null, that means we're at the root node
// and we should always render
if (parentNode != null)
// Skip sections that are out-of-bounds.
// If not done some sections will appear and/or generate
// outside the desired render distance
if (!this.isSectionPosInBounds(quadNode.sectionPos))
{
// check if all adjacent nodes are ready to render
// this check is done to prevent some overlapping due to the parent node
// still being active
for (int i = 0; i < 4; i++)
{
QuadNode<LodRenderSection> adjNode = parentNode.getChildByIndex(i);
// nodes shouldn't be null, but just in case there's an issue
if (adjNode != null
&& adjNode.value != null
&& !adjNode.value.gpuUploadComplete())
{
// the node is present but not uploaded yet
allAdjNodesCanRender = false;
}
}
return true;
}
if (allAdjNodesCanRender
&& quadNode.value != null
if (quadNode.value != null
&& quadNode.value.gpuUploadComplete())
{
this.tickNodeHolder.addEnableDeleteChildrenNode(quadNode);
return true;
}
else
{
return false;
}
}