From 789306ccff0079b3aa0af6445e41b7a0328d7da9 Mon Sep 17 00:00:00 2001 From: James Seibel Date: Sat, 25 Oct 2025 11:06:19 -0500 Subject: [PATCH] Add far clip fading --- .../distanthorizons/core/config/Config.java | 8 + ...RenderQualityPresetConfigEventHandler.java | 11 +- .../core/render/renderer/DhFadeRenderer.java | 161 +++++++++++++++++ .../core/render/renderer/LodRenderer.java | 9 + .../render/renderer/VanillaFadeRenderer.java | 9 +- .../renderer/shaders/DhFadeApplyShader.java | 128 ++++++++++++++ .../render/renderer/shaders/DhFadeShader.java | 165 ++++++++++++++++++ .../assets/distanthorizons/lang/en_us.json | 4 + .../main/resources/shaders/dhFade/apply.frag | 27 +++ .../main/resources/shaders/dhFade/fade.frag | 66 +++++++ 10 files changed, 581 insertions(+), 7 deletions(-) create mode 100644 core/src/main/java/com/seibel/distanthorizons/core/render/renderer/DhFadeRenderer.java create mode 100644 core/src/main/java/com/seibel/distanthorizons/core/render/renderer/shaders/DhFadeApplyShader.java create mode 100644 core/src/main/java/com/seibel/distanthorizons/core/render/renderer/shaders/DhFadeShader.java create mode 100644 core/src/main/resources/shaders/dhFade/apply.frag create mode 100644 core/src/main/resources/shaders/dhFade/fade.frag 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 6a8c372b6..e331ce356 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 @@ -312,6 +312,14 @@ public class Config + "") .build(); + public static ConfigEntry dhFadeFarClipPlane = new ConfigEntry.Builder() + .set(true) + .comment("" + + "Should DH fade out before reaching the far clip plane? \n" + + "This is helpful to prevent DH clouds from cutting off in the distance. \n" + + "") + .build(); + public static ConfigEntry brightnessMultiplier = new ConfigEntry.Builder() // TODO: Make this a float (the ClassicConfigGUI doesnt support floats) .set(1.0) .comment("" diff --git a/core/src/main/java/com/seibel/distanthorizons/core/config/eventHandlers/presets/RenderQualityPresetConfigEventHandler.java b/core/src/main/java/com/seibel/distanthorizons/core/config/eventHandlers/presets/RenderQualityPresetConfigEventHandler.java index 2c1b1bf81..14896ebfc 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/config/eventHandlers/presets/RenderQualityPresetConfigEventHandler.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/config/eventHandlers/presets/RenderQualityPresetConfigEventHandler.java @@ -30,7 +30,6 @@ import com.seibel.distanthorizons.core.config.ConfigPresetOptions; import com.seibel.distanthorizons.core.config.listeners.ConfigChangeListener; import com.seibel.distanthorizons.core.config.types.AbstractConfigBase; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; -import org.apache.logging.log4j.LogManager; import com.seibel.distanthorizons.core.logging.DhLogger; import java.util.*; @@ -97,6 +96,15 @@ public class RenderQualityPresetConfigEventHandler extends AbstractPresetConfigE this.put(EDhApiQualityPreset.HIGH, EDhApiMcRenderingFadeMode.DOUBLE_PASS); this.put(EDhApiQualityPreset.EXTREME, EDhApiMcRenderingFadeMode.DOUBLE_PASS); }}); + private final ConfigPresetOptions dhFadeFarClipPlane = new ConfigPresetOptions<>(Config.Client.Advanced.Graphics.Quality.dhFadeFarClipPlane, + new HashMap() + {{ + this.put(EDhApiQualityPreset.MINIMUM, false); + this.put(EDhApiQualityPreset.LOW, false); + this.put(EDhApiQualityPreset.MEDIUM, true); + this.put(EDhApiQualityPreset.HIGH, true); + this.put(EDhApiQualityPreset.EXTREME, true); + }}); private final ConfigPresetOptions dhDither = new ConfigPresetOptions<>(Config.Client.Advanced.Graphics.Quality.ditherDhFade, new HashMap() {{ @@ -140,6 +148,7 @@ public class RenderQualityPresetConfigEventHandler extends AbstractPresetConfigE this.configList.add(this.horizontalQuality); this.configList.add(this.transparency); this.configList.add(this.ssaoEnabled); + this.configList.add(this.dhFadeFarClipPlane); this.configList.add(this.vanillaFade); this.configList.add(this.dhDither); this.configList.add(this.caveCulling); diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/DhFadeRenderer.java b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/DhFadeRenderer.java new file mode 100644 index 000000000..ff3728f99 --- /dev/null +++ b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/DhFadeRenderer.java @@ -0,0 +1,161 @@ +/* + * This file is part of the Distant Horizons mod + * licensed under the GNU LGPL v3 License. + * + * Copyright (C) 2020 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.renderer; + +import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector; +import com.seibel.distanthorizons.core.logging.DhLogger; +import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; +import com.seibel.distanthorizons.core.render.glObject.GLState; +import com.seibel.distanthorizons.core.render.renderer.shaders.DhFadeApplyShader; +import com.seibel.distanthorizons.core.render.renderer.shaders.DhFadeShader; +import com.seibel.distanthorizons.core.util.math.Mat4f; +import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper; +import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftGLWrapper; +import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper; +import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IProfilerWrapper; +import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper; +import org.lwjgl.opengl.GL32; + +import java.nio.ByteBuffer; + +/** + * Handles fading MC and DH together via {@link DhFadeShader} and {@link DhFadeApplyShader}.

