Merge branch 'distant-horizons-core-shadow.frustum.culling'

This commit is contained in:
James Seibel
2024-02-06 19:23:53 -06:00
parent f6e2f2f52a
commit 9392decd35
2 changed files with 124 additions and 30 deletions
@@ -12,25 +12,36 @@ public class DhFrustumBounds
private final FrustumIntersection frustum;
private final Vector3f boundsMin = new Vector3f();
private final Vector3f boundsMax = new Vector3f();
private final float worldMinY;
private final float worldMaxY;
public float worldMinY;
public float worldMaxY;
public DhFrustumBounds(Matrix4fc matWorldViewProjection, float minY, float maxY)
//=============//
// constructor //
//=============//
public DhFrustumBounds()
{
this.frustum = new FrustumIntersection();
}
//=========//
// methods //
//=========//
public void updateFrustum(Matrix4fc matWorldViewProjection)
{
this.frustum.set(matWorldViewProjection);
Matrix4fc matWorldViewProjectionInv = new Matrix4f(matWorldViewProjection).invert();
matWorldViewProjectionInv.frustumAabb(this.boundsMin, this.boundsMax);
this.worldMinY = minY;
this.worldMaxY = maxY;
}
/** returns true if the LOD bounds intersect the frustum **/
public boolean Intersects(@NotNull DhLodPos lodBounds)
public boolean intersects(@NotNull DhLodPos lodBounds)
{
int lodPosX = lodBounds.getX().toBlockWidth();
int lodPosZ = lodBounds.getZ().toBlockWidth();
@@ -45,4 +56,5 @@ public class DhFrustumBounds
return this.frustum.testAab(lodMin, lodMax);
}
}
@@ -21,6 +21,7 @@ package com.seibel.distanthorizons.core.render;
import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiRenderParam;
import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.dependencyInjection.ModAccessorInjector;
import com.seibel.distanthorizons.core.enums.EDhDirection;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.logging.f3.F3Screen;
@@ -32,6 +33,7 @@ import com.seibel.distanthorizons.core.render.renderer.LodRenderer;
import com.seibel.distanthorizons.core.util.LodUtil;
import com.seibel.distanthorizons.core.util.objects.SortedArraySet;
import com.seibel.distanthorizons.core.util.objects.quadTree.QuadNode;
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IIrisAccessor;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
import com.seibel.distanthorizons.coreapi.util.math.Vec3f;
import org.apache.logging.log4j.Logger;
@@ -50,6 +52,8 @@ public class RenderBufferHandler implements AutoCloseable
{
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
private static final IIrisAccessor IRIS_ACCESSOR = ModAccessorInjector.INSTANCE.get(IIrisAccessor.class);
/** contains all relevant data */
public final LodQuadTree lodQuadTree;
@@ -58,7 +62,14 @@ public class RenderBufferHandler implements AutoCloseable
private final AtomicBoolean rebuildAllBuffers = new AtomicBoolean(false);
public F3Screen.DynamicMessage f3Message;
public F3Screen.MultiDynamicMessage f3Message;
private final DhFrustumBounds frustumBounds;
private int visibleBufferCount;
private int culledBufferCount;
private int shadowVisibleBufferCount;
private int shadowCulledBufferCount;
@@ -69,17 +80,43 @@ public class RenderBufferHandler implements AutoCloseable
public RenderBufferHandler(LodQuadTree lodQuadTree)
{
this.lodQuadTree = lodQuadTree;
this.culledBufferCount = 0;
this.f3Message = new F3Screen.DynamicMessage(() ->
{
// should never be null, but just in case something goes wrong, then the F3 menu won't break
String countText = (this.loadedNearToFarBuffers != null) ? this.loadedNearToFarBuffers.size()+"" : "NULL";
return LodUtil.formatLog("Rendered Buffer Count: " + countText);
this.frustumBounds = new DhFrustumBounds();
this.f3Message = new F3Screen.MultiDynamicMessage(
() ->
{
String countText = this.visibleBufferCount + "";
if (!Config.Client.Advanced.Graphics.AdvancedGraphics.disableFrustumCulling.get())
{
countText += "/" + (this.visibleBufferCount + this.culledBufferCount);
}
return LodUtil.formatLog("Rendered Buffer Count: " + countText);
},
() ->
{
boolean hasIrisShaders = (IRIS_ACCESSOR != null && IRIS_ACCESSOR.isShaderPackInUse());
if (!hasIrisShaders)
{
return null;
}
String countText = this.shadowVisibleBufferCount + "";
if (!Config.Client.Advanced.Graphics.AdvancedGraphics.disableFrustumCulling.get())
{
countText += "/" + (this.shadowVisibleBufferCount + this.shadowCulledBufferCount);
}
return LodUtil.formatLog("Shadow Buffer Count: " + countText);
});
}
//=================//
// render building //
//=================//
/**
* The following buildRenderList sorting method is based on the following reddit post: <br>
* <a href="https://www.reddit.com/r/VoxelGameDev/comments/a0l8zc/correct_depthordering_for_translucent_discrete/">correct_depth_ordering_for_translucent_discrete</a> <br><br>
@@ -188,16 +225,39 @@ public class RenderBufferHandler implements AutoCloseable
return loadedBufferA.pos.getDetailLevel() - loadedBufferB.pos.getDetailLevel(); // If all else fails, sort by detail
};
// Build the sorted list
this.loadedNearToFarBuffers = new SortedArraySet<>((a, b) -> -farToNearComparator.compare(a, b)); // TODO is the comparator named wrong?
float worldMinY = clientLevelWrapper.getMinHeight();
float worldHeight = clientLevelWrapper.getHeight();
DhFrustumBounds frustumBounds = new DhFrustumBounds(matWorldViewProjection, worldMinY, worldMinY + worldHeight);
boolean enableFrustumCulling = !Config.Client.Advanced.Graphics.AdvancedGraphics.disableFrustumCulling.get();
// Update the sections
// update the frustum if necessary
boolean enableFrustumCulling = !Config.Client.Advanced.Graphics.AdvancedGraphics.disableFrustumCulling.get();
if (enableFrustumCulling)
{
float worldMinY = clientLevelWrapper.getMinHeight();
float worldHeight = clientLevelWrapper.getHeight();
this.frustumBounds.worldMinY = worldMinY;
this.frustumBounds.worldMaxY = worldMinY + worldHeight;
this.frustumBounds.updateFrustum(matWorldViewProjection);
}
//=========================//
// Update the section list //
//=========================//
boolean isShadowPass = (IRIS_ACCESSOR != null && IRIS_ACCESSOR.isRenderingShadowPass());
if (isShadowPass)
{
this.shadowCulledBufferCount = 0;
}
else
{
this.culledBufferCount = 0;
}
boolean rebuildAllBuffers = this.rebuildAllBuffers.getAndSet(false);
Iterator<QuadNode<LodRenderSection>> nodeIterator = this.lodQuadTree.nodeIterator();
while (nodeIterator.hasNext())
@@ -213,10 +273,22 @@ public class RenderBufferHandler implements AutoCloseable
try
{
DhLodPos lodBounds = renderSection.pos.getSectionBBoxPos();
if (enableFrustumCulling && !frustumBounds.Intersects(lodBounds))
if (enableFrustumCulling)
{
continue;
DhLodPos lodBounds = renderSection.pos.getSectionBBoxPos();
if (!this.frustumBounds.intersects(lodBounds))
{
if (isShadowPass)
{
this.shadowCulledBufferCount++;
}
else
{
this.culledBufferCount++;
}
continue;
}
}
if (rebuildAllBuffers)
@@ -245,16 +317,31 @@ public class RenderBufferHandler implements AutoCloseable
renderSection.markBufferDirty();
}
}
if (isShadowPass)
{
this.shadowVisibleBufferCount = this.loadedNearToFarBuffers.size();
}
else
{
this.visibleBufferCount = this.loadedNearToFarBuffers.size();
}
}
public void MarkAllBuffersDirty() { this.rebuildAllBuffers.set(true); }
//================//
// render methods //
//================//
public void renderOpaque(LodRenderer renderContext, DhApiRenderParam renderEventParam)
{
//TODO: Directional culling
this.loadedNearToFarBuffers.forEach(loadedBuffer -> loadedBuffer.buffer.renderOpaque(renderContext, renderEventParam));
}
public void renderTransparent(LodRenderer renderContext, DhApiRenderParam renderEventParam)
{
//TODO: Directional culling
ListIterator<LoadedRenderBuffer> iter = this.loadedNearToFarBuffers.listIterator(this.loadedNearToFarBuffers.size());
while (iter.hasPrevious())
{
@@ -263,11 +350,6 @@ public class RenderBufferHandler implements AutoCloseable
}
}
public void MarkAllBuffersDirty()
{
rebuildAllBuffers.set(true);
}
//=========//