SSAO works

This commit is contained in:
mcrcortex
2024-02-01 22:47:05 +10:00
parent f0bf39b848
commit ebe2fcc752
15 changed files with 266 additions and 33 deletions

View File

@@ -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");
}
}

View File

@@ -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();

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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();
}
}

View File

@@ -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());
}
}
}

View File

@@ -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;
}
}

View File

@@ -19,3 +19,7 @@ uint faceHasAlphaCuttoutOverride(uint faceData) {
bool modelHasBiomeLUT(BlockModel model) {
return ((model.flagsA)&2) != 0;
}
bool modelIsTranslucent(BlockModel model) {
return ((model.flagsA)&4) != 0;
}

View File

@@ -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);
}

View File

@@ -19,8 +19,7 @@ void main() {
//Transform ipos with respect to the vertex corner
ivec3 pos = (((ipos<<detail)-baseSectionPos)<<5);
pos += aabbOffset;
pos -= (1<<detail);
pos += (aabbOffset-1)*(1<<detail);
pos += (ivec3(gl_VertexID&1, (gl_VertexID>>2)&1, (gl_VertexID>>1)&1)*(size+2))*(1<<detail);
gl_Position = MVP * vec4(vec3(pos),1);

View File

@@ -6,17 +6,17 @@ layout(binding = 0) uniform sampler2D blockModelAtlas;
layout(location = 0) in vec2 uv;
layout(location = 1) in flat vec2 baseUV;
layout(location = 2) in flat vec4 colourTinting;
layout(location = 3) in flat uint discardAlpha;
layout(location = 2) in flat vec4 tinting;
layout(location = 3) in flat vec4 addin;
layout(location = 4) in flat uint flags;
layout(location = 0) out vec4 outColour;
void main() {
vec2 uv = mod(uv, vec2(1))*(1f/(vec2(3,2)*256f));
vec4 colour = texture(blockModelAtlas, uv + baseUV);
if (discardAlpha == 1 && colour.a <= 0.25f) {
if ((flags&1) == 1 && colour.a <= 0.25f) {
discard;
}
outColour = colour * colourTinting;
outColour = (colour * tinting) + addin;
//outColour = vec4(uv + baseUV, 0, 1);
}

View File

@@ -8,8 +8,9 @@
layout(location = 0) out vec2 uv;
layout(location = 1) out flat vec2 baseUV;
layout(location = 2) out flat vec4 colourTinting;
layout(location = 3) out flat uint discardAlpha;
layout(location = 2) out flat vec4 tinting;
layout(location = 3) out flat vec4 addin;
layout(location = 4) out flat uint discardAlpha;
uint extractLodLevel() {
return uint(gl_BaseInstance)>>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);
}

View File

@@ -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<<lod), viewNormal);//1
//if (any(lessThan(ivec3(4), abs(repro-offset)))) {// || all(lessThan(abs(repro-offset), ivec3(0.01)))
//return;
//}
if (d<0.1) {
return;
}
//vec4 ocolour = vec4(max(0, d), abs(min(0,d)), 0, 1);
//vec4 ocolour = vec4(repro-(viewNormal/2), 1);
//vec4 ocolour = vec4(viewNormal/2+0.5, 1);
vec4 ocolour = colour;
ocolour.xyz *= ((1-d)/2+0.5);
ocolour.w = 1;
imageStore(colourTex, ivec2(gl_GlobalInvocationID.xy), ocolour);
}