This commit is contained in:
James Seibel
2026-03-03 07:47:58 -06:00
parent 84c212a780
commit 225c2df8df
6 changed files with 381 additions and 8 deletions
@@ -29,6 +29,7 @@ import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.render.DhApiRenderProxy; import com.seibel.distanthorizons.core.render.DhApiRenderProxy;
import com.seibel.distanthorizons.core.render.RenderBufferHandler; import com.seibel.distanthorizons.core.render.RenderBufferHandler;
import com.seibel.distanthorizons.core.render.renderer.generic.GenericObjectRenderer; import com.seibel.distanthorizons.core.render.renderer.generic.GenericObjectRenderer;
import com.seibel.distanthorizons.core.util.math.Mat4f;
import com.seibel.distanthorizons.core.util.math.Vec3d; import com.seibel.distanthorizons.core.util.math.Vec3d;
import com.seibel.distanthorizons.core.util.objects.SortedArraySet; import com.seibel.distanthorizons.core.util.objects.SortedArraySet;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
@@ -148,6 +149,7 @@ public class McLodRenderer
IMcLodRenderer lodRenderer = SingletonInjector.INSTANCE.get(IMcLodRenderer.class); IMcLodRenderer lodRenderer = SingletonInjector.INSTANCE.get(IMcLodRenderer.class);
IMcSsaoRenderer ssaoRenderer = SingletonInjector.INSTANCE.get(IMcSsaoRenderer.class); IMcSsaoRenderer ssaoRenderer = SingletonInjector.INSTANCE.get(IMcSsaoRenderer.class);
IMcFogRenderer fogRenderer = SingletonInjector.INSTANCE.get(IMcFogRenderer.class);
@@ -214,12 +216,12 @@ public class McLodRenderer
// this is done to fix issues with: underwater fog, blindness effect, etc. // this is done to fix issues with: underwater fog, blindness effect, etc.
|| renderParams.vanillaFogEnabled) || renderParams.vanillaFogEnabled)
{ {
//profiler.popPush("LOD Fog"); profiler.popPush("LOD Fog");
//
//Mat4f combinedMatrix = new Mat4f(renderParams.dhProjectionMatrix); Mat4f combinedMatrix = new Mat4f(renderParams.dhProjectionMatrix);
//combinedMatrix.multiply(renderParams.dhModelViewMatrix); combinedMatrix.multiply(renderParams.dhModelViewMatrix);
//
//FogRenderer.INSTANCE.render(combinedMatrix, renderParams.partialTicks); fogRenderer.render(combinedMatrix, renderParams.partialTicks);
} }
@@ -243,9 +243,9 @@ public class FogShader extends AbstractShaderRenderer
return fogColor; return fogColor;
} }
public void setProjectionMatrix(Mat4f projectionMatrix) public void setProjectionMatrix(Mat4f modelViewProjectionMatrix)
{ {
this.inverseMvmProjMatrix = new Mat4f(projectionMatrix); this.inverseMvmProjMatrix = new Mat4f(modelViewProjectionMatrix);
this.inverseMvmProjMatrix.invert(); this.inverseMvmProjMatrix.invert();
} }
@@ -0,0 +1,30 @@
/*
* This file is part of the Distant Horizons mod
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020 James Seibel
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.seibel.distanthorizons.core.wrapperInterfaces.render;
import com.seibel.distanthorizons.api.objects.math.DhApiMat4f;
import com.seibel.distanthorizons.coreapi.interfaces.dependencyInjection.IBindable;
public interface IMcFogRenderer extends IBindable
{
void render(DhApiMat4f modelViewProjectionMatrix, float partialTicks);
}
@@ -0,0 +1,27 @@
#version 150 core
in vec2 TexCoord;
out vec4 fragColor;
uniform sampler2D uColorTexture;
uniform sampler2D uDhDepthTexture;
/**
* Fog application shader
*
* This merges the rendered fog onto DH's rendered LODs
*/
void main()
{
fragColor = vec4(0.0);
// a fragment depth of "1" means the fragment wasn't drawn to,
// only update fragments that were drawn to
float fragmentDepth = textureLod(uDhDepthTexture, TexCoord, 0).r;
if (fragmentDepth != 1)
{
fragColor = texture(uColorTexture, TexCoord);
}
}
@@ -0,0 +1,299 @@
#version 150 core
in vec2 TexCoord;
out vec4 fragColor;
layout (std140) uniform fragUniformBlock
{
// fog uniforms
vec4 uFogColor;
float uFogScale;
float uFogVerticalScale;
int uFogDebugMode;
int uFogFalloffType;
// fog config
float uFarFogStart;
float uFarFogLength;
float uFarFogMin;
float uFarFogRange;
float uFarFogDensity;
// height fog config
float uHeightFogStart;
float uHeightFogLength;
float uHeightFogMin;
float uHeightFogRange;
float uHeightFogDensity;
// ???
bool uHeightFogEnabled;
int uHeightFogFalloffType;
bool uHeightBasedOnCamera;
float uHeightFogBaseHeight;
bool uHeightFogAppliesUp;
bool uHeightFogAppliesDown;
bool uUseSphericalFog;
int uHeightFogMixingMode;
float uCameraBlockYPos;
// inverted model view matrix and projection matrix
mat4 uInvMvmProj;
};
uniform sampler2D uDhDepthTexture;
//====================//
// method definitions //
//====================//
vec3 calcViewPosition(float fragmentDepth);
float getFarFogThickness(float dist);
float getHeightFogThickness(float dist);
float calculateHeightFogDepth(float worldYPos);
float mixFogThickness(float far, float height);
float linearFog(float worldDist, float fogStart, float fogLength, float fogMin, float fogRange);
float exponentialFog(float x, float fogStart, float fogLength, float fogMin, float fogRange, float fogDensity);
float exponentialSquaredFog(float x, float fogStart, float fogLength, float fogMin, float fogRange, float fogDensity);
//======//
// main //
//======//
/**
* Fragment shader for fog.
* This should be run last so it applies above other affects like Ambient Occlusioning
*/
void main()
{
float fragmentDepth = texture(uDhDepthTexture, TexCoord).r;
fragColor = vec4(uFogColor.rgb, 0.0);
// a fragment depth of "1" means the fragment wasn't drawn to,
// we only want to apply Fog to LODs, not to the sky outside the LODs
if (fragmentDepth < 1.0)
{
int fogDebugMode = uFogDebugMode;
if (fogDebugMode == 0)
{
// render fog based on distance from the camera
vec3 vertexWorldPos = calcViewPosition(fragmentDepth);
float horizontalWorldDistance = length(vertexWorldPos.xz) * uFogScale;
float worldDistance = length(vertexWorldPos.xyz) * uFogScale;
float activeDistance = uUseSphericalFog ? worldDistance : horizontalWorldDistance;
// far fog
float farFogThickness = getFarFogThickness(activeDistance);
// height fog
float heightFogDepth = calculateHeightFogDepth(vertexWorldPos.y);
float heightFogThickness = getHeightFogThickness(heightFogDepth);
// combined fog
float mixedFogThickness = mixFogThickness(farFogThickness, heightFogThickness);
fragColor.a = clamp(mixedFogThickness, 0.0, 1.0);
}
else if (fogDebugMode == 1)
{
// test code
// render everything with the fog color
fragColor.a = 1.0;
}
else
{
// test code.
// this can be fired by manually changing the fullFogMode to a (normally)
// invalid value (like 7).
// By having a separate if statement defined by
// a uniform we don't have to worry about GLSL optimizing away different
// options when testing, causing a bunch of headaches if we just want to render the screen red.
float depthValue = textureLod(uDhDepthTexture, TexCoord, 0).r;
fragColor.rgb = vec3(depthValue); // Convert depth value to grayscale color
fragColor.a = 1.0;
}
}
}
//================//
// helper methods //
//================//
vec3 calcViewPosition(float fragmentDepth)
{
vec4 ndc = vec4(TexCoord.xy, fragmentDepth, 1.0);
ndc.xyz = ndc.xyz * 2.0 - 1.0;
vec4 eyeCoord = uInvMvmProj * ndc;
return eyeCoord.xyz / eyeCoord.w;
}
//=========//
// far fog //
//=========//
float getFarFogThickness(float dist)
{
if (uFogFalloffType == 0) // LINEAR
{
return linearFog(dist, uFarFogStart, uFarFogLength, uFarFogMin, uFarFogRange);
}
else if (uFogFalloffType == 1) // EXPONENTIAL
{
return exponentialFog(dist, uFarFogStart, uFarFogLength, uFarFogMin, uFarFogRange, uFarFogDensity);
}
else // EXPONENTIAL_SQUARED
{
return exponentialSquaredFog(dist, uFarFogStart, uFarFogLength, uFarFogMin, uFarFogRange, uFarFogDensity);
}
}
float getHeightFogThickness(float dist)
{
if (!uHeightFogEnabled)
{
return 0.0;
}
if (uHeightFogFalloffType == 0) // LINEAR
{
return linearFog(dist, uHeightFogStart, uHeightFogLength, uHeightFogMin, uHeightFogRange);
}
else if (uHeightFogFalloffType == 1) // EXPONENTIAL
{
return exponentialFog(dist, uHeightFogStart, uHeightFogLength, uHeightFogMin, uHeightFogRange, uHeightFogDensity);
}
else // EXPONENTIAL_SQUARED
{
return exponentialSquaredFog(dist, uHeightFogStart, uHeightFogLength, uHeightFogMin, uHeightFogRange, uHeightFogDensity);
}
}
float linearFog(float worldDist, float fogStart, float fogLength, float fogMin, float fogRange)
{
worldDist = (worldDist - fogStart) / fogLength;
worldDist = clamp(worldDist, 0.0, 1.0);
return fogMin + fogRange * worldDist;
}
float exponentialFog(
float x, float fogStart, float fogLength,
float fogMin, float fogRange, float fogDensity)
{
x = max((x-fogStart)/fogLength, 0.0) * fogDensity;
return fogMin + fogRange - fogRange/exp(x);
}
float exponentialSquaredFog(
float x, float fogStart, float fogLength,
float fogMin, float fogRange, float fogDensity)
{
x = max((x-fogStart)/fogLength, 0.0) * fogDensity;
return fogMin + fogRange - fogRange/exp(x*x);
}
//============//
// height fog //
//============//
/** 1 = full fog, 0 = no fog */
float calculateHeightFogDepth(float worldYPos)
{
// worldYPos -65 - 384
//worldYPos = worldYPos * -1; // negative, fog below height; positive, fog above height
//return worldYPos * uFogVerticalScale; // "* uFogVerticalScale" is done to convert world position to a percent of the world height;
if (!uHeightFogEnabled)
{
// ignore the height
return 0.0;
}
if (!uHeightBasedOnCamera)
{
worldYPos -= (uHeightFogBaseHeight - uCameraBlockYPos);
}
if (uHeightFogAppliesDown && uHeightFogAppliesUp)
{
return abs(worldYPos) * uFogVerticalScale;
}
else if (uHeightFogAppliesDown)
{
// apploy fog below given height
return -worldYPos * uFogVerticalScale;
}
else if (uHeightFogAppliesUp)
{
// apply fog above given height
return worldYPos * uFogVerticalScale;
}
else
{
// shouldn't happen,
return 0.0;
}
}
float mixFogThickness(float far, float height)
{
switch (uHeightFogMixingMode)
{
case 0: // BASIC
case 1: // IGNORE_HEIGHT
return far;
case 2: // MAX
return max(far, height);
case 3: // ADDITION
return (far + height);
case 4: // MULTIPLY
return far * height;
case 5: // INVERSE_MULTIPLY
return (1.0 - (1.0-far)*(1.0-height));
case 6: // LIMITED_ADDITION
return (far + max(far, height));
case 7: // MULTIPLY_ADDITION
return (far + far*height);
case 8: // INVERSE_MULTIPLY_ADDITION
return (far + 1.0 - (1.0-far)*(1.0-height));
case 9: // AVERAGE
return (far*0.5 + height*0.5);
}
// shouldn't happen, but default to BASIC / IGNORE_HEIGHT
// if an invalid option is selected
return far;
}
@@ -0,0 +1,15 @@
#version 150 core
in vec2 vPosition;
out vec2 TexCoord;
/**
* This is specifically used by application shaders.
* IE post process or pixel transfer shaders, anything that is rendered using a single rectangle.
*/
void main()
{
gl_Position = vec4(vPosition, 1.0, 1.0);
TexCoord = vPosition.xy * 0.5 + 0.5;
}