From ebe2fcc752db9d9cbe1623715df1de21205e9eba Mon Sep 17 00:00:00 2001 From: mcrcortex <18544518+MCRcortex@users.noreply.github.com> Date: Thu, 1 Feb 2024 22:47:05 +1000 Subject: [PATCH] SSAO works --- .../cortex/voxy/client/config/VoxyConfig.java | 4 +- .../me/cortex/voxy/client/core/VoxelCore.java | 3 +- .../voxy/client/core/gl/shader/Shader.java | 4 + .../voxy/client/core/model/ModelManager.java | 2 +- .../client/core/model/ModelTextureBakery.java | 5 ++ .../core/rendering/Gl46FarWorldRenderer.java | 4 + .../core/rendering/post/PostProcessing.java | 58 +++++++++--- .../core/rendering/util/GlStateCapture.java | 84 +++++++++++++++++ .../mixin/minecraft/MixinGameRenderer.java | 7 ++ .../voxy/shaders/lod/gl46/block_model.glsl | 4 + .../voxy/shaders/lod/gl46/cull/raster.frag | 4 +- .../voxy/shaders/lod/gl46/cull/raster.vert | 3 +- .../assets/voxy/shaders/lod/gl46/quads.frag | 10 +-- .../assets/voxy/shaders/lod/gl46/quads.vert | 18 ++-- .../assets/voxy/shaders/post/ssao.comp | 89 +++++++++++++++++++ 15 files changed, 266 insertions(+), 33 deletions(-) create mode 100644 src/main/java/me/cortex/voxy/client/core/rendering/util/GlStateCapture.java diff --git a/src/main/java/me/cortex/voxy/client/config/VoxyConfig.java b/src/main/java/me/cortex/voxy/client/config/VoxyConfig.java index 0f9f28f3..e2d9c13d 100644 --- a/src/main/java/me/cortex/voxy/client/config/VoxyConfig.java +++ b/src/main/java/me/cortex/voxy/client/config/VoxyConfig.java @@ -23,7 +23,7 @@ public class VoxyConfig { public int qualityScale = 20; public int maxSections = 200_000; public int geometryBufferSize = (1<<30)/8; - public int ingestThreads = 2; + public int ingestThreads = 5; public int savingThreads = 10; public int renderThreads = 5; public int savingCompressionLevel = 7; @@ -63,7 +63,7 @@ public class VoxyConfig { private static Path getConfigPath() { return FabricLoader.getInstance() .getConfigDir() - .resolve("zenith-config.json"); + .resolve("voxy-config.json"); } } diff --git a/src/main/java/me/cortex/voxy/client/core/VoxelCore.java b/src/main/java/me/cortex/voxy/client/core/VoxelCore.java index c7afd015..9f0b460a 100644 --- a/src/main/java/me/cortex/voxy/client/core/VoxelCore.java +++ b/src/main/java/me/cortex/voxy/client/core/VoxelCore.java @@ -127,8 +127,9 @@ public class VoxelCore { // occlusion culler this.renderer.renderFarAwayOpaque(matrices, cameraX, cameraY, cameraZ); + //Compute the SSAO of the rendered terrain - this.postProcessing.computeSSAO(); + this.postProcessing.computeSSAO(matrices); //We can render the translucent directly after as it is the furthest translucent objects this.renderer.renderFarAwayTranslucent(); diff --git a/src/main/java/me/cortex/voxy/client/core/gl/shader/Shader.java b/src/main/java/me/cortex/voxy/client/core/gl/shader/Shader.java index 3cb79d96..e88044f8 100644 --- a/src/main/java/me/cortex/voxy/client/core/gl/shader/Shader.java +++ b/src/main/java/me/cortex/voxy/client/core/gl/shader/Shader.java @@ -23,6 +23,10 @@ public class Shader extends TrackedObject { return new Builder((aa,source)->source); } + public int id() { + return this.id; + } + public void bind() { glUseProgram(this.id); } diff --git a/src/main/java/me/cortex/voxy/client/core/model/ModelManager.java b/src/main/java/me/cortex/voxy/client/core/model/ModelManager.java index 6c3e1cfb..35a55c94 100644 --- a/src/main/java/me/cortex/voxy/client/core/model/ModelManager.java +++ b/src/main/java/me/cortex/voxy/client/core/model/ModelManager.java @@ -266,7 +266,7 @@ public class ModelManager { int modelFlags = 0; modelFlags |= colourProvider != null?1:0; modelFlags |= hasBiomeColourResolver?2:0;//Basicly whether to use the next int as a colour or as a base index/id into a colour buffer for biome dependent colours - + modelFlags |= blockRenderLayer == RenderLayer.getTranslucent()?4:0; //modelFlags |= blockRenderLayer == RenderLayer.getSolid()?0:1;// should discard alpha MemoryUtil.memPutInt(uploadPtr, modelFlags); diff --git a/src/main/java/me/cortex/voxy/client/core/model/ModelTextureBakery.java b/src/main/java/me/cortex/voxy/client/core/model/ModelTextureBakery.java index 0f54c1a5..4a334d41 100644 --- a/src/main/java/me/cortex/voxy/client/core/model/ModelTextureBakery.java +++ b/src/main/java/me/cortex/voxy/client/core/model/ModelTextureBakery.java @@ -32,6 +32,8 @@ import java.util.ArrayList; import java.util.List; import static org.lwjgl.opengl.ARBFramebufferObject.*; +import static org.lwjgl.opengl.ARBImaging.GL_FUNC_ADD; +import static org.lwjgl.opengl.ARBImaging.glBlendEquation; import static org.lwjgl.opengl.ARBShaderImageLoadStore.GL_FRAMEBUFFER_BARRIER_BIT; import static org.lwjgl.opengl.ARBShaderImageLoadStore.glMemoryBarrier; import static org.lwjgl.opengl.GL11.*; @@ -127,6 +129,9 @@ public class ModelTextureBakery { RenderSystem.enableDepthTest(); RenderSystem.enableCull(); RenderSystem.depthFunc(GL_LESS); + + glBlendEquation(GL_FUNC_ADD);//TODO: reset this to the default + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); glStencilOp(GL_KEEP, GL_KEEP, GL_INCR); diff --git a/src/main/java/me/cortex/voxy/client/core/rendering/Gl46FarWorldRenderer.java b/src/main/java/me/cortex/voxy/client/core/rendering/Gl46FarWorldRenderer.java index 0269f741..27de4adc 100644 --- a/src/main/java/me/cortex/voxy/client/core/rendering/Gl46FarWorldRenderer.java +++ b/src/main/java/me/cortex/voxy/client/core/rendering/Gl46FarWorldRenderer.java @@ -106,6 +106,9 @@ public class Gl46FarWorldRenderer extends AbstractFarWorldRenderer { return; } + glDisable(GL_BLEND); + + //this.models.addEntry(0, Blocks.STONE.getDefaultState()); @@ -140,6 +143,7 @@ public class Gl46FarWorldRenderer extends AbstractFarWorldRenderer { glMemoryBarrier(GL_PIXEL_BUFFER_BARRIER_BIT | GL_FRAMEBUFFER_BARRIER_BIT); this.cullShader.bind(); + glColorMask(false, false, false, false); glDepthMask(false); diff --git a/src/main/java/me/cortex/voxy/client/core/rendering/post/PostProcessing.java b/src/main/java/me/cortex/voxy/client/core/rendering/post/PostProcessing.java index 69fd118d..5e1b6421 100644 --- a/src/main/java/me/cortex/voxy/client/core/rendering/post/PostProcessing.java +++ b/src/main/java/me/cortex/voxy/client/core/rendering/post/PostProcessing.java @@ -1,13 +1,27 @@ package me.cortex.voxy.client.core.rendering.post; +import com.mojang.blaze3d.systems.RenderSystem; import me.cortex.voxy.client.core.gl.GlFramebuffer; import me.cortex.voxy.client.core.gl.GlTexture; import me.cortex.voxy.client.core.gl.shader.Shader; import me.cortex.voxy.client.core.gl.shader.ShaderType; +import me.cortex.voxy.client.core.rendering.util.GlStateCapture; +import net.minecraft.client.util.math.MatrixStack; +import org.joml.Matrix4f; +import org.lwjgl.opengl.GL11C; +import static org.lwjgl.opengl.ARBComputeShader.glDispatchCompute; import static org.lwjgl.opengl.ARBFramebufferObject.*; +import static org.lwjgl.opengl.ARBShaderImageLoadStore.glBindImageTexture; import static org.lwjgl.opengl.GL11.*; import static org.lwjgl.opengl.GL13.*; +import static org.lwjgl.opengl.GL15.GL_READ_WRITE; +import static org.lwjgl.opengl.GL15C.GL_READ_ONLY; +import static org.lwjgl.opengl.GL20.glUniformMatrix4fv; +import static org.lwjgl.opengl.GL20C.glGetUniformLocation; +import static org.lwjgl.opengl.GL20C.glGetUniformfv; +import static org.lwjgl.opengl.GL30C.GL_R32F; +import static org.lwjgl.opengl.GL43.GL_DEPTH_STENCIL_TEXTURE_MODE; import static org.lwjgl.opengl.GL44C.glBindImageTextures; import static org.lwjgl.opengl.GL45C.glBlitNamedFramebuffer; @@ -20,6 +34,15 @@ public class PostProcessing { private final FullscreenBlit emptyBlit = new FullscreenBlit("voxy:post/noop.frag"); private final FullscreenBlit blitTexture = new FullscreenBlit("voxy:post/blit_texture_cutout.frag"); + private final Shader ssaoComp = Shader.make() + .add(ShaderType.COMPUTE, "voxy:post/ssao.comp") + .compile(); + private final GlStateCapture glStateCapture = GlStateCapture.make() + .addCapability(GL_STENCIL_TEST) + .addCapability(GL_DEPTH_TEST) + .addTexture(GL_TEXTURE0) + .addTexture(GL_TEXTURE1) + .build(); public PostProcessing() { this.framebuffer = new GlFramebuffer(); @@ -51,9 +74,12 @@ public class PostProcessing { if (this.depthStencil != null) this.depthStencil.free(); this.emptyBlit.delete(); this.blitTexture.delete(); + this.ssaoComp.free(); } public void setup(int width, int height, int sourceFB) { + this.glStateCapture.capture(); + this.setSize(width, height); glBindFramebuffer(GL_FRAMEBUFFER, this.framebuffer.id); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); @@ -95,17 +121,23 @@ public class PostProcessing { //Computes ssao on the current framebuffer data and updates it // this means that translucency wont be effected etc - public void computeSSAO() { + public void computeSSAO(MatrixStack stack) { + this.ssaoComp.bind(); + float[] data = new float[4*4]; + var mat = new Matrix4f(RenderSystem.getProjectionMatrix()).mul(stack.peek().getPositionMatrix()); + mat.get(data); + glUniformMatrix4fv(2, false, data);//MVP + mat.invert(); + mat.get(data); + glUniformMatrix4fv(3, false, data);//invMVP - //this.ssao.bind(); - //glActiveTexture(GL_TEXTURE1); - //glBindTexture(GL_TEXTURE_2D, this.depthStencil.id); - //glBindImageTexture(0, this.colour.id, 0, false,0, GL_READ_WRITE, GL_RGBA8); - ////glDispatchCompute(this.width/32, this.height/32, 1); - //glTextureBarrier(); - //glActiveTexture(GL_TEXTURE0); - //glBindTexture(GL_TEXTURE_2D, this.colour.id); - //glDrawArrays(GL11C.GL_TRIANGLES, 0, 3); + glBindImageTexture(0, this.colour.id, 0, false,0, GL_READ_WRITE, GL_RGBA8); + //glBindImageTexture(1, this.depthStencil.id, 0, false,0, GL_READ_ONLY, GL_R32F); + glActiveTexture(GL_TEXTURE1); + GL11C.glBindTexture(GL_TEXTURE_2D, this.depthStencil.id); + glTexParameteri (GL_TEXTURE_2D, GL_DEPTH_STENCIL_TEXTURE_MODE, GL_DEPTH_COMPONENT); + + glDispatchCompute((this.width+31)/32, (this.height+31)/32, 1); } @@ -122,16 +154,14 @@ public class PostProcessing { - int oldActiveTexture = glGetInteger(GL_ACTIVE_TEXTURE); glActiveTexture(GL_TEXTURE0); - int oldBoundTexture = glGetInteger(GL_TEXTURE_BINDING_2D); glBindTexture(GL_TEXTURE_2D, this.colour.id); glEnable(GL_DEPTH_TEST); glDepthMask(false); this.blitTexture.blit(); glDisable(GL_DEPTH_TEST); glDepthMask(true); - glBindTexture(GL_TEXTURE_2D, oldBoundTexture); - glActiveTexture(oldActiveTexture); + + this.glStateCapture.restore(); } } diff --git a/src/main/java/me/cortex/voxy/client/core/rendering/util/GlStateCapture.java b/src/main/java/me/cortex/voxy/client/core/rendering/util/GlStateCapture.java new file mode 100644 index 00000000..e0803d37 --- /dev/null +++ b/src/main/java/me/cortex/voxy/client/core/rendering/util/GlStateCapture.java @@ -0,0 +1,84 @@ +package me.cortex.voxy.client.core.rendering.util; + +import it.unimi.dsi.fastutil.ints.IntArrayList; + +import static org.lwjgl.opengl.GL11.*; +import static org.lwjgl.opengl.GL13.GL_ACTIVE_TEXTURE; +import static org.lwjgl.opengl.GL13.glActiveTexture; + +public class GlStateCapture { + private final int[] capabilityIds; + private final boolean[] enabledCaps; + + + private final int[] textureUnits; + private final int[] textures; + private GlStateCapture(int[] caps, int[] textureUnits) { + this.capabilityIds = caps; + this.enabledCaps = new boolean[caps.length]; + + this.textureUnits = textureUnits; + this.textures = new int[textureUnits.length]; + } + + public void capture() { + this.textureUnits[0] = glGetInteger(GL_ACTIVE_TEXTURE); + //Capture all the texture data + for (int i = 0; i < this.textures.length; i++) { + glActiveTexture(this.textureUnits[i]); + this.textures[i] = glGetInteger(GL_TEXTURE_BINDING_2D); + } + //Reset the original active texture + glActiveTexture(this.textureUnits[0]); + + for (int i = 0; i < this.capabilityIds.length; i++) { + this.enabledCaps[i] = glIsEnabled(this.capabilityIds[i]); + } + } + + public void restore() { + //Capture all the texture data + for (int i = 1; i < this.textures.length; i++) { + glActiveTexture(this.textureUnits[i]); + glBindTexture(GL_TEXTURE_2D, this.textures[i]); + } + //Reset the original active texture + glActiveTexture(this.textureUnits[0]); + glBindTexture(GL_TEXTURE_2D, this.textures[0]); + + for (int i = 0; i < this.capabilityIds.length; i++) { + if (this.enabledCaps[i]) { + glEnable(this.capabilityIds[i]); + } else { + glDisable(this.capabilityIds[i]); + } + } + } + + public static Builder make() { + return new Builder(); + } + + public static class Builder { + private final IntArrayList caps = new IntArrayList(); + private final IntArrayList textures = new IntArrayList(); + + private Builder() { + this.addTexture(-1);//Special texture unit, used to capture the current texture unit + } + + public Builder addCapability(int cap) { + this.caps.add(cap); + return this; + } + + public Builder addTexture(int unit) { + this.textures.add(unit); + return this; + } + + public GlStateCapture build() { + return new GlStateCapture(this.caps.toIntArray(), this.textures.toIntArray()); + } + } +} diff --git a/src/main/java/me/cortex/voxy/client/mixin/minecraft/MixinGameRenderer.java b/src/main/java/me/cortex/voxy/client/mixin/minecraft/MixinGameRenderer.java index 33eb33b3..94f15a37 100644 --- a/src/main/java/me/cortex/voxy/client/mixin/minecraft/MixinGameRenderer.java +++ b/src/main/java/me/cortex/voxy/client/mixin/minecraft/MixinGameRenderer.java @@ -3,7 +3,9 @@ package me.cortex.voxy.client.mixin.minecraft; import net.minecraft.client.render.GameRenderer; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Constant; import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.ModifyConstant; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; @Mixin(GameRenderer.class) @@ -13,4 +15,9 @@ public class MixinGameRenderer { cir.setReturnValue(16 * 3000f); cir.cancel(); } + + @ModifyConstant(method = "getBasicProjectionMatrix", constant = @Constant(floatValue = 0.05F)) + public float modifyNearplane(float constant) { + return 10; + } } \ No newline at end of file diff --git a/src/main/resources/assets/voxy/shaders/lod/gl46/block_model.glsl b/src/main/resources/assets/voxy/shaders/lod/gl46/block_model.glsl index ac1cc3c0..c12397fc 100644 --- a/src/main/resources/assets/voxy/shaders/lod/gl46/block_model.glsl +++ b/src/main/resources/assets/voxy/shaders/lod/gl46/block_model.glsl @@ -18,4 +18,8 @@ uint faceHasAlphaCuttoutOverride(uint faceData) { bool modelHasBiomeLUT(BlockModel model) { return ((model.flagsA)&2) != 0; +} + +bool modelIsTranslucent(BlockModel model) { + return ((model.flagsA)&4) != 0; } \ No newline at end of file diff --git a/src/main/resources/assets/voxy/shaders/lod/gl46/cull/raster.frag b/src/main/resources/assets/voxy/shaders/lod/gl46/cull/raster.frag index 7d3d4745..32f5d59e 100644 --- a/src/main/resources/assets/voxy/shaders/lod/gl46/cull/raster.frag +++ b/src/main/resources/assets/voxy/shaders/lod/gl46/cull/raster.frag @@ -6,9 +6,9 @@ layout(early_fragment_tests) in; flat in uint id; flat in uint value; -//out vec4 colour; +out vec4 colour; void main() { visibilityData[id] = value; - //colour = vec4(float(id&7)/7, float((id>>3)&7)/7, float((id>>6)&7)/7, 1); + colour = vec4(float(id&7)/7, float((id>>3)&7)/7, float((id>>6)&7)/7, 1); } \ No newline at end of file diff --git a/src/main/resources/assets/voxy/shaders/lod/gl46/cull/raster.vert b/src/main/resources/assets/voxy/shaders/lod/gl46/cull/raster.vert index 8c8936b5..afa2877c 100644 --- a/src/main/resources/assets/voxy/shaders/lod/gl46/cull/raster.vert +++ b/src/main/resources/assets/voxy/shaders/lod/gl46/cull/raster.vert @@ -19,8 +19,7 @@ void main() { //Transform ipos with respect to the vertex corner ivec3 pos = (((ipos<>2)&1, (gl_VertexID>>1)&1)*(size+2))*(1<>29; @@ -93,20 +94,25 @@ void main() { discardAlpha |= uint(any(greaterThan(quadSize, ivec2(1)))) & faceHasAlphaCuttoutOverride(faceData); //Compute lighting - colourTinting = getLighting(extractLightId(quad)); + tinting = getLighting(extractLightId(quad)); //Apply model colour tinting uint tintColour = model.colourTint; if (modelHasBiomeLUT(model)) { tintColour = colourData[tintColour + extractBiomeId(quad)]; } - colourTinting *= uint2vec4RGBA(tintColour).yzwx; + tinting *= uint2vec4RGBA(tintColour).yzwx; + addin = vec4(0); + if (!modelIsTranslucent(model)) { + tinting.w = 0; + addin.w = float(face|(lodLevel<<3))/255; + } //Apply face tint if (face == 0) { - colourTinting.xyz *= vec3(0.75, 0.75, 0.75); + tinting.xyz *= vec3(0.75, 0.75, 0.75); } else if (face != 1) { - colourTinting.xyz *= vec3((float(face-2)/4)*0.6 + 0.4); + tinting.xyz *= vec3((float(face-2)/4)*0.7 + 0.3); } diff --git a/src/main/resources/assets/voxy/shaders/post/ssao.comp b/src/main/resources/assets/voxy/shaders/post/ssao.comp index e69de29b..0917f1f4 100644 --- a/src/main/resources/assets/voxy/shaders/post/ssao.comp +++ b/src/main/resources/assets/voxy/shaders/post/ssao.comp @@ -0,0 +1,89 @@ +#version 460 +#extension GL_NV_compute_shader_derivatives : require +layout(local_size_x = 32, local_size_y = 32, local_size_x = 1) in; + + +layout(binding = 0, rgba8) uniform restrict image2D colourTex; +layout(binding = 1) uniform sampler2D depthTex; +layout(location = 2) uniform mat4 MVP; +layout(location = 3) uniform mat4 invMVP; + +vec3 rev3d(vec3 clip) { + vec4 view = invMVP * vec4(clip*2-1,1); + return view.xyz/view.w; +} + +vec3 proj3dscreen(vec3 pos) { + vec4 view = MVP * vec4(pos, 1); + view.xyz /= view.w; + return view.xyz * 0.5 + 0.5; +} + +vec3 reDeProject(vec3 pos) { + vec4 view = MVP * vec4(pos, 1); + view.xy /= view.w; + view.z = texture(depthTex, clamp(view.xy*0.5+0.5, 0, 1)).x*2-1; + view.w = 1; + view = invMVP * view; + return view.xyz/view.w; +} + +vec3 reDeProjectContained(vec3 pos) { + vec4 view = MVP * vec4(pos, 1); + view.xy /= view.w; + float depth = texture(depthTex, clamp(view.xy*0.5+0.5, 0, 1)).x*2-1; + view.z = min(view.z, depth); + view.w = 1; + view = invMVP * view; + return view.xyz/view.w; +} + +vec3 computeDifference(vec3 pos, vec3 offset) { + return reDeProject(pos + offset) - pos - offset; +} + +float computeAngleDifference(vec3 pos, vec3 offset) { + vec3 repro = reDeProject(pos + offset) - pos; + return dot(repro, offset)/(length(repro) * length(offset)); +} + +float computeAOAngle(vec3 pos, float testHeight, vec3 normal) { + vec3 repro = reDeProject(pos + normal*testHeight) - pos; + float len = length(repro); + return dot(repro, normal)/len; +} + +void main() { + ivec2 size = imageSize(colourTex);//TODO: dont use imageSize as it is slow, swap for uniform + vec2 point = vec2(gl_GlobalInvocationID.xy)/size; + float depth = texture(depthTex, point).r; + if (depth == 1.0f || any(lessThanEqual(size, gl_GlobalInvocationID.xy))) { + return; + } + vec4 colour = imageLoad(colourTex, ivec2(gl_GlobalInvocationID.xy)); + uint metadata = uint(colour.w*255); + uint face = metadata&7; + uint lod = (metadata>>3)&7; + vec3 pos = rev3d(vec3(point, depth)); + + //TODO: TODO: only encode the axis, then use then it as as a mask along with pos and multiply by the -sign of everything + vec3 viewNormal = vec3(uint((face>>1)==2), uint((face>>1)==0), uint((face>>1)==1)) * (float(int(face)&1)*2-1);//normalize(cross(dFdx(pos), dFdy(pos))); + //vec3 viewNormal = vec3(uint((face>>1)==2), uint((face>>1)==0), uint((face>>1)==1)) * (-sign(pos));//normalize(cross(dFdx(pos), dFdy(pos))); + + + float d = computeAOAngle(pos, 0.75*(1<