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
public void onInitializeClient() {
ClientLifecycleEvents.CLIENT_STARTED.register(client->{
BudgetBufferRenderer.init();
boolean systemSupported = Capabilities.INSTANCE.compute && Capabilities.INSTANCE.indirectParameters;
if (systemSupported) {
VoxyCommon.setInstanceFactory(VoxyClientInstance::new);
} else {
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 float subDivisionSize = 64;
public boolean renderVanillaFog = false;
public boolean useEnvironmentalFog = false;
public boolean renderStatistics = false;
public static VoxyConfig loadOrCreate() {

View File

@@ -129,6 +129,14 @@ public abstract class VoxyConfigScreenPages {
}, s -> s.sectionRenderDistance)
.setImpact(OptionImpact.LOW)
.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)
.setName(Text.translatable("voxy.config.general.vanilla_fog"))
.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.world.WorldEngine;
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.render.Camera;
import net.minecraft.client.render.Frustum;
@@ -127,7 +128,7 @@ public class VoxyRenderSystem {
).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()) {
return;
}
@@ -164,11 +165,13 @@ public class VoxyRenderSystem {
int[] dims = new int[4];
glGetIntegerv(GL_VIEWPORT, dims);
var viewport = this.renderer.getViewport();
viewport
.setProjection(projection)
.setModelView(new Matrix4f(matrices.modelView()))
.setCamera(cameraX, cameraY, cameraZ)
.setScreenSize(dims[2], dims[3])
.setFogParameters(fogParameters)
.update();
viewport.frameId++;
@@ -195,7 +198,7 @@ public class VoxyRenderSystem {
TimingStatistics.F.start();
this.postProcessing.renderPost(projection, matrices.projection(), boundFB);
this.postProcessing.renderPost(viewport, matrices.projection(), boundFB);
TimingStatistics.F.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.rendering.util.HiZBuffer;
import net.caffeinemc.mods.sodium.client.util.FogParameters;
import net.minecraft.util.math.MathHelper;
import org.joml.*;
@@ -29,6 +30,7 @@ public abstract class Viewport <A extends Viewport<A>> {
public double cameraX;
public double cameraY;
public double cameraZ;
public FogParameters fogParameters;
public final Matrix4f MVP = new Matrix4f();
public final Vector3i section = new Vector3i();
@@ -75,6 +77,11 @@ public abstract class Viewport <A extends Viewport<A>> {
return (A) this;
}
public A setFogParameters(FogParameters fogParameters) {
this.fogParameters = fogParameters;
return (A) this;
}
public A update() {
//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.ShaderType;
import java.util.function.Function;
import static org.lwjgl.opengl.GL11C.GL_TRIANGLES;
import static org.lwjgl.opengl.GL11C.glDrawArrays;
import static org.lwjgl.opengl.GL30C.glBindVertexArray;
@@ -13,9 +15,12 @@ public class FullscreenBlit {
private final Shader shader;
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.FRAGMENT, fragId)
.add(ShaderType.FRAGMENT, fragId))
.compile();
}

View File

@@ -1,14 +1,14 @@
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.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.Viewport;
import me.cortex.voxy.client.core.rendering.util.GlStateCapture;
import net.minecraft.client.util.math.MatrixStack;
import org.joml.Matrix4f;
import org.joml.Matrix4fc;
import org.lwjgl.opengl.GL11C;
import static org.lwjgl.opengl.ARBComputeShader.glDispatchCompute;
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.*;
public class PostProcessing {
private final boolean useEnvFog = VoxyConfig.CONFIG.useEnvironmentalFog;
private final GlFramebuffer framebuffer;
private final GlFramebuffer framebufferSSAO;
private int width;
@@ -31,7 +32,8 @@ public class PostProcessing {
private final FullscreenBlit setDepth0 = new FullscreenBlit("voxy:post/depth0.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_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()
.add(ShaderType.COMPUTE, "voxy:post/ssao.comp")
.compile();
@@ -158,7 +160,7 @@ public class PostProcessing {
//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);
@@ -172,12 +174,17 @@ public class PostProcessing {
this.blitTexture.bind();
float[] data = new float[4*4];
var mat = new Matrix4f(fromProjection).invert();
mat.get(data);
new Matrix4f(vp.MVP).invert().get(data);
glUniformMatrix4fv(2, false, data);//inverse fromProjection
tooProjection.get(data);
new Matrix4f(tooProjection).mul(vp.modelView).get(data);
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);

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)
private void voxy$modifyFog(FogData instance, float distance) {
var vrs = (IGetVoxyRenderSystem) MinecraftClient.getInstance().worldRenderer;
if (VoxyConfig.CONFIG.renderVanillaFog || vrs == null || vrs.getVoxyRenderSystem() == null) {
instance.renderDistanceEnd = distance;
} else {
instance.renderDistanceStart = 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) {
var renderer = ((IGetVoxyRenderSystem) MinecraftClient.getInstance().worldRenderer).getVoxyRenderSystem();
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 {
@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) {
var renderer = ((IGetVoxyRenderSystem) MinecraftClient.getInstance().worldRenderer).getVoxyRenderSystem();
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.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.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(location = 2) uniform mat4 invProjMat;
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;
in vec2 UV;
@@ -28,7 +32,16 @@ void main() {
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 = depth * 0.5f + 0.5f;
depth = gl_DepthRange.diff * depth + gl_DepthRange.near;