From f63e3d4b6d7aec3063a8c3328b5f424178638f06 Mon Sep 17 00:00:00 2001 From: James Seibel Date: Mon, 30 Sep 2024 21:59:19 -0500 Subject: [PATCH] Add experimental DH/vanilla fading --- .../core/api/internal/ClientApi.java | 10 ++ .../distanthorizons/core/config/Config.java | 10 ++ .../core/render/renderer/FadeRenderer.java | 166 ++++++++++++++++++ .../core/render/renderer/FogRenderer.java | 4 +- .../renderer/shaders/FadeApplyShader.java | 121 +++++++++++++ .../render/renderer/shaders/FadeShader.java | 160 +++++++++++++++++ .../minecraft/IMinecraftRenderWrapper.java | 1 + .../assets/distanthorizons/lang/en_us.json | 4 + .../main/resources/shaders/fade/apply.frag | 27 +++ .../src/main/resources/shaders/fade/fade.frag | 70 ++++++++ 10 files changed, 571 insertions(+), 2 deletions(-) create mode 100644 core/src/main/java/com/seibel/distanthorizons/core/render/renderer/FadeRenderer.java create mode 100644 core/src/main/java/com/seibel/distanthorizons/core/render/renderer/shaders/FadeApplyShader.java create mode 100644 core/src/main/java/com/seibel/distanthorizons/core/render/renderer/shaders/FadeShader.java create mode 100644 core/src/main/resources/shaders/fade/apply.frag create mode 100644 core/src/main/resources/shaders/fade/fade.frag diff --git a/core/src/main/java/com/seibel/distanthorizons/core/api/internal/ClientApi.java b/core/src/main/java/com/seibel/distanthorizons/core/api/internal/ClientApi.java index 479f858d4..b5d59827e 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/api/internal/ClientApi.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/api/internal/ClientApi.java @@ -26,6 +26,7 @@ import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhAp import com.seibel.distanthorizons.core.file.structure.ClientOnlySaveStructure; import com.seibel.distanthorizons.core.pos.DhChunkPos; import com.seibel.distanthorizons.core.render.DhApiRenderProxy; +import com.seibel.distanthorizons.core.render.renderer.FadeRenderer; import com.seibel.distanthorizons.core.util.TimerUtil; import com.seibel.distanthorizons.core.util.objects.Pair; import com.seibel.distanthorizons.coreapi.DependencyInjection.ApiEventInjector; @@ -550,6 +551,15 @@ public class ClientApi } } + /** should be called after DH and MC finish rendering so we can smooth the transition between the two */ + public void renderFade(Mat4f mcModelViewMatrix, Mat4f mcProjectionMatrix, float partialTicks) + { + if (Config.Client.Advanced.Graphics.Quality.fadeOutVanillaRendering.get()) + { + FadeRenderer.INSTANCE.render(mcModelViewMatrix, mcProjectionMatrix, partialTicks); + } + } + 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 2c759b333..fcc268e79 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 @@ -255,6 +255,16 @@ public class Config .addListener(ReloadLodsConfigEventHandler.INSTANCE) .build(); + public static ConfigEntry fadeOutVanillaRendering = new ConfigEntry.Builder() + .set(true) + .comment("" + + "If true vanilla chunks will fade out the further away they are \n" + + "smoothing the transition between Distant Horizons and vanilla rendering. \n" + + "") + .setPerformance(EConfigEntryPerformance.LOW) + .addListener(ReloadLodsConfigEventHandler.INSTANCE) + .build(); + // TODO fixme // public static ConfigEntry lodBiomeBlending = new ConfigEntry.Builder() // .setMinDefaultMax(0,1,7) diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/FadeRenderer.java b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/FadeRenderer.java new file mode 100644 index 000000000..8db4b8302 --- /dev/null +++ b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/FadeRenderer.java @@ -0,0 +1,166 @@ +/* + * 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.renderer; + +import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector; +import com.seibel.distanthorizons.core.render.glObject.GLState; +import com.seibel.distanthorizons.core.render.renderer.shaders.FadeApplyShader; +import com.seibel.distanthorizons.core.render.renderer.shaders.FadeShader; +import com.seibel.distanthorizons.core.util.math.Mat4f; +import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper; +import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper; +import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IProfilerWrapper; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.lwjgl.opengl.GL32; + +import java.nio.ByteBuffer; + +/** + * Handles fading MC and DH together via {@link FadeShader} and {@link FadeApplyShader}.

