diff --git a/api/src/main/java/com/seibel/distanthorizons/api/enums/rendering/EDhApiFogFalloff.java b/api/src/main/java/com/seibel/distanthorizons/api/enums/rendering/EDhApiFogFalloff.java index 3437cd00a..8fbe37a2a 100644 --- a/api/src/main/java/com/seibel/distanthorizons/api/enums/rendering/EDhApiFogFalloff.java +++ b/api/src/main/java/com/seibel/distanthorizons/api/enums/rendering/EDhApiFogFalloff.java @@ -25,7 +25,7 @@ package com.seibel.distanthorizons.api.enums.rendering; * EXPONENTIAL_SQUARED
* * @author Leetom - * @version 2022-6-30 + * @version 2024-11-09 * @since API 2.0.0 */ public enum EDhApiFogFalloff @@ -35,8 +35,17 @@ public enum EDhApiFogFalloff // when removing items up the API major version - LINEAR, - EXPONENTIAL, - EXPONENTIAL_SQUARED, + LINEAR(0), + EXPONENTIAL(1), + EXPONENTIAL_SQUARED(2); + + + /** + * Stable version of {@link EDhApiFogFalloff#ordinal()} + * @since API 4.0.0 + */ + public final int value; + + EDhApiFogFalloff(int value) { this.value = value; } } diff --git a/api/src/main/java/com/seibel/distanthorizons/api/enums/rendering/EDhApiHeightFogMode.java b/api/src/main/java/com/seibel/distanthorizons/api/enums/rendering/EDhApiHeightFogDirection.java similarity index 68% rename from api/src/main/java/com/seibel/distanthorizons/api/enums/rendering/EDhApiHeightFogMode.java rename to api/src/main/java/com/seibel/distanthorizons/api/enums/rendering/EDhApiHeightFogDirection.java index 81a847630..624b391f6 100644 --- a/api/src/main/java/com/seibel/distanthorizons/api/enums/rendering/EDhApiHeightFogMode.java +++ b/api/src/main/java/com/seibel/distanthorizons/api/enums/rendering/EDhApiHeightFogDirection.java @@ -31,28 +31,28 @@ package com.seibel.distanthorizons.api.enums.rendering; * @version 2024-4-6 * @since API 2.0.0 */ -public enum EDhApiHeightFogMode +public enum EDhApiHeightFogDirection { // Reminder: // when adding items up the API minor version // when removing items up the API major version - ABOVE_CAMERA(true, true, false), - BELOW_CAMERA(true, false, true), - ABOVE_AND_BELOW_CAMERA(true, true, true), - ABOVE_SET_HEIGHT(false, true, false), - BELOW_SET_HEIGHT(false, false, true), - ABOVE_AND_BELOW_SET_HEIGHT(false, true, true); + ABOVE_CAMERA (true, true, false), + BELOW_CAMERA (true, false, true), + ABOVE_AND_BELOW_CAMERA (true, true, true), + ABOVE_SET_HEIGHT (false, true, false), + BELOW_SET_HEIGHT (false, false, true), + ABOVE_AND_BELOW_SET_HEIGHT (false, true, true); public final boolean basedOnCamera; - public final boolean above; - public final boolean below; + public final boolean fogAppliesUp; + public final boolean fogAppliesDown; - EDhApiHeightFogMode(boolean basedOnCamera, boolean above, boolean below) + EDhApiHeightFogDirection(boolean basedOnCamera, boolean fogAppliesUp, boolean fogAppliesDown) { this.basedOnCamera = basedOnCamera; - this.above = above; - this.below = below; + this.fogAppliesUp = fogAppliesUp; + this.fogAppliesDown = fogAppliesDown; } } diff --git a/api/src/main/java/com/seibel/distanthorizons/api/enums/rendering/EDhApiHeightFogMixMode.java b/api/src/main/java/com/seibel/distanthorizons/api/enums/rendering/EDhApiHeightFogMixMode.java index 56226f2da..c2e5e7f38 100644 --- a/api/src/main/java/com/seibel/distanthorizons/api/enums/rendering/EDhApiHeightFogMixMode.java +++ b/api/src/main/java/com/seibel/distanthorizons/api/enums/rendering/EDhApiHeightFogMixMode.java @@ -20,10 +20,11 @@ package com.seibel.distanthorizons.api.enums.rendering; /** - * BASIC
- * IGNORE_HEIGHT
- * ADDITION
+ * SPHERICAL
+ * CYLINDRICAL
+ *
* MAX
+ * ADDITION
* MULTIPLY
* INVERSE_MULTIPLY
* LIMITED_ADDITION
@@ -37,14 +38,36 @@ package com.seibel.distanthorizons.api.enums.rendering; */ public enum EDhApiHeightFogMixMode { - BASIC, - IGNORE_HEIGHT, - ADDITION, - MAX, - MULTIPLY, - INVERSE_MULTIPLY, - LIMITED_ADDITION, - MULTIPLY_ADDITION, - INVERSE_MULTIPLY_ADDITION, - AVERAGE, + /** + * Basic just means the fog will be based on the fragment depth + * not on any special height calculation IE spherical fog.

+ * + * Not to be confused with {@link EDhApiHeightFogMixMode#CYLINDRICAL} + * which causes fog to only apply based on horizontal distance. + */ + SPHERICAL(0), + /** + * Fog is applied based on horizontal distance from the camera, + * IE cylindrical fog. + */ + CYLINDRICAL(1), + + MAX(2), + ADDITION(3), + MULTIPLY(4), + INVERSE_MULTIPLY(5), + LIMITED_ADDITION(6), + MULTIPLY_ADDITION(7), + INVERSE_MULTIPLY_ADDITION(8), + AVERAGE(9); + + + /** + * Stable version of {@link EDhApiFogFalloff#ordinal()} + * @since API 4.0.0 + */ + public final int value; + + EDhApiHeightFogMixMode(int value) { this.value = value; } + } diff --git a/api/src/main/java/com/seibel/distanthorizons/api/interfaces/config/client/IDhApiHeightFogConfig.java b/api/src/main/java/com/seibel/distanthorizons/api/interfaces/config/client/IDhApiHeightFogConfig.java index 754cc01a9..f348f94ba 100644 --- a/api/src/main/java/com/seibel/distanthorizons/api/interfaces/config/client/IDhApiHeightFogConfig.java +++ b/api/src/main/java/com/seibel/distanthorizons/api/interfaces/config/client/IDhApiHeightFogConfig.java @@ -21,7 +21,7 @@ package com.seibel.distanthorizons.api.interfaces.config.client; import com.seibel.distanthorizons.api.enums.rendering.EDhApiFogFalloff; import com.seibel.distanthorizons.api.enums.rendering.EDhApiHeightFogMixMode; -import com.seibel.distanthorizons.api.enums.rendering.EDhApiHeightFogMode; +import com.seibel.distanthorizons.api.enums.rendering.EDhApiHeightFogDirection; import com.seibel.distanthorizons.api.interfaces.config.IDhApiConfigGroup; import com.seibel.distanthorizons.api.interfaces.config.IDhApiConfigValue; @@ -42,11 +42,14 @@ public interface IDhApiHeightFogConfig extends IDhApiConfigGroup /** Defines how the height fog mixes. */ IDhApiConfigValue heightFogMixMode(); - /** Defines how the height fog is drawn relative to the camera or world. */ - IDhApiConfigValue heightFogMode(); + /** + * Defines which direction height fog is drawn relative to the world. + * @since API 4.0.0 + */ + IDhApiConfigValue heightFogDirection(); /** - * Defines the height fog's base height if {@link IDhApiHeightFogConfig#heightFogMode()} + * Defines the height fog's base height if {@link IDhApiHeightFogConfig#heightFogDirection()} * is set to use a specific height. */ IDhApiConfigValue heightFogBaseHeight(); diff --git a/core/src/main/java/com/seibel/distanthorizons/core/api/external/methods/config/client/DhApiHeightFogConfig.java b/core/src/main/java/com/seibel/distanthorizons/core/api/external/methods/config/client/DhApiHeightFogConfig.java index b65925172..05f3b3e43 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/api/external/methods/config/client/DhApiHeightFogConfig.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/api/external/methods/config/client/DhApiHeightFogConfig.java @@ -21,7 +21,7 @@ package com.seibel.distanthorizons.core.api.external.methods.config.client; import com.seibel.distanthorizons.api.enums.rendering.EDhApiFogFalloff; import com.seibel.distanthorizons.api.enums.rendering.EDhApiHeightFogMixMode; -import com.seibel.distanthorizons.api.enums.rendering.EDhApiHeightFogMode; +import com.seibel.distanthorizons.api.enums.rendering.EDhApiHeightFogDirection; import com.seibel.distanthorizons.api.interfaces.config.IDhApiConfigValue; import com.seibel.distanthorizons.api.interfaces.config.client.IDhApiHeightFogConfig; import com.seibel.distanthorizons.api.objects.config.DhApiConfigValue; @@ -40,8 +40,8 @@ public class DhApiHeightFogConfig implements IDhApiHeightFogConfig { return new DhApiConfigValue(Config.Client.Advanced.Graphics.Fog.HeightFog.heightFogMixMode); } @Override - public IDhApiConfigValue heightFogMode() - { return new DhApiConfigValue(Config.Client.Advanced.Graphics.Fog.HeightFog.heightFogMode); } + public IDhApiConfigValue heightFogDirection() + { return new DhApiConfigValue(Config.Client.Advanced.Graphics.Fog.HeightFog.heightFogDirection); } @Override public IDhApiConfigValue heightFogBaseHeight() 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 1dd476e92..73910ed05 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 @@ -39,7 +39,6 @@ import com.seibel.distanthorizons.coreapi.ModInfo; import org.apache.logging.log4j.Logger; import org.lwjgl.util.tinyfd.TinyFileDialogs; -import javax.swing.*; import java.awt.*; import java.io.File; import java.util.*; @@ -549,40 +548,40 @@ public class Config public static class HeightFog { public static ConfigEntry heightFogMixMode = new ConfigEntry.Builder() - .set(EDhApiHeightFogMixMode.BASIC) + .set(EDhApiHeightFogMixMode.SPHERICAL) .comment("" + "How should height effect the fog thickness? \n" + "Note: height fog is combined with the other fog settings. \n" + "\n" - + EDhApiHeightFogMixMode.BASIC + ": No special height fog effect. Fog is calculated based on camera distance \n" - + EDhApiHeightFogMixMode.IGNORE_HEIGHT + ": Ignore height completely. Fog is only calculated with horizontal distance \n" - + EDhApiHeightFogMixMode.ADDITION + ": heightFog + farFog \n" + + EDhApiHeightFogMixMode.SPHERICAL + ": Fog is calculated based on camera distance. \n" + + EDhApiHeightFogMixMode.CYLINDRICAL + ": Ignore height, fog is calculated based on horizontal distance. \n" + + "\n" + EDhApiHeightFogMixMode.MAX + ": max(heightFog, farFog) \n" + + EDhApiHeightFogMixMode.ADDITION + ": heightFog + farFog \n" + EDhApiHeightFogMixMode.MULTIPLY + ": heightFog * farFog \n" + EDhApiHeightFogMixMode.INVERSE_MULTIPLY + ": 1 - (1-heightFog) * (1-farFog) \n" + EDhApiHeightFogMixMode.LIMITED_ADDITION + ": farFog + max(farFog, heightFog) \n" + EDhApiHeightFogMixMode.MULTIPLY_ADDITION + ": farFog + farFog * heightFog \n" + EDhApiHeightFogMixMode.INVERSE_MULTIPLY_ADDITION + ": farFog + 1 - (1-heightFog) * (1-farFog) \n" + EDhApiHeightFogMixMode.AVERAGE + ": farFog*0.5 + heightFog*0.5 \n" - + "\n" - + "Note: height fog settings are ignored if '" + EDhApiHeightFogMixMode.BASIC + "' or '" + EDhApiHeightFogMixMode.IGNORE_HEIGHT + "' are selected.") + + "\n") .build(); - public static ConfigEntry heightFogMode = new ConfigEntry.Builder() - .set(EDhApiHeightFogMode.ABOVE_AND_BELOW_CAMERA) + public static ConfigEntry heightFogDirection = new ConfigEntry.Builder() + .set(EDhApiHeightFogDirection.BELOW_SET_HEIGHT) .comment("" + "Where should the height fog start? \n" + "\n" - + EDhApiHeightFogMode.ABOVE_CAMERA + ": Height fog starts at the camera and goes towards the sky \n" - + EDhApiHeightFogMode.BELOW_CAMERA + ": Height fog starts at the camera and goes towards the void \n" - + EDhApiHeightFogMode.ABOVE_AND_BELOW_CAMERA + ": Height fog starts from the camera to goes towards both the sky and void \n" - + EDhApiHeightFogMode.ABOVE_SET_HEIGHT + ": Height fog starts from a set height and goes towards the sky \n" - + EDhApiHeightFogMode.BELOW_SET_HEIGHT + ": Height fog starts from a set height and goes towards the void \n" - + EDhApiHeightFogMode.ABOVE_AND_BELOW_SET_HEIGHT + ": Height fog starts from a set height and goes towards both the sky and void") + + EDhApiHeightFogDirection.ABOVE_CAMERA + ": Height fog starts at the camera and goes towards the sky \n" + + EDhApiHeightFogDirection.BELOW_CAMERA + ": Height fog starts at the camera and goes towards the void \n" + + EDhApiHeightFogDirection.ABOVE_AND_BELOW_CAMERA + ": Height fog starts from the camera to goes towards both the sky and void \n" + + EDhApiHeightFogDirection.ABOVE_SET_HEIGHT + ": Height fog starts from a set height and goes towards the sky \n" + + EDhApiHeightFogDirection.BELOW_SET_HEIGHT + ": Height fog starts from a set height and goes towards the void \n" + + EDhApiHeightFogDirection.ABOVE_AND_BELOW_SET_HEIGHT + ": Height fog starts from a set height and goes towards both the sky and void") .build(); public static ConfigEntry heightFogBaseHeight = new ConfigEntry.Builder() - .setMinDefaultMax(-4096.0, 70.0, 4096.0) + .setMinDefaultMax(-4096.0, 80.0, 4096.0) .comment("If the height fog is calculated around a set height, what is that height position?") .build(); @@ -596,7 +595,7 @@ public class Config .build(); public static ConfigEntry heightFogEnd = new ConfigEntry.Builder() - .setMinDefaultMax(FOG_RANGE_MIN, 1.0, FOG_RANGE_MAX) + .setMinDefaultMax(FOG_RANGE_MIN, 0.6, FOG_RANGE_MAX) .comment("" + "Should the end of the height fog be offset? \n" + "\n" @@ -605,7 +604,7 @@ public class Config .build(); public static ConfigEntry heightFogMin = new ConfigEntry.Builder() - .setMinDefaultMax(-5.0, 0.0, FOG_RANGE_MAX) + .setMinDefaultMax(0.0, 0.0, FOG_RANGE_MAX) .comment("" + "What is the minimum fog thickness? \n" + "\n" @@ -633,7 +632,7 @@ public class Config .build(); public static ConfigEntry heightFogDensity = new ConfigEntry.Builder() - .setMinDefaultMax(0.01, 2.5, 50.0) + .setMinDefaultMax(0.01, 20.0, 50.0) .comment("What is the height fog's density?") .build(); diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/fog/LodFogConfig.java b/core/src/main/java/com/seibel/distanthorizons/core/render/fog/LodFogConfig.java deleted file mode 100644 index 3ea6f8455..000000000 --- a/core/src/main/java/com/seibel/distanthorizons/core/render/fog/LodFogConfig.java +++ /dev/null @@ -1,420 +0,0 @@ -/* - * This file is part of the Distant Horizons mod - * licensed under the GNU LGPL v3 License. - * - * Copyright (C) 2020-2023 James Seibel - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, version 3. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -package com.seibel.distanthorizons.core.render.fog; - -import com.seibel.distanthorizons.api.enums.rendering.*; -import com.seibel.distanthorizons.core.config.Config; -import com.seibel.distanthorizons.core.dependencyInjection.ModAccessorInjector; -import com.seibel.distanthorizons.core.render.glObject.GLProxy; -import com.seibel.distanthorizons.core.render.glObject.shader.Shader; -import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IOptifineAccessor; - -import java.io.FileOutputStream; -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.util.Objects; - -/** - * This holds fog related settings and - * creates the fog related shader code. - * - * @author Leetom - * @author James Seibel - * @version 2022-11-24 - */ -// TODO: Move lots out of here, there should be a listener hooked onto the config to update the shader -public class LodFogConfig -{ - private static final IOptifineAccessor OPTIFINE = ModAccessorInjector.INSTANCE.get(IOptifineAccessor.class); - - public static final boolean DEBUG_DUMP_GENERATED_CODE = false; - - public final FogSettings farFogSetting; - public final FogSettings heightFogSetting; - public final EDhApiHeightFogMixMode heightFogMixMode; - public final EDhApiHeightFogMode heightFogMode; - public final float heightFogHeight; - - // TODO: Move these out of here - public final int earthCurveRatio; - - // Noise Values - public final boolean noiseEnable; - public final int noiseSteps; - public final float noiseIntensity; - public final int noiseDropoff; - - - public static LodFogConfig generateFogConfig() { return new LodFogConfig(); } - - /** sets all fog options from the config */ - private LodFogConfig() - { - // TODO: Move these out of here - this.earthCurveRatio = Config.Client.Advanced.Graphics.Experimental.earthCurveRatio.get(); - - this.noiseEnable = Config.Client.Advanced.Graphics.NoiseTexture.enableNoiseTexture.get(); - this.noiseSteps = Config.Client.Advanced.Graphics.NoiseTexture.noiseSteps.get(); - this.noiseIntensity = Config.Client.Advanced.Graphics.NoiseTexture.noiseIntensity.get().floatValue(); - this.noiseDropoff = Config.Client.Advanced.Graphics.NoiseTexture.noiseDropoff.get(); - - - if (Config.Client.Advanced.Graphics.Fog.enableDhFog.get()) - { - // fog should be drawn - - this.farFogSetting = new FogSettings( - Config.Client.Advanced.Graphics.Fog.farFogStart.get(), - Config.Client.Advanced.Graphics.Fog.farFogEnd.get(), - Config.Client.Advanced.Graphics.Fog.farFogMin.get(), - Config.Client.Advanced.Graphics.Fog.farFogMax.get(), - Config.Client.Advanced.Graphics.Fog.farFogDensity.get(), - Config.Client.Advanced.Graphics.Fog.farFogFalloff.get() - ); - - this.heightFogMixMode = Config.Client.Advanced.Graphics.Fog.HeightFog.heightFogMixMode.get(); - if (this.heightFogMixMode == EDhApiHeightFogMixMode.IGNORE_HEIGHT - || this.heightFogMixMode == EDhApiHeightFogMixMode.BASIC) - { - // basic fog mixing - - this.heightFogSetting = null; - this.heightFogMode = null; - this.heightFogHeight = 0.f; - } - else - { - // advanced fog mixing - - this.heightFogSetting = new FogSettings( - Config.Client.Advanced.Graphics.Fog.HeightFog.heightFogDensity.get(), - Config.Client.Advanced.Graphics.Fog.HeightFog.heightFogEnd.get(), - Config.Client.Advanced.Graphics.Fog.HeightFog.heightFogMin.get(), - Config.Client.Advanced.Graphics.Fog.HeightFog.heightFogMax.get(), - Config.Client.Advanced.Graphics.Fog.HeightFog.heightFogDensity.get(), - Config.Client.Advanced.Graphics.Fog.HeightFog.heightFogFalloff.get() - ); - - this.heightFogMode = Config.Client.Advanced.Graphics.Fog.HeightFog.heightFogMode.get(); - - if (this.heightFogMode.basedOnCamera) - { - this.heightFogHeight = 0.f; - } - else - { - this.heightFogHeight = Config.Client.Advanced.Graphics.Fog.HeightFog.heightFogBaseHeight.get().floatValue(); - } - } - } - else - { - // fog disabled - - this.farFogSetting = null; - this.heightFogMixMode = null; - this.heightFogMode = null; - this.heightFogSetting = null; - this.heightFogHeight = 0.f; - } - } - - public StringBuilder loadAndProcessFragShader(String path, boolean absoluteFilePath) - { - StringBuilder stringBuilder = this.makeRuntimeDefine(); - this.generateRuntimeShaderCode(Shader.loadFile(path, absoluteFilePath, stringBuilder)); - - if (DEBUG_DUMP_GENERATED_CODE) - { - try (FileOutputStream file = new FileOutputStream("debugGenerated.frag", false)) - { - file.write(stringBuilder.toString().getBytes(StandardCharsets.UTF_8)); - GLProxy.GL_LOGGER.info("Debug dumped generated code to debugGenerated.frag for {}", path); - } - catch (IOException e) - { - GLProxy.GL_LOGGER.warn("Failed to debug dump generated code to file for {}", path); - } - } - - return stringBuilder; - } - - /** Generates the necessary constants for a fragment shader */ - private void generateRuntimeShaderCode(StringBuilder str) - { - str.append("// =======RUNTIME GENERATED CODE SECTION======== //\n"); - - // Generate method: float getNearFogThickness(float dist); - str.append("" + - "float getNearFogThickness(float dist) \n" + - "{ \n" + - " return linearFog(dist, uNearFogStart, uNearFogLength, 0.0, 1.0); \n" + - "} \n"); - - - if (this.farFogSetting == null) - { - str.append("\n" + - "float getFarFogThickness(float dist) { return 0.0; } \n" + - "float getHeightFogThickness(float dist) { return 0.0; } \n" + - "float calculateFarFogDepth(float horizontal, float dist, float uNearFogStart) { return 0.0; } \n" + - "float calculateHeightFogDepth(float vertical, float realY) { return 0.0; } \n" + - "float mixFogThickness(float near, float far, float height) \n" + - "{ \n" + - " return 0.0; \n" + - "} \n\n"); - } - else - { - // Generate method: float getFarFogThickness(float dist); - str.append("" + - "float getFarFogThickness(float dist) \n" + - "{ \n" + - getFarFogMethod(this.farFogSetting.fogType) + "\n" + - "} \n"); - - - // Generate method: float getHeightFogThickness(float dist); - str.append("" + - "float getHeightFogThickness(float dist) \n" + - "{ \n" + - (this.heightFogSetting != null ? getHeightFogMethod(this.heightFogSetting.fogType) : " return 0.0;") + "\n" + - "} \n"); - - - // Generate method: float calculateHeightFogDepth(float vertical, float realY); - str.append("" + - "float calculateHeightFogDepth(float vertical, float realY) \n" + - "{ \n" + - (this.heightFogSetting != null ? getHeightDepthMethod(this.heightFogMode, this.heightFogHeight) : " return 0.0;") + "\n" + - "} \n"); - - - // Generate method: calculateFarFogDepth(float horizontal, float dist, float uNearFogStart); - str.append("" + - "float calculateFarFogDepth(float horizontal, float dist, float uNearFogStart) \n" + - "{ \n" + - " return " + (this.heightFogMixMode == EDhApiHeightFogMixMode.BASIC ? - "(dist - uNearFogStart)/(1.0 - uNearFogStart);" : - "(horizontal - uNearFogStart)/(1.0 - uNearFogStart);") + - "} \n"); - - // Generate method: float mixFogThickness(float near, float far, float height); - str.append("" + - "float mixFogThickness(float near, float far, float height) \n" + - "{ \n" + - getMixFogLine(this.heightFogMixMode) + "\n" + - "} \n"); - } - } - - - - //=================// - // shader creation // - // helper methods // - //=================// - - private StringBuilder makeRuntimeDefine() - { - StringBuilder str = new StringBuilder(); - str.append("// =======RUNTIME GENERATED DEFINE SECTION======== //\n"); - str.append("#version 150 core\n"); - - FogSettings activeFarFogSetting = this.farFogSetting != null ? this.farFogSetting : FogSettings.EMPTY; - FogSettings activeHeightFogSetting = this.heightFogSetting != null ? this.heightFogSetting : FogSettings.EMPTY; - - str.append("\n" + - "#define farFogStart " + activeFarFogSetting.start + "\n" + - "#define farFogLength " + (activeFarFogSetting.end - activeFarFogSetting.start) + "\n" + - "#define farFogMin " + activeFarFogSetting.min + "\n" + - "#define farFogRange " + (activeFarFogSetting.max - activeFarFogSetting.min) + "\n" + - "#define farFogDensity " + activeFarFogSetting.density + "\n" + - "\n" + - "#define heightFogStart " + activeHeightFogSetting.start + "\n" + - "#define heightFogLength " + (activeHeightFogSetting.end - activeHeightFogSetting.start) + "\n" + - "#define heightFogMin " + activeHeightFogSetting.min + "\n" + - "#define heightFogRange " + (activeHeightFogSetting.max - activeHeightFogSetting.min) + "\n" + - "#define heightFogDensity " + activeHeightFogSetting.density + "\n" + - "\n"); - - str.append("// =======RUNTIME END======== //\n"); - return str; - } - - private static String getFarFogMethod(EDhApiFogFalloff fogType) - { - switch (fogType) - { - case LINEAR: - return "return linearFog(dist, farFogStart, farFogLength, farFogMin, farFogRange);\n"; - case EXPONENTIAL: - return "return exponentialFog(dist, farFogStart, farFogLength, farFogMin, farFogRange, farFogDensity);\n"; - case EXPONENTIAL_SQUARED: - return "return exponentialSquaredFog(dist, farFogStart, farFogLength, farFogMin, farFogRange, farFogDensity);\n"; - - default: - throw new IllegalArgumentException("FogType [" + fogType + "] not implemented for [getFarFogMethod]."); - } - } - - private static String getHeightDepthMethod(EDhApiHeightFogMode heightMode, float heightFogHeight) - { - String str = ""; - if (!heightMode.basedOnCamera) - { - str = " vertical = realY - (" + heightFogHeight + ");\n"; - } - - if (heightMode.below && heightMode.above) - { - str += " return abs(vertical);\n"; - } - else if (heightMode.below) - { - str += " return -vertical;\n"; - } - else if (heightMode.above) - { - str += " return vertical;\n"; - } - else - { - str += " return 0;\n"; - } - return str; - } - - /** - * Returns the method call for the given fog type.
- * Example:
- * " return linearFog(dist, heightFogStart, heightFogLength, heightFogMin, heightFogRange);" - */ - private static String getHeightFogMethod(EDhApiFogFalloff fogType) - { - switch (fogType) - { - case LINEAR: - return " return linearFog(dist, heightFogStart, heightFogLength, heightFogMin, heightFogRange);\n"; - case EXPONENTIAL: - return " return exponentialFog(dist, heightFogStart, heightFogLength, heightFogMin, heightFogRange, heightFogDensity);\n"; - case EXPONENTIAL_SQUARED: - return " return exponentialSquaredFog(dist, heightFogStart, heightFogLength, heightFogMin, heightFogRange, heightFogDensity);\n"; - - default: - throw new IllegalArgumentException("FogType [" + fogType + "] not implemented for [getHeightFogMethod]."); - } - } - - /** - * creates a line in the format
- * " return max(1.0-near, far);" - */ - private static String getMixFogLine(EDhApiHeightFogMixMode heightFogMode) - { - String str = " return "; - - switch (heightFogMode) - { - case BASIC: - case IGNORE_HEIGHT: - str += "near * far;\n"; - break; - - case ADDITION: - str += "near * (far + height);\n"; - break; - - case MAX: - str += "near * max(far, height);\n"; - break; - - case INVERSE_MULTIPLY: - str += "near * (1.0 - (1.0-far)*(1.0-height));\n"; - break; - - case MULTIPLY: - str += "near * far * height;\n"; - break; - - case LIMITED_ADDITION: - str += "near * (far + max(far, height));\n"; - break; - - case MULTIPLY_ADDITION: - str += "near * (far + far*height);\n"; - break; - - case INVERSE_MULTIPLY_ADDITION: - str += "near * (far + 1.0 - (1.0-far)*(1.0-height));\n"; - break; - - case AVERAGE: - str += "near * (far*0.5 + height*0.5);\n"; - break; - - default: - throw new IllegalArgumentException("FogType [" + heightFogMode + "] not implemented for [getMixFogMethod]."); - } - - return str; - } - - - - - - - //========================// - // default object methods // - //========================// - - @Override - public boolean equals(Object other) - { - if (this == other) - { - return true; - } - else if (other == null || this.getClass() != other.getClass()) - { - return false; - } - else - { - LodFogConfig that = (LodFogConfig) other; - return Float.compare(that.heightFogHeight, this.heightFogHeight) == 0 && - Objects.equals(this.farFogSetting, that.farFogSetting) && - Objects.equals(this.heightFogSetting, that.heightFogSetting) && this.heightFogMixMode == that.heightFogMixMode && - this.heightFogMode == that.heightFogMode - // TODO: Move these out of here - && this.earthCurveRatio == that.earthCurveRatio - && this.noiseEnable == that.noiseEnable && this.noiseSteps == that.noiseSteps && this.noiseIntensity == that.noiseIntensity && this.noiseDropoff == that.noiseDropoff; - } - } - - @Override - public int hashCode() - { - return Objects.hash(this.farFogSetting, this.heightFogSetting, this.heightFogMixMode, this.heightFogMode, this.heightFogHeight, this.earthCurveRatio, this.noiseEnable, this.noiseSteps, this.noiseIntensity, this.noiseDropoff); - } - -} diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/glObject/shader/ShaderProgram.java b/core/src/main/java/com/seibel/distanthorizons/core/render/glObject/shader/ShaderProgram.java index fc821a461..94c1284a1 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/render/glObject/shader/ShaderProgram.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/render/glObject/shader/ShaderProgram.java @@ -49,6 +49,8 @@ public class ShaderProgram /** Stores the handle of the program. */ public final int id; + + // TODO: A better way to set the fragData output name /** * Creates a shader program. @@ -73,20 +75,20 @@ public class ShaderProgram } - public ShaderProgram(List> vert, List> frag, String[] attributes) + public ShaderProgram(List> vertSupplierList, List> fragSupplierList, String[] attributes) { - id = GL32.glCreateProgram(); + this.id = GL32.glCreateProgram(); - for (Supplier v : vert) + for (Supplier vertSupplier : vertSupplierList) { - Shader vertShader = new Shader(GL32.GL_VERTEX_SHADER, v.get()); + Shader vertShader = new Shader(GL32.GL_VERTEX_SHADER, vertSupplier.get()); GL32.glAttachShader(this.id, vertShader.id); vertShader.free(); // important! } - for (Supplier f : frag) + for (Supplier fragSupplier : fragSupplierList) { - Shader fragShader = new Shader(GL32.GL_FRAGMENT_SHADER, f.get()); + Shader fragShader = new Shader(GL32.GL_FRAGMENT_SHADER, fragSupplier.get()); GL32.glAttachShader(this.id, fragShader.id); fragShader.free(); // important! } @@ -101,28 +103,22 @@ public class ShaderProgram if (status != GL32.GL_TRUE) { String message = "Shader Link Error. Details: " + GL32.glGetProgramInfoLog(this.id); - free(); // important! + this.free(); // important! throw new RuntimeException(message); } - GL32.glUseProgram(id); // This HAVE to be a direct call to prevent calling the overloaded version + GL32.glUseProgram(this.id); // This HAVE to be a direct call to prevent calling the overloaded version } - /** This will bind ShaderProgram */ - public void bind() - { - GL32.glUseProgram(id); - } - /** This will unbind ShaderProgram */ - public void unbind() - { - GL32.glUseProgram(0); - } - // REMEMBER to always free the resource! - public void free() - { - GL32.glDeleteProgram(id); - } + + + public void bind() { GL32.glUseProgram(this.id); } + public void unbind() { GL32.glUseProgram(0); } + + public void free() { GL32.glDeleteProgram(this.id); } + + + /** * WARNING: Slow native call! Cache it if possible! @@ -139,12 +135,12 @@ public class ShaderProgram if (i == -1) throw new RuntimeException("Attribute name not found: " + name); return i; } - // Same as above but without throwing errors. - // Return -1 if attribute doesn't exist or has been optimized out + /** + * Same as above but without throwing errors.
+ * Returns -1 if the attribute doesn't exist or has been optimized out. + */ public int tryGetAttributeLocation(CharSequence name) - { - return GL32.glGetAttribLocation(id, name); - } + { return GL32.glGetAttribLocation(this.id, name); } /** * WARNING: Slow native call! Cache it if possible! @@ -168,41 +164,34 @@ public class ShaderProgram // Same as above but without throwing errors. // Return -1 if uniform doesn't exist or has been optimized out public int tryGetUniformLocation(CharSequence name) - { - return GL32.glGetUniformLocation(id, name); - } + { return GL32.glGetUniformLocation(this.id, name); } - /** Requires ShaderProgram binded. */ - public void setUniform(int location, boolean value) - { - // This use -1 for false as that equals all one set - GL32.glUniform1i(location, value ? 1 : 0); - } + /** Requires a bound ShaderProgram. */ + public void setUniform(int location, boolean value) { GL32.glUniform1i(location, value ? 1 : 0); } + /** @see ShaderProgram#setUniform(int, boolean) */ + public void trySetUniform(int location, boolean value) { if (location != -1) { this.setUniform(location, value); } } - /** Requires ShaderProgram binded. */ - public void setUniform(int location, int value) - { - GL32.glUniform1i(location, value); - } + /** Requires a bound ShaderProgram. */ + public void setUniform(int location, int value) { GL32.glUniform1i(location, value); } + /** @see ShaderProgram#setUniform(int, int) */ + public void trySetUniform(int location, int value) { if (location != -1) { this.setUniform(location, value); } } - /** Requires ShaderProgram binded. */ - public void setUniform(int location, float value) - { - GL32.glUniform1f(location, value); - } + /** Requires a bound ShaderProgram. */ + public void setUniform(int location, float value) { GL32.glUniform1f(location, value); } + /** @see ShaderProgram#setUniform(int, float) */ + public void trySetUniform(int location, float value) { if (location != -1) { this.setUniform(location, value); } } - /** Requires ShaderProgram binded. */ - public void setUniform(int location, Vec3f value) - { - GL32.glUniform3f(location, value.x, value.y, value.z); - } - /** Requires ShaderProgram binded. */ - public void setUniform(int location, DhApiVec3i value) - { - GL32.glUniform3i(location, value.x, value.y, value.z); - } + /** Requires a bound ShaderProgram. */ + public void setUniform(int location, Vec3f value) { GL32.glUniform3f(location, value.x, value.y, value.z); } + /** @see ShaderProgram#setUniform(int, Vec3f) */ + public void trySetUniform(int location, Vec3f value) { if (location != -1) { this.setUniform(location, value); } } - /** Requires ShaderProgram binded. */ + /** Requires a bound ShaderProgram. */ + public void setUniform(int location, DhApiVec3i value) { GL32.glUniform3i(location, value.x, value.y, value.z); } + /** @see ShaderProgram#setUniform(int, Mat4f) */ + public void trySetUniform(int location, DhApiVec3i value) { if (location != -1) { this.setUniform(location, value); } } + + /** Requires a bound ShaderProgram. */ public void setUniform(int location, Mat4f value) { try (MemoryStack stack = MemoryStack.stackPush()) @@ -212,14 +201,22 @@ public class ShaderProgram GL32.glUniformMatrix4fv(location, false, buffer); } } + /** @see ShaderProgram#setUniform(int, Mat4f) */ + public void trySetUniform(int location, Mat4f value) { if (location != -1) { this.setUniform(location, value); } } /** - * Converts the color's RGBA values into values between 0 and 1. - * Requires ShaderProgram binded. + * Converts the color's RGBA values into values between 0 and 1.
+ * Requires a bound ShaderProgram. */ public void setUniform(int location, Color value) { - GL32.glUniform4f(location, value.getRed() / 256.0f, value.getGreen() / 256.0f, value.getBlue() / 256.0f, value.getAlpha() / 256.0f); + GL32.glUniform4f(location, + value.getRed() / 256.0f, + value.getGreen() / 256.0f, + value.getBlue() / 256.0f, + value.getAlpha() / 256.0f); } + /** @see ShaderProgram#setUniform(int, Color) */ + public void trySetUniform(int location, Color value) { if (location != -1) { this.setUniform(location, value); } } } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/LodRenderer.java b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/LodRenderer.java index cf91f4d5e..692fb8842 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/LodRenderer.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/LodRenderer.java @@ -44,7 +44,6 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRen import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IProfilerWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.misc.ILightMapWrapper; import com.seibel.distanthorizons.api.enums.rendering.EDhApiFogColorMode; -import com.seibel.distanthorizons.core.render.fog.LodFogConfig; import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.AbstractOptifineAccessor; import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IIrisAccessor; import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper; @@ -104,8 +103,7 @@ public class LodRenderer // The shader program - IDhApiShaderProgram lodRenderProgram = null; - LodFogConfig fogConfig; + private IDhApiShaderProgram lodRenderProgram = null; public QuadElementBuffer quadIBO = null; public boolean isSetupComplete = false; @@ -634,22 +632,6 @@ public class LodRenderer } else { - LodFogConfig newFogConfig = LodFogConfig.generateFogConfig(); // TODO use a config listener instead - if (this.fogConfig == null) - { - this.fogConfig = newFogConfig; - } - - if (!this.fogConfig.equals(newFogConfig)) - { - this.fogConfig = newFogConfig; - - this.lodRenderProgram.free(); - this.lodRenderProgram = new DhTerrainShaderProgram(); - - FogShader.INSTANCE.free(); - FogShader.INSTANCE = new FogShader(newFogConfig); - } this.lodRenderProgram.bind(); } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/shaders/FogShader.java b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/shaders/FogShader.java index f35eafc94..51666a335 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/shaders/FogShader.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/shaders/FogShader.java @@ -20,11 +20,11 @@ package com.seibel.distanthorizons.core.render.renderer.shaders; import com.seibel.distanthorizons.api.enums.rendering.EDhApiFogColorMode; +import com.seibel.distanthorizons.api.enums.rendering.EDhApiHeightFogDirection; +import com.seibel.distanthorizons.api.enums.rendering.EDhApiHeightFogMixMode; import com.seibel.distanthorizons.core.config.Config; import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector; -import com.seibel.distanthorizons.core.render.fog.LodFogConfig; import com.seibel.distanthorizons.core.render.glObject.GLState; -import com.seibel.distanthorizons.core.render.glObject.shader.Shader; import com.seibel.distanthorizons.core.render.glObject.shader.ShaderProgram; import com.seibel.distanthorizons.core.render.renderer.LodRenderer; import com.seibel.distanthorizons.core.render.renderer.ScreenQuad; @@ -38,7 +38,7 @@ import java.awt.*; public class FogShader extends AbstractShaderRenderer { - public static FogShader INSTANCE = new FogShader(LodFogConfig.generateFogConfig()); + public static final FogShader INSTANCE = new FogShader(); private static final IMinecraftClientWrapper MC = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class); private static final IVersionConstants VERSION_CONSTANTS = SingletonInjector.INSTANCE.get(IVersionConstants.class); @@ -46,21 +46,46 @@ public class FogShader extends AbstractShaderRenderer public int frameBuffer; - private final LodFogConfig fogConfig; private Mat4f inverseMvmProjMatrix; - // Uniforms + //==========// + // Uniforms // + //==========// + + public int uDepthMap; + /** Inverted Model View Projection matrix */ + public int uInvMvmProj; + + // fog uniforms public int uFogColor; public int uFogScale; public int uFogVerticalScale; - public int uNearFogStart; - public int uNearFogLength; public int uFullFogMode; - /** Inverted Model View Projection matrix */ - public int uInvMvmProj; - public int uDepthMap; + // far fog + public int uFarFogStart; + public int uFarFogLength; + public int uFarFogMin; + public int uFarFogRange; + public int uFarFogDensity; + + // height fog + public int uHeightFogStart; + public int uHeightFogLength; + public int uHeightFogMin; + public int uHeightFogRange; + public int uHeightFogDensity; + + public int uHeightFogEnabled; + public int uHeightFogFalloffType; + public int uHeightBasedOnCamera; + public int uHeightFogBaseHeight; + public int uHeightFogAppliesUp; + public int uHeightFogAppliesDown; + public int uUseSphericalFog; + public int uHeightFogMixingMode; + public int uCameraBlockYPos; @@ -68,15 +93,13 @@ public class FogShader extends AbstractShaderRenderer // constructor // //=============// - public FogShader(LodFogConfig fogConfig) { this.fogConfig = fogConfig; } - + public FogShader() { } + @Override public void onInit() { this.shader = new ShaderProgram( - // TODO rename normal.vert to something like "postProcess.vert" - () -> Shader.loadFile("shaders/normal.vert", false, new StringBuilder()).toString(), - () -> this.fogConfig.loadAndProcessFragShader("shaders/fog/fog.frag", false).toString(), + "shaders/normal.vert", "shaders/fog/fog.frag", "fragColor", new String[]{"vPosition"} ); @@ -87,15 +110,35 @@ public class FogShader extends AbstractShaderRenderer this.uInvMvmProj = this.shader.getUniformLocation("uInvMvmProj"); // Fog uniforms - this.uFogScale = this.shader.tryGetUniformLocation("uFogScale"); - this.uFogVerticalScale = this.shader.tryGetUniformLocation("uFogVerticalScale"); - this.uFogColor = this.shader.tryGetUniformLocation("uFogColor"); - this.uFullFogMode = this.shader.tryGetUniformLocation("uFullFogMode"); + this.uFogScale = this.shader.getUniformLocation("uFogScale"); + this.uFogVerticalScale = this.shader.getUniformLocation("uFogVerticalScale"); + this.uFogColor = this.shader.getUniformLocation("uFogColor"); + this.uFullFogMode = this.shader.getUniformLocation("uFullFogMode"); - // near fog - this.uNearFogStart = this.shader.tryGetUniformLocation("uNearFogStart"); - this.uNearFogLength = this.shader.tryGetUniformLocation("uNearFogLength"); + // fog config + this.uFarFogStart = this.shader.getUniformLocation("uFarFogStart"); + this.uFarFogLength = this.shader.getUniformLocation("uFarFogLength"); + this.uFarFogMin = this.shader.getUniformLocation("uFarFogMin"); + this.uFarFogRange = this.shader.getUniformLocation("uFarFogRange"); + this.uFarFogDensity = this.shader.getUniformLocation("uFarFogDensity"); + // height fog + this.uHeightFogStart = this.shader.getUniformLocation("uHeightFogStart"); + this.uHeightFogLength = this.shader.getUniformLocation("uHeightFogLength"); + this.uHeightFogMin = this.shader.getUniformLocation("uHeightFogMin"); + this.uHeightFogRange = this.shader.getUniformLocation("uHeightFogRange"); + this.uHeightFogDensity = this.shader.getUniformLocation("uHeightFogDensity"); + + this.uHeightFogEnabled = this.shader.getUniformLocation("uHeightFogEnabled"); + this.uHeightFogFalloffType = this.shader.getUniformLocation("uHeightFogFalloffType"); + this.uHeightBasedOnCamera = this.shader.getUniformLocation("uHeightBasedOnCamera"); + this.uHeightFogBaseHeight = this.shader.getUniformLocation("uHeightFogBaseHeight"); + this.uHeightFogAppliesUp = this.shader.getUniformLocation("uHeightFogAppliesUp"); + this.uHeightFogAppliesDown = this.shader.getUniformLocation("uHeightFogAppliesDown"); + this.uUseSphericalFog = this.shader.getUniformLocation("uUseSphericalFog"); + this.uHeightFogMixingMode = this.shader.getUniformLocation("uHeightFogMixingMode"); + this.uCameraBlockYPos = this.shader.getUniformLocation("uCameraBlockYPos"); + } @@ -107,22 +150,66 @@ public class FogShader extends AbstractShaderRenderer @Override protected void onApplyUniforms(float partialTicks) { + int lodDrawDistance = Config.Client.Advanced.Graphics.Quality.lodChunkRenderDistanceRadius.get() * LodUtil.CHUNK_WIDTH; + + + if (this.inverseMvmProjMatrix != null) { this.shader.setUniform(this.uInvMvmProj, this.inverseMvmProjMatrix); } - int lodDrawDistance = Config.Client.Advanced.Graphics.Quality.lodChunkRenderDistanceRadius.get() * LodUtil.CHUNK_WIDTH; - // Fog - if (this.uFullFogMode != -1) this.shader.setUniform(this.uFullFogMode, MC_RENDER.isFogStateSpecial() ? 1 : 0); - if (this.uFogColor != -1) this.shader.setUniform(this.uFogColor, MC_RENDER.isFogStateSpecial() ? this.getSpecialFogColor(partialTicks) : this.getFogColor(partialTicks)); + // Fog uniforms + this.shader.setUniform(this.uFogColor, MC_RENDER.isFogStateSpecial() ? this.getSpecialFogColor(partialTicks) : this.getFogColor(partialTicks)); + this.shader.setUniform(this.uFogScale, 1.f / lodDrawDistance); + this.shader.setUniform(this.uFogVerticalScale, 1.f / MC.getWrappedClientLevel().getMaxHeight()); + this.shader.setUniform(this.uFullFogMode, MC_RENDER.isFogStateSpecial() ? 1 : 0); + + + // fog config + float farFogStart = Config.Client.Advanced.Graphics.Fog.farFogStart.get().floatValue(); + float farFogEnd = Config.Client.Advanced.Graphics.Fog.farFogEnd.get().floatValue(); + float farFogMin = Config.Client.Advanced.Graphics.Fog.farFogMin.get().floatValue(); + float farFogMax = Config.Client.Advanced.Graphics.Fog.farFogMax.get().floatValue(); + float farFogDensity = Config.Client.Advanced.Graphics.Fog.farFogDensity.get().floatValue(); + + this.shader.setUniform(this.uFarFogStart, farFogStart); + this.shader.setUniform(this.uFarFogLength, farFogEnd - farFogStart); + this.shader.setUniform(this.uFarFogMin, farFogMin); + this.shader.setUniform(this.uFarFogRange, farFogMax - farFogMin); + this.shader.setUniform(this.uFarFogDensity, farFogDensity); + + + // height config + EDhApiHeightFogMixMode heightFogMixingMode = Config.Client.Advanced.Graphics.Fog.HeightFog.heightFogMixMode.get(); + boolean heightFogEnabled = heightFogMixingMode != EDhApiHeightFogMixMode.SPHERICAL && heightFogMixingMode != EDhApiHeightFogMixMode.CYLINDRICAL; + boolean useSphericalFog = heightFogMixingMode == EDhApiHeightFogMixMode.SPHERICAL; + EDhApiHeightFogDirection heightFogCameraDirection = Config.Client.Advanced.Graphics.Fog.HeightFog.heightFogDirection.get(); + + float heightFogStart = Config.Client.Advanced.Graphics.Fog.HeightFog.heightFogStart.get().floatValue(); + float heightFogEnd = Config.Client.Advanced.Graphics.Fog.HeightFog.heightFogEnd.get().floatValue(); + float heightFogMin = Config.Client.Advanced.Graphics.Fog.HeightFog.heightFogMin.get().floatValue(); + float heightFogMax = Config.Client.Advanced.Graphics.Fog.HeightFog.heightFogMax.get().floatValue(); + float heightFogDensity = Config.Client.Advanced.Graphics.Fog.HeightFog.heightFogDensity.get().floatValue(); + + this.shader.setUniform(this.uHeightFogStart, heightFogStart); + this.shader.setUniform(this.uHeightFogLength, heightFogEnd - heightFogStart); + this.shader.setUniform(this.uHeightFogMin, heightFogMin); + this.shader.setUniform(this.uHeightFogRange, heightFogMax - heightFogMin); + this.shader.setUniform(this.uHeightFogDensity, heightFogDensity); + + + this.shader.setUniform(this.uHeightFogEnabled, heightFogEnabled); + this.shader.setUniform(this.uHeightFogFalloffType, Config.Client.Advanced.Graphics.Fog.HeightFog.heightFogFalloff.get().value); + this.shader.setUniform(this.uHeightFogBaseHeight, Config.Client.Advanced.Graphics.Fog.HeightFog.heightFogBaseHeight.get().floatValue()); + this.shader.setUniform(this.uHeightBasedOnCamera, heightFogCameraDirection.basedOnCamera); + this.shader.setUniform(this.uHeightFogAppliesUp, heightFogCameraDirection.fogAppliesUp); + this.shader.setUniform(this.uHeightFogAppliesDown, heightFogCameraDirection.fogAppliesDown); + this.shader.setUniform(this.uUseSphericalFog, useSphericalFog); + this.shader.setUniform(this.uHeightFogMixingMode, heightFogMixingMode.value); + this.shader.setUniform(this.uCameraBlockYPos, (float)MC_RENDER.getCameraExactPosition().y); - float nearFogStart = (VERSION_CONSTANTS.isVanillaRenderedChunkSquare() ? (float) Math.sqrt(2.0) : 1.0f) / lodDrawDistance; - if (this.uNearFogStart != -1) this.shader.setUniform(this.uNearFogStart, nearFogStart); - if (this.uNearFogLength != -1) this.shader.setUniform(this.uNearFogLength, 0.0f); - if (this.uFogScale != -1) this.shader.setUniform(this.uFogScale, 1.f / lodDrawDistance); - if (this.uFogVerticalScale != -1) this.shader.setUniform(this.uFogVerticalScale, 1.f / MC.getWrappedClientLevel().getMaxHeight()); } private Color getFogColor(float partialTicks) { 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 80675ad7b..a2940b8c9 100644 --- a/core/src/main/resources/assets/distanthorizons/lang/en_us.json +++ b/core/src/main/resources/assets/distanthorizons/lang/en_us.json @@ -269,10 +269,10 @@ "distanthorizons.config.client.advanced.graphics.fog.heightFog.heightFogMixMode": "Height Fog Mix Mode", "distanthorizons.config.client.advanced.graphics.fog.heightFog.heightFogMixMode.@tooltip": - "How the height should effect the fog thickness combined with the normal function? \n\nBASIC: No special height fog effect. Fog is calculated based on camera distance \nIGNORE_HEIGHT: Ignore height completely. Fog is calculated based on horizontal distance \nADDITION: heightFog + farFog \nMAX: max(heightFog, farFog) \nMULTIPLY: heightFog * farFog \nINVERSE_MULTIPLY: 1 - (1-heightFog) * (1-farFog) \nLIMITED_ADDITION: farFog + max(farFog, heightFog) \nMULTIPLY_ADDITION: farFog + farFog * heightFog \nINVERSE_MULTIPLY_ADDITION: farFog + 1 - (1-heightFog) * (1-farFog) \nAVERAGE: farFog*0.5 + heightFog*0.5 \n\nNote that for 'BASIC' mode and 'IGNORE_HEIGHT' mode, fog settings for height fog has no effect.\n", - "distanthorizons.config.client.advanced.graphics.fog.heightFog.heightFogMode": - "Height Fog Mode", - "distanthorizons.config.client.advanced.graphics.fog.heightFog.heightFogMode.@tooltip": + "Defines how height effects fog. \nWhen in doubt start with SPHERICAL, ADDITION, or MAX. \n\nSPHERICAL: Fog is calculated based on camera distance. \nCYLINDRICAL: Ignore height, fog is calculated based on horizontal distance. \nMAX: max(heightFog, farFog) \nADDITION: heightFog + farFog \nMULTIPLY: heightFog * farFog \nINVERSE_MULTIPLY: 1 - (1-heightFog) * (1-farFog) \nLIMITED_ADDITION: farFog + max(farFog, heightFog) \nMULTIPLY_ADDITION: farFog + farFog * heightFog \nINVERSE_MULTIPLY_ADDITION: farFog + 1 - (1-heightFog) * (1-farFog) \nAVERAGE: farFog*0.5 + heightFog*0.5", + "distanthorizons.config.client.advanced.graphics.fog.heightFog.heightFogDirection": + "Height Fog Direction", + "distanthorizons.config.client.advanced.graphics.fog.heightFog.heightFogDirection.@tooltip": "Where should the height fog be located? \n\nABOVE_CAMERA: Height fog starts from camera to the sky \nBELOW_CAMERA: Height fog starts from camera to the void \nABOVE_AND_BELOW_CAMERA: Height fog starts from camera to both the sky and the void \nABOVE_SET_HEIGHT: Height fog starts from a set height to the sky \nBELOW_SET_HEIGHT: Height fog starts from a set height to the void \nABOVE_AND_BELOW_SET_HEIGHT: Height fog starts from a set height to both the sky and the void \n", "distanthorizons.config.client.advanced.graphics.fog.heightFog.heightFogBaseHeight": "Height Fog Base Height", @@ -805,10 +805,10 @@ "distanthorizons.config.enum.EDhApiFogFalloff.EXPONENTIAL_SQUARED": "Exponential squared", - "distanthorizons.config.enum.EDhApiHeightFogMixMode.BASIC": - "Basic", - "distanthorizons.config.enum.EDhApiHeightFogMixMode.IGNORE_HEIGHT": - "Ignore Height", + "distanthorizons.config.enum.EDhApiHeightFogMixMode.SPHERICAL": + "Spherical", + "distanthorizons.config.enum.EDhApiHeightFogMixMode.CYLINDRICAL": + "Cylindrical", "distanthorizons.config.enum.EDhApiHeightFogMixMode.ADDITION": "Addition", "distanthorizons.config.enum.EDhApiHeightFogMixMode.MAX": @@ -826,17 +826,17 @@ "distanthorizons.config.enum.EDhApiHeightFogMixMode.AVERAGE": "Average", - "distanthorizons.config.enum.EDhApiHeightFogMode.ABOVE_CAMERA": + "distanthorizons.config.enum.EDhApiHeightFogDirection.ABOVE_CAMERA": "Above Camera", - "distanthorizons.config.enum.EDhApiHeightFogMode.BELOW_CAMERA": + "distanthorizons.config.enum.EDhApiHeightFogDirection.BELOW_CAMERA": "Below Camera", - "distanthorizons.config.enum.EDhApiHeightFogMode.ABOVE_AND_BELOW_CAMERA": + "distanthorizons.config.enum.EDhApiHeightFogDirection.ABOVE_AND_BELOW_CAMERA": "Above And Below Camera", - "distanthorizons.config.enum.EDhApiHeightFogMode.ABOVE_SET_HEIGHT": + "distanthorizons.config.enum.EDhApiHeightFogDirection.ABOVE_SET_HEIGHT": "Above Set Height", - "distanthorizons.config.enum.EDhApiHeightFogMode.BELOW_SET_HEIGHT": + "distanthorizons.config.enum.EDhApiHeightFogDirection.BELOW_SET_HEIGHT": "Below Set Height", - "distanthorizons.config.enum.EDhApiHeightFogMode.ABOVE_AND_BELOW_SET_HEIGHT": + "distanthorizons.config.enum.EDhApiHeightFogDirection.ABOVE_AND_BELOW_SET_HEIGHT": "Above And Below Set Height", "distanthorizons.config.enum.EDhApiVanillaOverdraw.NEVER": diff --git a/core/src/main/resources/shaders/fog/fog.frag b/core/src/main/resources/shaders/fog/fog.frag index eed4c6b6b..a4495bd82 100644 --- a/core/src/main/resources/shaders/fog/fog.frag +++ b/core/src/main/resources/shaders/fog/fog.frag @@ -1,99 +1,120 @@ +#version 150 core in vec2 TexCoord; out vec4 fragColor; + + uniform sampler2D uDepthMap; // inverted model view matrix and projection matrix uniform mat4 uInvMvmProj; +// fog uniforms +uniform vec4 uFogColor; uniform float uFogScale; uniform float uFogVerticalScale; -uniform vec4 uFogColor; uniform int uFullFogMode; +uniform int uFogFalloffType; -uniform float uNearFogStart; -uniform float uNearFogLength; +// fog config +uniform float uFarFogStart; +uniform float uFarFogLength; +uniform float uFarFogMin; +uniform float uFarFogRange; +uniform float uFarFogDensity; + +// height fog config +uniform float uHeightFogStart; +uniform float uHeightFogLength; +uniform float uHeightFogMin; +uniform float uHeightFogRange; +uniform float uHeightFogDensity; -/* ========MARCO DEFINED BY RUNTIME CODE GEN========= +uniform bool uHeightFogEnabled; +uniform int uHeightFogFalloffType; +uniform bool uHeightBasedOnCamera; +uniform float uHeightFogBaseHeight; +uniform bool uHeightFogAppliesUp; +uniform bool uHeightFogAppliesDown; +uniform bool uUseSphericalFog; +uniform int uHeightFogMixingMode; +uniform float uCameraBlockYPos; -float farFogStart; -float farFogLength; -float farFogMin; -float farFogRange; -float farFogDensity; - -float heightFogStart; -float heightFogLength; -float heightFogMin; -float heightFogRange; -float heightFogDensity; -*/ - -// method definitions -// ==== The below 5 methods will be run-time generated. ==== -float getNearFogThickness(float dist); -float getFarFogThickness(float dist); -float getHeightFogThickness(float dist); -float calculateFarFogDepth(float horizontal, float dist, float nearFogStart); -float calculateHeightFogDepth(float vertical, float realY); -float mixFogThickness(float near, float far, float height); -// ========================================================= const vec3 MAGIC = vec3(0.06711056, 0.00583715, 52.9829189); -float InterleavedGradientNoise(const in vec2 pixel) { - float x = dot(pixel, MAGIC.xy); - return fract(MAGIC.z * fract(x)); -} -vec3 calcViewPosition(float fragmentDepth) { - vec4 ndc = vec4(TexCoord.xy, fragmentDepth, 1.0); - ndc.xyz = ndc.xyz * 2.0 - 1.0; - vec4 eyeCoord = uInvMvmProj * ndc; - return eyeCoord.xyz / eyeCoord.w; -} +//====================// +// method definitions // +//====================// + +float InterleavedGradientNoise(const in vec2 pixel); +vec3 calcViewPosition(float fragmentDepth); + +float getFarFogThickness(float dist); +float getHeightFogThickness(float dist); +float calculateHeightFogDepth(float worldYPos); +float mixFogThickness(float far, float height); + + + +//======// +// main // +//======// /** * Fragment shader for fog. - * This should be passed last so it applies above other affects like AO - * - * version: 2023-6-21 + * This should be run last so it applies above other affects like Ambient Occlusioning */ -void main() +void main() { - float vertexYPos = 100.0f; float fragmentDepth = texture(uDepthMap, TexCoord).r; fragColor = vec4(uFogColor.rgb, 0.0); // a fragment depth of "1" means the fragment wasn't drawn to, // we only want to apply Fog to LODs, not to the sky outside the LODs - if (fragmentDepth < 1.0) { - if (uFullFogMode == 0) { + if (fragmentDepth < 1.0) + { + int fogMode = uFullFogMode; + if (fogMode == 0) + { // render fog based on distance from the camera vec3 vertexWorldPos = calcViewPosition(fragmentDepth); - float horizontalDist = length(vertexWorldPos.xz) * uFogScale; - float heightDist = calculateHeightFogDepth(vertexWorldPos.y, vertexYPos) * uFogVerticalScale; - float farDist = calculateFarFogDepth(horizontalDist, length(vertexWorldPos.xyz) * uFogScale, uNearFogStart); + float horizontalWorldDistance = length(vertexWorldPos.xz) * uFogScale; + float worldDistance = length(vertexWorldPos.xyz) * uFogScale; + float activeDistance = uUseSphericalFog ? worldDistance : horizontalWorldDistance; - float nearFogThickness = getNearFogThickness(horizontalDist); - float farFogThickness = getFarFogThickness(farDist); - float heightFogThickness = getHeightFogThickness(heightDist); - float mixedFogThickness = mixFogThickness(nearFogThickness, farFogThickness, heightFogThickness); + + // far fog + float farFogThickness = getFarFogThickness(activeDistance); + + // height fog + float heightFogDepth = calculateHeightFogDepth(vertexWorldPos.y); + float heightFogThickness = getHeightFogThickness(heightFogDepth); + + // combined fog + float mixedFogThickness = mixFogThickness(farFogThickness, heightFogThickness); fragColor.a = clamp(mixedFogThickness, 0.0, 1.0); - float dither = InterleavedGradientNoise(gl_FragCoord.xy) - 0.5; - fragColor.a += dither / 255.0; + // test + //fragColor.a = heightFogThickness; + + // dither fog (to smooth out aliasing) + //float dither = InterleavedGradientNoise(gl_FragCoord.xy) - 0.5; + //fragColor.a += dither / 255.0; } - else if (uFullFogMode == 1) { + else if (fogMode == 1) + { // render everything with the fog color fragColor.a = 1.0; } - else { + else + { // test code. // this can be fired by manually changing the fullFogMode to a (normally) @@ -108,22 +129,174 @@ void main() } } -// Are these still needed? -float linearFog(float x, float fogStart, float fogLength, float fogMin, float fogRange) { - x = clamp((x-fogStart)/fogLength, 0.0, 1.0); - return fogMin + fogRange * x; + +// +// methods // +// + +float InterleavedGradientNoise(const in vec2 pixel) +{ + float x = dot(pixel, MAGIC.xy); + return fract(MAGIC.z * fract(x)); +} + +vec3 calcViewPosition(float fragmentDepth) +{ + vec4 ndc = vec4(TexCoord.xy, fragmentDepth, 1.0); + ndc.xyz = ndc.xyz * 2.0 - 1.0; + + vec4 eyeCoord = uInvMvmProj * ndc; + return eyeCoord.xyz / eyeCoord.w; +} + + + +float linearFog(float worldDist, float fogStart, float fogLength, float fogMin, float fogRange) +{ + worldDist = (worldDist - fogStart) / fogLength; + worldDist = clamp(worldDist, 0.0, 1.0); + return fogMin + fogRange * worldDist; } float exponentialFog(float x, float fogStart, float fogLength, - float fogMin, float fogRange, float fogDensity) +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 fogMin, float fogRange, float fogDensity) { x = max((x-fogStart)/fogLength, 0.0) * fogDensity; return fogMin + fogRange - fogRange/exp(x*x); } + + + +// +// generated methods // +// + +float getFarFogThickness(float dist) +{ + if (uFogFalloffType == 0) // LINEAR + { + return linearFog(dist, uFarFogStart, uFarFogLength, uFarFogMin, uFarFogRange); + } + else if (uFogFalloffType == 1) // EXPONENTIAL + { + return exponentialFog(dist, uFarFogStart, uFarFogLength, uFarFogMin, uFarFogRange, uFarFogDensity); + } + else // EXPONENTIAL_SQUARED + { + return exponentialSquaredFog(dist, uFarFogStart, uFarFogLength, uFarFogMin, uFarFogRange, uFarFogDensity); + } +} + +float getHeightFogThickness(float dist) +{ + if (!uHeightFogEnabled) + { + return 0.0; + } + + if (uHeightFogFalloffType == 0) // LINEAR + { + return linearFog(dist, uHeightFogStart, uHeightFogLength, uHeightFogMin, uHeightFogRange); + } + else if (uHeightFogFalloffType == 1) // EXPONENTIAL + { + return exponentialFog(dist, uHeightFogStart, uHeightFogLength, uHeightFogMin, uHeightFogRange, uHeightFogDensity); + } + else // EXPONENTIAL_SQUARED + { + return exponentialSquaredFog(dist, uHeightFogStart, uHeightFogLength, uHeightFogMin, uHeightFogRange, uHeightFogDensity); + } +} + +/** 1 = full fog, 0 = no fog */ +float calculateHeightFogDepth(float worldYPos) +{ + // worldYPos -65 - 384 + + + //worldYPos = worldYPos * -1; // negative, fog below height; positive, fog above height + //return worldYPos * uFogVerticalScale; // "* uFogVerticalScale" is done to convert world position to a percent of the world height; + + if (!uHeightFogEnabled) + { + // ignore the height + return 0.0; + } + + + if (!uHeightBasedOnCamera) + { + worldYPos -= (uHeightFogBaseHeight - uCameraBlockYPos); + } + + + if (uHeightFogAppliesDown && uHeightFogAppliesUp) + { + // TODO this aint right + return abs(worldYPos) * uFogVerticalScale; + } + else if (uHeightFogAppliesDown) + { + // apploy fog below given height + return -worldYPos * uFogVerticalScale; + } + else if (uHeightFogAppliesUp) + { + // apply fog above given height + return worldYPos * uFogVerticalScale; + } + else + { + // shouldn't happen, + return 0; + } + +} + +float mixFogThickness(float far, float height) +{ + switch (uHeightFogMixingMode) + { + case 0: // BASIC + case 1: // IGNORE_HEIGHT + return far; + + case 2: // MAX + return max(far, height); + + case 3: // ADDITION + return (far + height); + + case 4: // MULTIPLY + return far * height; + + case 5: // INVERSE_MULTIPLY + return (1.0 - (1.0-far)*(1.0-height)); + + case 6: // LIMITED_ADDITION + return (far + max(far, height)); + + case 7: // MULTIPLY_ADDITION + return (far + far*height); + + case 8: // INVERSE_MULTIPLY_ADDITION + return (far + 1.0 - (1.0-far)*(1.0-height)); + + case 9: // AVERAGE + return (far*0.5 + height*0.5); + } + + // shouldn't happen, but default to BASIC / IGNORE_HEIGHT + // if an invalid option is selected + return far; +} + + +