Add dynamic overdraw distance based on camera speed
This commit is contained in:
@@ -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 <br>
|
||||
*
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -713,21 +713,32 @@ public class Config
|
||||
public static ConfigUIComment cullingHeader = new ConfigUIComment.Builder().setParentConfigClass(Culling.class).build();
|
||||
|
||||
public static ConfigEntry<Double> overdrawPrevention = new ConfigEntry.Builder<Double>()
|
||||
.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<Boolean> reduceOverdrawWithFastMovement = new ConfigEntry.Builder<Boolean>()
|
||||
.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<Boolean> enableCaveCulling = new ConfigEntry.Builder<Boolean>()
|
||||
.set(true)
|
||||
.comment(""
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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":
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user