Add Cave Culling setting + cleanup + fix leo's adjData
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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<Quad>[] 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<Quad>();
|
||||
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;
|
||||
|
||||
@@ -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<LodUtil.REGION_DETAIL_LEVEL &&
|
||||
posToRender.contains((byte) (detailLevel+1), xAdj/2, zAdj/2))
|
||||
adjDetail = (byte) (detailLevel+1);
|
||||
else continue;
|
||||
}
|
||||
if (adjRegion == null) continue;
|
||||
if (renderAdjPos && !adjSkip) {
|
||||
//The adj data is at same detail and is extracted
|
||||
adjData[lodDirection.ordinal() - 2][0] = adjRegion.getAllData(adjDetail, xAdj, zAdj);
|
||||
} else if (renderLowerAdjPos)
|
||||
{
|
||||
//The adj data is at lower detail and is extracted in two steps
|
||||
xAdj *= 2;
|
||||
zAdj *= 2;
|
||||
adjDetail = (byte) (detailLevel - 1);
|
||||
|
||||
if (adjDetail < detailLevel-1 || adjDetail > 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);
|
||||
|
||||
@@ -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));
|
||||
|
||||
+14
-1
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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":
|
||||
|
||||
Reference in New Issue
Block a user