+ * + * {@link DhFadeShader} - draws the Fade to a texture.
+ * {@link DhFadeApplyShader} - draws the Fade texture to MC's FrameBuffer.
+ */ +public class DhFadeRenderer +{ + + public static DhFadeRenderer INSTANCE = new DhFadeRenderer(); + private static final DhLogger LOGGER = new DhLoggerBuilder().build(); + + private static final IMinecraftClientWrapper MC_CLIENT = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class); + private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class); + private static final IMinecraftGLWrapper GLMC = SingletonInjector.INSTANCE.get(IMinecraftGLWrapper.class); + + + private boolean init = false; + + private int width = -1; + private int height = -1; + private int fadeFramebuffer = -1; + + private int fadeTexture = -1; + + + + //=============// + // constructor // + //=============// + + private DhFadeRenderer() { } + + public void init() + { + if (this.init) return; + this.init = true; + + DhFadeShader.INSTANCE.init(); + DhFadeApplyShader.INSTANCE.init(); + } + + private void createFramebuffer(int width, int height) + { + if (this.fadeFramebuffer != -1) + { + GL32.glDeleteFramebuffers(this.fadeFramebuffer); + this.fadeFramebuffer = -1; + } + + this.fadeFramebuffer = GL32.glGenFramebuffers(); + GLMC.glBindFramebuffer(GL32.GL_FRAMEBUFFER, this.fadeFramebuffer); + + + if (this.fadeTexture != -1) + { + GLMC.glDeleteTextures(this.fadeTexture); + this.fadeTexture = -1; + } + + this.fadeTexture = GL32.glGenTextures(); + GLMC.glBindTexture(this.fadeTexture); + GL32.glTexImage2D(GL32.GL_TEXTURE_2D, 0, GL32.GL_RGBA16, width, height, 0, GL32.GL_RGBA, GL32.GL_UNSIGNED_SHORT_4_4_4_4, (ByteBuffer) null); + GL32.glTexParameteri(GL32.GL_TEXTURE_2D, GL32.GL_TEXTURE_MIN_FILTER, GL32.GL_LINEAR); + GL32.glTexParameteri(GL32.GL_TEXTURE_2D, GL32.GL_TEXTURE_MAG_FILTER, GL32.GL_LINEAR); + GL32.glFramebufferTexture2D(GL32.GL_FRAMEBUFFER, GL32.GL_COLOR_ATTACHMENT0, GL32.GL_TEXTURE_2D, this.fadeTexture, 0); + } + + + + //========// + // render // + //========// + + public void render(Mat4f mcModelViewMatrix, Mat4f mcProjectionMatrix, float partialTicks, IProfilerWrapper profiler) + { + GLState mcState = new GLState(); + + try + { + profiler.push("Fade Generate"); + + this.init(); + + // resize the framebuffer if necessary + int width = MC_RENDER.getTargetFramebufferViewportWidth(); + int height = MC_RENDER.getTargetFramebufferViewportHeight(); + if (this.width != width || this.height != height) + { + this.width = width; + this.height = height; + this.createFramebuffer(width, height); + } + + + DhFadeShader.INSTANCE.frameBuffer = this.fadeFramebuffer; + DhFadeShader.INSTANCE.setProjectionMatrix(mcModelViewMatrix, mcProjectionMatrix, partialTicks); + DhFadeShader.INSTANCE.render(partialTicks); + + // restored so we can write the fade texture to the main frame buffer + //mcState.restore(); + + profiler.popPush("Fade Apply"); + + DhFadeApplyShader.INSTANCE.fadeTexture = this.fadeTexture; + DhFadeApplyShader.INSTANCE.render(partialTicks); + } + catch (Exception e) + { + LOGGER.error("Unexpected error during fade render, error: ["+e.getMessage()+"].", e); + } + finally + { + // make sure we always revert to MC's state to prevent GL state corruption + // this is especially important on MC 1.16.5 or when other rendering mods are present + mcState.restore(); + + profiler.pop(); + } + } + + + +} 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 dd9ffbab2..f36bcdf01 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 @@ -242,6 +242,15 @@ public class LodRenderer this.renderLodPass(lodShaderProgram, renderBufferHandler, renderParams, /*opaquePass*/ false); } + // far plane clip fading + if (Config.Client.Advanced.Graphics.Quality.dhFadeFarClipPlane.get()) + { + profiler.popPush("Fade Far Clip Fade"); + DhFadeRenderer.INSTANCE.render( + new Mat4f(renderParams.mcModelViewMatrix), new Mat4f(renderParams.mcProjectionMatrix), + renderParams.partialTicks, profiler); + } + // fog if (Config.Client.Advanced.Graphics.Fog.enableDhFog.get()) { diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/VanillaFadeRenderer.java b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/VanillaFadeRenderer.java index 172daf01f..83f8ded32 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/VanillaFadeRenderer.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/VanillaFadeRenderer.java @@ -122,14 +122,14 @@ public class VanillaFadeRenderer { IProfilerWrapper profiler = MC_CLIENT.getProfiler(); profiler.pop(); // get out of "terrain" - profiler.push("DH-RenderLevel"); + profiler.push("DH-Vanilla Fade"); GLState mcState = new GLState(); try { - profiler.push("Fade Generate"); + profiler.push("Vanilla Fade Generate"); this.init(); @@ -149,10 +149,7 @@ public class VanillaFadeRenderer VanillaFadeShader.INSTANCE.setLevelMaxHeight(level.getMaxHeight()); VanillaFadeShader.INSTANCE.render(partialTicks); - // restored so we can write the fade texture to the main frame buffer - //mcState.restore(); - - profiler.popPush("Fade Apply"); + profiler.popPush("Vanilla Fade Apply"); // Applying the fade texture is only needed if MC is drawing to their own frame buffer, // otherwise we can directly render to their texture diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/shaders/DhFadeApplyShader.java b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/shaders/DhFadeApplyShader.java new file mode 100644 index 000000000..913288c0e --- /dev/null +++ b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/shaders/DhFadeApplyShader.java @@ -0,0 +1,128 @@ +/* + * This file is part of the Distant Horizons mod + * licensed under the GNU LGPL v3 License. + * + * Copyright (C) 2020 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.renderer.shaders; + +import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector; +import com.seibel.distanthorizons.core.render.glObject.shader.ShaderProgram; +import com.seibel.distanthorizons.core.render.renderer.DhFadeRenderer; +import com.seibel.distanthorizons.core.render.renderer.LodRenderer; +import com.seibel.distanthorizons.core.render.renderer.ScreenQuad; +import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftGLWrapper; +import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper; +import org.lwjgl.opengl.GL32; + +/** + * Draws the Fade texture onto Minecraft's FrameBuffer.

