From b85681573bf85bb2b0a691a50df0b016cd1cc3d8 Mon Sep 17 00:00:00 2001
From: IntegratedQuantum <jahe788@gmail.com>
Date: Fri, 6 Dec 2024 21:47:12 +0100
Subject: [PATCH] Fog with ARB_fragment_shader_interlock: quick and dirty
 prototype

a prototype of #817
---
 .../bloom/color_extractor_downsample.fs       |  4 +--
 .../shaders/chunks/transparent_fragment.fs    | 22 ++++++++----
 assets/cubyz/shaders/deferred_render_pass.fs  |  4 +--
 assets/cubyz/shaders/depth_copy.fs            | 16 +++++++++
 assets/cubyz/shaders/depth_copy.vs            | 10 ++++++
 src/graphics.zig                              |  4 +++
 src/renderer.zig                              | 34 +++++++++++++++++--
 7 files changed, 81 insertions(+), 13 deletions(-)
 create mode 100644 assets/cubyz/shaders/depth_copy.fs
 create mode 100644 assets/cubyz/shaders/depth_copy.vs

diff --git a/assets/cubyz/shaders/bloom/color_extractor_downsample.fs b/assets/cubyz/shaders/bloom/color_extractor_downsample.fs
index 122a7e80b..d7e82c7f8 100644
--- a/assets/cubyz/shaders/bloom/color_extractor_downsample.fs
+++ b/assets/cubyz/shaders/bloom/color_extractor_downsample.fs
@@ -44,7 +44,7 @@ float calculateFogDistance(float depthBufferValue, float fogDensity) {
 }
 
 vec3 applyFrontfaceFog(float fogDistance, vec3 fogColor, vec3 inColor) {
-	float fogFactor = exp(fogDistance);
+	float fogFactor = exp(-fogDistance);
 	inColor *= fogFactor;
 	inColor += fogColor;
 	inColor -= fogColor*fogFactor;
@@ -54,7 +54,7 @@ vec3 applyFrontfaceFog(float fogDistance, vec3 fogColor, vec3 inColor) {
 vec3 fetch(ivec2 pos) {
 	vec4 rgba = texelFetch(color, pos, 0);
 	float densityAdjustment = sqrt(dot(tanXY*(normalizedTexCoords*2 - 1), tanXY*(normalizedTexCoords*2 - 1)) + 1);
-	float fogDistance = calculateFogDistance(texelFetch(depthTexture, pos, 0).r, fog.density*densityAdjustment);
+	float fogDistance = texelFetch(depthTexture, pos, 0).r*fog.density*densityAdjustment;
 	vec3 fogColor = fog.color;
 	rgba.rgb = applyFrontfaceFog(fogDistance, fog.color, rgba.rgb);
 	return rgba.rgb/rgba.a;
diff --git a/assets/cubyz/shaders/chunks/transparent_fragment.fs b/assets/cubyz/shaders/chunks/transparent_fragment.fs
index d398b74b7..ccc8acb70 100644
--- a/assets/cubyz/shaders/chunks/transparent_fragment.fs
+++ b/assets/cubyz/shaders/chunks/transparent_fragment.fs
@@ -1,5 +1,9 @@
 #version 430
 
+#extension GL_ARB_fragment_shader_interlock : require
+layout(sample_interlock_ordered) in;
+layout(early_fragment_tests) in;
+
 in vec3 mvVertexPos;
 in vec3 direction;
 in vec3 light;
@@ -16,7 +20,7 @@ uniform samplerCube reflectionMap;
 uniform float reflectionMapSize;
 uniform float contrast;
 
-layout(binding = 5) uniform sampler2D depthTexture;
+layout(binding = 5, r16f) coherent uniform image2D depthTexture;
 
 layout (location = 0, index = 0) out vec4 fragColor;
 layout (location = 0, index = 1) out vec4 blendColor;
@@ -91,9 +95,9 @@ void applyFrontfaceFog(float fogDistance, vec3 fogColor) {
 }
 
 void applyBackfaceFog(float fogDistance, vec3 fogColor) {
-	float fogFactor = exp(-fogDistance);
-	fragColor.rgb = fragColor.rgb*fogFactor + fogColor*(1 - fogFactor);
-	fragColor.a *= fogFactor;
+	//float fogFactor = exp(-fogDistance);
+	//fragColor.rgb = fragColor.rgb*fogFactor + fogColor*(1 - fogFactor);
+	//fragColor.a *= fogFactor;
 }
 
 vec4 fixedCubeMapLookup(vec3 v) { // Taken from http://the-witness.net/news/2012/02/seamless-cube-map-filtering/
@@ -106,13 +110,17 @@ vec4 fixedCubeMapLookup(vec3 v) { // Taken from http://the-witness.net/news/2012
 }
 
 void main() {
+	beginInvocationInterlockARB();
+	float prevDepth = imageLoad(depthTexture, ivec2(gl_FragCoord.xy)).r;
+	imageStore(depthTexture, ivec2(gl_FragCoord.xy), vec4(abs(mvVertexPos.y), 0, 0, 0));
+	endInvocationInterlockARB();
 	float animatedTextureIndex = animatedTexture[textureIndex];
 	vec3 textureCoords = vec3(uv, animatedTextureIndex);
 	float normalVariation = lightVariation(normal);
 	float densityAdjustment = sqrt(dot(mvVertexPos, mvVertexPos))/abs(mvVertexPos.y);
-	float dist = zFromDepth(texelFetch(depthTexture, ivec2(gl_FragCoord.xy), 0).r);
-	float fogDistance = calculateFogDistance(dist, fogData[int(animatedTextureIndex)].fogDensity*densityAdjustment);
-	float airFogDistance = calculateFogDistance(dist, fog.density*densityAdjustment);
+	float dist = abs(mvVertexPos.y) - prevDepth;//zFromDepth(texelFetch(depthTexture1, ivec2(gl_FragCoord.xy), 0).r);
+	float fogDistance = dist*fogData[int(animatedTextureIndex)].fogDensity*densityAdjustment;
+	float airFogDistance = dist*fog.density*densityAdjustment;
 	vec3 fogColor = unpackColor(fogData[int(animatedTextureIndex)].fogColor);
 	vec3 pixelLight = max(light*normalVariation, texture(emissionSampler, textureCoords).r*4);
 	vec4 textureColor = texture(texture_sampler, textureCoords)*vec4(pixelLight, 1);
diff --git a/assets/cubyz/shaders/deferred_render_pass.fs b/assets/cubyz/shaders/deferred_render_pass.fs
index 6441f5c66..585f8c8c5 100644
--- a/assets/cubyz/shaders/deferred_render_pass.fs
+++ b/assets/cubyz/shaders/deferred_render_pass.fs
@@ -43,7 +43,7 @@ float calculateFogDistance(float depthBufferValue, float fogDensity) {
 }
 
 vec3 applyFrontfaceFog(float fogDistance, vec3 fogColor, vec3 inColor) {
-	float fogFactor = exp(fogDistance);
+	float fogFactor = exp(-fogDistance);
 	inColor *= fogFactor;
 	inColor += fogColor;
 	inColor -= fogColor*fogFactor;
@@ -54,7 +54,7 @@ void main() {
 	fragColor = texture(color, texCoords);
 	fragColor += texture(bloomColor, texCoords);
 	float densityAdjustment = sqrt(dot(tanXY*(texCoords*2 - 1), tanXY*(texCoords*2 - 1)) + 1);
-	float fogDistance = calculateFogDistance(texture(depthTexture, texCoords).r, fog.density*densityAdjustment);
+	float fogDistance = texture(depthTexture, texCoords).r*fog.density*densityAdjustment;
 	fragColor.rgb = applyFrontfaceFog(fogDistance, fog.color, fragColor.rgb);
 	float maxColor = max(1.0, max(fragColor.r, max(fragColor.g, fragColor.b)));
 	fragColor.rgb = fragColor.rgb/maxColor;
diff --git a/assets/cubyz/shaders/depth_copy.fs b/assets/cubyz/shaders/depth_copy.fs
new file mode 100644
index 000000000..3f9da977d
--- /dev/null
+++ b/assets/cubyz/shaders/depth_copy.fs
@@ -0,0 +1,16 @@
+#version 430
+out vec4 fragColor;
+in vec2 texCoords;
+
+uniform float zNear;
+uniform float zFar;
+
+layout(binding = 5) uniform sampler2D depthBuffer;
+
+float zFromDepth(float depthBufferValue) {
+	return zNear*zFar/(depthBufferValue*(zNear - zFar) + zFar);
+}
+
+void main() {
+	fragColor.r = zFromDepth(texture(depthBuffer, texCoords).r);
+}
\ No newline at end of file
diff --git a/assets/cubyz/shaders/depth_copy.vs b/assets/cubyz/shaders/depth_copy.vs
new file mode 100644
index 000000000..ef5ed4080
--- /dev/null
+++ b/assets/cubyz/shaders/depth_copy.vs
@@ -0,0 +1,10 @@
+#version 430
+
+layout (location=0)  in vec2 inTexCoords;
+
+out vec2 texCoords;
+
+void main() {
+	texCoords = inTexCoords;
+	gl_Position = vec4(inTexCoords*2 - vec2(1, 1), 0, 1);
+}
\ No newline at end of file
diff --git a/src/graphics.zig b/src/graphics.zig
index 2f6846ada..e6a0e9121 100644
--- a/src/graphics.zig
+++ b/src/graphics.zig
@@ -1565,6 +1565,10 @@ pub const FrameBuffer = struct { // MARK: FrameBuffer
 		c.glBindTexture(c.GL_TEXTURE_2D, self.texture);
 	}
 
+	pub fn bindImage(self: *const FrameBuffer, binding: u5, format: c_uint) void {
+		c.glBindImageTexture(binding, self.texture, 0, c.GL_FALSE, 0, c.GL_READ_WRITE, format);
+	}
+
 	pub fn bindDepthTexture(self: *const FrameBuffer, target: c_uint) void {
 		std.debug.assert(self.hasDepthTexture);
 		c.glActiveTexture(target);
diff --git a/src/renderer.zig b/src/renderer.zig
index a03568c9f..d47c696a1 100644
--- a/src/renderer.zig
+++ b/src/renderer.zig
@@ -43,6 +43,11 @@ var deferredUniforms: struct {
 	zNear: c_int,
 	zFar: c_int,
 } = undefined;
+var depthCopyShader: graphics.Shader = undefined;
+var depthCopyUniforms: struct {
+	zNear: c_int,
+	zFar: c_int,
+} = undefined;
 var fakeReflectionShader: graphics.Shader = undefined;
 var fakeReflectionUniforms: struct {
 	normalVector: c_int,
@@ -60,8 +65,11 @@ var reflectionCubeMap: graphics.CubeMapTexture = undefined;
 pub fn init() void {
 	deferredRenderPassShader = Shader.initAndGetUniforms("assets/cubyz/shaders/deferred_render_pass.vs", "assets/cubyz/shaders/deferred_render_pass.fs", "", &deferredUniforms);
 	fakeReflectionShader = Shader.initAndGetUniforms("assets/cubyz/shaders/fake_reflection.vs", "assets/cubyz/shaders/fake_reflection.fs", "", &fakeReflectionUniforms);
+	depthCopyShader = Shader.initAndGetUniforms("assets/cubyz/shaders/depth_copy.vs", "assets/cubyz/shaders/depth_copy.fs", "", &depthCopyUniforms);
 	worldFrameBuffer.init(true, c.GL_NEAREST, c.GL_CLAMP_TO_EDGE);
 	worldFrameBuffer.updateSize(Window.width, Window.height, c.GL_RGB16F);
+	transparentDepthFrameBuffer.init(false, c.GL_NEAREST, c.GL_CLAMP_TO_EDGE);
+	transparentDepthFrameBuffer.updateSize(Window.width, Window.height, c.GL_R16F);
 	Bloom.init();
 	MeshSelection.init();
 	MenuBackGround.init() catch |err| {
@@ -78,6 +86,7 @@ pub fn deinit() void {
 	deferredRenderPassShader.deinit();
 	fakeReflectionShader.deinit();
 	worldFrameBuffer.deinit();
+	transparentDepthFrameBuffer.deinit();
 	Bloom.deinit();
 	MeshSelection.deinit();
 	MenuBackGround.deinit();
@@ -108,6 +117,7 @@ fn initReflectionCubeMap() void {
 }
 
 var worldFrameBuffer: graphics.FrameBuffer = undefined;
+var transparentDepthFrameBuffer: graphics.FrameBuffer = undefined;
 
 var lastWidth: u31 = 0;
 var lastHeight: u31 = 0;
@@ -119,6 +129,8 @@ pub fn updateViewport(width: u31, height: u31, fov: f32) void {
 	game.projectionMatrix = Mat4f.perspective(std.math.degreesToRadians(fov), @as(f32, @floatFromInt(lastWidth))/@as(f32, @floatFromInt(lastHeight)), zNear, zFar);
 	worldFrameBuffer.updateSize(lastWidth, lastHeight, c.GL_RGB16F);
 	worldFrameBuffer.unbind();
+	transparentDepthFrameBuffer.updateSize(lastWidth, lastHeight, c.GL_R16F);
+	transparentDepthFrameBuffer.unbind();
 }
 
 pub fn render(playerPosition: Vec3d) void {
@@ -221,9 +233,27 @@ pub fn renderWorld(world: *World, ambientLight: Vec3f, skyColor: Vec3f, playerPo
 	gpu_performance_measuring.stopQuery();
 
 	// Render transparent chunk meshes:
-	worldFrameBuffer.bindDepthTexture(c.GL_TEXTURE5);
+
 
 	gpu_performance_measuring.startQuery(.transparent_rendering_preparation);
+
+	worldFrameBuffer.bindDepthTexture(c.GL_TEXTURE5);
+	c.glTextureBarrier();
+	transparentDepthFrameBuffer.bind();
+	depthCopyShader.bind();
+	c.glUniform1f(depthCopyUniforms.zNear, zNear);
+	c.glUniform1f(depthCopyUniforms.zFar, zFar);
+	c.glDisable(c.GL_DEPTH_TEST);
+	c.glDisable(c.GL_CULL_FACE);
+	c.glDisable(c.GL_BLEND);
+	c.glBindVertexArray(graphics.draw.rectVAO);
+	c.glDrawArrays(c.GL_TRIANGLE_STRIP, 0, 4);
+	c.glEnable(c.GL_BLEND);
+	c.glEnable(c.GL_DEPTH_TEST);
+	c.glEnable(c.GL_CULL_FACE);
+	worldFrameBuffer.bind();
+	transparentDepthFrameBuffer.bindImage(5, c.GL_R16F);
+	c.glMemoryBarrier(c.GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
 	c.glTextureBarrier();
 
 	c.glBlendEquation(c.GL_FUNC_ADD);
@@ -260,7 +290,7 @@ pub fn renderWorld(world: *World, ambientLight: Vec3f, skyColor: Vec3f, playerPo
 	gpu_performance_measuring.startQuery(.final_copy);
 	if(activeFrameBuffer == 0) c.glViewport(0, 0, main.Window.width, main.Window.height);
 	worldFrameBuffer.bindTexture(c.GL_TEXTURE3);
-	worldFrameBuffer.bindDepthTexture(c.GL_TEXTURE4);
+	transparentDepthFrameBuffer.bindTexture(c.GL_TEXTURE4);
 	worldFrameBuffer.unbind();
 	deferredRenderPassShader.bind();
 	c.glUniform1i(deferredUniforms.color, 3);