Fix fog reading/writing to the same buffer

This commit is contained in:
James Seibel
2024-07-13 11:09:49 -05:00
parent 6c960a81c0
commit 859cbb6161
8 changed files with 359 additions and 46 deletions
@@ -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 <https://www.gnu.org/licenses/>.
*/
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}. <br><br>
*
* {@link FogShader} - draws the Fog to a texture. <br>
* {@link FogApplyShader} - draws the Fog texture to DH's FrameBuffer. <br>
*/
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();
}
}
@@ -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 */
@@ -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();
}
}
@@ -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 <https://www.gnu.org/licenses/>.
*/
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. <br><br>
*
* See Also: <br>
* {@link FogRenderer} - Parent to this shader. <br>
* {@link FogShader} - draws the Fog texture. <br>
*/
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();
}
}
@@ -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();
@@ -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 //
//========//
@@ -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 //
//========//
@@ -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);
}
}