From 1859d0ea96078099c41d1a53ad87df4e6527a735 Mon Sep 17 00:00:00 2001 From: James Seibel Date: Tue, 6 Feb 2024 21:39:42 -0600 Subject: [PATCH] Add IDhApiCullingFrustum --- .../rendering/IDhApiCullingFrustum.java | 58 +++++++++++++++++++ .../coreapi/util/math/Mat4f.java | 16 ++++- .../core/pos/DhFrustumBounds.java | 38 +++++++----- .../core/render/RenderBufferHandler.java | 28 +++++---- 4 files changed, 115 insertions(+), 25 deletions(-) create mode 100644 api/src/main/java/com/seibel/distanthorizons/api/interfaces/override/rendering/IDhApiCullingFrustum.java diff --git a/api/src/main/java/com/seibel/distanthorizons/api/interfaces/override/rendering/IDhApiCullingFrustum.java b/api/src/main/java/com/seibel/distanthorizons/api/interfaces/override/rendering/IDhApiCullingFrustum.java new file mode 100644 index 000000000..34ab19eb9 --- /dev/null +++ b/api/src/main/java/com/seibel/distanthorizons/api/interfaces/override/rendering/IDhApiCullingFrustum.java @@ -0,0 +1,58 @@ +/* + * This file is part of the Distant Horizons mod + * licensed under the GNU LGPL v3 License. + * + * Copyright (C) 2020-2023 James Seibel + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.seibel.distanthorizons.api.interfaces.override.rendering; + +import com.seibel.distanthorizons.api.enums.EDhApiDetailLevel; +import com.seibel.distanthorizons.api.interfaces.override.IDhApiOverrideable; +import com.seibel.distanthorizons.coreapi.util.math.Mat4f; + +/** + * Used to determine if a LOD should be rendered or is outside the + * user's field of view. + * + * @author James Seibel + * @version 2024-2-6 + * @since API 1.1.0 + */ +public interface IDhApiCullingFrustum extends IDhApiOverrideable +{ + + /** + * Called before a render pass is done. + * + * @param worldMinBlockY the lowest block position this level allows. + * @param worldMaxBlockY the highest block position this level allows. + * @param worldViewProjection the projection matrix used in this render pass. + */ + void update(int worldMinBlockY, int worldMaxBlockY, Mat4f worldViewProjection); + + /** + * returns true if the LOD bounds intersect this frustum + * + * @param lodBlockPosMinX this LOD's starting block X position closest to negative infinity + * @param lodBlockPosMinZ this LOD's starting block Z position closest to negative infinity + * @param lodBlockWidth this LOD's width in blocks + * @param lodDetailLevel this LOD's detail level + * + * @see EDhApiDetailLevel + */ + boolean intersects(int lodBlockPosMinX, int lodBlockPosMinZ, int lodBlockWidth, int lodDetailLevel); + +} diff --git a/api/src/main/java/com/seibel/distanthorizons/coreapi/util/math/Mat4f.java b/api/src/main/java/com/seibel/distanthorizons/coreapi/util/math/Mat4f.java index 6e0657244..9d24e9f41 100644 --- a/api/src/main/java/com/seibel/distanthorizons/coreapi/util/math/Mat4f.java +++ b/api/src/main/java/com/seibel/distanthorizons/coreapi/util/math/Mat4f.java @@ -20,6 +20,7 @@ package com.seibel.distanthorizons.coreapi.util.math; import org.joml.Matrix4f; +import org.joml.Matrix4fc; import java.nio.FloatBuffer; @@ -75,8 +76,8 @@ public class Mat4f this.m33 = sourceMatrix.m33; } - public Mat4f(Matrix4f sourceMatrix) { this(convertJomlMatrixToArray(sourceMatrix)); } - private static float[] convertJomlMatrixToArray(Matrix4f sourceMatrix) + public Mat4f(Matrix4fc sourceMatrix) { this(convertJomlMatrixToArray(sourceMatrix)); } + private static float[] convertJomlMatrixToArray(Matrix4fc sourceMatrix) { FloatBuffer buffer = FloatBuffer.allocate(16); @@ -216,6 +217,17 @@ public class Mat4f floatBuffer.put(bufferIndex(3, 3), this.m33); } + public Matrix4f createJomlMatrix() + { + return new Matrix4f( + this.m00, this.m10, this.m20, this.m30, + this.m01, this.m11, this.m21, this.m31, + this.m02, this.m12, this.m22, this.m32, + this.m03, this.m13, this.m23, this.m33 + ); + } + + private static int bufferIndex(int xIndex, int zIndex) { return (zIndex * 4) + xIndex; diff --git a/core/src/main/java/com/seibel/distanthorizons/core/pos/DhFrustumBounds.java b/core/src/main/java/com/seibel/distanthorizons/core/pos/DhFrustumBounds.java index 39e4234ac..62d3aac75 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/pos/DhFrustumBounds.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/pos/DhFrustumBounds.java @@ -1,13 +1,15 @@ package com.seibel.distanthorizons.core.pos; -import org.jetbrains.annotations.NotNull; +import com.seibel.distanthorizons.api.interfaces.override.rendering.IDhApiCullingFrustum; +import com.seibel.distanthorizons.coreapi.interfaces.dependencyInjection.IOverrideInjector; +import com.seibel.distanthorizons.coreapi.util.math.Mat4f; import org.joml.FrustumIntersection; import org.joml.Matrix4f; import org.joml.Matrix4fc; import org.joml.Vector3f; -public class DhFrustumBounds +public class DhFrustumBounds implements IDhApiCullingFrustum { private final FrustumIntersection frustum; private final Vector3f boundsMin = new Vector3f(); @@ -32,23 +34,24 @@ public class DhFrustumBounds // methods // //=========// - public void updateFrustum(Matrix4fc matWorldViewProjection) + @Override + public void update(int worldMinBlockY, int worldMaxBlockY, Mat4f dhWorldViewProjection) { - this.frustum.set(matWorldViewProjection); + this.worldMinY = worldMinBlockY; + this.worldMaxY = worldMaxBlockY; - Matrix4fc matWorldViewProjectionInv = new Matrix4f(matWorldViewProjection).invert(); + Matrix4f worldViewProjection = new Matrix4f(dhWorldViewProjection.createJomlMatrix()); + this.frustum.set(worldViewProjection); + + Matrix4fc matWorldViewProjectionInv = new Matrix4f(worldViewProjection).invert(); matWorldViewProjectionInv.frustumAabb(this.boundsMin, this.boundsMax); } - /** returns true if the LOD bounds intersect the frustum **/ - public boolean intersects(@NotNull DhLodPos lodBounds) + @Override + public boolean intersects(int lodBlockPosMinX, int lodBlockPosMinZ, int lodBlockWidth, int lodDetailLevel) { - int lodPosX = lodBounds.getX().toBlockWidth(); - int lodPosZ = lodBounds.getZ().toBlockWidth(); - int lodSize = lodBounds.getBlockWidth(); - - Vector3f lodMin = new Vector3f(lodPosX, this.worldMinY, lodPosZ); - Vector3f lodMax = new Vector3f(lodPosX + lodSize, this.worldMaxY, lodPosZ + lodSize); + Vector3f lodMin = new Vector3f(lodBlockPosMinX, this.worldMinY, lodBlockPosMinZ); + Vector3f lodMax = new Vector3f(lodBlockPosMinX + lodBlockWidth, this.worldMaxY, lodBlockPosMinZ + lodBlockWidth); if (lodMax.x < this.boundsMin.x || lodMin.x > this.boundsMax.x) return false; if (lodMax.z < this.boundsMin.z || lodMin.z > this.boundsMax.z) return false; @@ -57,4 +60,13 @@ public class DhFrustumBounds return this.frustum.testAab(lodMin, lodMax); } + + + //=====================// + // overridable methods // + //=====================// + + @Override + public int getPriority() { return IOverrideInjector.CORE_PRIORITY; } + } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/RenderBufferHandler.java b/core/src/main/java/com/seibel/distanthorizons/core/render/RenderBufferHandler.java index c89b85e19..6b29df28d 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/render/RenderBufferHandler.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/render/RenderBufferHandler.java @@ -19,6 +19,8 @@ package com.seibel.distanthorizons.core.render; +import com.seibel.distanthorizons.api.DhApi; +import com.seibel.distanthorizons.api.interfaces.override.rendering.IDhApiCullingFrustum; import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiRenderParam; import com.seibel.distanthorizons.core.config.Config; import com.seibel.distanthorizons.core.dependencyInjection.ModAccessorInjector; @@ -35,6 +37,8 @@ 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.interfaces.dependencyInjection.IOverrideInjector; +import com.seibel.distanthorizons.coreapi.util.math.Mat4f; import com.seibel.distanthorizons.coreapi.util.math.Vec3f; import org.apache.logging.log4j.Logger; import org.joml.Matrix4fc; @@ -64,8 +68,6 @@ public class RenderBufferHandler implements AutoCloseable public F3Screen.MultiDynamicMessage f3Message; - private final DhFrustumBounds frustumBounds; - private int visibleBufferCount; private int culledBufferCount; private int shadowVisibleBufferCount; @@ -82,7 +84,12 @@ public class RenderBufferHandler implements AutoCloseable this.lodQuadTree = lodQuadTree; this.culledBufferCount = 0; - this.frustumBounds = new DhFrustumBounds(); + IDhApiCullingFrustum coreFrustum = DhApi.overrides.get(IDhApiCullingFrustum.class, IOverrideInjector.CORE_PRIORITY); + if (coreFrustum == null) + { + DhApi.overrides.bind(IDhApiCullingFrustum.class, new DhFrustumBounds()); + } + this.f3Message = new F3Screen.MultiDynamicMessage( () -> @@ -231,15 +238,13 @@ public class RenderBufferHandler implements AutoCloseable // update the frustum if necessary boolean enableFrustumCulling = !Config.Client.Advanced.Graphics.AdvancedGraphics.disableFrustumCulling.get(); + IDhApiCullingFrustum frustum = DhApi.overrides.get(IDhApiCullingFrustum.class, IOverrideInjector.CORE_PRIORITY); if (enableFrustumCulling) { - float worldMinY = clientLevelWrapper.getMinHeight(); - float worldHeight = clientLevelWrapper.getHeight(); + int worldMinY = clientLevelWrapper.getMinHeight(); + int worldHeight = clientLevelWrapper.getHeight(); - this.frustumBounds.worldMinY = worldMinY; - this.frustumBounds.worldMaxY = worldMinY + worldHeight; - - this.frustumBounds.updateFrustum(matWorldViewProjection); + frustum.update(worldMinY, worldMinY + worldHeight, new Mat4f(matWorldViewProjection)); } @@ -276,7 +281,10 @@ public class RenderBufferHandler implements AutoCloseable if (enableFrustumCulling) { DhLodPos lodBounds = renderSection.pos.getSectionBBoxPos(); - if (!this.frustumBounds.intersects(lodBounds)) + int blockMinX = lodBounds.getX().toBlockWidth(); + int blockMinZ = lodBounds.getZ().toBlockWidth(); + int lodBlockWidth = lodBounds.getBlockWidth(); + if (!frustum.intersects(blockMinX, blockMinZ, lodBlockWidth, lodBounds.detailLevel)) { if (isShadowPass) {