Merge branch 'distant-horizons-core-shadow.frustum.culling'
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+105
-23
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//=========//
|
||||
|
||||
Reference in New Issue
Block a user