This commit is contained in:
James Seibel
2026-03-02 07:45:25 -06:00
parent 3d9ae5f088
commit 84c212a780
5 changed files with 267 additions and 6 deletions
@@ -33,10 +33,7 @@ import com.seibel.distanthorizons.core.util.math.Vec3d;
import com.seibel.distanthorizons.core.util.objects.SortedArraySet;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IProfilerWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.IMcGenericRenderer;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.IMcLodRenderer;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.IMcTestRenderer;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.IVertexBufferWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.*;
import com.seibel.distanthorizons.coreapi.DependencyInjection.ApiEventInjector;
import com.seibel.distanthorizons.core.util.math.Vec3f;
@@ -150,6 +147,7 @@ public class McLodRenderer
}
IMcLodRenderer lodRenderer = SingletonInjector.INSTANCE.get(IMcLodRenderer.class);
IMcSsaoRenderer ssaoRenderer = SingletonInjector.INSTANCE.get(IMcSsaoRenderer.class);
@@ -183,8 +181,8 @@ public class McLodRenderer
// SSAO
if (Config.Client.Advanced.Graphics.Ssao.enableSsao.get())
{
//profiler.popPush("LOD SSAO");
//SSAORenderer.INSTANCE.render(new Mat4f(renderParams.dhProjectionMatrix), renderParams.partialTicks);
profiler.popPush("LOD SSAO");
ssaoRenderer.render(renderParams.dhProjectionMatrix);
}
// custom objects without SSAO
@@ -0,0 +1,32 @@
/*
* 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.core.util.math.Mat4f;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
import com.seibel.distanthorizons.coreapi.interfaces.dependencyInjection.IBindable;
public interface IMcSsaoRenderer extends IBindable
{
void render(DhApiMat4f dhProjectionMatrix);
}
@@ -0,0 +1,137 @@
#version 150 core
#extension GL_ARB_derivative_control : enable
#define SAMPLE_MAX 64
#define saturate(x) (clamp((x), 0.0, 1.0))
in vec2 TexCoord;
out vec4 fragColor;
layout (std140) uniform fragUniformBlock
{
int uSampleCount;
float uRadius;
float uStrength;
float uMinLight;
float uBias;
float uFadeDistanceInBlocks;
mat4 uInvProj;
mat4 uProj;
};
uniform sampler2D uDhDepthTexture;
const float EPSILON = 1.e-6;
const float GOLDEN_ANGLE = 2.39996323;
const vec3 MAGIC = vec3(0.06711056, 0.00583715, 52.9829189);
const float PI = 3.1415926538;
const float TAU = PI * 2.0;
vec3 unproject(vec4 pos)
{
return pos.xyz / pos.w;
}
float InterleavedGradientNoise(const in vec2 pixel)
{
float x = dot(pixel, MAGIC.xy);
return fract(MAGIC.z * fract(x));
}
vec3 calcViewPosition(const in vec3 clipPos)
{
vec4 viewPos = uInvProj * vec4(clipPos * 2.0 - 1.0, 1.0);
return viewPos.xyz / viewPos.w;
}
float GetSpiralOcclusion(const in vec2 uv, const in vec3 viewPos, const in vec3 viewNormal)
{
float dither = InterleavedGradientNoise(gl_FragCoord.xy);
float rotatePhase = dither * TAU;
float rStep = uRadius / uSampleCount;
vec2 offset;
float ao = 0.0;
int sampleCount = 0;
float radius = rStep;
for (int i = 0; i < clamp(uSampleCount, 1, SAMPLE_MAX); i++) {
vec2 offset = vec2(
sin(rotatePhase),
cos(rotatePhase)
) * radius;
radius += rStep;
rotatePhase += GOLDEN_ANGLE;
vec3 sampleViewPos = viewPos + vec3(offset, -0.1);
vec3 sampleClipPos = unproject(uProj * vec4(sampleViewPos, 1.0)) * 0.5 + 0.5;
sampleClipPos = saturate(sampleClipPos);
float sampleClipDepth = textureLod(uDhDepthTexture, sampleClipPos.xy, 0.0).r;
if (sampleClipDepth >= 1.0 - EPSILON) continue;
sampleClipPos.z = sampleClipDepth;
sampleViewPos = unproject(uInvProj * vec4(sampleClipPos * 2.0 - 1.0, 1.0));
vec3 diff = sampleViewPos - viewPos;
float sampleDist = length(diff);
vec3 sampleNormal = diff / sampleDist;
float sampleNoLm = max(dot(viewNormal, sampleNormal) - uBias, 0.0);
float aoF = 1.0 - saturate(sampleDist / uRadius);
ao += sampleNoLm * aoF;
sampleCount++;
}
ao /= max(sampleCount, 1);
ao = smoothstep(0.0, uStrength, ao);
return ao * (1.0 - uMinLight);
}
void main()
{
float fragmentDepth = textureLod(uDhDepthTexture, TexCoord, 0).r;
float occlusion = 0.0;
// Do not apply to sky
if (fragmentDepth < 1.0)
{
vec3 viewPos = calcViewPosition(vec3(TexCoord, fragmentDepth));
// fading is done to prevent banding/noise
// at super far distance
float distanceFromCamera = length(viewPos);
float fadeDistance = uFadeDistanceInBlocks;
if (distanceFromCamera < fadeDistance)
{
#ifdef GL_ARB_derivative_control
// Get higher precision derivatives when available
vec3 viewNormal = cross(dFdxFine(viewPos.xyz), dFdyFine(viewPos.xyz));
#else
vec3 viewNormal = cross(dFdx(viewPos.xyz), dFdy(viewPos.xyz));
#endif
viewNormal = normalize(viewNormal);
occlusion = GetSpiralOcclusion(TexCoord, viewPos, viewNormal);
// linearly fade with distance
occlusion *= (fadeDistance - distanceFromCamera) / fadeDistance;
}
else
{
// we're out of range, no need to do any SSAO calculations
occlusion = 0.0;
}
}
fragColor = vec4(vec3(1.0 - occlusion), 1.0);
}
@@ -0,0 +1,79 @@
#version 150 core
in vec2 TexCoord;
out vec4 fragColor;
uniform sampler2D uSsaoColorTexture;
uniform sampler2D uDhDepthTexture;
uniform vec2 gViewSize;
uniform int gBlurRadius;
uniform float gNear;
uniform float gFar;
float linearizeDepth(const in float depth) {
return (gNear * gFar) / (depth * (gNear - gFar) + gFar);
}
float Gaussian(const in float sigma, const in float x) {
return exp(-(x*x) / (2.0 * (sigma*sigma)));
}
float BilateralGaussianBlur(const in vec2 texcoord, const in float linearDepth, const in float g_sigmaV) {
float g_sigmaX = 1.6;
float g_sigmaY = 1.6;
int radius = clamp(gBlurRadius, 1, 3);
vec2 pixelSize = 1.0 / gViewSize;
float accum = 0.0;
float total = 0.0;
for (int iy = -radius; iy <= radius; iy++) {
float fy = Gaussian(g_sigmaY, iy);
for (int ix = -radius; ix <= radius; ix++) {
float fx = Gaussian(g_sigmaX, ix);
vec2 sampleTex = texcoord + ivec2(ix, iy) * pixelSize;
float sampleValue = textureLod(uSsaoColorTexture, sampleTex, 0).r;
float sampleDepth = textureLod(uDhDepthTexture, sampleTex, 0).r;
float sampleLinearDepth = linearizeDepth(sampleDepth);
float depthDiff = abs(sampleLinearDepth - linearDepth);
float fv = Gaussian(g_sigmaV, depthDiff);
float weight = fx*fy*fv;
accum += weight * sampleValue;
total += weight;
}
}
if (total <= 1.e-4) return 1.0;
return accum / total;
}
void main()
{
fragColor = vec4(1.0);
float fragmentDepth = textureLod(uDhDepthTexture, TexCoord, 0).r;
// a fragment depth of "1" means the fragment wasn't drawn to,
// we only want to apply SSAO to LODs, not to the sky outside the LODs
if (fragmentDepth < 1)
{
if (gBlurRadius > 0)
{
float fragmentDepthLinear = linearizeDepth(fragmentDepth);
fragColor.a = BilateralGaussianBlur(TexCoord, fragmentDepthLinear, 1.6);
}
else
{
fragColor.a = texelFetch(uSsaoColorTexture, ivec2(gl_FragCoord.xy), 0).r;
}
}
}
@@ -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;
}