+ * + * {@link FadeShader} - draws the Fade to a texture.
+ * {@link FadeApplyShader} - draws the Fade texture to MC's FrameBuffer.
+ */ +public class FadeRenderer +{ + public static FadeRenderer INSTANCE = new FadeRenderer(); + + private static final Logger LOGGER = LogManager.getLogger(); + + private static final IMinecraftClientWrapper MC_CLIENT = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class); + private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class); + + + private boolean init = false; + + private int width = -1; + private int height = -1; + private int fadeFramebuffer = -1; + + private int fadeTexture = -1; + + + + //=============// + // constructor // + //=============// + + private FadeRenderer() { } + + public void init() + { + if (this.init) return; + this.init = true; + + FadeShader.INSTANCE.init(); + FadeApplyShader.INSTANCE.init(); + } + + private void createFramebuffer(int width, int height) + { + if (this.fadeFramebuffer != -1) + { + GL32.glDeleteFramebuffers(this.fadeFramebuffer); + this.fadeFramebuffer = -1; + } + + if (this.fadeTexture != -1) + { + GL32.glDeleteTextures(this.fadeTexture); + this.fadeTexture = -1; + } + + this.fadeFramebuffer = GL32.glGenFramebuffers(); + GL32.glBindFramebuffer(GL32.GL_FRAMEBUFFER, this.fadeFramebuffer); + + this.fadeTexture = GL32.glGenTextures(); + GL32.glBindTexture(GL32.GL_TEXTURE_2D, 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 = MC_CLIENT.getProfiler(); + profiler.pop(); // get out of "terrain" + profiler.push("DH-RenderLevel"); + + + GLState mcState = new GLState(); + GLState state = 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); + } + + + FadeShader.INSTANCE.frameBuffer = this.fadeFramebuffer; + FadeShader.INSTANCE.setProjectionMatrix(mcModelViewMatrix, mcProjectionMatrix); + FadeShader.INSTANCE.render(partialTicks); + + // restored so we can write the fade texture to the main frame buffer + mcState.restore(); + + profiler.popPush("Fade Apply"); + + FadeApplyShader.INSTANCE.fadeTexture = this.fadeTexture; + FadeApplyShader.INSTANCE.render(partialTicks); + + profiler.pop(); + } + catch (Exception e) + { + LOGGER.error("Unexpected error during fade render, error: ["+e.getMessage()+"].", e); + } + finally + { + state.restore(); + } + } + + public void free() + { + FadeShader.INSTANCE.free(); + FadeApplyShader.INSTANCE.free(); + } + +} diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/FogRenderer.java b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/FogRenderer.java index 1f2f17491..582d659e5 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/FogRenderer.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/FogRenderer.java @@ -98,7 +98,7 @@ public class FogRenderer // render // //========// - public void render(GLState primaryState, Mat4f projectionMatrix, float partialTicks) + public void render(GLState primaryState, Mat4f modelViewProjectionMatrix, float partialTicks) { GLState state = new GLState(); this.init(); @@ -114,7 +114,7 @@ public class FogRenderer } FogShader.INSTANCE.frameBuffer = this.fogFramebuffer; - FogShader.INSTANCE.setProjectionMatrix(projectionMatrix); + FogShader.INSTANCE.setProjectionMatrix(modelViewProjectionMatrix); FogShader.INSTANCE.render(partialTicks); // restored so we can write the SSAO texture to the main frame buffer diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/shaders/FadeApplyShader.java b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/shaders/FadeApplyShader.java new file mode 100644 index 000000000..68e4ae688 --- /dev/null +++ b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/shaders/FadeApplyShader.java @@ -0,0 +1,121 @@ +/* + * 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.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.FadeRenderer; +import com.seibel.distanthorizons.core.render.renderer.LodRenderer; +import com.seibel.distanthorizons.core.render.renderer.ScreenQuad; +import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper; +import org.lwjgl.opengl.GL32; + +/** + * Draws the Fade texture onto Minecraft's FrameBuffer.

