From e29974282e0101635e8e4f3de6310cc61e50ebed Mon Sep 17 00:00:00 2001 From: NULL511 Date: Fri, 1 Sep 2023 03:22:40 -0400 Subject: [PATCH 1/8] faster ssao --- .../render/renderer/shaders/SSAORenderer.java | 106 +++--------------- core/src/main/resources/shaders/ssao/ao.frag | 99 +++++++++------- .../resources/shaders/ssao/apply-frag.frag | 25 ----- 3 files changed, 73 insertions(+), 157 deletions(-) delete mode 100644 core/src/main/resources/shaders/ssao/apply-frag.frag 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 index bcddd4e1a..cd7ee6423 100644 --- 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 @@ -22,7 +22,7 @@ public class SSAORenderer private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class); - private static final int MAX_KERNEL_SIZE = 128; + private static final int MAX_KERNEL_SIZE = 32; private static final float[] box_vertices = { -1, -1, 1, -1, @@ -33,21 +33,14 @@ public class SSAORenderer }; - private ShaderProgram ssaoShader; - private ShaderProgram applyShader; + private GLVertexBuffer boxBuffer; private VertexAttribute va; private boolean init = false; private float[] kernel = new float[MAX_KERNEL_SIZE * 3]; - 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 @@ -61,15 +54,6 @@ public class SSAORenderer public int gDepthMapUniform; } - // apply uniforms - private final ApplyShaderUniforms applyShaderUniforms = new ApplyShaderUniforms(); - private static class ApplyShaderUniforms - { - public int gSSAOMapUniform; - public int gDepthMapUniform; - } - - //=============// // constructor // @@ -79,26 +63,19 @@ public class SSAORenderer public void init() { - if (this.init) - { - return; - } - - + 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.frag", - "fragColor", new String[]{"vPosition"}); - - - // SSAO uniform setup this.ssaoShaderUniforms.gProjUniform = this.ssaoShader.getUniformLocation("gProj"); this.ssaoShaderUniforms.gInvProjUniform = this.ssaoShader.getUniformLocation("gInvProj"); @@ -108,43 +85,12 @@ public class SSAORenderer this.ssaoShaderUniforms.gKernelUniform = this.ssaoShader.getUniformLocation("gKernel"); this.ssaoShaderUniforms.gDepthMapUniform = this.ssaoShader.getUniformLocation("gDepthMap"); - // Apply uniform setup - this.applyShaderUniforms.gSSAOMapUniform = this.applyShader.getUniformLocation("gSSAOMap"); - this.applyShaderUniforms.gDepthMapUniform = this.applyShader.getUniformLocation("gDepthMap"); - - - // Generate kernel this.kernel = genKernel(); // 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_RED, width, height, 0, GL32.GL_RED, GL32.GL_FLOAT, (ByteBuffer) null); - GL32.glTexParameteri(GL32.GL_TEXTURE_2D, GL32.GL_TEXTURE_MIN_FILTER, GL32.GL_NEAREST); - GL32.glTexParameteri(GL32.GL_TEXTURE_2D, GL32.GL_TEXTURE_MAG_FILTER, GL32.GL_NEAREST); - 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); @@ -194,24 +140,20 @@ public class SSAORenderer public void render(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_DEPTH_TEST); - GL32.glDisable(GL32.GL_BLEND); + 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.glBindFramebuffer(GL32.GL_FRAMEBUFFER, MC_RENDER.getTargetFrameBuffer()); GL32.glDisable(GL32.GL_SCISSOR_TEST); - Mat4f perspective = Mat4f.perspective( (float) MC_RENDER.getFov(partialTicks), MC_RENDER.getTargetFrameBufferViewportWidth() / (float) MC_RENDER.getTargetFrameBufferViewportHeight(), @@ -221,13 +163,12 @@ public class SSAORenderer Mat4f invertedPerspective = new Mat4f(perspective); invertedPerspective.invert(); - this.ssaoShader.bind(); this.ssaoShader.setUniform(this.ssaoShaderUniforms.gProjUniform, perspective); this.ssaoShader.setUniform(this.ssaoShaderUniforms.gInvProjUniform, invertedPerspective); this.ssaoShader.setUniform(this.ssaoShaderUniforms.gSampleRadUniform, 3.0f); - this.ssaoShader.setUniform(this.ssaoShaderUniforms.gFactorUniform, 0.8f); - this.ssaoShader.setUniform(this.ssaoShaderUniforms.gPowerUniform, 1.0f); + this.ssaoShader.setUniform(this.ssaoShaderUniforms.gFactorUniform, 0.7f); + this.ssaoShader.setUniform(this.ssaoShaderUniforms.gPowerUniform, 1.5f); this.va.bind(); this.va.bindBufferToAllBindingPoint(this.boxBuffer.getId()); @@ -240,30 +181,11 @@ public class SSAORenderer GL32.glDrawArrays(GL32.GL_TRIANGLES, 0, 6); - - this.applyShader.bind(); - - GL32.glEnable(GL11.GL_BLEND); - GL32.glBlendFunc(GL32.GL_SRC_ALPHA, GL32.GL_ONE_MINUS_SRC_ALPHA); - GL32.glBindFramebuffer(GL32.GL_FRAMEBUFFER, MC_RENDER.getTargetFrameBuffer()); - - GL32.glActiveTexture(GL32.GL_TEXTURE0); - GL32.glBindTexture(GL32.GL_TEXTURE_2D, this.ssaoTexture); - GL32.glUniform1i(this.applyShaderUniforms.gSSAOMapUniform, 0); - GL32.glActiveTexture(GL32.GL_TEXTURE1); - GL32.glBindTexture(GL32.GL_TEXTURE_2D, MC_RENDER.getDepthTextureId()); - GL32.glUniform1i(this.applyShaderUniforms.gDepthMapUniform, 1); - - GL32.glDrawArrays(GL32.GL_TRIANGLES, 0, 6); - - state.restore(); } public void free() { this.ssaoShader.free(); - this.applyShader.free(); } - } diff --git a/core/src/main/resources/shaders/ssao/ao.frag b/core/src/main/resources/shaders/ssao/ao.frag index fc48bcc05..32124d957 100644 --- a/core/src/main/resources/shaders/ssao/ao.frag +++ b/core/src/main/resources/shaders/ssao/ao.frag @@ -1,4 +1,5 @@ #version 150 core +#extension GL_ARB_derivative_control : enable in vec2 TexCoord; @@ -11,55 +12,73 @@ uniform float gPower; uniform mat4 gProj; uniform mat4 gInvProj; -const int MAX_KERNEL_SIZE = 128; +const float SAMPLE_BIAS = 0.1; +const int MAX_KERNEL_SIZE = 32; const float INV_MAX_KERNEL_SIZE_F = 1.0 / float(MAX_KERNEL_SIZE); -const vec2 HALF_2 = vec2(0.5); uniform vec3 gKernel[MAX_KERNEL_SIZE]; -vec3 calcViewPosition(vec2 coords) { - float fragmentDepth = texture(gDepthMap, coords).r; +const vec3 MAGIC = vec3(0.06711056, 0.00583715, 52.9829189); +const float PI = 3.1415926538; - vec4 ndc = vec4( - coords.x * 2.0 - 1.0, - coords.y * 2.0 - 1.0, - fragmentDepth * 2.0 - 1.0, - 1.0 - ); - vec4 vs_pos = gInvProj * ndc; - vs_pos.xyz = vs_pos.xyz / vs_pos.w; - return vs_pos.xyz; +float InterleavedGradientNoise(const in vec2 pixel) { + float x = dot(pixel, MAGIC.xy); + return fract(MAGIC.z * fract(x)); } -void main() -{ - vec3 viewPos = calcViewPosition(TexCoord); - vec3 viewNormal = normalize(cross(dFdy(viewPos.xyz), dFdx(viewPos.xyz)) * -1.0); +vec3 calcViewPosition(const in vec3 clipPos) { + vec4 viewPos = gInvProj * vec4(clipPos * 2.0 - 1.0, 1.0); + return viewPos.xyz / viewPos.w; +} - vec3 randomVec = vec3(0.0, -1.0, 0.0); +void main() { + float fragmentDepth = textureLod(gDepthMap, TexCoord, 0).r; + float occlusion = 1.0; + + if (fragmentDepth < 1.0) { + float dither = InterleavedGradientNoise(gl_FragCoord.xy); + vec3 viewPos = calcViewPosition(vec3(TexCoord, fragmentDepth)); + + #ifdef GL_ARB_derivative_control + vec3 viewNormal = normalize(cross(dFdxFine(viewPos.xyz), dFdyFine(viewPos.xyz))); + #else + vec3 viewNormal = normalize(cross(dFdx(viewPos.xyz), dFdy(viewPos.xyz))); + #endif - vec3 tangent = normalize(randomVec - viewNormal * dot(randomVec, viewNormal)); - vec3 bitangent = cross(viewNormal, tangent); - mat3 TBN = mat3(tangent, bitangent, viewNormal); + const vec3 upVec = vec3(0.0, -1.0, 0.0); - float occlusion_factor = 0.0; - for (int i = 0; i < MAX_KERNEL_SIZE; i++) - { - vec3 samplePos = vec3(0.0) + (TBN * gKernel[i]); - samplePos = viewPos + samplePos * gSampleRad; - - vec4 offset = gProj * vec4(samplePos + viewPos, 1.0); - offset.xy /= offset.w; - offset.xy = offset.xy * HALF_2 + HALF_2; - - float geometryDepth = calcViewPosition(offset.xy).z; - - float rangeCheck = smoothstep(0.0, 1.0, gSampleRad / abs(viewPos.z - geometryDepth)); - // the number added to the samplePos.z can be used to reduce noise in the SSAO application at the cost of reducing the overall affect - occlusion_factor += float(geometryDepth >= samplePos.z + 0.1) * rangeCheck; + float angle = dither * (PI * 2.0); + vec3 rotation = vec3(sin(angle), cos(angle), 0.0); + vec3 tangent = normalize(cross(viewNormal, rotation)); + vec3 bitangent = normalize(cross(viewNormal, tangent)); + mat3 TBN = mat3(tangent, bitangent, viewNormal); + + float maxWeight = 0.0; + float occlusion_factor = 0.0; + for (int i = 0; i < MAX_KERNEL_SIZE; i++) { + vec3 samplePos = TBN * gKernel[i]; + samplePos = viewPos + samplePos * gSampleRad; + + vec4 sampleNdcPos = gProj * vec4(samplePos + viewPos, 1.0); + sampleNdcPos = sampleNdcPos / sampleNdcPos.w; + if (any(greaterThanEqual(abs(sampleNdcPos.xy), vec2(1.0)))) continue; + + maxWeight += 1.0; + + vec2 sampleTexPos = sampleNdcPos.xy * 0.5 + 0.5; + float sampleDepth = textureLod(gDepthMap, sampleTexPos, 0).r; + float geometryDepth = calcViewPosition(vec3(sampleTexPos, sampleDepth)).z; + + float rangeCheck = smoothstep(0.0, 1.0, gSampleRad / abs(viewPos.z - geometryDepth)); + // the number added to the samplePos.z can be used to reduce noise in the SSAO application at the cost of reducing the overall affect + occlusion_factor += step(samplePos.z + SAMPLE_BIAS, geometryDepth) * rangeCheck; + } + + float visibility_factor = 1.0 - (occlusion_factor / maxWeight); + occlusion = (1.0 - pow(visibility_factor, gFactor)) * gPower; + occlusion = clamp(1.0 - occlusion, 0.25, 1.0); } - - float visibility_factor = 1.0 - (occlusion_factor / MAX_KERNEL_SIZE); - fragColor = vec4(clamp(1.0 - ((1.0 - pow(visibility_factor, gFactor)) * gPower), 0.1, 1.0)); -} \ No newline at end of file + + fragColor = vec4(vec3(1.0), occlusion); +} diff --git a/core/src/main/resources/shaders/ssao/apply-frag.frag b/core/src/main/resources/shaders/ssao/apply-frag.frag deleted file mode 100644 index 534306c50..000000000 --- a/core/src/main/resources/shaders/ssao/apply-frag.frag +++ /dev/null @@ -1,25 +0,0 @@ -#version 150 core - -in vec2 TexCoord; -in vec2 ViewRay; - -out vec4 fragColor; - -uniform sampler2D gSSAOMap; -uniform sampler2D gDepthMap; - -void main() -{ - float fragmentDepth = texture(gDepthMap, TexCoord).r; - // a fragment depth of "1" means the fragment wasn't drawn to, - // we only want to apply SSAO to LODs, not to the sky outside the LODs - if (fragmentDepth < 1) - { - fragColor = vec4(0.0, 0.0, 0.0, 1-texture(gSSAOMap, TexCoord).r); - } - else - { - // every pixel needs to be set to something, otherwise the pixel may be undefined by some drivers (specifically Intel) - fragColor = vec4(0.0, 0.0, 0.0, 0.0); - } -} From 88b02ef2f72dfd55ad300640be8c3ad9bdccb1aa Mon Sep 17 00:00:00 2001 From: NULL511 Date: Fri, 1 Sep 2023 12:11:26 -0400 Subject: [PATCH 2/8] revert ssao tuning --- .../core/render/renderer/shaders/SSAORenderer.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 index cd7ee6423..9d3321b2f 100644 --- 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 @@ -167,8 +167,8 @@ public class SSAORenderer this.ssaoShader.setUniform(this.ssaoShaderUniforms.gProjUniform, perspective); this.ssaoShader.setUniform(this.ssaoShaderUniforms.gInvProjUniform, invertedPerspective); this.ssaoShader.setUniform(this.ssaoShaderUniforms.gSampleRadUniform, 3.0f); - this.ssaoShader.setUniform(this.ssaoShaderUniforms.gFactorUniform, 0.7f); - this.ssaoShader.setUniform(this.ssaoShaderUniforms.gPowerUniform, 1.5f); + this.ssaoShader.setUniform(this.ssaoShaderUniforms.gFactorUniform, 0.8f); + this.ssaoShader.setUniform(this.ssaoShaderUniforms.gPowerUniform, 1.0f); this.va.bind(); this.va.bindBufferToAllBindingPoint(this.boxBuffer.getId()); From 3ee3b9c98cf29f74e2a918bfdbf9d8c32ef1f7c3 Mon Sep 17 00:00:00 2001 From: NULL511 Date: Fri, 1 Sep 2023 17:18:29 -0400 Subject: [PATCH 3/8] vanilla-matched ssao --- .../render/renderer/shaders/SSAORenderer.java | 6 +- .../main/resources/shaders/flat_shaded.frag | 106 ++++-------------- .../main/resources/shaders/noise/noise.frag | 8 -- core/src/main/resources/shaders/ssao/ao.frag | 13 ++- 4 files changed, 31 insertions(+), 102 deletions(-) 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 index 9d3321b2f..935112376 100644 --- 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 @@ -156,7 +156,7 @@ public class SSAORenderer Mat4f perspective = Mat4f.perspective( (float) MC_RENDER.getFov(partialTicks), - MC_RENDER.getTargetFrameBufferViewportWidth() / (float) MC_RENDER.getTargetFrameBufferViewportHeight(), + width / (float) height, RenderUtil.getNearClipPlaneDistanceInBlocks(partialTicks), (float) ((RenderUtil.getFarClipPlaneDistanceInBlocks() + LodUtil.REGION_WIDTH) * Math.sqrt(2))); @@ -167,8 +167,8 @@ public class SSAORenderer this.ssaoShader.setUniform(this.ssaoShaderUniforms.gProjUniform, perspective); this.ssaoShader.setUniform(this.ssaoShaderUniforms.gInvProjUniform, invertedPerspective); this.ssaoShader.setUniform(this.ssaoShaderUniforms.gSampleRadUniform, 3.0f); - this.ssaoShader.setUniform(this.ssaoShaderUniforms.gFactorUniform, 0.8f); - this.ssaoShader.setUniform(this.ssaoShaderUniforms.gPowerUniform, 1.0f); + this.ssaoShader.setUniform(this.ssaoShaderUniforms.gFactorUniform, 0.5f); + this.ssaoShader.setUniform(this.ssaoShaderUniforms.gPowerUniform, 6.0f); this.va.bind(); this.va.bindBufferToAllBindingPoint(this.boxBuffer.getId()); diff --git a/core/src/main/resources/shaders/flat_shaded.frag b/core/src/main/resources/shaders/flat_shaded.frag index 28109a009..edcddbcca 100644 --- a/core/src/main/resources/shaders/flat_shaded.frag +++ b/core/src/main/resources/shaders/flat_shaded.frag @@ -2,7 +2,7 @@ in vec4 vertexColor; in vec3 vertexWorldPos; -in float vertexYPos; +//in float vertexYPos; in vec4 vPos; out vec4 fragColor; @@ -15,50 +15,19 @@ uniform float noiseIntensity; uniform int noiseDropoff; -// method definitions - -float fade(float value, float start, float end) { - return (clamp(value, start, end) - start) / (end - start); -} - // The random functions for diffrent dimentions float rand(float co) { return fract(sin(co*(91.3458)) * 47453.5453); } -float rand(vec2 co){ return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453); } -float rand(vec3 co){ return rand(co.xy+rand(co.z)); } +float rand(vec2 co) { return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453); } +float rand(vec3 co) { return rand(co.xy + rand(co.z)); } // Puts steps in a float // EG. setting stepSize to 4 then this would be the result of this function // In: 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, ..., 1.1, 1.2, 1.3 // Out: 0.0, 0.0, 0.0, 0.25, 0.25, 0.5, 0.5, ..., 1.0, 1.0, 1.25 -float quantize(float val, int stepSize) { - return floor(val*stepSize)/stepSize; +vec3 quantize(vec3 val, int stepSize) { + return floor(val * stepSize) / stepSize; } -// The modulus function dosnt exist in GLSL so I made my own -// To speed up the mod function, this only accepts full numbers for y -float mod(float x, int y) { - return x - y * floor(x/y); -} - - -// Some HSV functions I stole somewhere online -vec3 RGB2HSV(vec3 c) { - vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0); - vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g)); - vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r)); - - float d = q.x - min(q.w, q.y); - float e = 1.0e-10; - return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x); -} - -vec3 HSV2RGB(vec3 c) { - vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); - vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www); - return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y); -} - - /** * Fragment Shader @@ -71,66 +40,31 @@ void main() { fragColor = vertexColor; - // TODO: Move into its own function instead of in an if statement if (noiseEnabled) { - vec3 vertexNormal = normalize(cross(dFdx(vPos.xyz), dFdy(vPos.xyz))); + vec3 vertexNormal = normalize(cross(dFdy(vPos.xyz), dFdx(vPos.xyz))); // This bit of code is required to fix the vertex position problem cus of floats in the verted world position varuable - vec3 fixedVPos = vPos.xyz - vertexNormal * 0.001; + vec3 fixedVPos = vPos.xyz + vertexNormal * 0.001; float noiseAmplification = noiseIntensity * 0.01; - noiseAmplification = (-1.0 * pow(2.0*((fragColor.x + fragColor.y + fragColor.z) / 3.0) - 1.0, 2.0) + 1.0) * noiseAmplification; // Lessen the effect on depending on how dark the object is, equasion for this is -(2x-1)^{2}+1 - noiseAmplification *= fragColor.w; // The effect would lessen on transparent objects + float lum = (fragColor.r + fragColor.g + fragColor.b) / 3.0; + noiseAmplification = (1.0 - pow(lum * 2.0 - 1.0, 2.0)) * noiseAmplification; // Lessen the effect on depending on how dark the object is, equasion for this is -(2x-1)^{2}+1 + noiseAmplification *= fragColor.a; // The effect would lessen on transparent objects // Random value for each position - float randomValue = rand(vec3( - quantize(fixedVPos.x, noiseSteps), - quantize(fixedVPos.y, noiseSteps), - quantize(fixedVPos.z, noiseSteps) - )) - * 2.0 * noiseAmplification - noiseAmplification; - - + float randomValue = rand(quantize(fixedVPos, noiseSteps)) + * 2.0 * noiseAmplification - noiseAmplification; + // Modifies the color // A value of 0 on the randomValue will result in the original color, while a value of 1 will result in a fully bright color vec3 newCol = fragColor.rgb + (1.0 - fragColor.rgb) * randomValue; + newCol = clamp(newCol, 0.0, 1.0); + + if (noiseDropoff != 0) { + float distF = min(length(vertexWorldPos) / noiseDropoff, 1.0); + newCol = mix(newCol, fragColor.rgb, distF); // The further away it gets, the less noise gets applied + } - // Clamps it and turns it back into a vec4 - if (noiseDropoff == 0) - fragColor = vec4(clamp(newCol.rgb, 0.0, 1.0), fragColor.w); - else - fragColor = mix( - vec4(clamp(newCol.rgb, 0.0, 1.0), fragColor.w), fragColor, - min(length(vertexWorldPos) / noiseDropoff, 1.0) // The further away it gets, the less noise gets applied - ); - - // For testing - // if (fragColor.r != 69420.) { - // fragColor = vec4( - // mod(fixedVPos.x, 1), - // mod(fixedVPos.y, 1), - // mod(fixedVPos.z, 1), - // fragColor.w); - // } + fragColor.rgb = newCol; } } - - - -// Are these still needed? -float linearFog(float x, float fogStart, float fogLength, float fogMin, float fogRange) { - x = clamp((x-fogStart)/fogLength, 0.0, 1.0); - return fogMin + fogRange * x; -} - -float exponentialFog(float x, float fogStart, float fogLength, -float fogMin, float fogRange, float fogDensity) { - x = max((x-fogStart)/fogLength, 0.0) * fogDensity; - return fogMin + fogRange - fogRange/exp(x); -} - -float exponentialSquaredFog(float x, float fogStart, float fogLength, -float fogMin, float fogRange, float fogDensity) { - x = max((x-fogStart)/fogLength, 0.0) * fogDensity; - return fogMin + fogRange - fogRange/exp(x*x); -} \ No newline at end of file diff --git a/core/src/main/resources/shaders/noise/noise.frag b/core/src/main/resources/shaders/noise/noise.frag index 9ae668cbe..1156311fc 100644 --- a/core/src/main/resources/shaders/noise/noise.frag +++ b/core/src/main/resources/shaders/noise/noise.frag @@ -30,14 +30,6 @@ vec3 quantize(vec3 val, int stepSize) { return floor(val*stepSize)/stepSize; } -// The modulus function dosnt exist in GLSL so I made my own -// To speed up the mod function, this only accepts full numbers for y -float mod(float x, int y) { - return x - y * floor(x/y); -} - - - /** * Fragment shader for adding noise to lods. diff --git a/core/src/main/resources/shaders/ssao/ao.frag b/core/src/main/resources/shaders/ssao/ao.frag index 32124d957..b23f6c901 100644 --- a/core/src/main/resources/shaders/ssao/ao.frag +++ b/core/src/main/resources/shaders/ssao/ao.frag @@ -12,7 +12,8 @@ uniform float gPower; uniform mat4 gProj; uniform mat4 gInvProj; -const float SAMPLE_BIAS = 0.1; +const float MIN_LIGHT = 0.6; +const float SAMPLE_BIAS = 0.5; const int MAX_KERNEL_SIZE = 32; const float INV_MAX_KERNEL_SIZE_F = 1.0 / float(MAX_KERNEL_SIZE); uniform vec3 gKernel[MAX_KERNEL_SIZE]; @@ -40,12 +41,13 @@ void main() { vec3 viewPos = calcViewPosition(vec3(TexCoord, fragmentDepth)); #ifdef GL_ARB_derivative_control - vec3 viewNormal = normalize(cross(dFdxFine(viewPos.xyz), dFdyFine(viewPos.xyz))); + vec3 viewNormal = cross(dFdxFine(viewPos.xyz), dFdyFine(viewPos.xyz)); #else - vec3 viewNormal = normalize(cross(dFdx(viewPos.xyz), dFdy(viewPos.xyz))); + vec3 viewNormal = cross(dFdx(viewPos.xyz), dFdy(viewPos.xyz)); #endif - const vec3 upVec = vec3(0.0, -1.0, 0.0); + viewNormal = normalize(viewNormal); + //const vec3 upVec = vec3(0.0, -1.0, 0.0); float angle = dither * (PI * 2.0); vec3 rotation = vec3(sin(angle), cos(angle), 0.0); @@ -58,6 +60,7 @@ void main() { float occlusion_factor = 0.0; for (int i = 0; i < MAX_KERNEL_SIZE; i++) { vec3 samplePos = TBN * gKernel[i]; + samplePos *= sign(dot(samplePos, viewNormal)); samplePos = viewPos + samplePos * gSampleRad; vec4 sampleNdcPos = gProj * vec4(samplePos + viewPos, 1.0); @@ -77,7 +80,7 @@ void main() { float visibility_factor = 1.0 - (occlusion_factor / maxWeight); occlusion = (1.0 - pow(visibility_factor, gFactor)) * gPower; - occlusion = clamp(1.0 - occlusion, 0.25, 1.0); + occlusion = clamp(1.0 - occlusion, MIN_LIGHT, 1.0); } fragColor = vec4(vec3(1.0), occlusion); From f692ddaf9365953bcbcece8d2ebfbd2517947057 Mon Sep 17 00:00:00 2001 From: NULL511 Date: Fri, 1 Sep 2023 17:56:59 -0400 Subject: [PATCH 4/8] dither fog --- core/src/main/resources/shaders/fog/fog.frag | 61 ++++++++------------ core/src/main/resources/shaders/ssao/ao.frag | 4 +- 2 files changed, 25 insertions(+), 40 deletions(-) diff --git a/core/src/main/resources/shaders/fog/fog.frag b/core/src/main/resources/shaders/fog/fog.frag index 8e9f0767a..04eb3f7c1 100644 --- a/core/src/main/resources/shaders/fog/fog.frag +++ b/core/src/main/resources/shaders/fog/fog.frag @@ -42,23 +42,14 @@ float mixFogThickness(float near, float far, float height); // ========================================================= -// Puts steps in a float -// EG. setting stepSize to 4 then this would be the result of this function -// In: 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, ..., 1.1, 1.2, 1.3 -// Out: 0.0, 0.0, 0.0, 0.25, 0.25, 0.5, 0.5, ..., 1.0, 1.0, 1.25 -float quantize(float val, int stepSize) { - return floor(val*stepSize)/stepSize; +const vec3 MAGIC = vec3(0.06711056, 0.00583715, 52.9829189); + +float InterleavedGradientNoise(const in vec2 pixel) { + float x = dot(pixel, MAGIC.xy); + return fract(MAGIC.z * fract(x)); } -// The modulus function dosnt exist in GLSL so I made my own -// To speed up the mod function, this only accepts full numbers for y -float mod(float x, int y) { - return x - y * floor(x/y); -} - - -vec3 calcViewPosition(float fragmentDepth) -{ +vec3 calcViewPosition(float fragmentDepth) { vec4 ndc = vec4(TexCoord.xy, fragmentDepth, 1.0); ndc.xyz = ndc.xyz * 2.0 - 1.0; @@ -76,13 +67,12 @@ void main() { float vertexYPos = 100.0f; float fragmentDepth = texture(gDepthMap, TexCoord).r; + fragColor = vec4(fogColor.rgb, 0.0); // a fragment depth of "1" means the fragment wasn't drawn to, // we only want to apply Fog to LODs, not to the sky outside the LODs - if (fragmentDepth < 1) - { - if (fullFogMode == 0) - { + if (fragmentDepth < 1.0) { + if (fullFogMode == 0) { // render fog based on distance from the camera vec3 vertexWorldPos = calcViewPosition(fragmentDepth); @@ -94,17 +84,16 @@ void main() float farFogThickness = getFarFogThickness(farDist); float heightFogThickness = getHeightFogThickness(heightDist); float mixedFogThickness = mixFogThickness(nearFogThickness, farFogThickness, heightFogThickness); - mixedFogThickness = clamp(mixedFogThickness, 0.0, 1.0); + fragColor.a = clamp(mixedFogThickness, 0.0, 1.0); - fragColor = vec4(fogColor.rgb, mixedFogThickness); + float dither = InterleavedGradientNoise(gl_FragCoord.xy) - 0.5; + fragColor.a += dither / 255.0; } - else if (fullFogMode == 1) - { + else if (fullFogMode == 1) { // render everything with the fog color - fragColor = vec4(fogColor.rgb, 1.0); + fragColor.a = 1.0; } - else - { + else { // test code. // this can be fired by manually changing the fullFogMode to a (normally) @@ -112,19 +101,13 @@ void main() // a uniform we don't have to worry about GLSL optimizing away different // options when testing, causing a bunch of headaches if we just want to render the screen red. - float depthValue = texture(gDepthMap, TexCoord).r; - fragColor = vec4(vec3(depthValue), 1.0); // Convert depth value to grayscale color + float depthValue = textureLod(gDepthMap, TexCoord, 0).r; + fragColor.rgb = vec3(depthValue); // Convert depth value to grayscale color + fragColor.a = 1.0; } } - else - { - // every pixel needs to be set to something, otherwise the pixel may be undefined by some drivers (specifically Intel) - fragColor = vec4(0.0, 0.0, 0.0, 0.0); - } } - - // Are these still needed? float linearFog(float x, float fogStart, float fogLength, float fogMin, float fogRange) { x = clamp((x-fogStart)/fogLength, 0.0, 1.0); @@ -132,13 +115,15 @@ float linearFog(float x, float fogStart, float fogLength, float fogMin, float fo } float exponentialFog(float x, float fogStart, float fogLength, -float fogMin, float fogRange, float fogDensity) { + float fogMin, float fogRange, float fogDensity) +{ x = max((x-fogStart)/fogLength, 0.0) * fogDensity; return fogMin + fogRange - fogRange/exp(x); } float exponentialSquaredFog(float x, float fogStart, float fogLength, -float fogMin, float fogRange, float fogDensity) { + float fogMin, float fogRange, float fogDensity) +{ x = max((x-fogStart)/fogLength, 0.0) * fogDensity; return fogMin + fogRange - fogRange/exp(x*x); -} \ No newline at end of file +} diff --git a/core/src/main/resources/shaders/ssao/ao.frag b/core/src/main/resources/shaders/ssao/ao.frag index b23f6c901..abd315fdb 100644 --- a/core/src/main/resources/shaders/ssao/ao.frag +++ b/core/src/main/resources/shaders/ssao/ao.frag @@ -13,7 +13,7 @@ uniform mat4 gProj; uniform mat4 gInvProj; const float MIN_LIGHT = 0.6; -const float SAMPLE_BIAS = 0.5; +const float SAMPLE_BIAS = 0.6; const int MAX_KERNEL_SIZE = 32; const float INV_MAX_KERNEL_SIZE_F = 1.0 / float(MAX_KERNEL_SIZE); uniform vec3 gKernel[MAX_KERNEL_SIZE]; @@ -60,7 +60,7 @@ void main() { float occlusion_factor = 0.0; for (int i = 0; i < MAX_KERNEL_SIZE; i++) { vec3 samplePos = TBN * gKernel[i]; - samplePos *= sign(dot(samplePos, viewNormal)); + //samplePos *= sign(dot(samplePos, viewNormal)); samplePos = viewPos + samplePos * gSampleRad; vec4 sampleNdcPos = gProj * vec4(samplePos + viewPos, 1.0); From 8c7937f9a237d282140a2a2fcd13adfe26b3cff6 Mon Sep 17 00:00:00 2001 From: NULL511 Date: Fri, 1 Sep 2023 18:25:37 -0400 Subject: [PATCH 5/8] cleanup --- .../render/renderer/shaders/SSAORenderer.java | 16 +++++++++------- core/src/main/resources/shaders/ssao/ao.frag | 2 +- 2 files changed, 10 insertions(+), 8 deletions(-) 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 index 935112376..9d49ee098 100644 --- 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 @@ -105,13 +105,13 @@ public class SSAORenderer private static float[] genKernel() { float[] kernel = new float[MAX_KERNEL_SIZE * 3]; + for (int i = 0; i < MAX_KERNEL_SIZE; i++) { - float sampleX = (float) (Math.random() * 2.0 - 1.0); - float sampleY = (float) (Math.random() * 2.0 - 1.0); - float sampleZ = (float) Math.random(); - - + float sampleX = (float)Math.random() * 2f - 1f; + float sampleY = (float)Math.random() * 2f - 1f; + float sampleZ = (float)Math.random() * 2f - 1f; + // Normalize float magnitude = (float) Math.sqrt(Math.pow(sampleX, 2) + Math.pow(sampleY, 2) + Math.pow(sampleZ, 2)); sampleX /= magnitude; @@ -119,15 +119,17 @@ public class SSAORenderer sampleZ /= magnitude; float scale = i / (float) MAX_KERNEL_SIZE; - float interpolatedScale = (float) (0.1 + (scale * scale) * (0.9)); + float interpolatedScale = (float) (0.1 + 0.9 * (scale * scale)); sampleX *= interpolatedScale; sampleY *= interpolatedScale; sampleZ *= interpolatedScale; - kernel[i * 3] = sampleX; + + kernel[i * 3 ] = sampleX; kernel[i * 3 + 1] = sampleY; kernel[i * 3 + 2] = sampleZ; } + return kernel; } diff --git a/core/src/main/resources/shaders/ssao/ao.frag b/core/src/main/resources/shaders/ssao/ao.frag index abd315fdb..f2677e86b 100644 --- a/core/src/main/resources/shaders/ssao/ao.frag +++ b/core/src/main/resources/shaders/ssao/ao.frag @@ -60,7 +60,7 @@ void main() { float occlusion_factor = 0.0; for (int i = 0; i < MAX_KERNEL_SIZE; i++) { vec3 samplePos = TBN * gKernel[i]; - //samplePos *= sign(dot(samplePos, viewNormal)); + samplePos *= sign(dot(samplePos, viewNormal)); samplePos = viewPos + samplePos * gSampleRad; vec4 sampleNdcPos = gProj * vec4(samplePos + viewPos, 1.0); From 4f1f11e7690b8cd98c59808e834c22877174f9d5 Mon Sep 17 00:00:00 2001 From: NULL511 Date: Sun, 3 Sep 2023 23:33:30 -0400 Subject: [PATCH 6/8] add debug ssao settings; improve vanilla matching --- .../config/client/IDhApiGraphicsConfig.java | 8 + .../config/client/DhApiGraphicsConfig.java | 16 ++ .../distanthorizons/core/config/Config.java | 20 ++ ...RenderQualityPresetConfigEventHandler.java | 2 +- .../render/renderer/shaders/SSAORenderer.java | 177 ++++++++++++------ .../assets/distanthorizons/lang/en_us.json | 8 + core/src/main/resources/shaders/ssao/ao.frag | 119 +++++++----- .../main/resources/shaders/ssao/apply.frag | 77 ++++++++ 8 files changed, 324 insertions(+), 103 deletions(-) create mode 100644 core/src/main/resources/shaders/ssao/apply.frag diff --git a/api/src/main/java/com/seibel/distanthorizons/api/interfaces/config/client/IDhApiGraphicsConfig.java b/api/src/main/java/com/seibel/distanthorizons/api/interfaces/config/client/IDhApiGraphicsConfig.java index c42e31bae..a1d033fa1 100644 --- a/api/src/main/java/com/seibel/distanthorizons/api/interfaces/config/client/IDhApiGraphicsConfig.java +++ b/api/src/main/java/com/seibel/distanthorizons/api/interfaces/config/client/IDhApiGraphicsConfig.java @@ -86,6 +86,14 @@ public interface IDhApiGraphicsConfig extends IDhApiConfigGroup IDhApiConfigValue ambientOcclusion(); + IDhApiConfigValue ambientOcclusionRadius(); + + IDhApiConfigValue ambientOcclusionStrength(); + + IDhApiConfigValue ambientOcclusionBias(); + + IDhApiConfigValue ambientOcclusionMinLight(); + IDhApiConfigValue transparency(); /** Defines what blocks won't be rendered as LODs. */ diff --git a/core/src/main/java/com/seibel/distanthorizons/core/api/external/methods/config/client/DhApiGraphicsConfig.java b/core/src/main/java/com/seibel/distanthorizons/core/api/external/methods/config/client/DhApiGraphicsConfig.java index c07bb82cf..91224c0c6 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/api/external/methods/config/client/DhApiGraphicsConfig.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/api/external/methods/config/client/DhApiGraphicsConfig.java @@ -84,6 +84,22 @@ public class DhApiGraphicsConfig implements IDhApiGraphicsConfig public IDhApiConfigValue ambientOcclusion() { return new DhApiConfigValue(Config.Client.Advanced.Graphics.Quality.ssao); } + @Override + public IDhApiConfigValue ambientOcclusionRadius() + { return new DhApiConfigValue(Config.Client.Advanced.Graphics.Quality.ssaoRadius); } + + @Override + public IDhApiConfigValue ambientOcclusionStrength() + { return new DhApiConfigValue(Config.Client.Advanced.Graphics.Quality.ssaoStrength); } + + @Override + public IDhApiConfigValue ambientOcclusionBias() + { return new DhApiConfigValue(Config.Client.Advanced.Graphics.Quality.ssaoBias); } + + @Override + public IDhApiConfigValue ambientOcclusionMinLight() + { return new DhApiConfigValue(Config.Client.Advanced.Graphics.Quality.ssaoMinLight); } + @Override public IDhApiConfigValue transparency() { return new DhApiConfigValue(Config.Client.Advanced.Graphics.Quality.transparency); } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/config/Config.java b/core/src/main/java/com/seibel/distanthorizons/core/config/Config.java index c1233ce7e..b9e962daf 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/config/Config.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/config/Config.java @@ -179,6 +179,26 @@ public class Config .comment("Enable Screen Space Ambient Occlusion") .build(); + public static ConfigEntry ssaoRadius = new ConfigEntry.Builder() + .set(3.0) + .comment("Radius of Screen Space Ambient Occlusion effect in blocks") + .build(); + + public static ConfigEntry ssaoStrength = new ConfigEntry.Builder() + .set(6.0) + .comment("Strength of Screen Space Ambient Occlusion effect") + .build(); + + public static ConfigEntry ssaoBias = new ConfigEntry.Builder() + .set(0.0) + .comment("Bias of Screen Space Ambient Occlusion effect") + .build(); + + public static ConfigEntry ssaoMinLight = new ConfigEntry.Builder() + .set(0.3) + .comment("Minimum brightness of Screen Space Ambient Occlusion effect") + .build(); + public static ConfigEntry horizontalQuality = new ConfigEntry.Builder() .set(EHorizontalQuality.MEDIUM) .comment("" diff --git a/core/src/main/java/com/seibel/distanthorizons/core/config/eventHandlers/presets/RenderQualityPresetConfigEventHandler.java b/core/src/main/java/com/seibel/distanthorizons/core/config/eventHandlers/presets/RenderQualityPresetConfigEventHandler.java index 5ae270f1d..7017a2a2f 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/config/eventHandlers/presets/RenderQualityPresetConfigEventHandler.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/config/eventHandlers/presets/RenderQualityPresetConfigEventHandler.java @@ -66,7 +66,7 @@ public class RenderQualityPresetConfigEventHandler extends AbstractPresetConfigE this.put(EQualityPreset.HIGH, true); this.put(EQualityPreset.EXTREME, true); }}); - + //==============// 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 index 9d49ee098..c9252dc31 100644 --- 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 @@ -1,6 +1,7 @@ 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; @@ -22,7 +23,6 @@ public class SSAORenderer private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class); - private static final int MAX_KERNEL_SIZE = 32; private static final float[] box_vertices = { -1, -1, 1, -1, @@ -34,12 +34,17 @@ public class SSAORenderer private ShaderProgram ssaoShader; + private ShaderProgram applyShader; private GLVertexBuffer boxBuffer; private VertexAttribute va; private boolean init = false; - private float[] kernel = new float[MAX_KERNEL_SIZE * 3]; + private int width = -1; + private int height = -1; + private int ssaoFramebuffer = -1; + + private int ssaoTexture = -1; // ssao uniforms private final SsaoShaderUniforms ssaoShaderUniforms = new SsaoShaderUniforms(); @@ -47,13 +52,24 @@ public class SSAORenderer { public int gProjUniform; public int gInvProjUniform; - public int gSampleRadUniform; - public int gFactorUniform; - public int gPowerUniform; - public int gKernelUniform; + public int gRadiusUniform; + public int gStrengthUniform; + public int gBiasUniform; + public int gMinLightUniform; 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 gNearUniform; + public int gFarUniform; + } + //=============// // constructor // @@ -66,7 +82,6 @@ public class SSAORenderer if (this.init) return; this.init = true; - this.va = VertexAttribute.create(); this.va.bind(); @@ -76,20 +91,53 @@ public class SSAORenderer 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.gSampleRadUniform = this.ssaoShader.getUniformLocation("gSampleRad"); - this.ssaoShaderUniforms.gFactorUniform = this.ssaoShader.getUniformLocation("gFactor"); - this.ssaoShaderUniforms.gPowerUniform = this.ssaoShader.getUniformLocation("gPower"); - this.ssaoShaderUniforms.gKernelUniform = this.ssaoShader.getUniformLocation("gKernel"); + 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"); - // Generate kernel - this.kernel = genKernel(); + // Apply uniform setup + this.applyShaderUniforms.gSSAOMapUniform = this.applyShader.getUniformLocation("gSSAOMap"); + this.applyShaderUniforms.gDepthMapUniform = this.applyShader.getUniformLocation("gDepthMap"); + this.applyShaderUniforms.gViewSizeUniform = tryGetUniformLocation(this.applyShader, "gViewSize"); + this.applyShaderUniforms.gNearUniform = tryGetUniformLocation(this.applyShader, "gNear"); + this.applyShaderUniforms.gFarUniform = tryGetUniformLocation(this.applyShader, "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() { @@ -97,43 +145,12 @@ public class SSAORenderer 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); } - private static float[] genKernel() - { - float[] kernel = new float[MAX_KERNEL_SIZE * 3]; - - for (int i = 0; i < MAX_KERNEL_SIZE; i++) - { - float sampleX = (float)Math.random() * 2f - 1f; - float sampleY = (float)Math.random() * 2f - 1f; - float sampleZ = (float)Math.random() * 2f - 1f; - - // Normalize - float magnitude = (float) Math.sqrt(Math.pow(sampleX, 2) + Math.pow(sampleY, 2) + Math.pow(sampleZ, 2)); - sampleX /= magnitude; - sampleY /= magnitude; - sampleZ /= magnitude; - - float scale = i / (float) MAX_KERNEL_SIZE; - float interpolatedScale = (float) (0.1 + 0.9 * (scale * scale)); - - sampleX *= interpolatedScale; - sampleY *= interpolatedScale; - sampleZ *= interpolatedScale; - - kernel[i * 3 ] = sampleX; - kernel[i * 3 + 1] = sampleY; - kernel[i * 3 + 2] = sampleZ; - } - - return kernel; - } - - //========// // render // @@ -148,29 +165,42 @@ public class SSAORenderer 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_DEPTH_TEST); - 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.glBindFramebuffer(GL32.GL_FRAMEBUFFER, MC_RENDER.getTargetFrameBuffer()); 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, - RenderUtil.getNearClipPlaneDistanceInBlocks(partialTicks), - (float) ((RenderUtil.getFarClipPlaneDistanceInBlocks() + LodUtil.REGION_WIDTH) * Math.sqrt(2))); + near, far); Mat4f invertedPerspective = new Mat4f(perspective); invertedPerspective.invert(); + float radius = Config.Client.Advanced.Graphics.Quality.ssaoRadius.get().floatValue(); + float strength = Config.Client.Advanced.Graphics.Quality.ssaoStrength.get().floatValue(); + float minLight = Config.Client.Advanced.Graphics.Quality.ssaoMinLight.get().floatValue(); + float bias = Config.Client.Advanced.Graphics.Quality.ssaoBias.get().floatValue(); + this.ssaoShader.bind(); this.ssaoShader.setUniform(this.ssaoShaderUniforms.gProjUniform, perspective); this.ssaoShader.setUniform(this.ssaoShaderUniforms.gInvProjUniform, invertedPerspective); - this.ssaoShader.setUniform(this.ssaoShaderUniforms.gSampleRadUniform, 3.0f); - this.ssaoShader.setUniform(this.ssaoShaderUniforms.gFactorUniform, 0.5f); - this.ssaoShader.setUniform(this.ssaoShaderUniforms.gPowerUniform, 6.0f); + 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()); @@ -178,16 +208,51 @@ public class SSAORenderer GL32.glActiveTexture(GL32.GL_TEXTURE0); GL32.glBindTexture(GL32.GL_TEXTURE_2D, MC_RENDER.getDepthTextureId()); - GL32.glUniform3fv(this.ssaoShaderUniforms.gKernelUniform, this.kernel); GL32.glUniform1i(this.ssaoShaderUniforms.gDepthMapUniform, 0); GL32.glDrawArrays(GL32.GL_TRIANGLES, 0, 6); + this.applyShader.bind(); + + GL32.glBindFramebuffer(GL32.GL_FRAMEBUFFER, MC_RENDER.getTargetFrameBuffer()); + + 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, this.ssaoTexture); + GL32.glUniform1i(this.applyShaderUniforms.gSSAOMapUniform, 0); + GL32.glActiveTexture(GL32.GL_TEXTURE1); + GL32.glBindTexture(GL32.GL_TEXTURE_2D, MC_RENDER.getDepthTextureId()); + GL32.glUniform1i(this.applyShaderUniforms.gDepthMapUniform, 1); + + 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(); } + private int tryGetUniformLocation(ShaderProgram shader, String uniformName) + { + try { + return shader.getUniformLocation(uniformName); + } + catch (RuntimeException error) { + return -1; + } + } + public void free() { this.ssaoShader.free(); + this.applyShader.free(); } } diff --git a/core/src/main/resources/assets/distanthorizons/lang/en_us.json b/core/src/main/resources/assets/distanthorizons/lang/en_us.json index bd549717e..d386bf7cd 100644 --- a/core/src/main/resources/assets/distanthorizons/lang/en_us.json +++ b/core/src/main/resources/assets/distanthorizons/lang/en_us.json @@ -96,6 +96,14 @@ "How quickly LODs drop off in quality.\n\nLarger numbers will improve how distant terrain looks\nbut will increase memory and GPU usage.", "distanthorizons.config.client.advanced.graphics.quality.ssao": "SSAO", + "distanthorizons.config.client.advanced.graphics.quality.ssaoRadius": + "SSAO Radius", + "distanthorizons.config.client.advanced.graphics.quality.ssaoStrength": + "SSAO Strength", + "distanthorizons.config.client.advanced.graphics.quality.ssaoMinLight": + "SSAO Min Light", + "distanthorizons.config.client.advanced.graphics.quality.ssaoBias": + "SSAO Bias", "distanthorizons.config.client.advanced.graphics.quality.ssao.@tooltip": "Screen Space Ambient Occlusion adds depth to the lighting of blocks.", "distanthorizons.config.client.advanced.graphics.quality.horizontalQuality": diff --git a/core/src/main/resources/shaders/ssao/ao.frag b/core/src/main/resources/shaders/ssao/ao.frag index f2677e86b..e700a3d81 100644 --- a/core/src/main/resources/shaders/ssao/ao.frag +++ b/core/src/main/resources/shaders/ssao/ao.frag @@ -1,27 +1,34 @@ #version 150 core #extension GL_ARB_derivative_control : enable +#define saturate(x) (clamp((x), 0.0, 1.0)) +#define rcp(x) (1.0 / (x)) + +const float SSAO_SAMPLES = 24; // [2 4 6 8 10 12 14 16 24 32] + in vec2 TexCoord; out vec4 fragColor; uniform sampler2D gDepthMap; -uniform float gSampleRad; -uniform float gFactor; -uniform float gPower; -uniform mat4 gProj; +uniform float gRadius; +uniform float gStrength; +uniform float gMinLight; +uniform float gBias; uniform mat4 gInvProj; +uniform mat4 gProj; -const float MIN_LIGHT = 0.6; -const float SAMPLE_BIAS = 0.6; -const int MAX_KERNEL_SIZE = 32; -const float INV_MAX_KERNEL_SIZE_F = 1.0 / float(MAX_KERNEL_SIZE); -uniform vec3 gKernel[MAX_KERNEL_SIZE]; - +const float EPSILON = 1.e-6; +const float GOLDEN_ANGLE = 2.39996323; const vec3 MAGIC = vec3(0.06711056, 0.00583715, 52.9829189); const float PI = 3.1415926538; +const float TAU = PI * 2.0; +vec3 unproject(vec4 pos) { + return pos.xyz / pos.w; +} + float InterleavedGradientNoise(const in vec2 pixel) { float x = dot(pixel, MAGIC.xy); return fract(MAGIC.z * fract(x)); @@ -32,12 +39,64 @@ vec3 calcViewPosition(const in vec3 clipPos) { return viewPos.xyz / viewPos.w; } + +float GetSpiralOcclusion(const in vec2 uv, const in vec3 viewPos, const in vec3 viewNormal) { + const float inv = rcp(SSAO_SAMPLES); + float rStep = inv * gRadius; + + float dither = InterleavedGradientNoise(gl_FragCoord.xy); + float rotatePhase = dither * TAU; + + float radius = rStep; + vec2 offset; + + float ao = 0.0; + int sampleCount = 0; + for (int i = 0; i < SSAO_SAMPLES; i++) { + offset.x = sin(rotatePhase); + offset.y = cos(rotatePhase); + offset *= radius; + radius += rStep; + + rotatePhase += GOLDEN_ANGLE; + + vec3 sampleViewPos = viewPos + vec3(offset, -0.1); + vec3 sampleClipPos = unproject(gProj * vec4(sampleViewPos, 1.0)) * 0.5 + 0.5; + //if (sampleClipPos != saturate(sampleClipPos)) continue; + sampleClipPos = saturate(sampleClipPos); + + float sampleClipDepth = textureLod(gDepthMap, sampleClipPos.xy, 0.0).r; + if (sampleClipDepth >= 1.0 - EPSILON) continue; + + sampleClipPos.z = sampleClipDepth; + sampleViewPos = unproject(gInvProj * vec4(sampleClipPos * 2.0 - 1.0, 1.0)); + + vec3 diff = sampleViewPos - viewPos; + float sampleDist = length(diff); + vec3 sampleNormal = diff / sampleDist; + + float sampleNoLm = max(dot(viewNormal, sampleNormal) - gBias, 0.0); + float aoF = 1.0 - saturate(sampleDist / gRadius); + ao += sampleNoLm * aoF; + + sampleCount += 1; + } + + ao /= max(sampleCount, 1); + //ao = max(ao - SSAO_THRESHOLD, 0.0) * gStrength; + //ao /= ao + 0.25; + + ao = smoothstep(0.0, gStrength, ao); + + return ao * (1.0 - gMinLight); +} + + void main() { float fragmentDepth = textureLod(gDepthMap, TexCoord, 0).r; - float occlusion = 1.0; + float occlusion = 0.0; if (fragmentDepth < 1.0) { - float dither = InterleavedGradientNoise(gl_FragCoord.xy); vec3 viewPos = calcViewPosition(vec3(TexCoord, fragmentDepth)); #ifdef GL_ARB_derivative_control @@ -47,41 +106,9 @@ void main() { #endif viewNormal = normalize(viewNormal); - //const vec3 upVec = vec3(0.0, -1.0, 0.0); - float angle = dither * (PI * 2.0); - vec3 rotation = vec3(sin(angle), cos(angle), 0.0); - vec3 tangent = normalize(cross(viewNormal, rotation)); - - vec3 bitangent = normalize(cross(viewNormal, tangent)); - mat3 TBN = mat3(tangent, bitangent, viewNormal); - - float maxWeight = 0.0; - float occlusion_factor = 0.0; - for (int i = 0; i < MAX_KERNEL_SIZE; i++) { - vec3 samplePos = TBN * gKernel[i]; - samplePos *= sign(dot(samplePos, viewNormal)); - samplePos = viewPos + samplePos * gSampleRad; - - vec4 sampleNdcPos = gProj * vec4(samplePos + viewPos, 1.0); - sampleNdcPos = sampleNdcPos / sampleNdcPos.w; - if (any(greaterThanEqual(abs(sampleNdcPos.xy), vec2(1.0)))) continue; - - maxWeight += 1.0; - - vec2 sampleTexPos = sampleNdcPos.xy * 0.5 + 0.5; - float sampleDepth = textureLod(gDepthMap, sampleTexPos, 0).r; - float geometryDepth = calcViewPosition(vec3(sampleTexPos, sampleDepth)).z; - - float rangeCheck = smoothstep(0.0, 1.0, gSampleRad / abs(viewPos.z - geometryDepth)); - // the number added to the samplePos.z can be used to reduce noise in the SSAO application at the cost of reducing the overall affect - occlusion_factor += step(samplePos.z + SAMPLE_BIAS, geometryDepth) * rangeCheck; - } - - float visibility_factor = 1.0 - (occlusion_factor / maxWeight); - occlusion = (1.0 - pow(visibility_factor, gFactor)) * gPower; - occlusion = clamp(1.0 - occlusion, MIN_LIGHT, 1.0); + occlusion = GetSpiralOcclusion(TexCoord, viewPos, viewNormal); } - fragColor = vec4(vec3(1.0), occlusion); + fragColor = vec4(vec3(1.0 - occlusion), 1.0); } diff --git a/core/src/main/resources/shaders/ssao/apply.frag b/core/src/main/resources/shaders/ssao/apply.frag new file mode 100644 index 000000000..f9490e2ce --- /dev/null +++ b/core/src/main/resources/shaders/ssao/apply.frag @@ -0,0 +1,77 @@ +#version 150 core + +#define ENABLE_SSAO_BLUR + +in vec2 TexCoord; +//in vec2 ViewRay; + +out vec4 fragColor; + +uniform sampler2D gSSAOMap; +uniform sampler2D gDepthMap; +uniform vec2 gViewSize; +uniform float gNear; +uniform float gFar; + + +float linearizeDepth(const in float depth) { + return (gNear * gFar) / (depth * (gNear - gFar) + gFar); +} + +float Gaussian(const in float sigma, const in float x) { + return exp(-(x*x) / (2.0 * (sigma*sigma))); +} + +float BilateralGaussianBlur(const in vec2 texcoord, const in float linearDepth, const in float g_sigmaV) { + float g_sigmaX = 1.6; + float g_sigmaY = 1.6; + + const float c_halfSamplesX = 2.0; + const float c_halfSamplesY = 2.0; + + vec2 pixelSize = 1.0 / gViewSize; + + float accum = 0.0; + float total = 0.0; + for (float iy = -c_halfSamplesY; iy <= c_halfSamplesY; iy++) { + float fy = Gaussian(g_sigmaY, iy); + + for (float ix = -c_halfSamplesX; ix <= c_halfSamplesX; ix++) { + float fx = Gaussian(g_sigmaX, ix); + + vec2 sampleTex = texcoord + vec2(ix, iy) * pixelSize; + float sampleValue = textureLod(gSSAOMap, sampleTex, 0).r; + float sampleDepth = textureLod(gDepthMap, sampleTex, 0).r; + float sampleLinearDepth = linearizeDepth(sampleDepth); + + float depthDiff = abs(sampleLinearDepth - linearDepth); + float fv = Gaussian(g_sigmaV, depthDiff); + + float weight = fx*fy*fv; + accum += weight * sampleValue; + total += weight; + } + } + + if (total <= 1.e-4) return 1.0; + return accum / total; +} + + +void main() +{ + fragColor = vec4(1.0); + + float fragmentDepth = textureLod(gDepthMap, TexCoord, 0).r; + + // a fragment depth of "1" means the fragment wasn't drawn to, + // we only want to apply SSAO to LODs, not to the sky outside the LODs + if (fragmentDepth < 1) { + #ifdef ENABLE_SSAO_BLUR + float fragmentDepthLinear = linearizeDepth(fragmentDepth); + fragColor.a = BilateralGaussianBlur(TexCoord, fragmentDepthLinear, 1.6); + #else + fragColor.a = textureLod(gSSAOMap, TexCoord, 0).r; + #endif + } +} From 4cd6bc06f168ad0f6dc56fa670664af30461285c Mon Sep 17 00:00:00 2001 From: NULL511 Date: Mon, 4 Sep 2023 00:12:45 -0400 Subject: [PATCH 7/8] reset default ssao settings --- .../config/client/IDhApiGraphicsConfig.java | 10 ++++++---- .../methods/config/client/DhApiGraphicsConfig.java | 12 ++++++++---- .../seibel/distanthorizons/core/config/Config.java | 13 +++++++++---- .../core/render/renderer/shaders/SSAORenderer.java | 4 ++++ .../assets/distanthorizons/lang/en_us.json | 2 ++ core/src/main/resources/shaders/ssao/ao.frag | 10 +++------- core/src/main/resources/shaders/ssao/apply.frag | 1 - 7 files changed, 32 insertions(+), 20 deletions(-) diff --git a/api/src/main/java/com/seibel/distanthorizons/api/interfaces/config/client/IDhApiGraphicsConfig.java b/api/src/main/java/com/seibel/distanthorizons/api/interfaces/config/client/IDhApiGraphicsConfig.java index a1d033fa1..ea8478856 100644 --- a/api/src/main/java/com/seibel/distanthorizons/api/interfaces/config/client/IDhApiGraphicsConfig.java +++ b/api/src/main/java/com/seibel/distanthorizons/api/interfaces/config/client/IDhApiGraphicsConfig.java @@ -86,13 +86,15 @@ public interface IDhApiGraphicsConfig extends IDhApiConfigGroup IDhApiConfigValue ambientOcclusion(); - IDhApiConfigValue ambientOcclusionRadius(); + IDhApiConfigValue ambientOcclusion_SampleCount(); - IDhApiConfigValue ambientOcclusionStrength(); + IDhApiConfigValue ambientOcclusion_Radius(); - IDhApiConfigValue ambientOcclusionBias(); + IDhApiConfigValue ambientOcclusion_Strength(); - IDhApiConfigValue ambientOcclusionMinLight(); + IDhApiConfigValue ambientOcclusion_Bias(); + + IDhApiConfigValue ambientOcclusion_MinLight(); IDhApiConfigValue transparency(); diff --git a/core/src/main/java/com/seibel/distanthorizons/core/api/external/methods/config/client/DhApiGraphicsConfig.java b/core/src/main/java/com/seibel/distanthorizons/core/api/external/methods/config/client/DhApiGraphicsConfig.java index 91224c0c6..55dfa5758 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/api/external/methods/config/client/DhApiGraphicsConfig.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/api/external/methods/config/client/DhApiGraphicsConfig.java @@ -85,19 +85,23 @@ public class DhApiGraphicsConfig implements IDhApiGraphicsConfig { return new DhApiConfigValue(Config.Client.Advanced.Graphics.Quality.ssao); } @Override - public IDhApiConfigValue ambientOcclusionRadius() + public IDhApiConfigValue ambientOcclusion_SampleCount() + { return new DhApiConfigValue(Config.Client.Advanced.Graphics.Quality.ssaoSampleCount); } + + @Override + public IDhApiConfigValue ambientOcclusion_Radius() { return new DhApiConfigValue(Config.Client.Advanced.Graphics.Quality.ssaoRadius); } @Override - public IDhApiConfigValue ambientOcclusionStrength() + public IDhApiConfigValue ambientOcclusion_Strength() { return new DhApiConfigValue(Config.Client.Advanced.Graphics.Quality.ssaoStrength); } @Override - public IDhApiConfigValue ambientOcclusionBias() + public IDhApiConfigValue ambientOcclusion_Bias() { return new DhApiConfigValue(Config.Client.Advanced.Graphics.Quality.ssaoBias); } @Override - public IDhApiConfigValue ambientOcclusionMinLight() + public IDhApiConfigValue ambientOcclusion_MinLight() { return new DhApiConfigValue(Config.Client.Advanced.Graphics.Quality.ssaoMinLight); } @Override diff --git a/core/src/main/java/com/seibel/distanthorizons/core/config/Config.java b/core/src/main/java/com/seibel/distanthorizons/core/config/Config.java index b9e962daf..3ee3ff8b1 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/config/Config.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/config/Config.java @@ -179,23 +179,28 @@ public class Config .comment("Enable Screen Space Ambient Occlusion") .build(); + public static ConfigEntry ssaoSampleCount = new ConfigEntry.Builder() + .set(6) + .comment("Number of samples to use for Screen Space Ambient Occlusion") + .build(); + public static ConfigEntry ssaoRadius = new ConfigEntry.Builder() - .set(3.0) + .set(4.0) .comment("Radius of Screen Space Ambient Occlusion effect in blocks") .build(); public static ConfigEntry ssaoStrength = new ConfigEntry.Builder() - .set(6.0) + .set(0.2) .comment("Strength of Screen Space Ambient Occlusion effect") .build(); public static ConfigEntry ssaoBias = new ConfigEntry.Builder() - .set(0.0) + .set(0.02) .comment("Bias of Screen Space Ambient Occlusion effect") .build(); public static ConfigEntry ssaoMinLight = new ConfigEntry.Builder() - .set(0.3) + .set(0.25) .comment("Minimum brightness of Screen Space Ambient Occlusion effect") .build(); 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 index c9252dc31..bd6ad3988 100644 --- 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 @@ -52,6 +52,7 @@ public class SSAORenderer { public int gProjUniform; public int gInvProjUniform; + public int gSampleCountUniform; public int gRadiusUniform; public int gStrengthUniform; public int gBiasUniform; @@ -97,6 +98,7 @@ public class SSAORenderer // 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"); @@ -189,6 +191,7 @@ public class SSAORenderer Mat4f invertedPerspective = new Mat4f(perspective); invertedPerspective.invert(); + int sampleCount = Config.Client.Advanced.Graphics.Quality.ssaoSampleCount.get(); float radius = Config.Client.Advanced.Graphics.Quality.ssaoRadius.get().floatValue(); float strength = Config.Client.Advanced.Graphics.Quality.ssaoStrength.get().floatValue(); float minLight = Config.Client.Advanced.Graphics.Quality.ssaoMinLight.get().floatValue(); @@ -197,6 +200,7 @@ public class SSAORenderer 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); diff --git a/core/src/main/resources/assets/distanthorizons/lang/en_us.json b/core/src/main/resources/assets/distanthorizons/lang/en_us.json index d386bf7cd..526ecdf8e 100644 --- a/core/src/main/resources/assets/distanthorizons/lang/en_us.json +++ b/core/src/main/resources/assets/distanthorizons/lang/en_us.json @@ -96,6 +96,8 @@ "How quickly LODs drop off in quality.\n\nLarger numbers will improve how distant terrain looks\nbut will increase memory and GPU usage.", "distanthorizons.config.client.advanced.graphics.quality.ssao": "SSAO", + "distanthorizons.config.client.advanced.graphics.quality.ssaoSampleCount": + "SSAO Sample Count", "distanthorizons.config.client.advanced.graphics.quality.ssaoRadius": "SSAO Radius", "distanthorizons.config.client.advanced.graphics.quality.ssaoStrength": diff --git a/core/src/main/resources/shaders/ssao/ao.frag b/core/src/main/resources/shaders/ssao/ao.frag index e700a3d81..94901abba 100644 --- a/core/src/main/resources/shaders/ssao/ao.frag +++ b/core/src/main/resources/shaders/ssao/ao.frag @@ -4,13 +4,12 @@ #define saturate(x) (clamp((x), 0.0, 1.0)) #define rcp(x) (1.0 / (x)) -const float SSAO_SAMPLES = 24; // [2 4 6 8 10 12 14 16 24 32] - in vec2 TexCoord; out vec4 fragColor; uniform sampler2D gDepthMap; +uniform int gSampleCount; uniform float gRadius; uniform float gStrength; uniform float gMinLight; @@ -41,7 +40,7 @@ vec3 calcViewPosition(const in vec3 clipPos) { float GetSpiralOcclusion(const in vec2 uv, const in vec3 viewPos, const in vec3 viewNormal) { - const float inv = rcp(SSAO_SAMPLES); + float inv = rcp(gSampleCount); float rStep = inv * gRadius; float dither = InterleavedGradientNoise(gl_FragCoord.xy); @@ -52,7 +51,7 @@ float GetSpiralOcclusion(const in vec2 uv, const in vec3 viewPos, const in vec3 float ao = 0.0; int sampleCount = 0; - for (int i = 0; i < SSAO_SAMPLES; i++) { + for (int i = 0; i < gSampleCount; i++) { offset.x = sin(rotatePhase); offset.y = cos(rotatePhase); offset *= radius; @@ -83,9 +82,6 @@ float GetSpiralOcclusion(const in vec2 uv, const in vec3 viewPos, const in vec3 } ao /= max(sampleCount, 1); - //ao = max(ao - SSAO_THRESHOLD, 0.0) * gStrength; - //ao /= ao + 0.25; - ao = smoothstep(0.0, gStrength, ao); return ao * (1.0 - gMinLight); diff --git a/core/src/main/resources/shaders/ssao/apply.frag b/core/src/main/resources/shaders/ssao/apply.frag index f9490e2ce..f91e787b2 100644 --- a/core/src/main/resources/shaders/ssao/apply.frag +++ b/core/src/main/resources/shaders/ssao/apply.frag @@ -3,7 +3,6 @@ #define ENABLE_SSAO_BLUR in vec2 TexCoord; -//in vec2 ViewRay; out vec4 fragColor; From 1da2b3558e5dbf788fa144064e268f1d39df8e59 Mon Sep 17 00:00:00 2001 From: NULL511 Date: Mon, 4 Sep 2023 03:09:25 -0400 Subject: [PATCH 8/8] add sample count --- .../config/client/IDhApiGraphicsConfig.java | 2 ++ .../config/client/DhApiGraphicsConfig.java | 4 +++ .../distanthorizons/core/config/Config.java | 5 ++++ .../render/renderer/shaders/SSAORenderer.java | 6 ++++- .../assets/distanthorizons/lang/en_us.json | 6 +++-- core/src/main/resources/shaders/ssao/ao.frag | 26 +++++++++---------- .../main/resources/shaders/ssao/apply.frag | 21 +++++++-------- 7 files changed, 43 insertions(+), 27 deletions(-) diff --git a/api/src/main/java/com/seibel/distanthorizons/api/interfaces/config/client/IDhApiGraphicsConfig.java b/api/src/main/java/com/seibel/distanthorizons/api/interfaces/config/client/IDhApiGraphicsConfig.java index ea8478856..b5bfce8f0 100644 --- a/api/src/main/java/com/seibel/distanthorizons/api/interfaces/config/client/IDhApiGraphicsConfig.java +++ b/api/src/main/java/com/seibel/distanthorizons/api/interfaces/config/client/IDhApiGraphicsConfig.java @@ -96,6 +96,8 @@ public interface IDhApiGraphicsConfig extends IDhApiConfigGroup IDhApiConfigValue ambientOcclusion_MinLight(); + IDhApiConfigValue ambientOcclusion_BlurRadius(); + IDhApiConfigValue transparency(); /** Defines what blocks won't be rendered as LODs. */ diff --git a/core/src/main/java/com/seibel/distanthorizons/core/api/external/methods/config/client/DhApiGraphicsConfig.java b/core/src/main/java/com/seibel/distanthorizons/core/api/external/methods/config/client/DhApiGraphicsConfig.java index 55dfa5758..478645a28 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/api/external/methods/config/client/DhApiGraphicsConfig.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/api/external/methods/config/client/DhApiGraphicsConfig.java @@ -104,6 +104,10 @@ public class DhApiGraphicsConfig implements IDhApiGraphicsConfig public IDhApiConfigValue ambientOcclusion_MinLight() { return new DhApiConfigValue(Config.Client.Advanced.Graphics.Quality.ssaoMinLight); } + @Override + public IDhApiConfigValue ambientOcclusion_BlurRadius() + { return new DhApiConfigValue(Config.Client.Advanced.Graphics.Quality.ssaoBlurRadius); } + @Override public IDhApiConfigValue transparency() { return new DhApiConfigValue(Config.Client.Advanced.Graphics.Quality.transparency); } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/config/Config.java b/core/src/main/java/com/seibel/distanthorizons/core/config/Config.java index 3ee3ff8b1..e74e4900d 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/config/Config.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/config/Config.java @@ -204,6 +204,11 @@ public class Config .comment("Minimum brightness of Screen Space Ambient Occlusion effect") .build(); + public static ConfigEntry ssaoBlurRadius = new ConfigEntry.Builder() + .set(2) + .comment("Radius in pixels of Screen Space Ambient Occlusion blurring") + .build(); + public static ConfigEntry horizontalQuality = new ConfigEntry.Builder() .set(EHorizontalQuality.MEDIUM) .comment("" 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 index bd6ad3988..fcd01ecab 100644 --- 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 @@ -55,8 +55,8 @@ public class SSAORenderer public int gSampleCountUniform; public int gRadiusUniform; public int gStrengthUniform; - public int gBiasUniform; public int gMinLightUniform; + public int gBiasUniform; public int gDepthMapUniform; } @@ -67,6 +67,7 @@ public class SSAORenderer public int gSSAOMapUniform; public int gDepthMapUniform; public int gViewSizeUniform; + public int gBlurRadiusUniform; public int gNearUniform; public int gFarUniform; } @@ -109,6 +110,7 @@ public class SSAORenderer this.applyShaderUniforms.gSSAOMapUniform = this.applyShader.getUniformLocation("gSSAOMap"); this.applyShaderUniforms.gDepthMapUniform = this.applyShader.getUniformLocation("gDepthMap"); this.applyShaderUniforms.gViewSizeUniform = tryGetUniformLocation(this.applyShader, "gViewSize"); + this.applyShaderUniforms.gBlurRadiusUniform = tryGetUniformLocation(this.applyShader, "gBlurRadius"); this.applyShaderUniforms.gNearUniform = tryGetUniformLocation(this.applyShader, "gNear"); this.applyShaderUniforms.gFarUniform = tryGetUniformLocation(this.applyShader, "gFar"); @@ -192,6 +194,7 @@ public class SSAORenderer invertedPerspective.invert(); int sampleCount = Config.Client.Advanced.Graphics.Quality.ssaoSampleCount.get(); + int blurRadius = Config.Client.Advanced.Graphics.Quality.ssaoBlurRadius.get(); float radius = Config.Client.Advanced.Graphics.Quality.ssaoRadius.get().floatValue(); float strength = Config.Client.Advanced.Graphics.Quality.ssaoStrength.get().floatValue(); float minLight = Config.Client.Advanced.Graphics.Quality.ssaoMinLight.get().floatValue(); @@ -229,6 +232,7 @@ public class SSAORenderer GL32.glActiveTexture(GL32.GL_TEXTURE1); GL32.glBindTexture(GL32.GL_TEXTURE_2D, MC_RENDER.getDepthTextureId()); GL32.glUniform1i(this.applyShaderUniforms.gDepthMapUniform, 1); + GL32.glUniform1i(this.applyShaderUniforms.gBlurRadiusUniform, blurRadius); if (this.applyShaderUniforms.gViewSizeUniform >= 0) GL32.glUniform2f(this.applyShaderUniforms.gViewSizeUniform, width, height); diff --git a/core/src/main/resources/assets/distanthorizons/lang/en_us.json b/core/src/main/resources/assets/distanthorizons/lang/en_us.json index 526ecdf8e..0cade8c24 100644 --- a/core/src/main/resources/assets/distanthorizons/lang/en_us.json +++ b/core/src/main/resources/assets/distanthorizons/lang/en_us.json @@ -96,6 +96,8 @@ "How quickly LODs drop off in quality.\n\nLarger numbers will improve how distant terrain looks\nbut will increase memory and GPU usage.", "distanthorizons.config.client.advanced.graphics.quality.ssao": "SSAO", + "distanthorizons.config.client.advanced.graphics.quality.ssao.@tooltip": + "Screen Space Ambient Occlusion adds depth to the lighting of blocks.", "distanthorizons.config.client.advanced.graphics.quality.ssaoSampleCount": "SSAO Sample Count", "distanthorizons.config.client.advanced.graphics.quality.ssaoRadius": @@ -106,8 +108,8 @@ "SSAO Min Light", "distanthorizons.config.client.advanced.graphics.quality.ssaoBias": "SSAO Bias", - "distanthorizons.config.client.advanced.graphics.quality.ssao.@tooltip": - "Screen Space Ambient Occlusion adds depth to the lighting of blocks.", + "distanthorizons.config.client.advanced.graphics.quality.ssaoBlurRadius": + "SSAO Blur Radius", "distanthorizons.config.client.advanced.graphics.quality.horizontalQuality": "Horizontal Quality", "distanthorizons.config.client.advanced.graphics.quality.horizontalQuality.@tooltip": diff --git a/core/src/main/resources/shaders/ssao/ao.frag b/core/src/main/resources/shaders/ssao/ao.frag index 94901abba..149736efb 100644 --- a/core/src/main/resources/shaders/ssao/ao.frag +++ b/core/src/main/resources/shaders/ssao/ao.frag @@ -1,8 +1,9 @@ #version 150 core #extension GL_ARB_derivative_control : enable +#define SAMPLE_MAX 64 + #define saturate(x) (clamp((x), 0.0, 1.0)) -#define rcp(x) (1.0 / (x)) in vec2 TexCoord; @@ -40,28 +41,26 @@ vec3 calcViewPosition(const in vec3 clipPos) { float GetSpiralOcclusion(const in vec2 uv, const in vec3 viewPos, const in vec3 viewNormal) { - float inv = rcp(gSampleCount); - float rStep = inv * gRadius; - float dither = InterleavedGradientNoise(gl_FragCoord.xy); float rotatePhase = dither * TAU; + float rStep = gRadius / gSampleCount; - float radius = rStep; vec2 offset; float ao = 0.0; int sampleCount = 0; - for (int i = 0; i < gSampleCount; i++) { - offset.x = sin(rotatePhase); - offset.y = cos(rotatePhase); - offset *= radius; + float radius = rStep; + for (int i = 0; i < clamp(gSampleCount, 1, SAMPLE_MAX); i++) { + vec2 offset = vec2( + sin(rotatePhase), + cos(rotatePhase) + ) * radius; + radius += rStep; - rotatePhase += GOLDEN_ANGLE; vec3 sampleViewPos = viewPos + vec3(offset, -0.1); vec3 sampleClipPos = unproject(gProj * vec4(sampleViewPos, 1.0)) * 0.5 + 0.5; - //if (sampleClipPos != saturate(sampleClipPos)) continue; sampleClipPos = saturate(sampleClipPos); float sampleClipDepth = textureLod(gDepthMap, sampleClipPos.xy, 0.0).r; @@ -77,8 +76,7 @@ float GetSpiralOcclusion(const in vec2 uv, const in vec3 viewPos, const in vec3 float sampleNoLm = max(dot(viewNormal, sampleNormal) - gBias, 0.0); float aoF = 1.0 - saturate(sampleDist / gRadius); ao += sampleNoLm * aoF; - - sampleCount += 1; + sampleCount++; } ao /= max(sampleCount, 1); @@ -92,10 +90,12 @@ void main() { float fragmentDepth = textureLod(gDepthMap, TexCoord, 0).r; float occlusion = 0.0; + // Do not apply to sky if (fragmentDepth < 1.0) { vec3 viewPos = calcViewPosition(vec3(TexCoord, fragmentDepth)); #ifdef GL_ARB_derivative_control + // Get higher precision derivatives when available vec3 viewNormal = cross(dFdxFine(viewPos.xyz), dFdyFine(viewPos.xyz)); #else vec3 viewNormal = cross(dFdx(viewPos.xyz), dFdy(viewPos.xyz)); diff --git a/core/src/main/resources/shaders/ssao/apply.frag b/core/src/main/resources/shaders/ssao/apply.frag index f91e787b2..44026c96c 100644 --- a/core/src/main/resources/shaders/ssao/apply.frag +++ b/core/src/main/resources/shaders/ssao/apply.frag @@ -1,7 +1,5 @@ #version 150 core -#define ENABLE_SSAO_BLUR - in vec2 TexCoord; out vec4 fragColor; @@ -9,6 +7,7 @@ out vec4 fragColor; uniform sampler2D gSSAOMap; uniform sampler2D gDepthMap; uniform vec2 gViewSize; +uniform int gBlurRadius; uniform float gNear; uniform float gFar; @@ -25,20 +24,19 @@ float BilateralGaussianBlur(const in vec2 texcoord, const in float linearDepth, float g_sigmaX = 1.6; float g_sigmaY = 1.6; - const float c_halfSamplesX = 2.0; - const float c_halfSamplesY = 2.0; + int radius = clamp(gBlurRadius, 1, 3); vec2 pixelSize = 1.0 / gViewSize; float accum = 0.0; float total = 0.0; - for (float iy = -c_halfSamplesY; iy <= c_halfSamplesY; iy++) { + for (int iy = -radius; iy <= radius; iy++) { float fy = Gaussian(g_sigmaY, iy); - for (float ix = -c_halfSamplesX; ix <= c_halfSamplesX; ix++) { + for (int ix = -radius; ix <= radius; ix++) { float fx = Gaussian(g_sigmaX, ix); - vec2 sampleTex = texcoord + vec2(ix, iy) * pixelSize; + vec2 sampleTex = texcoord + ivec2(ix, iy) * pixelSize; float sampleValue = textureLod(gSSAOMap, sampleTex, 0).r; float sampleDepth = textureLod(gDepthMap, sampleTex, 0).r; float sampleLinearDepth = linearizeDepth(sampleDepth); @@ -66,11 +64,12 @@ void main() // a fragment depth of "1" means the fragment wasn't drawn to, // we only want to apply SSAO to LODs, not to the sky outside the LODs if (fragmentDepth < 1) { - #ifdef ENABLE_SSAO_BLUR + if (gBlurRadius > 0) { float fragmentDepthLinear = linearizeDepth(fragmentDepth); fragColor.a = BilateralGaussianBlur(TexCoord, fragmentDepthLinear, 1.6); - #else - fragColor.a = textureLod(gSSAOMap, TexCoord, 0).r; - #endif + } + else { + fragColor.a = texelFetch(gSSAOMap, ivec2(gl_FragCoord.xy), 0).r; + } } }