Merge branch 'distant-horizons-core-abstract.shader.refactor'

This commit is contained in:
James Seibel
2023-09-11 07:29:43 -05:00
11 changed files with 579 additions and 418 deletions
@@ -19,34 +19,32 @@
package com.seibel.distanthorizons.core.render.glObject;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import com.seibel.distanthorizons.api.enums.config.EGLErrorHandlingMode;
import com.seibel.distanthorizons.api.enums.config.EGpuUploadMethod;
import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.enums.EGLProxyContext;
import com.seibel.distanthorizons.core.logging.ConfigBasedLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.util.objects.GLMessage;
import com.seibel.distanthorizons.core.util.objects.GLMessageOutputStream;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
import com.seibel.distanthorizons.coreapi.ModInfo;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.lwjgl.glfw.GLFW;
import org.lwjgl.opengl.GL;
import org.lwjgl.opengl.GL32;
import org.lwjgl.opengl.GLCapabilities;
import org.lwjgl.opengl.GLUtil;
import java.io.PrintStream;
import java.lang.invoke.MethodHandles;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import com.seibel.distanthorizons.api.enums.config.EGLErrorHandlingMode;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.logging.ConfigBasedLogger;
import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.lwjgl.glfw.GLFW;
import org.lwjgl.opengl.GL;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL32;
import org.lwjgl.opengl.GLCapabilities;
import org.lwjgl.opengl.GLUtil;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import com.seibel.distanthorizons.coreapi.ModInfo;
import com.seibel.distanthorizons.api.enums.config.EGpuUploadMethod;
import com.seibel.distanthorizons.core.enums.EGLProxyContext;
import com.seibel.distanthorizons.core.util.objects.GLMessage;
import com.seibel.distanthorizons.core.util.objects.GLMessageOutputStream;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
/**
* A singleton that holds references to different openGL contexts
* and GPU capabilities.
@@ -108,7 +106,7 @@ public class GLProxy
// this must be created on minecraft's render context to work correctly
GL_LOGGER.info("Creating " + GLProxy.class.getSimpleName() + "... If this is the last message you see there must have been an OpenGL error.");
GL_LOGGER.info("Lod Render OpenGL version [" + GL11.glGetString(GL11.GL_VERSION) + "].");
GL_LOGGER.info("Lod Render OpenGL version [" + GL32.glGetString(GL32.GL_VERSION) + "].");
// getting Minecraft's context has to be done on the render thread,
// where the GL context is
@@ -243,16 +243,23 @@ public class LodRenderer
{
this.shaderProgram.free();
this.shaderProgram = new LodRenderProgram(newFogConfig);
FogShader.INSTANCE.free();
FogShader.INSTANCE = new FogShader(newFogConfig);
}
this.shaderProgram.bind();
}
GL32.glActiveTexture(GL32.GL_TEXTURE0);
/*---------Get required data--------*/
int vanillaBlockRenderedDistance = MC_RENDER.getRenderDistance() * LodUtil.CHUNK_WIDTH;
Mat4f modelViewProjectionMatrix = RenderUtil.createCombinedModelViewProjectionMatrix(baseProjectionMatrix, baseModelViewMatrix, partialTicks);
//Mat4f modelViewProjectionMatrix = RenderUtil.createCombinedModelViewProjectionMatrix(baseProjectionMatrix, baseModelViewMatrix, partialTicks);
Mat4f projectionMatrix = RenderUtil.createLodProjectionMatrix(baseProjectionMatrix, partialTicks);
Mat4f modelViewProjectionMatrix = new Mat4f(projectionMatrix);
modelViewProjectionMatrix.multiply(RenderUtil.createLodModelViewMatrix(baseModelViewMatrix));
/*---------Fill uniform data--------*/
this.shaderProgram.fillUniformData(modelViewProjectionMatrix, /*Light map = GL_TEXTURE0*/ 0,
@@ -283,12 +290,12 @@ public class LodRenderer
if (Config.Client.Advanced.Graphics.Ssao.enabled.get())
{
profiler.popPush("LOD SSAO");
SSAOShader.INSTANCE.setProjectionMatrix(projectionMatrix);
SSAORenderer.INSTANCE.render(minecraftGlState, partialTicks);
}
profiler.popPush("LOD Fog");
// TODO add the model view/projection matrices to the render() function
FogShader.INSTANCE.setModelViewProjectionMatrix(modelViewProjectionMatrix);
FogShader.INSTANCE.render(partialTicks);
@@ -0,0 +1,125 @@
/*
* 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.SSAOApplyShader;
import com.seibel.distanthorizons.core.render.renderer.shaders.SSAOShader;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
import org.lwjgl.opengl.GL32;
import java.nio.ByteBuffer;
public class SSAORenderer
{
public static SSAORenderer INSTANCE = new SSAORenderer();
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 ssaoFramebuffer = -1;
private int ssaoTexture = -1;
//=============//
// constructor //
//=============//
private SSAORenderer() { }
public void init()
{
if (this.init) return;
this.init = true;
SSAOShader.INSTANCE.init();
SSAOApplyShader.INSTANCE.init();
}
private void createFramebuffer(int width, int height)
{
if (this.ssaoFramebuffer != -1)
{
GL32.glDeleteFramebuffers(this.ssaoFramebuffer);
this.ssaoFramebuffer = -1;
}
if (this.ssaoTexture != -1)
{
GL32.glDeleteTextures(this.ssaoTexture);
this.ssaoTexture = -1;
}
this.ssaoFramebuffer = GL32.glGenFramebuffers();
GL32.glBindFramebuffer(GL32.GL_FRAMEBUFFER, this.ssaoFramebuffer);
this.ssaoTexture = GL32.glGenTextures();
GL32.glBindTexture(GL32.GL_TEXTURE_2D, this.ssaoTexture);
GL32.glTexImage2D(GL32.GL_TEXTURE_2D, 0, GL32.GL_R16F, width, height, 0, GL32.GL_RED, GL32.GL_HALF_FLOAT, (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.ssaoTexture, 0);
}
//========//
// render //
//========//
public void render(GLState primaryState, float partialTicks)
{
GLState state = new GLState();
this.init();
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);
}
SSAOShader.INSTANCE.FrameBuffer = this.ssaoFramebuffer;
SSAOShader.INSTANCE.render(partialTicks);
primaryState.RestoreFrameBuffer();
SSAOApplyShader.INSTANCE.BufferTexture = this.ssaoTexture;
SSAOApplyShader.INSTANCE.render(partialTicks);
state.restore();
}
public void free()
{
SSAOShader.INSTANCE.free();
SSAOApplyShader.INSTANCE.free();
}
}
@@ -0,0 +1,91 @@
/*
* 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.api.enums.config.EGpuUploadMethod;
import com.seibel.distanthorizons.core.render.glObject.buffer.GLVertexBuffer;
import com.seibel.distanthorizons.core.render.glObject.vertexAttribute.VertexAttribute;
import org.lwjgl.opengl.GL32;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
public class ScreenQuad
{
public static ScreenQuad INSTANCE = new ScreenQuad();
private static final float[] box_vertices = {
-1, -1,
1, -1,
1, 1,
-1, -1,
1, 1,
-1, 1,
};
private GLVertexBuffer boxBuffer;
private VertexAttribute va;
private boolean init = false;
//=============//
// constructor //
//=============//
private ScreenQuad() { }
public void init()
{
if (this.init) return;
this.init = true;
this.va = VertexAttribute.create();
this.va.bind();
// Pos
this.va.setVertexAttribute(0, 0, VertexAttribute.VertexPointer.addVec2Pointer(false));
this.va.completeAndCheck(Float.BYTES * 2);
// Framebuffer
this.createBuffer();
}
public void render()
{
this.init();
this.va.bind();
this.va.bindBufferToAllBindingPoint(this.boxBuffer.getId());
GL32.glDrawArrays(GL32.GL_TRIANGLES, 0, 6);
}
private void createBuffer()
{
ByteBuffer buffer = ByteBuffer.allocateDirect(box_vertices.length * Float.BYTES);
buffer.order(ByteOrder.nativeOrder());
buffer.asFloatBuffer().put(box_vertices);
buffer.rewind();
this.boxBuffer = new GLVertexBuffer(false);
this.boxBuffer.bind();
this.boxBuffer.uploadBuffer(buffer, box_vertices.length, EGpuUploadMethod.DATA, box_vertices.length * Float.BYTES);
}
}
@@ -19,120 +19,56 @@
package com.seibel.distanthorizons.core.render.renderer.shaders;
import com.seibel.distanthorizons.api.enums.config.EGpuUploadMethod;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.render.glObject.GLState;
import com.seibel.distanthorizons.core.render.glObject.buffer.GLVertexBuffer;
import com.seibel.distanthorizons.core.render.glObject.shader.ShaderProgram;
import com.seibel.distanthorizons.core.render.glObject.vertexAttribute.VertexAttribute;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL32;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
public abstract class AbstractShaderRenderer
{
protected static final IMinecraftClientWrapper MC = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
protected static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class);
private static final float[] box_vertices = {
-1, -1,
1, -1,
1, 1,
-1, -1,
1, 1,
-1, 1,
};
protected final ShaderProgram shader;
public GLVertexBuffer boxBuffer;
protected VertexAttribute va;
boolean init = false;
protected ShaderProgram shader;
protected boolean init = false;
protected AbstractShaderRenderer(ShaderProgram shader)
protected AbstractShaderRenderer() {}
public void init()
{
this.shader = shader;
if (this.init) return;
this.init = true;
this.onInit();
}
private void init()
{
if (init) return;
init = true;
va = VertexAttribute.create();
va.bind();
// Pos
setVertexAttributes();
va.completeAndCheck(Float.BYTES * 2);
// Some shader stuff needs to be set a bit later than
this.postInit();
// Framebuffer
this.createBuffer();
}
/** Sets all the vertex attributes */
void setVertexAttributes()
{
va.setVertexAttribute(0, 0, VertexAttribute.VertexPointer.addVec2Pointer(false));
}
/** Overwrite this to apply uniforms to the shader */
void setShaderUniforms(float partialTicks) { }
/** Overwrite if you need to run something on runtime */
void postInit() { }
// TODO pass in the Model View and Projection Matrices along with the ticks
public void render(float partialTicks)
{
GLState state = new GLState();
this.init();
this.shader.bind();
this.onApplyUniforms(partialTicks);
int width = MC_RENDER.getTargetFrameBufferViewportWidth();
int height = MC_RENDER.getTargetFrameBufferViewportHeight();
GL32.glViewport(0, 0, width, height);
GL32.glDisable(GL32.GL_DEPTH_TEST);
GL32.glDisable(GL32.GL_SCISSOR_TEST);
shader.bind();
this.setShaderUniforms(partialTicks);
this.onRender();
va.bind();
va.bindBufferToAllBindingPoint(boxBuffer.getId());
GL32.glActiveTexture(GL32.GL_TEXTURE0);
GL32.glBindTexture(GL32.GL_TEXTURE_2D, MC_RENDER.getDepthTextureId());
GL32.glEnable(GL11.GL_BLEND);
GL32.glBlendFunc(GL32.GL_SRC_ALPHA, GL32.GL_ONE_MINUS_SRC_ALPHA);
GL32.glDrawArrays(GL32.GL_TRIANGLES, 0, 6);
state.restore();
}
private void createBuffer()
{
ByteBuffer buffer = ByteBuffer.allocateDirect(box_vertices.length * Float.BYTES);
buffer.order(ByteOrder.nativeOrder());
buffer.asFloatBuffer().put(box_vertices);
buffer.rewind();
this.boxBuffer = new GLVertexBuffer(false);
this.boxBuffer.bind();
this.boxBuffer.uploadBuffer(buffer, box_vertices.length, EGpuUploadMethod.DATA, box_vertices.length * Float.BYTES);
this.shader.unbind();
}
public void free()
{
this.shader.free();
}
protected void onInit() {}
protected void onApplyUniforms(float partialTicks) {}
protected void onRender() {}
}
@@ -19,15 +19,45 @@
package com.seibel.distanthorizons.core.render.renderer.shaders;
import com.seibel.distanthorizons.core.render.glObject.GLState;
import com.seibel.distanthorizons.core.render.glObject.shader.ShaderProgram;
import com.seibel.distanthorizons.core.render.renderer.ScreenQuad;
import org.lwjgl.opengl.GL32;
public class DarkShader extends AbstractShaderRenderer
{
public static DarkShader INSTANCE = new DarkShader();
protected DarkShader()
@Override
public void onInit()
{
super(new ShaderProgram("shaders/normal.vert", "shaders/test/dark.frag", "fragColor", new String[]{"vPosition", "color"}));
this.shader = new ShaderProgram(
"shaders/normal.vert",
"shaders/test/dark.frag",
"fragColor",
new String[]{"vPosition", "color"});
}
@Override
protected void onApplyUniforms(float partialTicks)
{
GL32.glActiveTexture(GL32.GL_TEXTURE0);
GL32.glBindTexture(GL32.GL_TEXTURE_2D, MC_RENDER.getDepthTextureId());
}
@Override
protected void onRender()
{
GLState state = new GLState();
GL32.glDisable(GL32.GL_DEPTH_TEST);
GL32.glDisable(GL32.GL_SCISSOR_TEST);
GL32.glEnable(GL32.GL_BLEND);
GL32.glBlendFunc(GL32.GL_SRC_ALPHA, GL32.GL_ONE_MINUS_SRC_ALPHA);
ScreenQuad.INSTANCE.render();
state.restore();
}
}
@@ -23,11 +23,14 @@ import com.seibel.distanthorizons.api.enums.rendering.EFogColorMode;
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.ScreenQuad;
import com.seibel.distanthorizons.core.util.LodUtil;
import com.seibel.distanthorizons.core.util.RenderUtil;
import com.seibel.distanthorizons.core.wrapperInterfaces.IVersionConstants;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
import com.seibel.distanthorizons.coreapi.util.math.Mat4f;
import org.lwjgl.opengl.GL32;
@@ -36,31 +39,40 @@ import java.awt.*;
public class FogShader extends AbstractShaderRenderer
{
public static FogShader INSTANCE = new FogShader(LodFogConfig.generateFogConfig());
private static final IMinecraftClientWrapper MC = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
private static final IVersionConstants VERSION_CONSTANTS = SingletonInjector.INSTANCE.get(IVersionConstants.class);
public final int gInvertedModelViewProjectionUniform;
public final int gDepthMapUniform;
private final LodFogConfig fogConfig;
private Mat4f inverseMvmProjMatrix;
public int gInvertedModelViewProjectionUniform;
public int gDepthMapUniform;
// Fog Uniforms
public final int fogColorUniform;
public final int fogScaleUniform;
public final int fogVerticalScaleUniform;
public final int nearFogStartUniform;
public final int nearFogLengthUniform;
public final int fullFogModeUniform;
public int fogColorUniform;
public int fogScaleUniform;
public int fogVerticalScaleUniform;
public int nearFogStartUniform;
public int nearFogLengthUniform;
public int fullFogModeUniform;
public FogShader(LodFogConfig fogConfig)
{
super(new ShaderProgram(
this.fogConfig = fogConfig;
}
@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(),
() -> fogConfig.loadAndProcessFragShader("shaders/fog/fog.frag", false).toString(),
() -> this.fogConfig.loadAndProcessFragShader("shaders/fog/fog.frag", false).toString(),
"fragColor", new String[]{"vPosition"}
));
);
// all uniforms should be tryGet...
// because disabling fog can cause the GLSL to optimize out most (if not all) uniforms
@@ -79,9 +91,9 @@ public class FogShader extends AbstractShaderRenderer
}
@Override
void setShaderUniforms(float partialTicks)
protected void onApplyUniforms(float partialTicks)
{
this.shader.bind();
this.shader.setUniform(this.gInvertedModelViewProjectionUniform, this.inverseMvmProjMatrix);
int lodDrawDistance = RenderUtil.getFarClipPlaneDistanceInBlocks();
int vanillaDrawDistance = MC_RENDER.getRenderDistance() * LodUtil.CHUNK_WIDTH;
@@ -127,12 +139,25 @@ public class FogShader extends AbstractShaderRenderer
public void setModelViewProjectionMatrix(Mat4f combinedModelViewProjectionMatrix)
{
this.shader.bind();
this.inverseMvmProjMatrix = new Mat4f(combinedModelViewProjectionMatrix);
this.inverseMvmProjMatrix.invert();
}
@Override
protected void onRender()
{
GLState state = new GLState();
Mat4f inverseMvmProjMatrix = new Mat4f(combinedModelViewProjectionMatrix);
inverseMvmProjMatrix.invert();
this.shader.setUniform(this.gInvertedModelViewProjectionUniform, inverseMvmProjMatrix);
GL32.glDisable(GL32.GL_DEPTH_TEST);
GL32.glDisable(GL32.GL_SCISSOR_TEST);
GL32.glEnable(GL32.GL_BLEND);
GL32.glBlendFunc(GL32.GL_SRC_ALPHA, GL32.GL_ONE_MINUS_SRC_ALPHA);
this.shader.unbind();
GL32.glActiveTexture(GL32.GL_TEXTURE0);
GL32.glBindTexture(GL32.GL_TEXTURE_2D, MC_RENDER.getDepthTextureId());
ScreenQuad.INSTANCE.render();
state.restore();
}
}
@@ -0,0 +1,110 @@
/*
* 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.ScreenQuad;
import com.seibel.distanthorizons.core.util.LodUtil;
import com.seibel.distanthorizons.core.util.RenderUtil;
import org.lwjgl.opengl.GL32;
public class SSAOApplyShader extends AbstractShaderRenderer
{
public static SSAOApplyShader INSTANCE = new SSAOApplyShader();
public int BufferTexture;
// uniforms
public int gSSAOMapUniform;
public int gDepthMapUniform;
public int gViewSizeUniform;
public int gBlurRadiusUniform;
public int gNearUniform;
public int gFarUniform;
@Override
public void onInit()
{
this.shader = new ShaderProgram(
"shaders/normal.vert",
"shaders/ssao/apply.frag",
"fragColor",
new String[]{"vPosition"});
// uniform setup
this.gSSAOMapUniform = this.shader.getUniformLocation("gSSAOMap");
this.gDepthMapUniform = this.shader.getUniformLocation("gDepthMap");
this.gViewSizeUniform = this.shader.tryGetUniformLocation("gViewSize");
this.gBlurRadiusUniform = this.shader.tryGetUniformLocation("gBlurRadius");
this.gNearUniform = this.shader.tryGetUniformLocation("gNear");
this.gFarUniform = this.shader.tryGetUniformLocation("gFar");
}
@Override
protected void onApplyUniforms(float partialTicks)
{
GL32.glActiveTexture(GL32.GL_TEXTURE0);
GL32.glBindTexture(GL32.GL_TEXTURE_2D, MC_RENDER.getDepthTextureId());
GL32.glUniform1i(this.gDepthMapUniform, 0);
GL32.glActiveTexture(GL32.GL_TEXTURE1);
GL32.glBindTexture(GL32.GL_TEXTURE_2D, this.BufferTexture);
GL32.glUniform1i(this.gSSAOMapUniform, 1);
GL32.glUniform1i(this.gBlurRadiusUniform,
Config.Client.Advanced.Graphics.Ssao.blurRadius.get());
if (this.gViewSizeUniform >= 0)
{
GL32.glUniform2f(this.gViewSizeUniform,
MC_RENDER.getTargetFrameBufferViewportWidth(),
MC_RENDER.getTargetFrameBufferViewportHeight());
}
if (this.gNearUniform >= 0)
{
GL32.glUniform1f(this.gNearUniform,
RenderUtil.getNearClipPlaneDistanceInBlocks(partialTicks));
}
if (this.gFarUniform >= 0)
{
float far = (float) ((RenderUtil.getFarClipPlaneDistanceInBlocks() + LodUtil.REGION_WIDTH) * Math.sqrt(2));
GL32.glUniform1f(this.gFarUniform, far);
}
}
//========//
// render //
//========//
@Override
protected void onRender()
{
GL32.glEnable(GL32.GL_BLEND);
GL32.glBlendEquation(GL32.GL_FUNC_ADD);
GL32.glBlendFuncSeparate(GL32.GL_ZERO, GL32.GL_SRC_ALPHA, GL32.GL_ZERO, GL32.GL_ONE);
ScreenQuad.INSTANCE.render();
}
}
@@ -1,277 +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 <https://www.gnu.org/licenses/>.
*/
package com.seibel.distanthorizons.core.render.renderer.shaders;
import com.seibel.distanthorizons.api.enums.config.EGpuUploadMethod;
import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.render.glObject.GLState;
import com.seibel.distanthorizons.core.render.glObject.buffer.GLVertexBuffer;
import com.seibel.distanthorizons.core.render.glObject.shader.ShaderProgram;
import com.seibel.distanthorizons.core.render.glObject.vertexAttribute.VertexAttribute;
import com.seibel.distanthorizons.core.util.LodUtil;
import com.seibel.distanthorizons.core.util.RenderUtil;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
import com.seibel.distanthorizons.coreapi.util.math.Mat4f;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL32;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
public class SSAORenderer
{
public static SSAORenderer INSTANCE = new SSAORenderer();
private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class);
private static final float[] box_vertices = {
-1, -1,
1, -1,
1, 1,
-1, -1,
1, 1,
-1, 1,
};
private ShaderProgram ssaoShader;
private ShaderProgram applyShader;
private GLVertexBuffer boxBuffer;
private VertexAttribute va;
private boolean init = false;
private int width = -1;
private int height = -1;
private int ssaoFramebuffer = -1;
private int ssaoTexture = -1;
// ssao uniforms
private final SsaoShaderUniforms ssaoShaderUniforms = new SsaoShaderUniforms();
private static class SsaoShaderUniforms
{
public int gProjUniform;
public int gInvProjUniform;
public int gSampleCountUniform;
public int gRadiusUniform;
public int gStrengthUniform;
public int gMinLightUniform;
public int gBiasUniform;
public int gDepthMapUniform;
}
// apply uniforms
private final ApplyShaderUniforms applyShaderUniforms = new ApplyShaderUniforms();
private static class ApplyShaderUniforms
{
public int gSSAOMapUniform;
public int gDepthMapUniform;
public int gViewSizeUniform;
public int gBlurRadiusUniform;
public int gNearUniform;
public int gFarUniform;
}
//=============//
// constructor //
//=============//
private SSAORenderer() { }
public void init()
{
if (this.init) return;
this.init = true;
this.va = VertexAttribute.create();
this.va.bind();
// Pos
this.va.setVertexAttribute(0, 0, VertexAttribute.VertexPointer.addVec2Pointer(false));
this.va.completeAndCheck(Float.BYTES * 2);
this.ssaoShader = new ShaderProgram("shaders/normal.vert", "shaders/ssao/ao.frag",
"fragColor", new String[]{"vPosition"});
this.applyShader = new ShaderProgram("shaders/normal.vert", "shaders/ssao/apply.frag",
"fragColor", new String[]{"vPosition"});
// SSAO uniform setup
this.ssaoShaderUniforms.gProjUniform = this.ssaoShader.getUniformLocation("gProj");
this.ssaoShaderUniforms.gInvProjUniform = this.ssaoShader.getUniformLocation("gInvProj");
this.ssaoShaderUniforms.gSampleCountUniform = this.ssaoShader.getUniformLocation("gSampleCount");
this.ssaoShaderUniforms.gRadiusUniform = this.ssaoShader.getUniformLocation("gRadius");
this.ssaoShaderUniforms.gStrengthUniform = this.ssaoShader.getUniformLocation("gStrength");
this.ssaoShaderUniforms.gMinLightUniform = this.ssaoShader.getUniformLocation("gMinLight");
this.ssaoShaderUniforms.gBiasUniform = this.ssaoShader.getUniformLocation("gBias");
this.ssaoShaderUniforms.gDepthMapUniform = this.ssaoShader.getUniformLocation("gDepthMap");
// Apply uniform setup
this.applyShaderUniforms.gSSAOMapUniform = this.applyShader.getUniformLocation("gSSAOMap");
this.applyShaderUniforms.gDepthMapUniform = this.applyShader.getUniformLocation("gDepthMap");
this.applyShaderUniforms.gViewSizeUniform = this.applyShader.tryGetUniformLocation("gViewSize");
this.applyShaderUniforms.gBlurRadiusUniform = this.applyShader.tryGetUniformLocation("gBlurRadius");
this.applyShaderUniforms.gNearUniform = this.applyShader.tryGetUniformLocation("gNear");
this.applyShaderUniforms.gFarUniform = this.applyShader.tryGetUniformLocation("gFar");
// Framebuffer
this.createBuffer();
}
private void createFramebuffer(int width, int height)
{
if (this.ssaoFramebuffer != -1)
{
GL32.glDeleteFramebuffers(this.ssaoFramebuffer);
this.ssaoFramebuffer = -1;
}
if (this.ssaoTexture != -1)
{
GL32.glDeleteTextures(this.ssaoTexture);
this.ssaoTexture = -1;
}
this.ssaoFramebuffer = GL32.glGenFramebuffers();
GL32.glBindFramebuffer(GL32.GL_FRAMEBUFFER, this.ssaoFramebuffer);
this.ssaoTexture = GL32.glGenTextures();
GL32.glBindTexture(GL32.GL_TEXTURE_2D, this.ssaoTexture);
GL32.glTexImage2D(GL32.GL_TEXTURE_2D, 0, GL32.GL_R16F, width, height, 0, GL32.GL_RED, GL32.GL_HALF_FLOAT, (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.ssaoTexture, 0);
}
private void createBuffer()
{
ByteBuffer buffer = ByteBuffer.allocateDirect(box_vertices.length * Float.BYTES);
buffer.order(ByteOrder.nativeOrder());
buffer.asFloatBuffer().put(box_vertices);
buffer.rewind();
this.boxBuffer = new GLVertexBuffer(false);
this.boxBuffer.bind();
this.boxBuffer.uploadBuffer(buffer, box_vertices.length, EGpuUploadMethod.DATA, box_vertices.length * Float.BYTES);
}
//========//
// render //
//========//
public void render(GLState primaryState, float partialTicks)
{
GLState state = new GLState();
this.init();
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);
}
GL32.glBindFramebuffer(GL32.GL_FRAMEBUFFER, this.ssaoFramebuffer);
GL32.glViewport(0, 0, width, height);
GL32.glDisable(GL32.GL_SCISSOR_TEST);
GL32.glDisable(GL32.GL_DEPTH_TEST);
GL32.glDisable(GL11.GL_BLEND);
float near = RenderUtil.getNearClipPlaneDistanceInBlocks(partialTicks);
float far = (float) ((RenderUtil.getFarClipPlaneDistanceInBlocks() + LodUtil.REGION_WIDTH) * Math.sqrt(2));
Mat4f perspective = Mat4f.perspective(
(float) MC_RENDER.getFov(partialTicks),
width / (float) height,
near, far);
Mat4f invertedPerspective = new Mat4f(perspective);
invertedPerspective.invert();
int sampleCount = Config.Client.Advanced.Graphics.Ssao.sampleCount.get();
int blurRadius = Config.Client.Advanced.Graphics.Ssao.blurRadius.get();
float radius = Config.Client.Advanced.Graphics.Ssao.radius.get().floatValue();
float strength = Config.Client.Advanced.Graphics.Ssao.strength.get().floatValue();
float minLight = Config.Client.Advanced.Graphics.Ssao.minLight.get().floatValue();
float bias = Config.Client.Advanced.Graphics.Ssao.bias.get().floatValue();
this.ssaoShader.bind();
this.ssaoShader.setUniform(this.ssaoShaderUniforms.gProjUniform, perspective);
this.ssaoShader.setUniform(this.ssaoShaderUniforms.gInvProjUniform, invertedPerspective);
this.ssaoShader.setUniform(this.ssaoShaderUniforms.gSampleCountUniform, sampleCount);
this.ssaoShader.setUniform(this.ssaoShaderUniforms.gRadiusUniform, radius);
this.ssaoShader.setUniform(this.ssaoShaderUniforms.gStrengthUniform, strength);
this.ssaoShader.setUniform(this.ssaoShaderUniforms.gMinLightUniform, minLight);
this.ssaoShader.setUniform(this.ssaoShaderUniforms.gBiasUniform, bias);
this.va.bind();
this.va.bindBufferToAllBindingPoint(this.boxBuffer.getId());
GL32.glActiveTexture(GL32.GL_TEXTURE0);
GL32.glBindTexture(GL32.GL_TEXTURE_2D, MC_RENDER.getDepthTextureId());
GL32.glUniform1i(this.ssaoShaderUniforms.gDepthMapUniform, 0);
GL32.glDrawArrays(GL32.GL_TRIANGLES, 0, 6);
this.applyShader.bind();
primaryState.RestoreFrameBuffer();
GL32.glEnable(GL11.GL_BLEND);
GL32.glBlendEquation(GL32.GL_FUNC_ADD);
GL32.glBlendFuncSeparate(GL32.GL_ZERO, GL32.GL_SRC_ALPHA, GL32.GL_ZERO, GL32.GL_ONE);
GL32.glActiveTexture(GL32.GL_TEXTURE0);
GL32.glBindTexture(GL32.GL_TEXTURE_2D, MC_RENDER.getDepthTextureId());
GL32.glUniform1i(this.applyShaderUniforms.gDepthMapUniform, 0);
GL32.glActiveTexture(GL32.GL_TEXTURE1);
GL32.glBindTexture(GL32.GL_TEXTURE_2D, this.ssaoTexture);
GL32.glUniform1i(this.applyShaderUniforms.gSSAOMapUniform, 1);
GL32.glUniform1i(this.applyShaderUniforms.gBlurRadiusUniform, blurRadius);
if (this.applyShaderUniforms.gViewSizeUniform >= 0)
GL32.glUniform2f(this.applyShaderUniforms.gViewSizeUniform, width, height);
if (this.applyShaderUniforms.gNearUniform >= 0)
GL32.glUniform1f(this.applyShaderUniforms.gNearUniform, near);
if (this.applyShaderUniforms.gFarUniform >= 0)
GL32.glUniform1f(this.applyShaderUniforms.gFarUniform, far);
GL32.glDrawArrays(GL32.GL_TRIANGLES, 0, 6);
state.restore();
}
public void free()
{
this.ssaoShader.free();
this.applyShader.free();
}
}
@@ -0,0 +1,116 @@
/*
* 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.ScreenQuad;
import com.seibel.distanthorizons.coreapi.util.math.Mat4f;
import org.lwjgl.opengl.GL32;
public class SSAOShader extends AbstractShaderRenderer
{
public static SSAOShader INSTANCE = new SSAOShader();
public int FrameBuffer;
private Mat4f perspective;
private Mat4f invertedPerspective;
// uniforms
public int gProjUniform;
public int gInvProjUniform;
public int gSampleCountUniform;
public int gRadiusUniform;
public int gStrengthUniform;
public int gMinLightUniform;
public int gBiasUniform;
public int gDepthMapUniform;
@Override
public void onInit()
{
this.shader = new ShaderProgram("shaders/normal.vert", "shaders/ssao/ao.frag",
"fragColor", new String[]{"vPosition"});
// uniform setup
this.gProjUniform = this.shader.getUniformLocation("gProj");
this.gInvProjUniform = this.shader.getUniformLocation("gInvProj");
this.gSampleCountUniform = this.shader.getUniformLocation("gSampleCount");
this.gRadiusUniform = this.shader.getUniformLocation("gRadius");
this.gStrengthUniform = this.shader.getUniformLocation("gStrength");
this.gMinLightUniform = this.shader.getUniformLocation("gMinLight");
this.gBiasUniform = this.shader.getUniformLocation("gBias");
this.gDepthMapUniform = this.shader.getUniformLocation("gDepthMap");
}
public void setProjectionMatrix(Mat4f perspective)
{
this.perspective = perspective;
this.invertedPerspective = new Mat4f(perspective);
this.invertedPerspective.invert();
}
@Override
protected void onApplyUniforms(float partialTicks)
{
this.shader.setUniform(this.gProjUniform, this.perspective);
this.shader.setUniform(this.gInvProjUniform, this.invertedPerspective);
this.shader.setUniform(this.gSampleCountUniform,
Config.Client.Advanced.Graphics.Ssao.sampleCount.get());
this.shader.setUniform(this.gRadiusUniform,
Config.Client.Advanced.Graphics.Ssao.radius.get().floatValue());
this.shader.setUniform(this.gStrengthUniform,
Config.Client.Advanced.Graphics.Ssao.strength.get().floatValue());
this.shader.setUniform(this.gMinLightUniform,
Config.Client.Advanced.Graphics.Ssao.minLight.get().floatValue());
this.shader.setUniform(this.gBiasUniform,
Config.Client.Advanced.Graphics.Ssao.bias.get().floatValue());
GL32.glActiveTexture(GL32.GL_TEXTURE0);
GL32.glBindTexture(GL32.GL_TEXTURE_2D, MC_RENDER.getDepthTextureId());
GL32.glUniform1i(this.gDepthMapUniform, 0);
}
//========//
// render //
//========//
@Override
protected void onRender()
{
GL32.glBindFramebuffer(GL32.GL_FRAMEBUFFER, this.FrameBuffer);
GL32.glDisable(GL32.GL_SCISSOR_TEST);
GL32.glDisable(GL32.GL_DEPTH_TEST);
GL32.glDisable(GL32.GL_BLEND);
ScreenQuad.INSTANCE.render();
}
}
@@ -19,7 +19,7 @@
package com.seibel.distanthorizons.core.render.vertexFormat;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL32;
/**
* This object is used to build LodVertexFormats.
@@ -80,13 +80,13 @@ public class LodVertexFormatElement
public enum DataType
{
FLOAT(4, "Float", GL11.GL_FLOAT),
UBYTE(1, "Unsigned Byte", GL11.GL_UNSIGNED_BYTE),
BYTE(1, "Byte", GL11.GL_BYTE),
USHORT(2, "Unsigned Short", GL11.GL_UNSIGNED_SHORT),
SHORT(2, "Short", GL11.GL_SHORT),
UINT(4, "Unsigned Int", GL11.GL_UNSIGNED_INT),
INT(4, "Int", GL11.GL_INT);
FLOAT(4, "Float", GL32.GL_FLOAT),
UBYTE(1, "Unsigned Byte", GL32.GL_UNSIGNED_BYTE),
BYTE(1, "Byte", GL32.GL_BYTE),
USHORT(2, "Unsigned Short", GL32.GL_UNSIGNED_SHORT),
SHORT(2, "Short", GL32.GL_SHORT),
UINT(4, "Unsigned Int", GL32.GL_UNSIGNED_INT),
INT(4, "Int", GL32.GL_INT);
private final int size;
private final String name;