+ * + * See Also:
+ * {@link FadeRenderer} - Parent to this shader.
+ * {@link FadeShader} - draws the Fade texture.
+ */ +public class FadeApplyShader extends AbstractShaderRenderer +{ + public static FadeApplyShader INSTANCE = new FadeApplyShader(); + + private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.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/fade/apply.frag", + "fragColor", + new String[]{ "vPosition" }); + + // uniform setup + this.uFadeColorTextureUniform = this.shader.getUniformLocation("uFadeColorTextureUniform"); + this.uMcDepthTextureUniform = this.shader.getUniformLocation("uMcDepthTextureUniform"); + + } + + + + //=============// + // render prep // + //=============// + + @Override + protected void onApplyUniforms(float partialTicks) + { + GL32.glActiveTexture(GL32.GL_TEXTURE0); + GL32.glBindTexture(GL32.GL_TEXTURE_2D, this.fadeTexture); + GL32.glUniform1i(this.uFadeColorTextureUniform, 0); + + GL32.glActiveTexture(GL32.GL_TEXTURE1); + GL32.glBindTexture(GL32.GL_TEXTURE_2D, LodRenderer.getActiveDepthTextureId()); + GL32.glUniform1i(this.uDhDepthTextureUniform, 1); + + GL32.glActiveTexture(GL32.GL_TEXTURE2); + GL32.glBindTexture(GL32.GL_TEXTURE_2D, MC_RENDER.getDepthTextureId()); + GL32.glUniform1i(this.uMcDepthTextureUniform, 2); + + } + + + + //========// + // render // + //========// + + @Override + protected void onRender() + { + GL32.glEnable(GL32.GL_BLEND); + GL32.glBlendEquation(GL32.GL_FUNC_ADD); + GL32.glBlendFuncSeparate(GL32.GL_SRC_ALPHA, GL32.GL_ONE_MINUS_SRC_ALPHA, GL32.GL_ONE, GL32.GL_ONE_MINUS_SRC_ALPHA); + + // 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. + GL32.glDisable(GL32.GL_DEPTH_TEST); + + + // apply the rendered Fade to Minecraft's framebuffer + GL32.glBindFramebuffer(GL32.GL_READ_FRAMEBUFFER, FadeShader.INSTANCE.frameBuffer); + GL32.glBindFramebuffer(GL32.GL_DRAW_FRAMEBUFFER, MC_RENDER.getTargetFrameBuffer()); + + ScreenQuad.INSTANCE.render(); + } + +} diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/shaders/FadeShader.java b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/shaders/FadeShader.java new file mode 100644 index 000000000..c3a1f0034 --- /dev/null +++ b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/shaders/FadeShader.java @@ -0,0 +1,160 @@ +/* + * 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.renderer.shaders; + +import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector; +import com.seibel.distanthorizons.core.render.glObject.GLState; +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.LodUtil; +import com.seibel.distanthorizons.core.util.math.Mat4f; +import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper; +import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper; +import org.lwjgl.opengl.GL32; + +public class FadeShader extends AbstractShaderRenderer +{ + public static FadeShader INSTANCE = new FadeShader(); + + private static final IMinecraftClientWrapper MC_CLIENT = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class); + private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class); + + + public int frameBuffer = -1; + + private Mat4f inverseMvmProjMatrix; + + + // Uniforms + public int uMcDepthTexture = -1; + public int uCombinedMcDhColorTexture = -1; + public int uDhColorTexture = -1; + + /** Inverted Model View Projection matrix */ + public int uInvMvmProj = -1; + + public int uStartFadeBlockDistance = -1; + public int uEndFadeBlockDistance = -1; + + + + + //=============// + // constructor // + //=============// + + public FadeShader() { } + + @Override + public void onInit() + { + this.shader = new ShaderProgram( + "shaders/normal.vert", "shaders/fade/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.uInvMvmProj = this.shader.tryGetUniformLocation("uInvMvmProj"); + + this.uMcDepthTexture = this.shader.tryGetUniformLocation("uMcDepthMap"); + this.uCombinedMcDhColorTexture = this.shader.tryGetUniformLocation("uCombinedMcDhColorTexture"); + 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) + { + if (this.inverseMvmProjMatrix != null) + { + this.shader.setUniform(this.uInvMvmProj, this.inverseMvmProjMatrix); + } + + + int vanillaBlockRenderDistance = MC_RENDER.getRenderDistance() * LodUtil.CHUNK_WIDTH; + // measured in blocks + float fadeStartDistance = vanillaBlockRenderDistance * 0.5f; + float fadeEndDistance = vanillaBlockRenderDistance * 0.8f; + + if (this.uStartFadeBlockDistance != -1) this.shader.setUniform(this.uStartFadeBlockDistance, fadeStartDistance); + if (this.uEndFadeBlockDistance != -1) this.shader.setUniform(this.uEndFadeBlockDistance, fadeEndDistance); + } + + public void setProjectionMatrix(Mat4f mcModelViewMatrix, Mat4f mcProjectionMatrix) + { + Mat4f inverseModelViewProjectionMatrix = new Mat4f(mcProjectionMatrix); + inverseModelViewProjectionMatrix.multiply(mcModelViewMatrix); + inverseModelViewProjectionMatrix.invert(); + + this.inverseMvmProjMatrix = inverseModelViewProjectionMatrix; + } + + + + //========// + // render // + //========// + + @Override + protected void onRender() + { + GLState state = new GLState(); + + GL32.glBindFramebuffer(GL32.GL_FRAMEBUFFER, this.frameBuffer); + GL32.glDisable(GL32.GL_SCISSOR_TEST); + GL32.glDisable(GL32.GL_DEPTH_TEST); + GL32.glDisable(GL32.GL_BLEND); + + GL32.glActiveTexture(GL32.GL_TEXTURE0); + GL32.glBindTexture(GL32.GL_TEXTURE_2D, MC_RENDER.getDepthTextureId()); + GL32.glUniform1i(this.uMcDepthTexture, 0); + + GL32.glActiveTexture(GL32.GL_TEXTURE1); + GL32.glBindTexture(GL32.GL_TEXTURE_2D, MC_RENDER.getColorTextureId()); + GL32.glUniform1i(this.uCombinedMcDhColorTexture, 1); + + GL32.glActiveTexture(GL32.GL_TEXTURE2); + GL32.glBindTexture(GL32.GL_TEXTURE_2D, LodRenderer.getActiveColorTextureId()); + GL32.glUniform1i(this.uDhColorTexture, 2); + + // this is necessary for MC 1.16 (IE Legacy OpenGL) + // otherwise the framebuffer isn't cleared correctly and the fade smears across the screen + GL32.glClear(GL32.GL_COLOR_BUFFER_BIT | GL32.GL_DEPTH_BUFFER_BIT); + + + ScreenQuad.INSTANCE.render(); + + state.restore(); + } + +} diff --git a/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/minecraft/IMinecraftRenderWrapper.java b/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/minecraft/IMinecraftRenderWrapper.java index c581e3db9..f283d09dd 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/minecraft/IMinecraftRenderWrapper.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/minecraft/IMinecraftRenderWrapper.java @@ -64,6 +64,7 @@ public interface IMinecraftRenderWrapper extends IBindable int getTargetFrameBuffer(); // Note: Iris is now hooking onto this for DH + Iris compat, try not to change (unless we wanna deal with some annoyances) // Iris commit: https://github.com/IrisShaders/Iris/commit/a76a240527e93780bbcba57c09bef377419d47a7#diff-7b9ded0c79bbcdb130010373387756a28ee8d3640d522c0a5b7acd0abbfc20aeR16 int getDepthTextureId(); + int getColorTextureId(); int getTargetFrameBufferViewportWidth(); int getTargetFrameBufferViewportHeight(); 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 a4f46ed1b..d39a5b01f 100644 --- a/core/src/main/resources/assets/distanthorizons/lang/en_us.json +++ b/core/src/main/resources/assets/distanthorizons/lang/en_us.json @@ -114,6 +114,10 @@ "Tint With Avoided Blocks", "distanthorizons.config.client.advanced.graphics.quality.tintWithAvoidedBlocks.@tooltip": "§4Note: makes snow, carpet, and trapdoors look really bad§r\nShould the blocks underneath avoided blocks gain the color of the avoided block?\n§6True:§r a red flower on grass will tint the grass below it red\n§6False:§r skipped blocks will not change color of surface below them", + "distanthorizons.config.client.advanced.graphics.quality.fadeOutVanillaRendering": + "Fade Out Vanilla Rendering", + "distanthorizons.config.client.advanced.graphics.quality.fadeOutVanillaRendering.@tooltip": + "If true vanilla chunks will fade out the further away they are\nsmoothing the transition between Distant Horizons and vanilla rendering.", "distanthorizons.config.client.advanced.graphics.quality.lodBiomeBlending": "Biome Blending", "distanthorizons.config.client.advanced.graphics.quality.lodBiomeBlending.@tooltip": diff --git a/core/src/main/resources/shaders/fade/apply.frag b/core/src/main/resources/shaders/fade/apply.frag new file mode 100644 index 000000000..d3d21ffca --- /dev/null +++ b/core/src/main/resources/shaders/fade/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/fade/fade.frag b/core/src/main/resources/shaders/fade/fade.frag new file mode 100644 index 000000000..0d90b2fdd --- /dev/null +++ b/core/src/main/resources/shaders/fade/fade.frag @@ -0,0 +1,70 @@ +#version 150 core + +in vec2 TexCoord; + +out vec4 fragColor; + +uniform sampler2D uMcDepthTexture; +uniform sampler2D uCombinedMcDhColorTexture; +uniform sampler2D uDhColorTexture; +// inverted model view matrix and projection matrix +uniform mat4 uInvMvmProj; + +uniform float uStartFadeBlockDistance; +uniform float uEndFadeBlockDistance; + + + +vec3 calcViewPosition(float fragmentDepth) +{ + // normalized device coordinates + 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; +} + +/** + * 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(uCombinedMcDhColorTexture, 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; + } + + + + // a fragment depth of "1" means the fragment wasn't drawn to, + // we only want to fade vanilla rendered objects, not to the sky or LODs + float mcFragmentDepth = texture(uMcDepthTexture, TexCoord).r; + if (mcFragmentDepth < 1.0) + { + // fade based on distance from the camera + vec3 vertexWorldPos = calcViewPosition(mcFragmentDepth); + float fragmentDistance = length(vertexWorldPos.xzy); + + + // Smoothly transition between combinedMcDhColor and uDhColorTexture + // as the depth increases from the camera + float fadeStep = smoothstep(uStartFadeBlockDistance, uEndFadeBlockDistance, fragmentDistance); + fragColor = mix(combinedMcDhColor, dhColor, fadeStep); + fragColor.a = 1.0; // TODO is setting the alpha needed? + } + else + { + fragColor = vec4(combinedMcDhColor.rgb, 0.0); + } +} +