From 21253d130809f7ba0a5d62a257f7af8f62140590 Mon Sep 17 00:00:00 2001 From: tom lee Date: Sun, 20 Mar 2022 16:26:50 +0800 Subject: [PATCH] Add Cave Culling setting + cleanup + fix leo's adjData --- .../lod/core/objects/lod/LodRegion.java | 27 +++++- .../core/objects/opengl/LodQuadBuilder.java | 10 +- .../lod/core/objects/opengl/RenderRegion.java | 96 +++++++++---------- .../seibel/lod/core/util/LevelPosUtil.java | 30 +++--- .../config/ILodConfigWrapperSingleton.java | 15 ++- src/main/resources/assets/lod/lang/en_us.json | 4 + 6 files changed, 112 insertions(+), 70 deletions(-) diff --git a/src/main/java/com/seibel/lod/core/objects/lod/LodRegion.java b/src/main/java/com/seibel/lod/core/objects/lod/LodRegion.java index 266df6dd2..17e7bfdba 100644 --- a/src/main/java/com/seibel/lod/core/objects/lod/LodRegion.java +++ b/src/main/java/com/seibel/lod/core/objects/lod/LodRegion.java @@ -286,6 +286,28 @@ public class LodRegion { priority, genMode, shouldSort, needFarPos); } } + + public byte getRenderDetailLevelAt(int playerPosX, int playerPosZ, byte detailLevel, int offsetX, int offsetZ) { + GenerationPriority generationPriority = CONFIG.client().worldGenerator().getResolvedGenerationPriority(); + DropoffQuality dropoffQuality = CONFIG.client().graphics().quality().getResolvedDropoffQuality(); + + double minDistance = LevelPosUtil.minDistance(LodUtil.REGION_DETAIL_LEVEL, regionPosX, regionPosZ, + playerPosX, playerPosZ); + byte targetLevel = DetailDistanceUtil.getDetailLevelFromDistance(minDistance); + byte renderLevel; + if (targetLevel > dropoffQuality.fastModeSwitch) { + double centerDistance = LevelPosUtil.centerDistance(LodUtil.REGION_DETAIL_LEVEL, regionPosX, regionPosZ, playerPosX, playerPosZ); + renderLevel = DetailDistanceUtil.getDetailLevelFromDistance(centerDistance); + } else { + int size = 1 << (LodUtil.REGION_DETAIL_LEVEL - detailLevel); + double posMinDistance = LevelPosUtil.minDistance(detailLevel, + LevelPosUtil.getRegionModule(detailLevel, offsetX) + regionPosX*size, + LevelPosUtil.getRegionModule(detailLevel, offsetZ) + regionPosZ*size, + playerPosX, playerPosZ); + renderLevel = DetailDistanceUtil.getDetailLevelFromDistance(posMinDistance); + } + return (byte) Math.max(getMinDetailLevel(), renderLevel); + } public void getPosToRender(PosToRenderContainer posToRender, int playerPosX, int playerPosZ) @@ -314,9 +336,10 @@ public class LodRegion { priority); } else { // FarModeSwitchLevel or above is the level where a giant block of lod is not acceptable even if not all child data exist. - double maxDistance = LevelPosUtil.maxDistance(LodUtil.REGION_DETAIL_LEVEL, regionPosX, regionPosZ, playerPosX, playerPosZ); + double centerDistance = LevelPosUtil.centerDistance(LodUtil.REGION_DETAIL_LEVEL, regionPosX, regionPosZ, playerPosX, playerPosZ); + targetLevel = DetailDistanceUtil.getDetailLevelFromDistance(centerDistance); byte farModeSwitchLevel = (priority == GenerationPriority.NEAR_FIRST) ? 0 : - calculateFarModeSwitch(DetailDistanceUtil.getDetailLevelFromDistance(maxDistance)); + calculateFarModeSwitch(targetLevel); if (priority == GenerationPriority.FAR_FIRST) farModeSwitchLevel = 8; getPosToRenderFlat(posToRender, LodUtil.REGION_DETAIL_LEVEL, 0, 0, targetLevel, farModeSwitchLevel); } diff --git a/src/main/java/com/seibel/lod/core/objects/opengl/LodQuadBuilder.java b/src/main/java/com/seibel/lod/core/objects/opengl/LodQuadBuilder.java index c6dcc5e8d..0e988813e 100644 --- a/src/main/java/com/seibel/lod/core/objects/opengl/LodQuadBuilder.java +++ b/src/main/java/com/seibel/lod/core/objects/opengl/LodQuadBuilder.java @@ -10,8 +10,10 @@ import com.seibel.lod.core.api.ApiShared; import com.seibel.lod.core.enums.LodDirection; import com.seibel.lod.core.enums.LodDirection.Axis; import com.seibel.lod.core.enums.config.GpuUploadMethod; +import com.seibel.lod.core.handlers.dependencyInjection.SingletonHandler; import com.seibel.lod.core.util.ColorUtil; import com.seibel.lod.core.util.LodUtil; +import com.seibel.lod.core.wrapperInterfaces.config.ILodConfigWrapperSingleton; public class LodQuadBuilder { static final int MAX_BUFFER_SIZE = (1024 * 1024 * 1); @@ -19,7 +21,9 @@ public class LodQuadBuilder { static final int MAX_QUADS_PER_BUFFER = MAX_BUFFER_SIZE / QUAD_BYTE_SIZE; //static final int MAX_MERGED_QUAD_SIZE = 64; - public boolean skipSkylight0Quads = true; + static final ILodConfigWrapperSingleton CONFIG = SingletonHandler.get(ILodConfigWrapperSingleton.class); + + public final boolean skipSkylight0Quads; static class Quad { final short x; @@ -225,9 +229,10 @@ public class LodQuadBuilder { final ArrayList[] quads; - public LodQuadBuilder(int initialSize) { + public LodQuadBuilder(int initialSize, boolean enableSkylightCulling) { quads = new ArrayList[6]; for (int i=0; i<6; i++) quads[i] = new ArrayList(); + this.skipSkylight0Quads = enableSkylightCulling; } public void addQuadAdj(LodDirection dir, short x, short y, short z, short w0, short wy, int color, byte skylight, @@ -366,6 +371,7 @@ public class LodQuadBuilder { public void mergeQuads() { + if(true)return; long mergeCount = 0; long preQuadsCount = getCurrentQuadsCount(); if (preQuadsCount<=1) return; diff --git a/src/main/java/com/seibel/lod/core/objects/opengl/RenderRegion.java b/src/main/java/com/seibel/lod/core/objects/opengl/RenderRegion.java index 26b5c12f7..0c3376250 100644 --- a/src/main/java/com/seibel/lod/core/objects/opengl/RenderRegion.java +++ b/src/main/java/com/seibel/lod/core/objects/opengl/RenderRegion.java @@ -170,7 +170,10 @@ public class RenderRegion implements AutoCloseable return CompletableFuture.supplyAsync(() -> { try { if (ENABLE_EVENT_STEP_LOGGING) ApiShared.LOGGER.info("RenderRegion start QuadBuild @ {}", regionPos); - LodQuadBuilder builder = new LodQuadBuilder(10); + boolean useSkylightCulling = CONFIG.client().graphics().advancedGraphics().getEnableCaveCulling(); + useSkylightCulling &= !lodDim.dimension.hasCeiling(); + useSkylightCulling &= lodDim.dimension.hasSkyLight(); + LodQuadBuilder builder = new LodQuadBuilder(10, useSkylightCulling); Runnable buildRun = ()->{ makeLodRenderData(builder, region, adjRegions, playerPosX, playerPosZ); }; @@ -325,64 +328,53 @@ public class RenderRegion implements AutoCloseable try { int xAdj = posX + lodDirection.getNormal().x; int zAdj = posZ + lodDirection.getNormal().z; - byte adjDetail = detailLevel; int chunkXAdj = LevelPosUtil.getChunkPos(detailLevel, xAdj); int chunkZAdj = LevelPosUtil.getChunkPos(detailLevel, zAdj); Boolean isRenderedAdj = chunkGrid.get(chunkXAdj, chunkZAdj); - boolean adjSkip = isRenderedAdj!=null && isRenderedAdj; - - //We check if the adjPos is to be rendered - boolean renderAdjPos = posToRender.contains(detailLevel, xAdj, zAdj); - boolean doesAdjLowerPosExist = detailLevel==0 ? false : posToRender.contains((byte) (detailLevel-1), xAdj*2, zAdj*2); - boolean renderLowerAdjPos = doesAdjLowerPosExist; - LodRegion adjRegion = region; - - //since he system doesn't work for region border we need to check with another system - if(!renderAdjPos && (!doesAdjLowerPosExist || detailLevel==0)) - { - //we compute the distance from the adjPos - double minDistance = LevelPosUtil.minDistance(detailLevel, xAdj, zAdj, playerX, playerZ) - 1.4142*(2 << detailLevel); + if (isRenderedAdj!=null && isRenderedAdj) continue; + + boolean isCrossRegionBoundary = LevelPosUtil.getRegion(detailLevel, xAdj) != region.regionPosX || + LevelPosUtil.getRegion(detailLevel, zAdj) != region.regionPosZ; + + LodRegion adjRegion; + byte adjDetail; + int childXAdj = xAdj*2 + (lodDirection.getNormal().x<0 ? 1 : 0); + int childZAdj = zAdj*2 + (lodDirection.getNormal().z<0 ? 1 : 0); + + //we check if the detail of the adjPos is equal to the correct one (region border fix) + //or if the detail is wrong by 1 value (region+circle border fix) + if (isCrossRegionBoundary) { //we compute at which detail that position should be rendered adjRegion = adjRegions[lodDirection.ordinal()-2]; - byte minLevel; - if(adjRegion != null) - { - minLevel = (byte) Math.max(adjRegion.getMinDetailLevel(), - DetailDistanceUtil.getDetailLevelFromDistance(minDistance)); - } else{ - minLevel = DetailDistanceUtil.getDetailLevelFromDistance(minDistance); - } - - //we check if the detail of the adjPos is equal to the correct one (region border fix) - //or if the detail is wrong by 1 value (region+circle border fix) - renderAdjPos = detailLevel == minLevel; - renderLowerAdjPos = detailLevel==0 ? false : detailLevel-1 == minLevel; + if(adjRegion == null) continue; + adjDetail = adjRegion.getRenderDetailLevelAt(playerX, playerZ, detailLevel, xAdj, zAdj); + } else { + adjRegion = region; + if (posToRender.contains(detailLevel, xAdj, zAdj)) adjDetail = detailLevel; + else if (detailLevel>0 && + posToRender.contains((byte) (detailLevel-1), childXAdj, childZAdj)) + adjDetail = (byte) (detailLevel-1); + else if (detailLevel detailLevel+1) { + continue; + } + + if (adjDetail == detailLevel || adjDetail > detailLevel) { + adjData[lodDirection.ordinal() - 2][0] = adjRegion.getAllData(adjDetail, + LevelPosUtil.convert(detailLevel, xAdj, adjDetail), + LevelPosUtil.convert(detailLevel, zAdj, adjDetail)); + } else { adjData[lodDirection.ordinal() - 2] = new long[2][]; - isRenderedAdj = chunkGrid.get(chunkXAdj, chunkZAdj); - adjSkip = isRenderedAdj!=null && isRenderedAdj; - if (!adjSkip) { - adjData[lodDirection.ordinal() - 2][0] = adjRegion.getAllData(adjDetail, xAdj, zAdj); - } - - xAdj += Math.abs(lodDirection.getNormal().x); - zAdj += Math.abs(lodDirection.getNormal().z); - isRenderedAdj = chunkGrid.get(chunkXAdj, chunkZAdj); - adjSkip = isRenderedAdj!=null && isRenderedAdj; - if (!adjSkip) - { - adjData[lodDirection.ordinal() - 2][1] = adjRegion.getAllData(adjDetail, xAdj, zAdj); - } + adjData[lodDirection.ordinal() - 2][0] = adjRegion.getAllData(adjDetail, + childXAdj, childZAdj); + adjData[lodDirection.ordinal() - 2][1] = adjRegion.getAllData(adjDetail, + childXAdj + (lodDirection.getAxis()==LodDirection.Axis.X ? 0 : 1), + childZAdj + (lodDirection.getAxis()==LodDirection.Axis.Z ? 0 : 1)); } } catch (RuntimeException e) { ApiShared.LOGGER.warn("Failed to get adj data for [{}:{},{}] at [{}]", detailLevel, posX, posZ, lodDirection); diff --git a/src/main/java/com/seibel/lod/core/util/LevelPosUtil.java b/src/main/java/com/seibel/lod/core/util/LevelPosUtil.java index cbef70b8c..322e32c4f 100644 --- a/src/main/java/com/seibel/lod/core/util/LevelPosUtil.java +++ b/src/main/java/com/seibel/lod/core/util/LevelPosUtil.java @@ -148,22 +148,26 @@ public class LevelPosUtil { return convert(detailLevel, pos, LodUtil.CHUNK_DETAIL_LEVEL); } - - public static double myPow2(double x) - { - return x*x; + + public static double centerDistance(byte detailLevel, int posX, int posZ, int playerPosX, int playerPosZ) { + int width = 1 << detailLevel; + double cPosX = posX * width + width/2.; + double cPosZ = posZ * width + width/2.; + cPosX = playerPosX - cPosX; + cPosZ = playerPosZ - cPosZ; + return Math.sqrt(LodUtil.pow2(cPosX) + LodUtil.pow2(cPosZ)); } - + public static double maxDistance(byte detailLevel, int posX, int posZ, int playerPosX, int playerPosZ) { int width = 1 << detailLevel; double startPosX = posX * width; double startPosZ = posZ * width; - double endPosX = myPow2(playerPosX - startPosX - width); - double endPosZ = myPow2(playerPosZ - startPosZ - width); - startPosX = myPow2(playerPosX - startPosX); - startPosZ = myPow2(playerPosZ - startPosZ); + double endPosX = LodUtil.pow2(playerPosX - startPosX - width); + double endPosZ = LodUtil.pow2(playerPosZ - startPosZ - width); + startPosX = LodUtil.pow2(playerPosX - startPosX); + startPosZ = LodUtil.pow2(playerPosZ - startPosZ); double maxDistance = Math.sqrt(startPosX + startPosZ); maxDistance = Math.max(maxDistance, Math.sqrt(startPosX + endPosZ)); @@ -203,10 +207,10 @@ public class LevelPosUtil } else { - double startPosX2 = myPow2(playerPosX - startPosX); - double startPosZ2 = myPow2(playerPosZ - startPosZ); - double endPosX2 = myPow2(playerPosX - endPosX); - double endPosZ2 = myPow2(playerPosZ - endPosZ); + double startPosX2 = LodUtil.pow2(playerPosX - startPosX); + double startPosZ2 = LodUtil.pow2(playerPosZ - startPosZ); + double endPosX2 = LodUtil.pow2(playerPosX - endPosX); + double endPosZ2 = LodUtil.pow2(playerPosZ - endPosZ); double minDistance = Math.sqrt(startPosX2 + startPosZ2); minDistance = Math.min(minDistance, Math.sqrt(startPosX2 + endPosZ2)); diff --git a/src/main/java/com/seibel/lod/core/wrapperInterfaces/config/ILodConfigWrapperSingleton.java b/src/main/java/com/seibel/lod/core/wrapperInterfaces/config/ILodConfigWrapperSingleton.java index 2e1d5c814..929059899 100644 --- a/src/main/java/com/seibel/lod/core/wrapperInterfaces/config/ILodConfigWrapperSingleton.java +++ b/src/main/java/com/seibel/lod/core/wrapperInterfaces/config/ILodConfigWrapperSingleton.java @@ -523,7 +523,20 @@ public interface ILodConfigWrapperSingleton extends IBindable + " 2 = very saturated \n"; double getSaturationMultiplier(); void setSaturationMultiplier(double newSaturationMultiplier); - + + boolean ENABLE_CAVE_CULLING_DEFAULT = false; + String ENABLE_CAVE_CULLING_DESC = "" + + " If enabled caves will be culled \n" + + "\n" + + " NOTE: This feature is under development and \n" + + " it is VERY experimental! Please don't report \n" + + " any issues related to this feature. \n" + + "\n" + + " Additional Info: Currently this cull all faces \n" + + " with skylight value of 0 in dimensions that \n" + + " does not have a ceiling. \n"; + boolean getEnableCaveCulling(); + void setEnableCaveCulling(boolean newEnableCaveCulling); } } diff --git a/src/main/resources/assets/lod/lang/en_us.json b/src/main/resources/assets/lod/lang/en_us.json index 6ff35cc73..5a229b617 100644 --- a/src/main/resources/assets/lod/lang/en_us.json +++ b/src/main/resources/assets/lod/lang/en_us.json @@ -160,6 +160,10 @@ "Saturation Multiplier", "DistantHorizons.config.client.graphics.advancedGraphics.saturationMultiplier.@tooltip": "How saturated fake chunk colors are.\n\n0 = black and white \n1 = normal \n2 = vibrant", + "DistantHorizons.config.client.graphics.advancedGraphics.enableCaveCulling": + "Cave Culling §6(EXPERIMENTAL)§r", + "DistantHorizons.config.client.graphics.advancedGraphics.enableCaveCulling.@tooltip": + "If enabled caves will be culled \n\n§6NOTE: This feature is under development and \n it is VERY experimental! Please don't report \nany issues related to this feature.§r \n\nAdditional Info: Currently this cull all faces \n with skylight value of 0 in dimensions that \n does not have a ceiling. \n", "DistantHorizons.config.client.worldGenerator": "World generator", "DistantHorizons.config.client.worldGenerator.generationPriority":