Add the ability for LOD fog rendering to differ from Minecraft's

This commit is contained in:
James Seibel
2021-07-03 21:10:34 -05:00
parent 31ef1d4959
commit f977687ad6
9 changed files with 257 additions and 80 deletions
+22 -1
View File
@@ -1,10 +1,14 @@
package com.seibel.lod;
import org.lwjgl.opengl.GL;
import com.seibel.lod.handlers.LodConfig;
import com.seibel.lod.proxy.ClientProxy;
import com.seibel.lod.render.LodRenderer;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.DeferredWorkQueue;
import net.minecraftforge.fml.ModLoadingContext;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.config.ModConfig;
@@ -20,7 +24,7 @@ import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
* check out the ClientProxy.
*
* @author James Seibel
* @version 02-07-2021
* @version 7-3-2021
*/
@Mod(ModInfo.MODID)
public class LodMain
@@ -30,9 +34,26 @@ public class LodMain
public static ClientProxy client_proxy;
@SuppressWarnings("deprecation")
private void init(final FMLCommonSetupEvent event)
{
ModLoadingContext.get().registerConfig(ModConfig.Type.CLIENT, LodConfig.clientSpec);
Thread setFancyFog = new Thread(() ->
{
LodRenderer.fancyFogAvailable = GL.getCapabilities().GL_NV_fog_distance;
if (!LodRenderer.fancyFogAvailable)
{
ClientProxy.LOGGER.info("This GPU does not support GL_NV_fog_distance. This means that fancy fog options will not be available.");
}
});
// This will be run on the main thread when it is able.
// If it wasn't run on the main thread GL.getCapabilities()
// would fail.
DeferredWorkQueue.runLater(setFancyFog);
}
@@ -1,7 +1,7 @@
package com.seibel.lod.enums;
/**
* Near, far, or NEAR_AND_FAR.
* NEAR, FAR, or NEAR_AND_FAR.
*
* @author James Seibel
* @version 02-14-2021
@@ -10,8 +10,10 @@ public enum FogDistance
{
/** good for fast or fancy fog qualities. */
NEAR,
/** good for fast or fancy fog qualities. */
FAR,
/** only looks good if the fog quality is set to Fancy. */
NEAR_AND_FAR;
}
@@ -0,0 +1,26 @@
package com.seibel.lod.enums;
/**
* USE_OPTIFINE_FOG_SETTING, <br>
* NEVER_DRAW_FOG, <br>
* ALWAYS_DRAW_FOG_FAST, <br>
* ALWAYS_DRAW_FOG_FANCY <br>
*
* @author James Seibel
* @version 7-03-2021
*/
public enum FogDrawOverride
{
/** Use whatever Fog setting optifine is using.
* If optifine isn't installed this defaults to ALWAYS_DRAW_FOG. */
USE_OPTIFINE_FOG_SETTING,
/** Never draw fog on the LODs */
NEVER_DRAW_FOG,
/** Always draw fog on the LODs */
ALWAYS_DRAW_FOG_FAST,
/** Always draw fog on the LODs */
ALWAYS_DRAW_FOG_FANCY;
}
@@ -11,6 +11,7 @@ import com.electronwill.nightconfig.core.io.WritingMode;
import com.seibel.lod.ModInfo;
import com.seibel.lod.enums.DistanceGenerationMode;
import com.seibel.lod.enums.FogDistance;
import com.seibel.lod.enums.FogDrawOverride;
import com.seibel.lod.enums.LodDetail;
import com.seibel.lod.enums.LodTemplate;
@@ -33,6 +34,8 @@ public class LodConfig
public ForgeConfigSpec.EnumValue<FogDistance> fogDistance;
public ForgeConfigSpec.EnumValue<FogDrawOverride> fogDrawOverride;
public ForgeConfigSpec.BooleanValue debugMode;
public ForgeConfigSpec.EnumValue<LodTemplate> lodTemplate;
@@ -53,22 +56,31 @@ public class LodConfig
.comment("\n\n"
+ " If false LODs will not be drawn, \n"
+ " however they will still be generated \n"
+ " and saved to file for later use.")
+ " and saved to file for later use. \n")
.define("drawLODs", true);
fogDistance = builder
.comment("\n\n"
+ " At what distance should Fog be drawn on the LODs? \n"
+ " If the fog cuts off ubruptly or you are using Optifine's \"fast\" \n"
+ " fog option set this to " + FogDistance.NEAR.toString() + " or " + FogDistance.FAR.toString() + ".")
+ " fog option set this to " + FogDistance.NEAR.toString() + " or " + FogDistance.FAR.toString() + ". \n")
.defineEnum("fogDistance", FogDistance.NEAR_AND_FAR);
fogDrawOverride = builder
.comment("\n\n"
+ " When should fog be drawn? \n"
+ " " + FogDrawOverride.USE_OPTIFINE_FOG_SETTING.toString() + ": Use whatever Fog setting Optifine is using. If Optifine isn't installed this defaults to " + FogDrawOverride.ALWAYS_DRAW_FOG_FANCY.toString() + ". \n"
+ " " + FogDrawOverride.NEVER_DRAW_FOG.toString() + ": Never draw fog on the LODs \n"
+ " " + FogDrawOverride.ALWAYS_DRAW_FOG_FAST.toString() + ": Always draw fast fog on the LODs \n"
+ " " + FogDrawOverride.ALWAYS_DRAW_FOG_FANCY.toString() + ": Always draw fancy fog on the LODs (if your graphics card supports it) \n")
.defineEnum("fogDrawOverride", FogDrawOverride.USE_OPTIFINE_FOG_SETTING);
debugMode = builder
.comment("\n\n"
+ " If false the LODs will draw with their normal world colors. \n"
+ " If true they will draw as a black and white checkerboard. \n"
+ " This can be used for debugging or imagining you are playing a \n"
+ " giant game of chess ;)")
+ " giant game of chess ;) \n")
.define("drawCheckerBoard", false);
lodTemplate = builder
@@ -77,14 +89,16 @@ public class LodConfig
+ " " + LodTemplate.CUBIC.toString() + ": LOD Chunks are drawn as rectangular prisms (boxes). \n"
+ " " + LodTemplate.TRIANGULAR.toString() + ": LOD Chunks smoothly transition between other. \n"
+ " " + LodTemplate.DYNAMIC.toString() + ": LOD Chunks smoothly transition between other, \n"
+ " " + " unless a neighboring chunk is at a significantly different height. ")
+ " " + " unless a neighboring chunk is at a significantly different height. \n")
.defineEnum("lodTemplate", LodTemplate.CUBIC);
lodDetail = builder
.comment("\n\n"
+ " How detailed should the LODs be? \n"
+ " " + LodDetail.SINGLE.toString() + ": render 1 LOD for each Chunk. \n"
+ " " + LodDetail.DOUBLE.toString() + ": render 4 LODs for each Chunk.")
+ " " + LodDetail.DOUBLE.toString() + ": render 4 LODs for each Chunk. \n"
+ " " + LodDetail.QUAD.toString() + ": render 16 LODs for each Chunk. \n"
+ " " + LodDetail.HALF.toString() + ": render 64 LODs for each Chunk. \n")
.defineEnum("lodGeometryQuality", LodDetail.QUAD);
lodChunkRadiusMultiplier = builder
@@ -92,14 +106,15 @@ public class LodConfig
+ " This is multiplied by the default view distance \n"
+ " to determine how far out to generate/render LODs. \n"
+ " A value of 2 means that there is 1 render distance worth \n"
+ " of LODs in each cardinal direction. ")
+ " of LODs in each cardinal direction. \n")
.defineInRange("lodChunkRadiusMultiplier", 6, 2, 32);
distanceGenerationMode = builder
.comment("\n\n"
+ " Note: The times listed here are based on the developer's \n"
+ " PC, and are included to show the speed difference \n"
+ " between options. Your mileage may vary. \n"
+ " Note: The times listed here are the amount of time it took"
+ " the developer's PC to generate 1 chunk, \n"
+ " and are included so you can compare the \n"
+ " different generation options. Your mileage may vary. \n"
+ "\n"
+ " " + DistanceGenerationMode.BIOME_ONLY.toString() + " \n"
@@ -12,14 +12,13 @@ import net.minecraft.client.Minecraft;
* in Optifine.
*
* @author James Seibel
* @version 09-21-2020
* @version 7-03-2021
*/
public class ReflectionHandler
{
private Minecraft mc = Minecraft.getInstance();
public Field ofFogField = null;
public ReflectionHandler()
{
setupFogField();
@@ -34,14 +33,14 @@ public class ReflectionHandler
private void setupFogField()
{
// get every variable from the entity renderer
Field[] vars = mc.options.getClass().getDeclaredFields();
Field[] optionFields = mc.options.getClass().getDeclaredFields();
// try and find the ofFogType variable in gameSettings
for(Field f : vars)
for(Field field : optionFields)
{
if(f.getName().equals("ofFogType"))
if(field.getName().equals("ofFogType"))
{
ofFogField = f;
ofFogField = field;
return;
}
}
@@ -82,8 +81,12 @@ public class ReflectionHandler
switch (returnNum)
{
// optifine's "default" option,
// it should never be called in this case
case 0:
return FogQuality.FAST;
// normal options
case 1:
return FogQuality.FAST;
case 2:
@@ -1,28 +0,0 @@
package com.seibel.lod.objects;
import com.seibel.lod.enums.FogDistance;
/**
* This object is just a replacement for an array
* to make things easier to understand in the LodRenderer.
*
* @author James Seibel
* @version 02-27-2021
*/
public class NearFarFogSetting
{
public FogDistance nearFogSetting = FogDistance.NEAR;
public FogDistance farFogSetting = FogDistance.FAR;
public NearFarFogSetting()
{
}
public NearFarFogSetting(FogDistance newNearFogSetting, FogDistance newFarFogSetting)
{
nearFogSetting = newNearFogSetting;
farFogSetting = newFarFogSetting;
}
}
@@ -0,0 +1,46 @@
package com.seibel.lod.objects;
import com.seibel.lod.enums.FogDistance;
import com.seibel.lod.enums.FogQuality;
/**
* This object is just a replacement for an array
* to make things easier to understand in the LodRenderer.
*
* @author James Seibel
* @version 7-03-2021
*/
public class NearFarFogSettings
{
public NearOrFarSetting near = new NearOrFarSetting(FogDistance.NEAR);
public NearOrFarSetting far = new NearOrFarSetting(FogDistance.FAR);
/** If true that means Minecraft is
* rendering fog along side us */
public boolean vanillaIsRenderingFog = true;
public NearFarFogSettings()
{
}
/**
* This holds all relevant data to rendering fog at either
* near or far distances.
*/
public class NearOrFarSetting
{
public FogQuality quality = FogQuality.FANCY;
public FogDistance distance = FogDistance.FAR;
/** If true this section should render with fog */
public boolean enabled = true;
public NearOrFarSetting(FogDistance newFogDistance)
{
distance = newFogDistance;
}
}
}
@@ -99,7 +99,8 @@ public class ClientProxy
// LodConfig.CLIENT.lodColorStyle.set(LodColorStyle.INDIVIDUAL_SIDES);
// LodConfig.CLIENT.lodChunkRadiusMultiplier.set(12);
// LodConfig.CLIENT.distanceGenerationMode.set(DistanceGenerationMode.FEATURES);
// LodConfig.CLIENT.fogDistance.set(FogDistance.FAR);
// LodConfig.CLIENT.fogDistance.set(FogDistance.NEAR_AND_FAR);
// LodConfig.CLIENT.fogDrawOverride.set(FogDrawOverride.USE_OPTIFINE_FOG_SETTING);
// Note to self:
// if "unspecified" shows up in the pie chart, it is
@@ -6,19 +6,21 @@ import java.nio.FloatBuffer;
import java.util.HashSet;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.NVFogDistance;
import com.mojang.blaze3d.matrix.MatrixStack;
import com.mojang.blaze3d.platform.GlStateManager;
import com.mojang.blaze3d.systems.RenderSystem;
import com.seibel.lod.builders.LodBufferBuilder;
import com.seibel.lod.enums.FogDistance;
import com.seibel.lod.enums.FogDrawOverride;
import com.seibel.lod.enums.FogQuality;
import com.seibel.lod.handlers.LodConfig;
import com.seibel.lod.handlers.ReflectionHandler;
import com.seibel.lod.objects.LodChunk;
import com.seibel.lod.objects.LodDimension;
import com.seibel.lod.objects.NearFarBuffer;
import com.seibel.lod.objects.NearFarFogSetting;
import com.seibel.lod.objects.NearFarFogSettings;
import com.seibel.lod.proxy.ClientProxy;
import net.minecraft.client.Minecraft;
@@ -67,6 +69,10 @@ public class LodRenderer
*/
public static final int MAX_ALOCATEABLE_DIRECT_MEMORY = 64 * 1024 * 1024;
/** Does this computer's GPU support fancy fog? */
public static boolean fancyFogAvailable = false;
/** If true the LODs colors will be replaced with
* a checkerboard, this can be used for debugging. */
@@ -93,6 +99,7 @@ public class LodRenderer
private volatile VertexBuffer farVbo;
public static final VertexFormat LOD_VERTEX_FORMAT = DefaultVertexFormats.POSITION_COLOR;
/** This is used to determine if the LODs should be regenerated */
private int previousChunkRenderDistance = 0;
/** This is used to determine if the LODs should be regenerated */
@@ -266,14 +273,14 @@ public class LodRenderer
setupProjectionMatrix(partialTicks);
setupLighting(lodDim, partialTicks);
NearFarFogSetting fogSetting = determineFogSettings();
NearFarFogSettings fogSettings = determineFogSettings();
// determine the current fog settings so they can be
// reset after drawing the LODs
float defaultFogStartDist = GL11.glGetFloat(GL11.GL_FOG_START);
float defaultFogEndDist = GL11.glGetFloat(GL11.GL_FOG_END);
int defaultFogMode = GL11.glGetInteger(GL11.GL_FOG_MODE);
int defaultFogDistance = GL11.glGetInteger(NVFogDistance.GL_FOG_DISTANCE_MODE_NV);
@@ -285,10 +292,10 @@ public class LodRenderer
//===========//
profiler.popPush("LOD draw");
setupFog(fogSetting.nearFogSetting, reflectionHandler.getFogQuality());
setupFog(fogSettings.near.distance, fogSettings.near.quality);
sendLodsToGpuAndDraw(nearVbo, modelViewMatrix);
setupFog(fogSetting.farFogSetting, reflectionHandler.getFogQuality());
setupFog(fogSettings.far.distance, fogSettings.far.quality);
sendLodsToGpuAndDraw(farVbo, modelViewMatrix);
@@ -315,9 +322,7 @@ public class LodRenderer
// reset the fog settings so the normal chunks
// will be drawn correctly
RenderSystem.fogStart(defaultFogStartDist);
RenderSystem.fogEnd(defaultFogEndDist);
RenderSystem.fogMode(defaultFogMode);
cleanupFog(fogSettings, defaultFogStartDist, defaultFogEndDist, defaultFogMode, defaultFogDistance);
// reset the projection matrix so anything drawn after
// the LODs will use the correct projection matrix
@@ -380,10 +385,24 @@ public class LodRenderer
{
throw new IllegalArgumentException("setupFog doesn't accept the NEAR_AND_FAR fog distance.");
}
// determine the fog distance mode to use
int glFogDistanceMode = NVFogDistance.GL_EYE_RADIAL_NV;
if (fogQuality == FogQuality.FANCY)
{
// fancy fog (fragment distance based fog)
glFogDistanceMode = NVFogDistance.GL_EYE_RADIAL_NV;
}
else
{
// fast fog (frustum distance based fog)
glFogDistanceMode = NVFogDistance.GL_EYE_PLANE_ABSOLUTE_NV;
}
// the multipliers are percentages
// of the regular view distance.
if(fogDistance == FogDistance.NEAR)
{
// the reason that I wrote fogEnd then fogStart backwards
@@ -420,8 +439,34 @@ public class LodRenderer
}
}
RenderSystem.fogMode(GlStateManager.FogMode.LINEAR);
GL11.glEnable(GL11.GL_FOG);
RenderSystem.enableFog();
RenderSystem.setupNvFogDistance();
RenderSystem.fogMode(GlStateManager.FogMode.LINEAR);
GL11.glFogi(NVFogDistance.GL_FOG_DISTANCE_MODE_NV, glFogDistanceMode);
}
/**
* Revert any changes that were made to the fog.
*/
private void cleanupFog(NearFarFogSettings fogSettings,
float defaultFogStartDist, float defaultFogEndDist,
int defaultFogMode, int defaultFogDistance)
{
RenderSystem.fogStart(defaultFogStartDist);
RenderSystem.fogEnd(defaultFogEndDist);
RenderSystem.fogMode(defaultFogMode);
GL11.glFogi(NVFogDistance.GL_FOG_DISTANCE_MODE_NV, defaultFogDistance);
// disable fog if Minecraft wasn't rendering fog
// but we were
if(!fogSettings.vanillaIsRenderingFog &&
(fogSettings.near.quality != FogQuality.OFF ||
fogSettings.far.quality != FogQuality.OFF))
{
GL11.glDisable(GL11.GL_FOG);
}
}
@@ -614,68 +659,114 @@ public class LodRenderer
/**
* Based on the fogDistance setting and
* optifine's fogQuality setting return what fog
* settings should be used when rendering.
* Return what fog settings should be used when rendering.
*/
private NearFarFogSetting determineFogSettings()
private NearFarFogSettings determineFogSettings()
{
NearFarFogSetting fogSetting = new NearFarFogSetting();
NearFarFogSettings fogSettings = new NearFarFogSettings();
switch(reflectionHandler.getFogQuality())
FogQuality quality = reflectionHandler.getFogQuality();
FogDrawOverride override = LodConfig.CLIENT.fogDrawOverride.get();
if (quality == FogQuality.OFF)
fogSettings.vanillaIsRenderingFog = false;
else
fogSettings.vanillaIsRenderingFog = true;
// use any fog overrides the user may have set
switch(override)
{
case ALWAYS_DRAW_FOG_FANCY:
quality = FogQuality.FANCY;
break;
case NEVER_DRAW_FOG:
quality = FogQuality.OFF;
break;
case ALWAYS_DRAW_FOG_FAST:
quality = FogQuality.FAST;
break;
case USE_OPTIFINE_FOG_SETTING:
// don't override anything
break;
}
// only use fancy fog if the user's GPU can deliver
if (!fancyFogAvailable && quality == FogQuality.FANCY)
{
quality = FogQuality.FAST;
}
// how different distances are drawn depends on the quality set
switch(quality)
{
case FANCY:
fogSettings.near.quality = FogQuality.FANCY;
fogSettings.far.quality = FogQuality.FANCY;
switch(LodConfig.CLIENT.fogDistance.get())
{
case NEAR_AND_FAR:
fogSetting.nearFogSetting = FogDistance.NEAR;
fogSetting.farFogSetting = FogDistance.FAR;
fogSettings.near.distance = FogDistance.NEAR;
fogSettings.far.distance = FogDistance.FAR;
break;
case NEAR:
fogSetting.nearFogSetting = FogDistance.NEAR;
fogSetting.farFogSetting = FogDistance.NEAR;
fogSettings.near.distance = FogDistance.NEAR;
fogSettings.far.distance = FogDistance.NEAR;
break;
case FAR:
fogSetting.nearFogSetting = FogDistance.FAR;
fogSetting.farFogSetting = FogDistance.FAR;
fogSettings.near.distance = FogDistance.FAR;
fogSettings.far.distance = FogDistance.FAR;
break;
}
break;
case FAST:
fogSettings.near.quality = FogQuality.FAST;
fogSettings.far.quality = FogQuality.FAST;
// fast fog setting should only have one type of
// fog, since the LODs are separated into a near
// and far portion; and fast fog is rendered from the
// frustrum's perspective instead of the camera
switch(LodConfig.CLIENT.fogDistance.get())
{
case NEAR_AND_FAR:
fogSetting.nearFogSetting = FogDistance.NEAR;
fogSetting.farFogSetting = FogDistance.NEAR;
fogSettings.near.distance = FogDistance.NEAR;
fogSettings.far.distance = FogDistance.NEAR;
break;
case NEAR:
fogSetting.nearFogSetting = FogDistance.NEAR;
fogSetting.farFogSetting = FogDistance.NEAR;
fogSettings.near.distance = FogDistance.NEAR;
fogSettings.far.distance = FogDistance.NEAR;
break;
case FAR:
fogSetting.nearFogSetting = FogDistance.FAR;
fogSetting.farFogSetting = FogDistance.FAR;
fogSettings.near.distance = FogDistance.FAR;
fogSettings.far.distance = FogDistance.FAR;
break;
}
break;
break;
case OFF:
fogSettings.near.quality = FogQuality.OFF;
fogSettings.far.quality = FogQuality.OFF;
break;
}
return fogSetting;
return fogSettings;
}