diff --git a/core/src/main/java/com/seibel/distanthorizons/core/api/internal/ClientApi.java b/core/src/main/java/com/seibel/distanthorizons/core/api/internal/ClientApi.java
index 362621d6a..5a2dde41f 100644
--- a/core/src/main/java/com/seibel/distanthorizons/core/api/internal/ClientApi.java
+++ b/core/src/main/java/com/seibel/distanthorizons/core/api/internal/ClientApi.java
@@ -32,8 +32,9 @@ import com.seibel.distanthorizons.core.pos.DhChunkPos;
import com.seibel.distanthorizons.core.render.DhApiRenderProxy;
import com.seibel.distanthorizons.core.render.renderer.*;
import com.seibel.distanthorizons.core.util.TimerUtil;
+import com.seibel.distanthorizons.core.util.math.Vec3d;
import com.seibel.distanthorizons.core.util.objects.Pair;
-import com.seibel.distanthorizons.core.util.threading.PriorityTaskPicker;
+import com.seibel.distanthorizons.core.util.objects.RollingAverage;
import com.seibel.distanthorizons.core.util.threading.ThreadPoolUtil;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
import com.seibel.distanthorizons.coreapi.DependencyInjection.ApiEventInjector;
@@ -93,6 +94,13 @@ public class ClientApi
*/
public static final DhRenderState RENDER_STATE = new DhRenderState();
+ /**
+ * 50ms = 20 FPS
+ * @link https://fpstoms.com/
+ * @see ClientApi#cameraSpeedRollingAverage
+ */
+ private static final long MIN_MS_BETWEEN_SPEED_CHECKS = 50;
+
private boolean isDevBuildMessagePrinted = false;
private boolean lowMemoryWarningPrinted = false;
@@ -120,6 +128,21 @@ public class ClientApi
public String lastRenderParamValidationMessage = null;
+ /**
+ * measured in blocks/second
+ *
+ * The number of points tracked here is related
+ * to the rate at which we check for speed.
+ * So if the ms_between is changed the number of points
+ * tracked should also be to keep the ratio roughly the same.
+ * @see ClientApi#MIN_MS_BETWEEN_SPEED_CHECKS
+ */
+ public RollingAverage cameraSpeedRollingAverage = new RollingAverage(40);
+ private Vec3d lastCameraPosForSpeedCheck = new Vec3d();
+ private long msSinceLastSpeedCheck = 0L;
+
+
+
//==============//
// constructors //
@@ -384,12 +407,6 @@ public class ClientApi
private void renderLodLayer(boolean renderingDeferredLayer)
{
- //=========//
- // logging //
- //=========//
-
- this.sendQueuedChatMessages();
-
IProfilerWrapper profiler = MC_CLIENT.getProfiler();
profiler.pop(); // get out of "terrain"
profiler.push("DH-RenderLevel");
@@ -399,12 +416,27 @@ public class ClientApi
//=====================//
// render thread tasks //
//=====================//
+ ///region
// only run these tasks once per frame
if (!renderingDeferredLayer)
{
profiler.push("DH render thread tasks");
+
+
+ //===============//
+ // chat messages //
+ //===============//
+
+ this.sendQueuedChatMessages();
+
+
+
+ //======================//
+ // GL Proxy queued jobs //
+ //======================//
+
try
{
// make sure the GLProxy is created for future use
@@ -418,14 +450,41 @@ public class ClientApi
LOGGER.error("Unexpected issue running render thread tasks, error: [" + e.getMessage() + "].", e);
}
+
+
+ //==============//
+ // camera speed //
+ //==============//
+
+ long nowMs = System.currentTimeMillis();
+ if (this.msSinceLastSpeedCheck + MIN_MS_BETWEEN_SPEED_CHECKS < nowMs)
+ {
+ // calc time since last check
+ double secSinceLastCheck = (nowMs - this.msSinceLastSpeedCheck) / 1_000.0;
+ this.msSinceLastSpeedCheck = nowMs;
+
+ // get the distance traveled since last frame
+ Vec3d camPos = MC_RENDER.getCameraExactPosition();
+ double distanceInBlocks = camPos.getDistance(this.lastCameraPosForSpeedCheck);
+ double speed = distanceInBlocks / secSinceLastCheck;
+
+ // record new values for next check
+ this.cameraSpeedRollingAverage.add(speed);
+ this.lastCameraPosForSpeedCheck = camPos;
+ }
+
+
profiler.pop();
}
+ ///endregion
+
//=================//
// parameter setup //
//=================//
+ ///region
EDhApiRenderPass renderPass;
if (DhApiRenderProxy.INSTANCE.getDeferTransparentRendering())
@@ -451,16 +510,19 @@ public class ClientApi
RenderParams renderParams =
new RenderParams(
renderPass,
- RENDER_STATE.frameTime,
+ RENDER_STATE.partialTickTime,
RENDER_STATE.mcProjectionMatrix, RENDER_STATE.mcModelViewMatrix,
RENDER_STATE.clientLevelWrapper
);
+ ///endregion
+
//============//
// validation //
//============//
+ ///region
// TODO write this message to the F3 menu so people can see when a different mod screws with the lightmap
String validationMessage = renderParams.getValidationErrorMessage();
@@ -487,11 +549,14 @@ public class ClientApi
return;
}
+ ///endregion
+
//===========//
// rendering //
//===========//
+ ///region
try
{
@@ -545,6 +610,8 @@ public class ClientApi
MC_CLIENT.sendChatMessage(MinecraftTextFormat.DARK_RED + "Error: " + MinecraftTextFormat.CLEAR_FORMATTING + e);
}
+ ///endregion
+
profiler.pop(); // end LOD
@@ -578,7 +645,7 @@ public class ClientApi
// don't fade when Iris shaders are active, otherwise the rendering can get weird
&& !DhApiRenderProxy.INSTANCE.getDeferTransparentRendering())
{
- VanillaFadeRenderer.INSTANCE.render(RENDER_STATE.mcModelViewMatrix, RENDER_STATE.mcProjectionMatrix, RENDER_STATE.frameTime, RENDER_STATE.clientLevelWrapper);
+ VanillaFadeRenderer.INSTANCE.render(RENDER_STATE.mcModelViewMatrix, RENDER_STATE.mcProjectionMatrix, RENDER_STATE.partialTickTime, RENDER_STATE.clientLevelWrapper);
}
}
/**
@@ -602,7 +669,7 @@ public class ClientApi
&& !DhApiRenderProxy.INSTANCE.getDeferTransparentRendering();
if (renderFade)
{
- VanillaFadeRenderer.INSTANCE.render(RENDER_STATE.mcModelViewMatrix, RENDER_STATE.mcProjectionMatrix, RENDER_STATE.frameTime, RENDER_STATE.clientLevelWrapper);
+ VanillaFadeRenderer.INSTANCE.render(RENDER_STATE.mcModelViewMatrix, RENDER_STATE.mcProjectionMatrix, RENDER_STATE.partialTickTime, RENDER_STATE.clientLevelWrapper);
}
}
}
diff --git a/core/src/main/java/com/seibel/distanthorizons/core/config/Config.java b/core/src/main/java/com/seibel/distanthorizons/core/config/Config.java
index 6da68d6e6..f53049ca1 100644
--- a/core/src/main/java/com/seibel/distanthorizons/core/config/Config.java
+++ b/core/src/main/java/com/seibel/distanthorizons/core/config/Config.java
@@ -713,21 +713,32 @@ public class Config
public static ConfigUIComment cullingHeader = new ConfigUIComment.Builder().setParentConfigClass(Culling.class).build();
public static ConfigEntry overdrawPrevention = new ConfigEntry.Builder()
- .setMinDefaultMax(0.0, 0.0, 1.0) // TODO change -1 to auto
+ .setMinDefaultMax(-1.0, -1.0, 1.0)
.comment(""
- + "Determines how far from the camera Distant Horizons will start rendering. \n"
- + "Measured as a percentage of the vanilla render distance.\n"
- + "\n"
- + "0 = auto, overdraw will change based on the vanilla render distance.\n"
- + "\n"
- + "Higher values will prevent LODs from rendering behind vanilla blocks at a higher distance,\n"
- + "but may cause holes in the world. \n"
- + "Holes are most likely to appear when flying through unloaded terrain. \n"
- + "\n"
- + "Increasing the vanilla render distance increases the effectiveness of this setting."
- + "")
+ + "Determines how far from the camera Distant Horizons will start rendering. \n"
+ + "Measured as a percentage of the vanilla render distance.\n"
+ + "\n"
+ + "-1 = auto, overdraw will change based on the vanilla render distance.\n"
+ + "\n"
+ + "Higher values will prevent LODs from rendering behind vanilla blocks at a higher distance,\n"
+ + "but may cause holes in the world. \n"
+ + "Holes are most likely to appear when flying through unloaded terrain. \n"
+ + "\n"
+ + "Increasing the vanilla render distance increases the effectiveness of this setting."
+ + "")
.build();
+ public static ConfigEntry reduceOverdrawWithFastMovement = new ConfigEntry.Builder()
+ .set(true)
+ .comment(""
+ + "If set to true the overdraw prevention radius will get closer\n"
+ + "to the camera when flying/moving quickly.\n"
+ + "\n"
+ + "This helps reduce issues where Minecraft can't load or\n"
+ + "generate chunks fast enough to keep up with DH.\n"
+ + "")
+ .build();
+
public static ConfigEntry enableCaveCulling = new ConfigEntry.Builder()
.set(true)
.comment(""
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 46624efe1..643a9d791 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
@@ -42,7 +42,6 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IIrisAccess
import com.seibel.distanthorizons.coreapi.interfaces.dependencyInjection.IOverrideInjector;
import com.seibel.distanthorizons.core.util.math.Mat4f;
import com.seibel.distanthorizons.core.util.math.Vec3d;
-import org.jetbrains.annotations.Nullable;
import org.joml.Matrix4f;
import org.joml.Matrix4fc;
diff --git a/core/src/main/java/com/seibel/distanthorizons/core/util/RenderUtil.java b/core/src/main/java/com/seibel/distanthorizons/core/util/RenderUtil.java
index 39ae264c5..f03496cb1 100644
--- a/core/src/main/java/com/seibel/distanthorizons/core/util/RenderUtil.java
+++ b/core/src/main/java/com/seibel/distanthorizons/core/util/RenderUtil.java
@@ -19,6 +19,7 @@
package com.seibel.distanthorizons.core.util;
+import com.seibel.distanthorizons.core.api.internal.ClientApi;
import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
@@ -36,6 +37,19 @@ public class RenderUtil
private static final IMinecraftClientWrapper MC = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class);
+ /** all speeds are measured in blocks per second */
+ private static class DynamicOverdraw
+ {
+ /**
+ * A walking player moves around 4.1 blocks/sec
+ * A sprint jumping player around 7.1 blocks/sec
+ */
+ public static final float MIN_SPEED = 10.0f;
+ /** a max speed spectator player can move just shy of 100 blocks/sec */
+ public static final float MAX_SPEED = 100.0f;
+ public static final float MIN_OVERDRAW_RATIO = 0.2f;
+ }
+
//=====================//
@@ -95,11 +109,12 @@ public class RenderUtil
public static float getAutoOverdrawPrevention()
{
float overdraw = Config.Client.Advanced.Graphics.Culling.overdrawPrevention.get().floatValue();
-
- // 0 or less
- if (overdraw <= 0)
+ if (overdraw < 0)
{
- // at low render distances this hides the vanilla RD border
+ // automatic mode,
+ // get overdraw based on vanilla render distance.
+ // At low render distances this hides the vanilla RD border
+
int chunkRenderDistance = MC_RENDER.getRenderDistance();
if (chunkRenderDistance <= 2)
{
@@ -122,12 +137,38 @@ public class RenderUtil
overdraw = 0.9f;
}
}
-
+ else
+ {
+ // prevent setting an overdraw of 0
+ // since that will cause rendering issues
+ overdraw = MathUtil.clamp(0.05f, overdraw, 1.0f);
+ }
+
return overdraw;
}
public static float getNearClipPlaneInBlocksForFading(float partialTicks)
{
float overdraw = getAutoOverdrawPrevention();
+
+ if (Config.Client.Advanced.Graphics.Culling.reduceOverdrawWithFastMovement.get())
+ {
+ double avgSpeed = ClientApi.INSTANCE.cameraSpeedRollingAverage.getAverage();
+ if (avgSpeed >= DynamicOverdraw.MIN_SPEED)
+ {
+ // if the player is moving fast enough,
+ // smoothly decrease the fade distance
+ // to give MC have a chance to load/generate.
+
+ // convert the speed into a range of 0.0 - 1.0
+ float speedRange = (float)((DynamicOverdraw.MAX_SPEED - avgSpeed) / DynamicOverdraw.MAX_SPEED);
+ // if math.max isn't done here we could completely
+ // remove vanilla rendering at high speeds
+ speedRange = Math.max(speedRange, DynamicOverdraw.MIN_OVERDRAW_RATIO);
+
+ overdraw *= speedRange;
+ }
+ }
+
return getNearClipPlaneDistanceInBlocks(partialTicks, overdraw);
}
private static float getNearClipPlaneDistanceInBlocks(float partialTicks, float overdrawPreventionPercent)
diff --git a/core/src/main/resources/assets/distanthorizons/lang/en_us.json b/core/src/main/resources/assets/distanthorizons/lang/en_us.json
index 4357d439c..99b50f9d8 100644
--- a/core/src/main/resources/assets/distanthorizons/lang/en_us.json
+++ b/core/src/main/resources/assets/distanthorizons/lang/en_us.json
@@ -363,7 +363,11 @@
"distanthorizons.config.client.advanced.graphics.culling.overdrawPrevention":
"Overdraw Prevention",
"distanthorizons.config.client.advanced.graphics.culling.overdrawPrevention.@tooltip":
- "Determines how far from the camera Distant Horizons will start rendering. \nMeasured as a percentage of the vanilla render distance.\n0 = Auto, overdraw will change based on the vanilla render distance.\n\nHigher values will prevent LODs from rendering behind vanilla blocks at a higher distance,\nbut may cause holes to appear in the LODs. \nHoles are most likely to appear when flying through unloaded terrain. \n\nIncreasing the vanilla render distance increases the effectiveness of this setting.",
+ "Determines how far from the camera Distant Horizons will start rendering. \nMeasured as a percentage of the vanilla render distance.\n-1 = Auto, overdraw will change based on the vanilla render distance.\n\nHigher values will prevent LODs from rendering behind vanilla blocks at a higher distance,\nbut may cause holes to appear in the LODs. \nHoles are most likely to appear when flying through unloaded terrain. \n\nIncreasing the vanilla render distance increases the effectiveness of this setting.",
+ "distanthorizons.config.client.advanced.graphics.culling.reduceOverdrawWithFastMovement":
+ "Reduce Overdraw With Fast Movement",
+ "distanthorizons.config.client.advanced.graphics.culling.reduceOverdrawWithFastMovement.@tooltip":
+ "If set to true the overdraw prevention radius will get closer \nto the camera when flying/moving quickly. \n\nThis helps reduce issues where Minecraft can't load or \ngenerate chunks fast enough to keep up with DH.",
"distanthorizons.config.client.advanced.graphics.culling.enableCaveCulling":
"Cave Culling",
"distanthorizons.config.client.advanced.graphics.culling.enableCaveCulling.@tooltip":
diff --git a/core/src/main/resources/shaders/fog/fog.frag b/core/src/main/resources/shaders/fog/fog.frag
index d4982674d..607dd0740 100644
--- a/core/src/main/resources/shaders/fog/fog.frag
+++ b/core/src/main/resources/shaders/fog/fog.frag
@@ -158,15 +158,17 @@ float linearFog(float worldDist, float fogStart, float fogLength, float fogMin,
return fogMin + fogRange * worldDist;
}
-float exponentialFog(float x, float fogStart, float fogLength,
-float fogMin, float fogRange, float fogDensity)
+float exponentialFog(
+ float x, float fogStart, float fogLength,
+ float fogMin, float fogRange, float fogDensity)
{
x = max((x-fogStart)/fogLength, 0.0) * fogDensity;
return fogMin + fogRange - fogRange/exp(x);
}
-float exponentialSquaredFog(float x, float fogStart, float fogLength,
-float fogMin, float fogRange, float fogDensity)
+float exponentialSquaredFog(
+ float x, float fogStart, float fogLength,
+ float fogMin, float fogRange, float fogDensity)
{
x = max((x-fogStart)/fogLength, 0.0) * fogDensity;
return fogMin + fogRange - fogRange/exp(x*x);