Add support for vanilla enviromental fog

This commit is contained in:
mcrcortex
2025-06-23 00:51:54 +10:00
parent cf60d31b75
commit 7fa07ae5ea
12 changed files with 70 additions and 18 deletions

View File

@@ -19,13 +19,13 @@ public class VoxyClient implements ClientModInitializer {
@Override @Override
public void onInitializeClient() { public void onInitializeClient() {
ClientLifecycleEvents.CLIENT_STARTED.register(client->{ ClientLifecycleEvents.CLIENT_STARTED.register(client->{
BudgetBufferRenderer.init();
boolean systemSupported = Capabilities.INSTANCE.compute && Capabilities.INSTANCE.indirectParameters; boolean systemSupported = Capabilities.INSTANCE.compute && Capabilities.INSTANCE.indirectParameters;
if (systemSupported) { if (systemSupported) {
VoxyCommon.setInstanceFactory(VoxyClientInstance::new); VoxyCommon.setInstanceFactory(VoxyClientInstance::new);
} else { } else {
Logger.error("Voxy is unsupported on your system."); Logger.error("Voxy is unsupported on your system.");
} }
BudgetBufferRenderer.init();
}); });

View File

@@ -31,6 +31,7 @@ public class VoxyConfig implements OptionStorage<VoxyConfig> {
public int serviceThreads = (int) Math.max(CpuLayout.CORES.length/1.5, 1); public int serviceThreads = (int) Math.max(CpuLayout.CORES.length/1.5, 1);
public float subDivisionSize = 64; public float subDivisionSize = 64;
public boolean renderVanillaFog = false; public boolean renderVanillaFog = false;
public boolean useEnvironmentalFog = false;
public boolean renderStatistics = false; public boolean renderStatistics = false;
public static VoxyConfig loadOrCreate() { public static VoxyConfig loadOrCreate() {

View File

@@ -129,6 +129,14 @@ public abstract class VoxyConfigScreenPages {
}, s -> s.sectionRenderDistance) }, s -> s.sectionRenderDistance)
.setImpact(OptionImpact.LOW) .setImpact(OptionImpact.LOW)
.build() .build()
).add(OptionImpl.createBuilder(boolean.class, storage)
.setName(Text.translatable("voxy.config.general.environmental_fog"))
.setTooltip(Text.translatable("voxy.config.general.environmental_fog.tooltip"))
.setControl(TickBoxControl::new)
.setImpact(OptionImpact.VARIES)
.setBinding((s, v)-> s.useEnvironmentalFog = v, s -> s.useEnvironmentalFog)
.setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD)
.build()
).add(OptionImpl.createBuilder(boolean.class, storage) ).add(OptionImpl.createBuilder(boolean.class, storage)
.setName(Text.translatable("voxy.config.general.vanilla_fog")) .setName(Text.translatable("voxy.config.general.vanilla_fog"))
.setTooltip(Text.translatable("voxy.config.general.vanilla_fog.tooltip")) .setTooltip(Text.translatable("voxy.config.general.vanilla_fog.tooltip"))

View File

@@ -21,6 +21,7 @@ import me.cortex.voxy.common.Logger;
import me.cortex.voxy.common.thread.ServiceThreadPool; import me.cortex.voxy.common.thread.ServiceThreadPool;
import me.cortex.voxy.common.world.WorldEngine; import me.cortex.voxy.common.world.WorldEngine;
import net.caffeinemc.mods.sodium.client.render.chunk.ChunkRenderMatrices; import net.caffeinemc.mods.sodium.client.render.chunk.ChunkRenderMatrices;
import net.caffeinemc.mods.sodium.client.util.FogParameters;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.render.Camera; import net.minecraft.client.render.Camera;
import net.minecraft.client.render.Frustum; import net.minecraft.client.render.Frustum;
@@ -127,7 +128,7 @@ public class VoxyRenderSystem {
).mulLocal(makeProjectionMatrix(16, 16*3000)); ).mulLocal(makeProjectionMatrix(16, 16*3000));
} }
public void renderOpaque(ChunkRenderMatrices matrices, double cameraX, double cameraY, double cameraZ) { public void renderOpaque(ChunkRenderMatrices matrices, FogParameters fogParameters, double cameraX, double cameraY, double cameraZ) {
if (IrisUtil.irisShadowActive()) { if (IrisUtil.irisShadowActive()) {
return; return;
} }
@@ -164,11 +165,13 @@ public class VoxyRenderSystem {
int[] dims = new int[4]; int[] dims = new int[4];
glGetIntegerv(GL_VIEWPORT, dims); glGetIntegerv(GL_VIEWPORT, dims);
var viewport = this.renderer.getViewport(); var viewport = this.renderer.getViewport();
viewport viewport
.setProjection(projection) .setProjection(projection)
.setModelView(new Matrix4f(matrices.modelView())) .setModelView(new Matrix4f(matrices.modelView()))
.setCamera(cameraX, cameraY, cameraZ) .setCamera(cameraX, cameraY, cameraZ)
.setScreenSize(dims[2], dims[3]) .setScreenSize(dims[2], dims[3])
.setFogParameters(fogParameters)
.update(); .update();
viewport.frameId++; viewport.frameId++;
@@ -195,7 +198,7 @@ public class VoxyRenderSystem {
TimingStatistics.F.start(); TimingStatistics.F.start();
this.postProcessing.renderPost(projection, matrices.projection(), boundFB); this.postProcessing.renderPost(viewport, matrices.projection(), boundFB);
TimingStatistics.F.stop(); TimingStatistics.F.stop();
TimingStatistics.main.stop(); TimingStatistics.main.stop();

View File

@@ -2,6 +2,7 @@ package me.cortex.voxy.client.core.rendering;
import me.cortex.voxy.client.core.gl.GlBuffer; import me.cortex.voxy.client.core.gl.GlBuffer;
import me.cortex.voxy.client.core.rendering.util.HiZBuffer; import me.cortex.voxy.client.core.rendering.util.HiZBuffer;
import net.caffeinemc.mods.sodium.client.util.FogParameters;
import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.MathHelper;
import org.joml.*; import org.joml.*;
@@ -29,6 +30,7 @@ public abstract class Viewport <A extends Viewport<A>> {
public double cameraX; public double cameraX;
public double cameraY; public double cameraY;
public double cameraZ; public double cameraZ;
public FogParameters fogParameters;
public final Matrix4f MVP = new Matrix4f(); public final Matrix4f MVP = new Matrix4f();
public final Vector3i section = new Vector3i(); public final Vector3i section = new Vector3i();
@@ -75,6 +77,11 @@ public abstract class Viewport <A extends Viewport<A>> {
return (A) this; return (A) this;
} }
public A setFogParameters(FogParameters fogParameters) {
this.fogParameters = fogParameters;
return (A) this;
}
public A update() { public A update() {
//MVP //MVP
this.projection.mul(this.modelView, this.MVP); this.projection.mul(this.modelView, this.MVP);

View File

@@ -3,6 +3,8 @@ package me.cortex.voxy.client.core.rendering.post;
import me.cortex.voxy.client.core.gl.shader.Shader; import me.cortex.voxy.client.core.gl.shader.Shader;
import me.cortex.voxy.client.core.gl.shader.ShaderType; import me.cortex.voxy.client.core.gl.shader.ShaderType;
import java.util.function.Function;
import static org.lwjgl.opengl.GL11C.GL_TRIANGLES; import static org.lwjgl.opengl.GL11C.GL_TRIANGLES;
import static org.lwjgl.opengl.GL11C.glDrawArrays; import static org.lwjgl.opengl.GL11C.glDrawArrays;
import static org.lwjgl.opengl.GL30C.glBindVertexArray; import static org.lwjgl.opengl.GL30C.glBindVertexArray;
@@ -13,9 +15,12 @@ public class FullscreenBlit {
private final Shader shader; private final Shader shader;
public FullscreenBlit(String fragId) { public FullscreenBlit(String fragId) {
this.shader = Shader.make() this(fragId, (a)->a);
}
public <T extends Shader> FullscreenBlit(String fragId, Function<Shader.Builder<T>, Shader.Builder<T>> builder) {
this.shader = builder.apply((Shader.Builder<T>) Shader.make()
.add(ShaderType.VERTEX, "voxy:post/fullscreen.vert") .add(ShaderType.VERTEX, "voxy:post/fullscreen.vert")
.add(ShaderType.FRAGMENT, fragId) .add(ShaderType.FRAGMENT, fragId))
.compile(); .compile();
} }

View File

@@ -1,14 +1,14 @@
package me.cortex.voxy.client.core.rendering.post; package me.cortex.voxy.client.core.rendering.post;
import me.cortex.voxy.client.config.VoxyConfig;
import me.cortex.voxy.client.core.gl.GlFramebuffer; import me.cortex.voxy.client.core.gl.GlFramebuffer;
import me.cortex.voxy.client.core.gl.GlTexture; 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.Shader;
import me.cortex.voxy.client.core.gl.shader.ShaderType; import me.cortex.voxy.client.core.gl.shader.ShaderType;
import me.cortex.voxy.client.core.rendering.Viewport;
import me.cortex.voxy.client.core.rendering.util.GlStateCapture; import me.cortex.voxy.client.core.rendering.util.GlStateCapture;
import net.minecraft.client.util.math.MatrixStack;
import org.joml.Matrix4f; import org.joml.Matrix4f;
import org.joml.Matrix4fc; import org.joml.Matrix4fc;
import org.lwjgl.opengl.GL11C;
import static org.lwjgl.opengl.ARBComputeShader.glDispatchCompute; import static org.lwjgl.opengl.ARBComputeShader.glDispatchCompute;
import static org.lwjgl.opengl.ARBShaderImageLoadStore.glBindImageTexture; import static org.lwjgl.opengl.ARBShaderImageLoadStore.glBindImageTexture;
@@ -20,6 +20,7 @@ import static org.lwjgl.opengl.GL43.GL_DEPTH_STENCIL_TEXTURE_MODE;
import static org.lwjgl.opengl.GL45C.*; import static org.lwjgl.opengl.GL45C.*;
public class PostProcessing { public class PostProcessing {
private final boolean useEnvFog = VoxyConfig.CONFIG.useEnvironmentalFog;
private final GlFramebuffer framebuffer; private final GlFramebuffer framebuffer;
private final GlFramebuffer framebufferSSAO; private final GlFramebuffer framebufferSSAO;
private int width; private int width;
@@ -31,7 +32,8 @@ public class PostProcessing {
private final FullscreenBlit setDepth0 = new FullscreenBlit("voxy:post/depth0.frag"); private final FullscreenBlit setDepth0 = new FullscreenBlit("voxy:post/depth0.frag");
private final FullscreenBlit emptyBlit = new FullscreenBlit("voxy:post/noop.frag"); private final FullscreenBlit emptyBlit = new FullscreenBlit("voxy:post/noop.frag");
//private final FullscreenBlit blitTexture = new FullscreenBlit("voxy:post/blit_texture_cutout.frag"); //private final FullscreenBlit blitTexture = new FullscreenBlit("voxy:post/blit_texture_cutout.frag");
private final FullscreenBlit blitTexture = new FullscreenBlit("voxy:post/blit_texture_depth_cutout.frag"); private final FullscreenBlit blitTexture = new FullscreenBlit("voxy:post/blit_texture_depth_cutout.frag",
a->a.defineIf("USE_ENV_FOG", useEnvFog));
private final Shader ssaoComp = Shader.make() private final Shader ssaoComp = Shader.make()
.add(ShaderType.COMPUTE, "voxy:post/ssao.comp") .add(ShaderType.COMPUTE, "voxy:post/ssao.comp")
.compile(); .compile();
@@ -158,7 +160,7 @@ public class PostProcessing {
//Executes the post processing and emits to whatever framebuffer is currently bound via a blit //Executes the post processing and emits to whatever framebuffer is currently bound via a blit
public void renderPost(Matrix4f fromProjection, Matrix4fc tooProjection, int outputFB) { public void renderPost(Viewport vp, Matrix4fc tooProjection, int outputFB) {
glDisable(GL_STENCIL_TEST); glDisable(GL_STENCIL_TEST);
@@ -172,12 +174,17 @@ public class PostProcessing {
this.blitTexture.bind(); this.blitTexture.bind();
float[] data = new float[4*4]; float[] data = new float[4*4];
var mat = new Matrix4f(fromProjection).invert(); new Matrix4f(vp.MVP).invert().get(data);
mat.get(data);
glUniformMatrix4fv(2, false, data);//inverse fromProjection glUniformMatrix4fv(2, false, data);//inverse fromProjection
tooProjection.get(data); new Matrix4f(tooProjection).mul(vp.modelView).get(data);
glUniformMatrix4fv(3, false, data);//tooProjection glUniformMatrix4fv(3, false, data);//tooProjection
if (useEnvFog) {
float start = vp.fogParameters.environmentalStart();
float end = vp.fogParameters.environmentalEnd();
float invEndFogDelta = 1f/(end-start);
glUniform3f(4, vp.fogParameters.environmentalEnd()/2f, invEndFogDelta, start*invEndFogDelta);
glUniform3f(5, vp.fogParameters.red(), vp.fogParameters.green(), vp.fogParameters.blue());
}
glBindTextureUnit(0, this.didSSAO?this.colourSSAO.id:this.colour.id); glBindTextureUnit(0, this.didSSAO?this.colourSSAO.id:this.colour.id);

View File

@@ -15,11 +15,16 @@ public class MixinFogRenderer {
@Redirect(method = "applyFog(Lnet/minecraft/client/render/Camera;IZLnet/minecraft/client/render/RenderTickCounter;FLnet/minecraft/client/world/ClientWorld;)Lorg/joml/Vector4f;", at = @At(value = "FIELD", target = "Lnet/minecraft/client/render/fog/FogData;renderDistanceEnd:F", opcode = Opcodes.PUTFIELD), require = 0) @Redirect(method = "applyFog(Lnet/minecraft/client/render/Camera;IZLnet/minecraft/client/render/RenderTickCounter;FLnet/minecraft/client/world/ClientWorld;)Lorg/joml/Vector4f;", at = @At(value = "FIELD", target = "Lnet/minecraft/client/render/fog/FogData;renderDistanceEnd:F", opcode = Opcodes.PUTFIELD), require = 0)
private void voxy$modifyFog(FogData instance, float distance) { private void voxy$modifyFog(FogData instance, float distance) {
var vrs = (IGetVoxyRenderSystem) MinecraftClient.getInstance().worldRenderer; var vrs = (IGetVoxyRenderSystem) MinecraftClient.getInstance().worldRenderer;
if (VoxyConfig.CONFIG.renderVanillaFog || vrs == null || vrs.getVoxyRenderSystem() == null) { if (VoxyConfig.CONFIG.renderVanillaFog || vrs == null || vrs.getVoxyRenderSystem() == null) {
instance.renderDistanceEnd = distance; instance.renderDistanceEnd = distance;
} else { } else {
instance.renderDistanceStart = 999999999;
instance.renderDistanceEnd = 999999999; instance.renderDistanceEnd = 999999999;
instance.environmentalEnd = 999999999; if (!VoxyConfig.CONFIG.useEnvironmentalFog) {
instance.environmentalStart = 99999999;
instance.environmentalEnd = 99999999;
}
} }
} }
} }

View File

@@ -18,7 +18,7 @@ public class MixinRenderPipeline {
private void voxy$injectRender(TerrainRenderPass pass, Viewport frustum, FogParameters fogParameters, ChunkRenderMatrices crm, double px, double py, double pz, CallbackInfo ci) { private void voxy$injectRender(TerrainRenderPass pass, Viewport frustum, FogParameters fogParameters, ChunkRenderMatrices crm, double px, double py, double pz, CallbackInfo ci) {
var renderer = ((IGetVoxyRenderSystem) MinecraftClient.getInstance().worldRenderer).getVoxyRenderSystem(); var renderer = ((IGetVoxyRenderSystem) MinecraftClient.getInstance().worldRenderer).getVoxyRenderSystem();
if (renderer != null) { if (renderer != null) {
renderer.renderOpaque(crm, px, py, pz); renderer.renderOpaque(crm, fogParameters, px, py, pz);
} }
} }
} }

View File

@@ -21,11 +21,11 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
public class MixinDefaultChunkRenderer { public class MixinDefaultChunkRenderer {
@Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/caffeinemc/mods/sodium/client/render/chunk/ShaderChunkRenderer;end(Lnet/caffeinemc/mods/sodium/client/render/chunk/terrain/TerrainRenderPass;)V", shift = At.Shift.BEFORE)) @Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/caffeinemc/mods/sodium/client/render/chunk/ShaderChunkRenderer;end(Lnet/caffeinemc/mods/sodium/client/render/chunk/terrain/TerrainRenderPass;)V", shift = At.Shift.BEFORE))
private void injectRender(ChunkRenderMatrices matrices, CommandList commandList, ChunkRenderListIterable renderLists, TerrainRenderPass renderPass, CameraTransform camera, FogParameters parameters, CallbackInfo ci) { private void injectRender(ChunkRenderMatrices matrices, CommandList commandList, ChunkRenderListIterable renderLists, TerrainRenderPass renderPass, CameraTransform camera, FogParameters fogParameters, CallbackInfo ci) {
if (renderPass == DefaultTerrainRenderPasses.CUTOUT) { if (renderPass == DefaultTerrainRenderPasses.CUTOUT) {
var renderer = ((IGetVoxyRenderSystem) MinecraftClient.getInstance().worldRenderer).getVoxyRenderSystem(); var renderer = ((IGetVoxyRenderSystem) MinecraftClient.getInstance().worldRenderer).getVoxyRenderSystem();
if (renderer != null) { if (renderer != null) {
renderer.renderOpaque(matrices, camera.x, camera.y, camera.z); renderer.renderOpaque(matrices, fogParameters, camera.x, camera.y, camera.z);
} }
} }
} }

View File

@@ -19,6 +19,9 @@
"voxy.config.general.renderDistance": "Render distance", "voxy.config.general.renderDistance": "Render distance",
"voxy.config.general.renderDistance.tooltip": "Render distance of voxy in chunks", "voxy.config.general.renderDistance.tooltip": "Render distance of voxy in chunks",
"voxy.config.general.environmental_fog": "Enable environmental fog",
"voxy.config.general.environmental_fog.tooltip": "Enables or disables voxy rendering environmental fog",
"voxy.config.general.vanilla_fog": "Enable vanilla fog", "voxy.config.general.vanilla_fog": "Enable vanilla fog",
"voxy.config.general.vanilla_fog.tooltip": "Enables or disables vanilla fog effect", "voxy.config.general.vanilla_fog.tooltip": "Enables or disables vanilla fog effect",

View File

@@ -4,6 +4,10 @@ layout(binding = 0) uniform sampler2D colourTex;
layout(binding = 1) uniform sampler2D depthTex; layout(binding = 1) uniform sampler2D depthTex;
layout(location = 2) uniform mat4 invProjMat; layout(location = 2) uniform mat4 invProjMat;
layout(location = 3) uniform mat4 projMat; layout(location = 3) uniform mat4 projMat;
#ifdef USE_ENV_FOG
layout(location = 4) uniform vec3 endParams;
layout(location = 5) uniform vec3 fogColour;
#endif
out vec4 colour; out vec4 colour;
in vec2 UV; in vec2 UV;
@@ -28,7 +32,16 @@ void main() {
discard; discard;
} }
depth = projDepth(rev3d(vec3(UV.xy, depth))); vec3 point = rev3d(vec3(UV.xy, depth));
#ifdef USE_ENV_FOG
{
float fogLerp = max(fma(min(length(point.xyz), endParams.x),endParams.y,endParams.z),0);//512 is 32*16 which is the render distance in blocks
colour.rgb = mix(colour.rgb, fogColour, fogLerp);
}
#endif
depth = projDepth(point);
depth = min(1.0f-(2.0f/((1<<24)-1)), depth); depth = min(1.0f-(2.0f/((1<<24)-1)), depth);
depth = depth * 0.5f + 0.5f; depth = depth * 0.5f + 0.5f;
depth = gl_DepthRange.diff * depth + gl_DepthRange.near; depth = gl_DepthRange.diff * depth + gl_DepthRange.near;