+ * + * See Also:
+ * {@link DhFadeRenderer} - Parent to this shader.
+ * {@link DhFadeShader} - draws the Fade texture.
+ */ +public class DhFadeApplyShader extends AbstractShaderRenderer +{ + public static DhFadeApplyShader INSTANCE = new DhFadeApplyShader(); + + private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class); + private static final IMinecraftGLWrapper GLMC = SingletonInjector.INSTANCE.get(IMinecraftGLWrapper.class); + + + + public int fadeTexture; + + // uniforms + public int uFadeColorTextureUniform = -1; + public int uDhDepthTextureUniform = -1; + public int uMcDepthTextureUniform = -1; + + + + //=============// + // constructor // + //=============// + + @Override + public void onInit() + { + this.shader = new ShaderProgram( + "shaders/normal.vert", + "shaders/dhFade/apply.frag", + "fragColor", + new String[]{ "vPosition" }); + + // uniform setup + this.uFadeColorTextureUniform = this.shader.getUniformLocation("uFadeColorTextureUniform"); + this.uDhDepthTextureUniform = this.shader.getUniformLocation("uDhDepthTextureUniform"); + this.uMcDepthTextureUniform = this.shader.getUniformLocation("uMcDepthTextureUniform"); + + } + + + + //=============// + // render prep // + //=============// + + @Override + protected void onApplyUniforms(float partialTicks) + { + GLMC.glActiveTexture(GL32.GL_TEXTURE0); + GLMC.glBindTexture(this.fadeTexture); + GL32.glUniform1i(this.uFadeColorTextureUniform, 0); + + GLMC.glActiveTexture(GL32.GL_TEXTURE1); + GLMC.glBindTexture(LodRenderer.INSTANCE.getActiveDepthTextureId()); + GL32.glUniform1i(this.uDhDepthTextureUniform, 1); + + GLMC.glActiveTexture(GL32.GL_TEXTURE2); + GLMC.glBindTexture(MC_RENDER.getDepthTextureId()); + GL32.glUniform1i(this.uMcDepthTextureUniform, 2); + + } + + + + //========// + // render // + //========// + + @Override + protected void onRender() + { + GLMC.disableBlend(); + + // Depth testing must be disabled otherwise this application shader won't apply anything. + // setting this isn't necessary in vanilla, but some mods may change this, requiring it to be set manually, + // it should be automatically restored after rendering is complete. + GLMC.disableDepthTest(); + + + // apply the rendered Fade to Minecraft's framebuffer + GLMC.glBindFramebuffer(GL32.GL_READ_FRAMEBUFFER, DhFadeShader.INSTANCE.frameBuffer); + GLMC.glBindFramebuffer(GL32.GL_DRAW_FRAMEBUFFER, LodRenderer.INSTANCE.getActiveFramebufferId()); + + ScreenQuad.INSTANCE.render(); + + GLMC.enableDepthTest(); + + } + + + +} diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/shaders/DhFadeShader.java b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/shaders/DhFadeShader.java new file mode 100644 index 000000000..e49ac0357 --- /dev/null +++ b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/shaders/DhFadeShader.java @@ -0,0 +1,165 @@ +/* + * This file is part of the Distant Horizons mod + * licensed under the GNU LGPL v3 License. + * + * Copyright (C) 2020 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.renderer.shaders; + +import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector; +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; +import com.seibel.distanthorizons.core.util.RenderUtil; +import com.seibel.distanthorizons.core.util.math.Mat4f; +import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftGLWrapper; +import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper; +import org.lwjgl.opengl.GL32; + +public class DhFadeShader extends AbstractShaderRenderer +{ + public static DhFadeShader INSTANCE = new DhFadeShader(); + + private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class); + private static final IMinecraftGLWrapper GLMC = SingletonInjector.INSTANCE.get(IMinecraftGLWrapper.class); + + + public int frameBuffer = -1; + + private Mat4f inverseDhMvmProjMatrix; + + + // Uniforms + + /** Inverted Model View Projection matrix */ + public int uDhInvMvmProj = -1; + + public int uDhDepthTexture = -1; + public int uMcColorTexture = -1; + public int uDhColorTexture = -1; + + public int uStartFadeBlockDistance = -1; + public int uEndFadeBlockDistance = -1; + + + + //=============// + // constructor // + //=============// + + public DhFadeShader() { } + + @Override + public void onInit() + { + this.shader = new ShaderProgram( + "shaders/normal.vert", "shaders/dhFade/fade.frag", + "fragColor", new String[]{"vPosition"} + ); + + // all uniforms should be tryGet... + // because disabling fade can cause the GLSL to optimize out most (if not all) uniforms + + // near fade + this.uDhInvMvmProj = this.shader.tryGetUniformLocation("uDhInvMvmProj"); + + this.uDhDepthTexture = this.shader.tryGetUniformLocation("uDhDepthTexture"); + this.uMcColorTexture = this.shader.tryGetUniformLocation("uMcColorTexture"); + this.uDhColorTexture = this.shader.tryGetUniformLocation("uDhColorTexture"); + + this.uStartFadeBlockDistance = this.shader.tryGetUniformLocation("uStartFadeBlockDistance"); + this.uEndFadeBlockDistance = this.shader.tryGetUniformLocation("uEndFadeBlockDistance"); + + } + + + + //=============// + // render prep // + //=============// + + @Override + protected void onApplyUniforms(float partialTicks) + { + this.shader.setUniform(this.uDhInvMvmProj, this.inverseDhMvmProjMatrix); + + + float dhFarClipDistance = RenderUtil.getFarClipPlaneDistanceInBlocks(); + + // measured in blocks + float fadeStartDistance = dhFarClipDistance * 0.5f; + float fadeEndDistance = dhFarClipDistance * 0.9f; + + this.shader.setUniform(this.uStartFadeBlockDistance, fadeStartDistance); + this.shader.setUniform(this.uEndFadeBlockDistance, fadeEndDistance); + + } + + public void setProjectionMatrix(Mat4f mcModelViewMatrix, Mat4f mcProjectionMatrix, float partialTicks) + { + Mat4f dhProjectionMatrix = RenderUtil.createLodProjectionMatrix(mcProjectionMatrix, partialTicks); + Mat4f dhModelViewMatrix = RenderUtil.createLodModelViewMatrix(mcModelViewMatrix); + + Mat4f inverseDhModelViewProjectionMatrix = new Mat4f(dhProjectionMatrix); + inverseDhModelViewProjectionMatrix.multiply(dhModelViewMatrix); + inverseDhModelViewProjectionMatrix.invert(); + this.inverseDhMvmProjMatrix = inverseDhModelViewProjectionMatrix; + } + + + //========// + // render // + //========// + + @Override + protected void onRender() + { + int depthTextureId = LodRenderer.INSTANCE.getActiveDepthTextureId(); + int colorTextureId = LodRenderer.INSTANCE.getActiveColorTextureId(); + + if (depthTextureId == -1 + || colorTextureId == -1) + { + // the renderer is currently being re-built and/or inactive, + // we don't need to/can't render fading + return; + } + + + + GLMC.glBindFramebuffer(GL32.GL_FRAMEBUFFER, this.frameBuffer); + GLMC.disableScissorTest(); + GLMC.disableDepthTest(); + GLMC.disableBlend(); + + + GLMC.glActiveTexture(GL32.GL_TEXTURE0); + GLMC.glBindTexture(depthTextureId); + GL32.glUniform1i(this.uDhDepthTexture, 0); + + GLMC.glActiveTexture(GL32.GL_TEXTURE1); + GLMC.glBindTexture(MC_RENDER.getColorTextureId()); + GL32.glUniform1i(this.uMcColorTexture, 1); + + GLMC.glActiveTexture(GL32.GL_TEXTURE2); + GLMC.glBindTexture(colorTextureId); + GL32.glUniform1i(this.uDhColorTexture, 2); + + + ScreenQuad.INSTANCE.render(); + } + +} 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 318a15d2c..2975ac46e 100644 --- a/core/src/main/resources/assets/distanthorizons/lang/en_us.json +++ b/core/src/main/resources/assets/distanthorizons/lang/en_us.json @@ -158,6 +158,10 @@ "Vanilla Fade Mode", "distanthorizons.config.client.advanced.graphics.quality.vanillaFadeMode.@tooltip": "How should vanilla Minecraft fade into Distant Horizons LODs? \n\nNONE: Fastest, there will be a pronounced border between DH and MC rendering. \nSINGLE_PASS: Fades after MC's transparent pass, opaque blocks underwater won't be faded. \nDOUBLE_PASS: Slowest, fades after both MC's opaque and transparent passes, provides the smoothest transition.", + "distanthorizons.config.client.advanced.graphics.quality.dhFadeFarClipPlane": + "Fade Before Far Clip Plane", + "distanthorizons.config.client.advanced.graphics.quality.dhFadeFarClipPlane.@tooltip": + "Should DH fade out before reaching the far plane? \nThis is helpful to prevent DH clouds from cutting off in the distance.", "distanthorizons.config.client.advanced.graphics.quality.brightnessMultiplier": "Brightness Multiplier", "distanthorizons.config.client.advanced.graphics.quality.brightnessMultiplier.@tooltip": diff --git a/core/src/main/resources/shaders/dhFade/apply.frag b/core/src/main/resources/shaders/dhFade/apply.frag new file mode 100644 index 000000000..d3d21ffca --- /dev/null +++ b/core/src/main/resources/shaders/dhFade/apply.frag @@ -0,0 +1,27 @@ +#version 150 core + +in vec2 TexCoord; + +out vec4 fragColor; + +uniform sampler2D uFadeColorTextureUniform; +uniform sampler2D uDhDepthTextureUniform; +uniform sampler2D uMcDepthTextureUniform; + + + +void main() +{ + fragColor = vec4(1.0); + + float dhFragmentDepth = textureLod(uDhDepthTextureUniform, TexCoord, 0).r; + float mcFragmentDepth = textureLod(uMcDepthTextureUniform, TexCoord, 0).r; + + // a fragment depth of "1" means the fragment wasn't drawn to, + // only update fragments that were drawn to + // TODO this check is currently ignored as a test, this may need to be re-enabled later + if (dhFragmentDepth != 10 && mcFragmentDepth != 0) + { + fragColor = texture(uFadeColorTextureUniform, TexCoord); + } +} diff --git a/core/src/main/resources/shaders/dhFade/fade.frag b/core/src/main/resources/shaders/dhFade/fade.frag new file mode 100644 index 000000000..598f7c3f4 --- /dev/null +++ b/core/src/main/resources/shaders/dhFade/fade.frag @@ -0,0 +1,66 @@ +#version 150 core + +in vec2 TexCoord; + +out vec4 fragColor; + +// inverted model view matrix and projection matrix +uniform mat4 uDhInvMvmProj; + +uniform sampler2D uDhDepthTexture; +uniform sampler2D uMcColorTexture; +uniform sampler2D uDhColorTexture; + +uniform float uStartFadeBlockDistance; +uniform float uEndFadeBlockDistance; + + + +vec3 calcViewPosition(float fragmentDepth, mat4 invMvmProj) +{ + // normalized device coordinates + vec4 ndc = vec4(TexCoord.xy, fragmentDepth, 1.0); + ndc.xyz = ndc.xyz * 2.0 - 1.0; + + vec4 eyeCoord = invMvmProj * ndc; + return eyeCoord.xyz / eyeCoord.w; +} + +/** + * Used to fade out vanilla chunks so the transition + * between DH and vanilla is smoother. + */ +void main() +{ + // includes both the vanilla chunks as well as DH + vec4 combinedMcDhColor = texture(uMcColorTexture, TexCoord); + // just the DH render pass + vec4 dhColor = texture(uDhColorTexture, TexCoord); + + + + // the DH texture will have white if nothing was written to that pixel. + // TODO replace with a depth texture check, this feels janky + if (dhColor == vec4(1)) + { + // if not done vanilla clouds will render incorrectly at night + dhColor = combinedMcDhColor; + } + + + float dhFragmentDepth = texture(uDhDepthTexture, TexCoord).r; + vec3 dhVertexWorldPos = calcViewPosition(dhFragmentDepth, uDhInvMvmProj); + float dhFragmentDistance = length(dhVertexWorldPos.xzy); + + + float startFade = uEndFadeBlockDistance; + float endFade = uStartFadeBlockDistance; + + // Smoothly transition between combinedMcDhColor and uDhColorTexture + // as the depth increases from the camera + float fadeStep = smoothstep(startFade, endFade, dhFragmentDistance); + fragColor = mix(combinedMcDhColor, dhColor, fadeStep); + fragColor.a = 1.0; // TODO is setting the alpha needed? + +} +