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 new file mode 100644 index 000000000..a3e9f2c09 --- /dev/null +++ b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/SSAORenderer.java @@ -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 . + */ + +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); + } + + ScreenQuad.INSTANCE.bind(); + + SSAOShader.INSTANCE.render(partialTicks, ssaoFramebuffer); + + primaryState.RestoreFrameBuffer(); + + SSAOApplyShader.INSTANCE.render(partialTicks, ssaoTexture); + + state.restore(); + } + + public void free() + { + SSAOShader.INSTANCE.free(); + SSAOApplyShader.INSTANCE.free(); + } +} diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/ScreenQuad.java b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/ScreenQuad.java new file mode 100644 index 000000000..774a3a289 --- /dev/null +++ b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/ScreenQuad.java @@ -0,0 +1,94 @@ +/* + * 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.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 bind() + { + this.init(); + + this.va.bind(); + this.va.bindBufferToAllBindingPoint(this.boxBuffer.getId()); + } + + public void render() + { + 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); + } +} diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/shaders/AbstractShaderRenderer.java b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/shaders/AbstractShaderRenderer.java index 9dc1006a5..3f9155c1d 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/shaders/AbstractShaderRenderer.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/shaders/AbstractShaderRenderer.java @@ -19,116 +19,26 @@ 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; + protected ShaderProgram shader; + boolean init = false; - protected AbstractShaderRenderer(ShaderProgram shader) - { - this.shader = shader; - } + protected AbstractShaderRenderer() {} - private void init() + public 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(); - - 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); - - 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); } public void free() diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/shaders/DarkShader.java b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/shaders/DarkShader.java index b0eab9b78..1028942ea 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/shaders/DarkShader.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/shaders/DarkShader.java @@ -19,15 +19,57 @@ 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 init() { - super(new ShaderProgram("shaders/normal.vert", "shaders/test/dark.frag", "fragColor", new String[]{"vPosition", "color"})); + super.init(); + + this.shader = new ShaderProgram( + "shaders/normal.vert", + "shaders/test/dark.frag", + "fragColor", + new String[]{"vPosition", "color"}); } + void setShaderUniforms() + { + GL32.glActiveTexture(GL32.GL_TEXTURE0); + GL32.glBindTexture(GL32.GL_TEXTURE_2D, MC_RENDER.getDepthTextureId()); + } + + public void render() + { + GLState state = new GLState(); + + this.init(); + + 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(); + + ScreenQuad.INSTANCE.bind(); + + GL32.glEnable(GL32.GL_BLEND); + GL32.glBlendFunc(GL32.GL_SRC_ALPHA, GL32.GL_ONE_MINUS_SRC_ALPHA); + ScreenQuad.INSTANCE.render(); + + state.restore(); + } } 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 efbc1f368..7349271d8 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 @@ -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,6 +39,8 @@ 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); @@ -51,15 +56,14 @@ public class FogShader extends AbstractShaderRenderer public final int fullFogModeUniform; - public FogShader(LodFogConfig fogConfig) { - super(new ShaderProgram( + 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(), "fragColor", new String[]{"vPosition"} - )); + ); // all uniforms should be tryGet... // because disabling fog can cause the GLSL to optimize out most (if not all) uniforms @@ -78,7 +82,7 @@ public class FogShader extends AbstractShaderRenderer this.nearFogLengthUniform = this.shader.tryGetUniformLocation("nearFogLength"); } - @Override + //@Override void setShaderUniforms(float partialTicks) { this.shader.bind(); @@ -135,4 +139,32 @@ public class FogShader extends AbstractShaderRenderer this.shader.unbind(); } -} + + public void render(float partialTicks) + { + GLState state = new GLState(); + + this.init(); + + 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); + + ScreenQuad.INSTANCE.bind(); + + GL32.glActiveTexture(GL32.GL_TEXTURE0); + GL32.glBindTexture(GL32.GL_TEXTURE_2D, MC_RENDER.getDepthTextureId()); + + GL32.glEnable(GL32.GL_BLEND); + GL32.glBlendFunc(GL32.GL_SRC_ALPHA, GL32.GL_ONE_MINUS_SRC_ALPHA); + 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 new file mode 100644 index 000000000..fb85a4bb5 --- /dev/null +++ b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/shaders/SSAOApplyShader.java @@ -0,0 +1,119 @@ +/* + * 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.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(); + + + // 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; + } + + + @Override + public void init() + { + super.init(); + + this.shader = new ShaderProgram( + "shaders/normal.vert", + "shaders/ssao/apply.frag", + "fragColor", + new String[]{"vPosition"}); + + // uniform setup + this.applyShaderUniforms.gSSAOMapUniform = this.shader.getUniformLocation("gSSAOMap"); + this.applyShaderUniforms.gDepthMapUniform = this.shader.getUniformLocation("gDepthMap"); + this.applyShaderUniforms.gViewSizeUniform = this.shader.tryGetUniformLocation("gViewSize"); + this.applyShaderUniforms.gBlurRadiusUniform = this.shader.tryGetUniformLocation("gBlurRadius"); + this.applyShaderUniforms.gNearUniform = this.shader.tryGetUniformLocation("gNear"); + this.applyShaderUniforms.gFarUniform = this.shader.tryGetUniformLocation("gFar"); + } + + private void setShaderUniforms(float partialTicks, int ssaoTexture) + { + 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, ssaoTexture); + GL32.glUniform1i(this.applyShaderUniforms.gSSAOMapUniform, 1); + + int blurRadius = Config.Client.Advanced.Graphics.Ssao.blurRadius.get(); + GL32.glUniform1i(this.applyShaderUniforms.gBlurRadiusUniform, blurRadius); + + if (this.applyShaderUniforms.gViewSizeUniform >= 0) + { + int width = MC_RENDER.getTargetFrameBufferViewportWidth(); + int height = MC_RENDER.getTargetFrameBufferViewportHeight(); + GL32.glUniform2f(this.applyShaderUniforms.gViewSizeUniform, width, height); + } + + if (this.applyShaderUniforms.gNearUniform >= 0) + { + float near = RenderUtil.getNearClipPlaneDistanceInBlocks(partialTicks); + GL32.glUniform1f(this.applyShaderUniforms.gNearUniform, near); + } + + if (this.applyShaderUniforms.gFarUniform >= 0) + { + float far = (float) ((RenderUtil.getFarClipPlaneDistanceInBlocks() + LodUtil.REGION_WIDTH) * Math.sqrt(2)); + GL32.glUniform1f(this.applyShaderUniforms.gFarUniform, far); + } + } + + //========// + // render // + //========// + + public void render(float partialTicks, int ssaoTexture) + { + this.init(); + + this.shader.bind(); + + setShaderUniforms(partialTicks, ssaoTexture); + + 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(); + } +} diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/shaders/SSAORenderer.java b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/shaders/SSAORenderer.java deleted file mode 100644 index c7eec888a..000000000 --- a/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/shaders/SSAORenderer.java +++ /dev/null @@ -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 . - */ - -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(); - } -} 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 new file mode 100644 index 000000000..9fe7e2fbe --- /dev/null +++ b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/shaders/SSAOShader.java @@ -0,0 +1,137 @@ +/* + * 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.ScreenQuad; +import com.seibel.distanthorizons.core.util.LodUtil; +import com.seibel.distanthorizons.core.util.RenderUtil; +import com.seibel.distanthorizons.coreapi.util.math.Mat4f; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL32; + +public class SSAOShader extends AbstractShaderRenderer +{ + public static SSAOShader INSTANCE = new SSAOShader(); + + + // 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; + } + + + @Override + public void init() + { + super.init(); + + this.shader = new ShaderProgram("shaders/normal.vert", "shaders/ssao/ao.frag", + "fragColor", new String[]{"vPosition"}); + + // uniform setup + this.ssaoShaderUniforms.gProjUniform = this.shader.getUniformLocation("gProj"); + this.ssaoShaderUniforms.gInvProjUniform = this.shader.getUniformLocation("gInvProj"); + this.ssaoShaderUniforms.gSampleCountUniform = this.shader.getUniformLocation("gSampleCount"); + this.ssaoShaderUniforms.gRadiusUniform = this.shader.getUniformLocation("gRadius"); + this.ssaoShaderUniforms.gStrengthUniform = this.shader.getUniformLocation("gStrength"); + this.ssaoShaderUniforms.gMinLightUniform = this.shader.getUniformLocation("gMinLight"); + this.ssaoShaderUniforms.gBiasUniform = this.shader.getUniformLocation("gBias"); + this.ssaoShaderUniforms.gDepthMapUniform = this.shader.getUniformLocation("gDepthMap"); + } + + void setShaderUniforms(float partialTicks) + { + int width = MC_RENDER.getTargetFrameBufferViewportWidth(); + int height = MC_RENDER.getTargetFrameBufferViewportHeight(); + 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(); + + this.shader.setUniform(this.ssaoShaderUniforms.gProjUniform, perspective); + + this.shader.setUniform(this.ssaoShaderUniforms.gInvProjUniform, invertedPerspective); + + this.shader.setUniform(this.ssaoShaderUniforms.gSampleCountUniform, + Config.Client.Advanced.Graphics.Ssao.sampleCount.get()); + + this.shader.setUniform(this.ssaoShaderUniforms.gRadiusUniform, + Config.Client.Advanced.Graphics.Ssao.radius.get().floatValue()); + + this.shader.setUniform(this.ssaoShaderUniforms.gStrengthUniform, + Config.Client.Advanced.Graphics.Ssao.strength.get().floatValue()); + + this.shader.setUniform(this.ssaoShaderUniforms.gMinLightUniform, + Config.Client.Advanced.Graphics.Ssao.minLight.get().floatValue()); + + this.shader.setUniform(this.ssaoShaderUniforms.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.ssaoShaderUniforms.gDepthMapUniform, 0); + } + + + //========// + // render // + //========// + + public void render(float partialTicks, int ssaoFramebuffer) + { + this.init(); + + int width = MC_RENDER.getTargetFrameBufferViewportWidth(); + int height = MC_RENDER.getTargetFrameBufferViewportHeight(); + + this.shader.bind(); + + setShaderUniforms(partialTicks); + + GL32.glBindFramebuffer(GL32.GL_FRAMEBUFFER, ssaoFramebuffer); + GL32.glViewport(0, 0, width, height); + GL32.glDisable(GL32.GL_SCISSOR_TEST); + GL32.glDisable(GL32.GL_DEPTH_TEST); + GL32.glDisable(GL11.GL_BLEND); + + ScreenQuad.INSTANCE.render(); + + shader.unbind(); + } +}