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 new file mode 100644 index 000000000..1f2f17491 --- /dev/null +++ b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/FogRenderer.java @@ -0,0 +1,135 @@ +/* + * 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.FogApplyShader; +import com.seibel.distanthorizons.core.render.renderer.shaders.FogShader; +import com.seibel.distanthorizons.core.util.math.Mat4f; +import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper; +import org.lwjgl.opengl.GL32; + +import java.nio.ByteBuffer; + +/** + * Handles adding SSAO via {@link FogShader} and {@link FogApplyShader}.

+ * + * {@link FogShader} - draws the Fog to a texture.
+ * {@link FogApplyShader} - draws the Fog texture to DH's FrameBuffer.
+ */ +public class FogRenderer +{ + public static FogRenderer INSTANCE = new FogRenderer(); + + 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 fogFramebuffer = -1; + + private int fogTexture = -1; + + + + //=============// + // constructor // + //=============// + + private FogRenderer() { } + + public void init() + { + if (this.init) return; + this.init = true; + + FogShader.INSTANCE.init(); + FogApplyShader.INSTANCE.init(); + } + + private void createFramebuffer(int width, int height) + { + if (this.fogFramebuffer != -1) + { + GL32.glDeleteFramebuffers(this.fogFramebuffer); + this.fogFramebuffer = -1; + } + + if (this.fogTexture != -1) + { + GL32.glDeleteTextures(this.fogTexture); + this.fogTexture = -1; + } + + this.fogFramebuffer = GL32.glGenFramebuffers(); + GL32.glBindFramebuffer(GL32.GL_FRAMEBUFFER, this.fogFramebuffer); + + this.fogTexture = GL32.glGenTextures(); + GL32.glBindTexture(GL32.GL_TEXTURE_2D, this.fogTexture); + 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.fogTexture, 0); + } + + + + //========// + // render // + //========// + + public void render(GLState primaryState, Mat4f projectionMatrix, float partialTicks) + { + GLState state = new GLState(); + 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); + } + + FogShader.INSTANCE.frameBuffer = this.fogFramebuffer; + FogShader.INSTANCE.setProjectionMatrix(projectionMatrix); + FogShader.INSTANCE.render(partialTicks); + + // restored so we can write the SSAO texture to the main frame buffer + primaryState.restore(); + + FogApplyShader.INSTANCE.fogTexture = this.fogTexture; + FogApplyShader.INSTANCE.render(partialTicks); + + state.restore(); + } + + public void free() + { + FogShader.INSTANCE.free(); + FogApplyShader.INSTANCE.free(); + } + +} 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 98835b259..681364ac2 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 @@ -327,6 +327,14 @@ public class LodRenderer } + //DarkShader.INSTANCE.render(partialTicks); // A test shader to make the world darker + + if (!deferTransparentRendering && Config.Client.Advanced.Graphics.Quality.transparency.get().transparencyEnabled) + { + this.renderTransparentBuffers(profiler, renderEventParam, renderEventParam.partialTicks); + } + + if (Config.Client.Advanced.Graphics.Fog.drawMode.get() != EDhApiFogDrawMode.FOG_DISABLED) { profiler.popPush("LOD Fog"); @@ -334,16 +342,9 @@ public class LodRenderer Mat4f combinedMatrix = new Mat4f(renderEventParam.dhProjectionMatrix); combinedMatrix.multiply(renderEventParam.dhModelViewMatrix); - FogShader.INSTANCE.setModelViewProjectionMatrix(combinedMatrix); - FogShader.INSTANCE.render(renderEventParam.partialTicks); + FogRenderer.INSTANCE.render(minecraftGlState, combinedMatrix, renderEventParam.partialTicks); } - //DarkShader.INSTANCE.render(partialTicks); // A test shader to make the world darker - - if (!deferTransparentRendering && Config.Client.Advanced.Graphics.Quality.transparency.get().transparencyEnabled) - { - this.renderTransparentBuffers(profiler, renderEventParam, renderEventParam.partialTicks); - } drawLagSpikeCatcher.end("LodDraw"); @@ -403,6 +404,17 @@ public class LodRenderer if (Config.Client.Advanced.Graphics.Quality.transparency.get().transparencyEnabled) { this.renderTransparentBuffers(profiler, renderEventParam, renderEventParam.partialTicks); + + + if (Config.Client.Advanced.Graphics.Fog.drawMode.get() != EDhApiFogDrawMode.FOG_DISABLED) + { + profiler.popPush("LOD Fog"); + + Mat4f combinedMatrix = new Mat4f(renderEventParam.dhProjectionMatrix); + combinedMatrix.multiply(renderEventParam.dhModelViewMatrix); + + FogRenderer.INSTANCE.render(minecraftGlState, combinedMatrix, renderEventParam.partialTicks); + } } drawLagSpikeCatcher.end("LodTranslucentDraw"); @@ -457,12 +469,6 @@ public class LodRenderer this.bufferHandler.renderTransparent(this, renderEventParam); GL32.glDepthMask(true); // Apparently the depth mask state is stored in the FBO, so glState fails to restore it... - - if (Config.Client.Advanced.Graphics.Fog.drawMode.get() != EDhApiFogDrawMode.FOG_DISABLED) - { - profiler.popPush("LOD Fog"); - FogShader.INSTANCE.render(partialTicks); - } } /** called by each {@link ColumnRenderBuffer} before rendering */ diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/SSAORenderer.java b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/SSAORenderer.java index 97c5d1cde..b9953cd31 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/SSAORenderer.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/SSAORenderer.java @@ -51,6 +51,7 @@ public class SSAORenderer private int ssaoTexture = -1; + //=============// // constructor // //=============// @@ -92,6 +93,7 @@ public class SSAORenderer } + //========// // render // //========// @@ -99,12 +101,11 @@ public class SSAORenderer public void render(GLState primaryState, Mat4f projectionMatrix, float partialTicks) { GLState state = new GLState(); - 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; @@ -116,6 +117,7 @@ public class SSAORenderer SSAOShader.INSTANCE.setProjectionMatrix(projectionMatrix); SSAOShader.INSTANCE.render(partialTicks); + // restored so we can write the SSAO texture to the main frame buffer primaryState.restore(); SSAOApplyShader.INSTANCE.ssaoTexture = this.ssaoTexture; @@ -129,4 +131,5 @@ public class SSAORenderer SSAOShader.INSTANCE.free(); SSAOApplyShader.INSTANCE.free(); } + } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/shaders/FogApplyShader.java b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/shaders/FogApplyShader.java new file mode 100644 index 000000000..45e2d8d39 --- /dev/null +++ b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/shaders/FogApplyShader.java @@ -0,0 +1,107 @@ +/* + * 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.config.Config; +import com.seibel.distanthorizons.core.render.glObject.shader.ShaderProgram; +import com.seibel.distanthorizons.core.render.renderer.FogRenderer; +import com.seibel.distanthorizons.core.render.renderer.LodRenderer; +import com.seibel.distanthorizons.core.render.renderer.SSAORenderer; +import com.seibel.distanthorizons.core.render.renderer.ScreenQuad; +import com.seibel.distanthorizons.core.util.RenderUtil; +import org.lwjgl.opengl.GL32; + +/** + * Draws the Fog texture onto DH's FrameBuffer.

+ * + * See Also:
+ * {@link FogRenderer} - Parent to this shader.
+ * {@link FogShader} - draws the Fog texture.
+ */ +public class FogApplyShader extends AbstractShaderRenderer +{ + public static FogApplyShader INSTANCE = new FogApplyShader(); + + public int fogTexture; + + // uniforms + public int gColorTextureUniform; + public int gDepthTextureUniform; + + + + //=============// + // constructor // + //=============// + + @Override + public void onInit() + { + this.shader = new ShaderProgram( + "shaders/normal.vert", + "shaders/fog/apply.frag", + "fragColor", + new String[]{ "vPosition" }); + + // uniform setup + this.gColorTextureUniform = this.shader.getUniformLocation("gColorTexture"); + this.gDepthTextureUniform = this.shader.getUniformLocation("gDepthTexture"); + + } + + + + //=============// + // render prep // + //=============// + + @Override + protected void onApplyUniforms(float partialTicks) + { + GL32.glActiveTexture(GL32.GL_TEXTURE0); + GL32.glBindTexture(GL32.GL_TEXTURE_2D, this.fogTexture); + GL32.glUniform1i(this.gColorTextureUniform, 0); + + GL32.glActiveTexture(GL32.GL_TEXTURE1); + GL32.glBindTexture(GL32.GL_TEXTURE_2D, LodRenderer.getActiveDepthTextureId()); + GL32.glUniform1i(this.gDepthTextureUniform, 1); + } + + + + //========// + // 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); + + // apply the rendered Fog to DH's framebuffer + GL32.glBindFramebuffer(GL32.GL_READ_FRAMEBUFFER, FogShader.INSTANCE.frameBuffer); + GL32.glBindFramebuffer(GL32.GL_DRAW_FRAMEBUFFER, LodRenderer.getActiveFramebufferId()); + + ScreenQuad.INSTANCE.render(); + } + +} 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 98e0b0b1b..a35037253 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 @@ -44,12 +44,13 @@ public class FogShader extends AbstractShaderRenderer private static final IVersionConstants VERSION_CONSTANTS = SingletonInjector.INSTANCE.get(IVersionConstants.class); + public int frameBuffer; + private final LodFogConfig fogConfig; private Mat4f inverseMvmProjMatrix; - public int gInvertedModelViewProjectionUniform; - public int gDepthMapUniform; - // Fog Uniforms + + // Uniforms public int fogColorUniform; public int fogScaleUniform; public int fogVerticalScaleUniform; @@ -57,11 +58,16 @@ public class FogShader extends AbstractShaderRenderer public int nearFogLengthUniform; public int fullFogModeUniform; + public int gInvertedModelViewProjectionUniform; + public int gDepthMapUniform; - public FogShader(LodFogConfig fogConfig) - { - this.fogConfig = fogConfig; - } + + + //=============// + // constructor // + //=============// + + public FogShader(LodFogConfig fogConfig) { this.fogConfig = fogConfig; } @Override public void onInit() @@ -76,8 +82,8 @@ public class FogShader extends AbstractShaderRenderer // all uniforms should be tryGet... // because disabling fog can cause the GLSL to optimize out most (if not all) uniforms - this.gInvertedModelViewProjectionUniform = this.shader.tryGetUniformLocation("gInvMvmProj"); - this.gDepthMapUniform = this.shader.tryGetUniformLocation("gDepthMap"); + this.gInvertedModelViewProjectionUniform = this.shader.getUniformLocation("gInvMvmProj"); + this.gDepthMapUniform = this.shader.getUniformLocation("gDepthMap"); // Fog uniforms this.fogColorUniform = this.shader.tryGetUniformLocation("fogColor"); @@ -90,23 +96,24 @@ public class FogShader extends AbstractShaderRenderer this.nearFogLengthUniform = this.shader.tryGetUniformLocation("nearFogLength"); } + + + //=============// + // render prep // + //=============// + @Override protected void onApplyUniforms(float partialTicks) { - this.shader.setUniform(this.gInvertedModelViewProjectionUniform, this.inverseMvmProjMatrix); + if (this.inverseMvmProjMatrix != null) + { + this.shader.setUniform(this.gInvertedModelViewProjectionUniform, this.inverseMvmProjMatrix); + } int lodDrawDistance = Config.Client.Advanced.Graphics.Quality.lodChunkRenderDistanceRadius.get() * LodUtil.CHUNK_WIDTH; int vanillaDrawDistance = MC_RENDER.getRenderDistance() * LodUtil.CHUNK_WIDTH; vanillaDrawDistance += LodUtil.CHUNK_WIDTH * 2; // Give it a 2 chunk boundary for near fog. - // bind the depth buffer - if (this.gDepthMapUniform != -1) - { - GL32.glActiveTexture(GL32.GL_TEXTURE1); - GL32.glBindTexture(GL32.GL_TEXTURE_2D, LodRenderer.getActiveDepthTextureId()); - GL32.glUniform1i(this.gDepthMapUniform, 1); - } - // Fog if (this.fullFogModeUniform != -1) this.shader.setUniform(this.fullFogModeUniform, MC_RENDER.isFogStateSpecial() ? 1 : 0); if (this.fogColorUniform != -1) this.shader.setUniform(this.fogColorUniform, MC_RENDER.isFogStateSpecial() ? this.getSpecialFogColor(partialTicks) : this.getFogColor(partialTicks)); @@ -118,7 +125,6 @@ public class FogShader extends AbstractShaderRenderer if (this.fogScaleUniform != -1) this.shader.setUniform(this.fogScaleUniform, 1.f / lodDrawDistance); if (this.fogVerticalScaleUniform != -1) this.shader.setUniform(this.fogVerticalScaleUniform, 1.f / MC.getWrappedClientLevel().getMaxHeight()); } - private Color getFogColor(float partialTicks) { Color fogColor; @@ -134,29 +140,34 @@ public class FogShader extends AbstractShaderRenderer return fogColor; } - private Color getSpecialFogColor(float partialTicks) { return MC_RENDER.getSpecialFogColor(partialTicks); } - public void setModelViewProjectionMatrix(Mat4f combinedModelViewProjectionMatrix) + public void setProjectionMatrix(Mat4f projectionMatrix) { - this.inverseMvmProjMatrix = new Mat4f(combinedModelViewProjectionMatrix); + this.inverseMvmProjMatrix = new Mat4f(projectionMatrix); this.inverseMvmProjMatrix.invert(); } + + + //========// + // render // + //========// + @Override protected void onRender() { GLState state = new GLState(); - GL32.glDisable(GL32.GL_DEPTH_TEST); + GL32.glBindFramebuffer(GL32.GL_FRAMEBUFFER, this.frameBuffer); GL32.glDisable(GL32.GL_SCISSOR_TEST); - - 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); + GL32.glDisable(GL32.GL_DEPTH_TEST); + GL32.glDisable(GL32.GL_BLEND); GL32.glActiveTexture(GL32.GL_TEXTURE0); - GL32.glBindTexture(GL32.GL_TEXTURE_2D, LodRenderer.getActiveColorTextureId()); + GL32.glBindTexture(GL32.GL_TEXTURE_2D, LodRenderer.getActiveDepthTextureId()); + GL32.glUniform1i(this.gDepthMapUniform, 0); + ScreenQuad.INSTANCE.render(); state.restore(); diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/shaders/SSAOApplyShader.java b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/shaders/SSAOApplyShader.java index eb871c92b..43da8521f 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/shaders/SSAOApplyShader.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/shaders/SSAOApplyShader.java @@ -50,6 +50,11 @@ public class SSAOApplyShader extends AbstractShaderRenderer public int gFarUniform; + + //=============// + // constructor // + //=============// + @Override public void onInit() { @@ -68,6 +73,12 @@ public class SSAOApplyShader extends AbstractShaderRenderer this.gFarUniform = this.shader.tryGetUniformLocation("gFar"); } + + + //=============// + // render prep // + //=============// + @Override protected void onApplyUniforms(float partialTicks) { @@ -102,6 +113,7 @@ public class SSAOApplyShader extends AbstractShaderRenderer } + //========// // render // //========// diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/shaders/SSAOShader.java b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/shaders/SSAOShader.java index d7659a1e0..05834e159 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/shaders/SSAOShader.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/shaders/SSAOShader.java @@ -38,11 +38,13 @@ public class SSAOShader extends AbstractShaderRenderer { public static SSAOShader INSTANCE = new SSAOShader(); + public int frameBuffer; private Mat4f projection; private Mat4f invertedProjection; + // uniforms public int gProjUniform; public int gInvProjUniform; @@ -54,11 +56,17 @@ public class SSAOShader extends AbstractShaderRenderer public int gDepthMapUniform; + + //=============// + // constructor // + //=============// + @Override public void onInit() { this.shader = new ShaderProgram("shaders/normal.vert", "shaders/ssao/ao.frag", - "fragColor", new String[]{"vPosition"}); + "fragColor", new String[]{ "vPosition" } + ); // uniform setup this.gProjUniform = this.shader.getUniformLocation("gProj"); @@ -71,6 +79,12 @@ public class SSAOShader extends AbstractShaderRenderer this.gDepthMapUniform = this.shader.getUniformLocation("gDepthMap"); } + + + //=============// + // render prep // + //=============// + public void setProjectionMatrix(Mat4f projectionMatrix) { this.projection = projectionMatrix; @@ -108,6 +122,7 @@ public class SSAOShader extends AbstractShaderRenderer } + //========// // render // //========// diff --git a/core/src/main/resources/shaders/fog/apply.frag b/core/src/main/resources/shaders/fog/apply.frag new file mode 100644 index 000000000..390599b07 --- /dev/null +++ b/core/src/main/resources/shaders/fog/apply.frag @@ -0,0 +1,24 @@ +#version 150 core + +in vec2 TexCoord; + +out vec4 fragColor; + +uniform sampler2D gColorTexture; +uniform sampler2D gDepthTexture; + + + +void main() +{ + fragColor = vec4(1.0); + + float fragmentDepth = textureLod(gDepthTexture, TexCoord, 0).r; + + // a fragment depth of "1" means the fragment wasn't drawn to, + // only update fragments that were drawn to + if (fragmentDepth != 1) + { + fragColor = texture(gColorTexture, TexCoord); + } +}