Files
Reimagined/shaderpacks/Reimagined - High/shaders/lib/atmospherics/volumetricLight.glsl
T
2026-05-07 21:38:27 +03:00

376 lines
16 KiB
GLSL

// Volumetric tracing from Robobo1221, highly modified
#include "/lib/shaderSettings/volumetricLight.glsl"
#include "/lib/shaderSettings/endBeams.glsl"
#include "/lib/shaderSettings/endFlash.glsl"
#include "/lib/colors/lightAndAmbientColors.glsl"
//#define BEDROCK_NOISE
float GetDepth(float depth) {
return 2.0 * near * far / (far + near - (2.0 * depth - 1.0) * (far - near));
}
float GetDistX(float dist) {
return (far * (dist - near)) / (dist * (far - near));
}
vec4 DistortShadow(vec4 shadowpos, float distortFactor) {
shadowpos.xy *= 1.0 / distortFactor;
shadowpos.z = shadowpos.z * 0.2;
shadowpos = shadowpos * 0.5 + 0.5;
return shadowpos;
}
vec4 GetVolumetricLight(inout vec3 color, inout float vlFactor, vec3 translucentMult, float lViewPos0, float lViewPos1, vec3 nViewPos, float VdotL, float VdotU, vec2 texCoord, float z0, float z1, float dither) {
vec4 volumetricLight = vec4(0.0);
#if defined BEDROCK_NOISE && defined OVERWORLD
if ((cameraPosition.y < bedrockLevel) && (eyeBrightnessM < 0.4)) return vec4(0.0);
#endif
float vlMult = 1.0 - maxBlindnessDarkness;
#if SHADOW_QUALITY > -1
// Optifine for some reason doesn't provide correct shadowMapResolution if Shadow Quality isn't 1x
vec2 shadowMapResolutionM = textureSize(shadowtex0, 0);
#endif
#ifdef IRIS_FEATURE_FADE_VARIABLE
vec3 texture6 = texelFetch(colortex6, texelCoord, 0).rgb;
float chunkFade = texture6.b > 0.50001 ? (1.0 - texture6.b) * 2.0 : 1.0;
float chunkFadeM = mix(1.0, chunkFade, pow2(clamp01(lViewPos0 * 0.015))); // don't do fade very close to the player
lViewPos1 = mix(far, lViewPos1, chunkFadeM);
#endif
#ifdef OVERWORLD
vec3 vlColor = lightColor;
vec3 vlColorReducer = vec3(1.0);
float vlSceneIntensity = isEyeInWater != 1 ? vlFactor : 1.0;
#ifdef SPECIAL_BIOME_WEATHER
vlSceneIntensity = mix(vlSceneIntensity, 1.0, inDry * rainFactor);
vlColor *= 1.0 + 0.6 * inDry * rainFactor;
#endif
if (sunVisibility < 0.5) {
vlSceneIntensity = 0.0;
float vlMultNightModifier = (0.3 + 0.4 * rainFactor2 + 0.5 * max0(far - lViewPos1) / far);
#ifdef SPECIAL_PALE_GARDEN_LIGHTSHAFTS
vlMultNightModifier = mix(vlMultNightModifier, 1.0, inPaleGarden);
#endif
vlMult *= vlMultNightModifier;
vlColor = normalize(pow(vlColor, vec3(1.0 - max0(1.0 - 1.5 * nightFactor) + rainFactor)));
vlColor *= 0.0766 + 0.0766 * vsBrightness;
} else {
vlColorReducer = 1.0 / sqrt(vlColor);
}
#if BLOOD_MOON > 0
vec3 hsvVlColor = rgb2hsv(vlColor);
vlColor = mix(vlColor, hsv2rgb(vec3(0, max(0.8, hsvVlColor.y), hsvVlColor.z * 1.7)), getBloodMoon(sunVisibility));
#endif
#ifdef SPECIAL_PALE_GARDEN_LIGHTSHAFTS
vlSceneIntensity = mix(vlSceneIntensity, 1.0, inPaleGarden);
vlMult *= 1.0 + (3.0 * inPaleGarden) * (1.0 - sunVisibility);
#endif
float rainyNight = (1.0 - sunVisibility) * rainFactor;
float VdotLM = max((VdotL + 1.0) / 2.0, 0.0);
float VdotUmax0 = max(VdotU, 0.0);
float VdotUM = mix(pow2(1.0 - VdotUmax0), 1.0, 0.5 * vlSceneIntensity);
VdotUM = smoothstep1(VdotUM);
VdotUM = pow(VdotUM, min(lViewPos1 / far, 1.0) * (3.0 - 2.0 * vlSceneIntensity));
vlMult *= mix(VdotUM * VdotLM, 1.0, 0.4 * rainyNight) * vlTime;
vlMult *= mix(invNoonFactor2 * 0.875 + 0.125, 1.0, max(vlSceneIntensity, rainFactor2));
#if LIGHTSHAFT_QUALI == 4
int sampleCount = vlSceneIntensity < 0.5 ? 30 : 50;
#elif LIGHTSHAFT_QUALI == 3
int sampleCount = vlSceneIntensity < 0.5 ? 15 : 30;
#elif LIGHTSHAFT_QUALI == 2
int sampleCount = vlSceneIntensity < 0.5 ? 10 : 20;
#elif LIGHTSHAFT_QUALI == 1
int sampleCount = vlSceneIntensity < 0.5 ? 6 : 12;
#endif
#ifndef TAA
sampleCount *= 2;
#endif
#ifdef LIGHTSHAFT_SMOKE
float totalSmoke = 0.0;
#endif
#else
translucentMult = sqrt(translucentMult); // Because we pow2() the vl result in composite for the End dimension
float vlSceneIntensity = 0.0;
#ifndef LOW_QUALITY_ENDER_NEBULA
int sampleCount = 16;
#else
int sampleCount = 10;
#endif
#endif
float addition = 1.0;
float maxDist = mix(max(far, 96.0) * 0.55, 80.0, vlSceneIntensity);
#if WATER_FOG_MULT != 100
if (isEyeInWater == 1) {
#define WATER_FOG_MULT_M WATER_FOG_MULT * 0.01;
maxDist /= WATER_FOG_MULT_M;
}
#endif
float distMult = maxDist / (sampleCount + addition);
float sampleMultIntense = isEyeInWater != 1 ? 1.0 : 0.85;
float viewFactor = 1.0 - 0.7 * pow2(dot(nViewPos.xy, nViewPos.xy));
float depth0 = GetDepth(z0);
float depth1 = GetDepth(z1);
#ifdef END
if (z0 == 1.0) depth0 = 1000.0;
if (z1 == 1.0) depth1 = 1000.0;
#endif
// Fast but inaccurate perspective distortion approximation
maxDist *= viewFactor;
distMult *= viewFactor;
#ifdef IRIS_FEATURE_FADE_VARIABLE
depth1 = mix(depth1, far, pow2(pow2(1.0 - chunkFadeM)));
#endif
#ifdef OVERWORLD
float maxCurrentDist = min(depth1, maxDist);
#else
float maxCurrentDist = min(depth1, far);
#endif
for (int i = 0; i < sampleCount; i++) {
float currentDist = (i + dither) * distMult + addition;
if (currentDist > maxCurrentDist) break;
vec4 viewPos = gbufferProjectionInverse * (vec4(texCoord, GetDistX(currentDist), 1.0) * 2.0 - 1.0);
viewPos /= viewPos.w;
vec4 wpos = gbufferModelViewInverse * viewPos;
vec3 playerPos = wpos.xyz / wpos.w;
#if defined END && defined END_BEAMS
playerPos *= 512.0 / far;
vec4 enderBeamSample = vec4(DrawEnderBeams(VdotU, playerPos, nViewPos), 1.0);
enderBeamSample /= sampleCount;
#endif
#if defined OVERWORLD && defined OVERWORLD_BEAMS
vec4 overworldBeamSample = DrawOverworldBeams(VdotU, playerPos, viewPos.xyz);
#endif
float shadowSample = 1.0;
vec3 vlSample = vec3(1.0);
#if SHADOW_QUALITY > -1
wpos = shadowModelView * wpos;
wpos = shadowProjection * wpos;
wpos /= wpos.w;
float distb = sqrt(wpos.x * wpos.x + wpos.y * wpos.y);
float distortFactor = 1.0 - shadowMapBias + distb * shadowMapBias;
vec4 shadowPosition = DistortShadow(wpos,distortFactor);
//shadowPosition.z += 0.0001;
#ifdef OVERWORLD
float percentComplete = currentDist / maxDist;
float sampleMult = mix(percentComplete * 3.0, sampleMultIntense, max(rainFactor, vlSceneIntensity));
if (currentDist < 5.0) sampleMult *= smoothstep1(clamp(currentDist / 5.0, 0.0, 1.0));
sampleMult /= sampleCount;
#endif
if (length(shadowPosition.xy * 2.0 - 1.0) < 1.0) {
// 28A3DK6 We need to use texelFetch here or a lot of Nvidia GPUs can't get a valid value
shadowSample = texelFetch(shadowtex0, ivec2(shadowPosition.xy * shadowMapResolutionM), 0).x;
shadowSample = clamp((shadowSample-shadowPosition.z)*65536.0,0.0,1.0);
vlSample = vec3(shadowSample);
#ifdef END_FLASH_SHADOW_INTERNAL
vlSample = mix(vec3(1.0), vlSample, endFlashIntensity);
#endif
#if SHADOW_QUALITY >= 1
if (shadowSample == 0.0) {
float testsample = shadow2D(shadowtex1, shadowPosition.xyz).z;
if (testsample == 1.0) {
vec3 colsample = texture2D(shadowcolor1, shadowPosition.xy).rgb * 4.0;
colsample *= colsample;
vlSample = colsample;
shadowSample = 1.0;
#ifdef OVERWORLD
vlSample *= vlColorReducer;
#endif
}
} else {
#ifdef OVERWORLD
// For water-tinting the water surface when observed from below the surface
if (translucentMult != vec3(1.0) && currentDist > depth0) {
vec3 tinter = vec3(1.0);
if (isEyeInWater == 1) {
vec3 translucentMultM = translucentMult * 2.8;
tinter = pow(translucentMultM, vec3(sunVisibility * 3.0 * clamp01(playerPos.y * 0.03)));
} else {
tinter = 0.1 + 0.9 * pow2(pow2(translucentMult * 1.7));
}
vlSample *= mix(vec3(1.0), tinter, clamp01(oceanAltitude - cameraPosition.y));
}
#endif
if (isEyeInWater == 1 && translucentMult == vec3(1.0)) vlSample = vec3(0.0);
}
#endif
}
#endif
if (currentDist > depth0) vlSample *= translucentMult;
#ifdef OVERWORLD
#ifdef LIGHTSHAFT_SMOKE
vec3 smokePos = 0.0015 * (playerPos + cameraPosition);
vec3 smokeWind = frameTimeCounter * vec3(0.0, 0.001, -0.002);
float smoke = 0.65 * Noise3D(smokePos + smokeWind)
+ 0.25 * Noise3D((smokePos - smokeWind) * 3.0)
+ 0.10 * Noise3D((smokePos + smokeWind) * 9.0);
smoke = smoothstep1(smoothstep1(smoothstep1(smoke)));
totalSmoke += smoke * shadowSample * sampleMult;
#endif
vec4 volumetricLightAdd = vec4(vlSample, shadowSample) * sampleMult;
#ifdef OVERWORLD_BEAMS
volumetricLight += volumetricLightAdd * mix(vec4(1.0), overworldBeamSample, overworldBeamSample.a);
#else
volumetricLight += volumetricLightAdd;
#endif
#else
#ifdef END_BEAMS
volumetricLight += vec4(vlSample, shadowSample) * enderBeamSample;
#endif
#endif
}
#ifdef LIGHTSHAFT_SMOKE
volumetricLight *= pow(totalSmoke / volumetricLight.a, min(1.0 - volumetricLight.a, 0.5));
volumetricLight.rgb /= pow(0.5, 1.0 - volumetricLight.a);
#endif
// Decision of Intensity for Scene Aware Light Shafts //
#if defined OVERWORLD && LIGHTSHAFT_BEHAVIOUR == 1 && SHADOW_QUALITY >= 1
if (viewWidth + viewHeight - gl_FragCoord.x - gl_FragCoord.y < 1.5) {
if (frameCounter % int(0.06666 / frameTimeSmooth + 0.5) == 0) { // Change speed is not too different above 10 fps
int salsX = 5;
int salsY = 5;
float heightThreshold = 6.0;
vec2 viewM = 1.0 / vec2(salsX, salsY);
float salsSampleSum = 0.0;
int salsSampleCount = 0;
for (float i = 0.25; i < salsX; i++) {
for (float h = 0.45; h < salsY; h++) {
vec2 coord = 0.3 + 0.4 * viewM * vec2(i, h);
ivec2 icoord = ivec2(coord * shadowMapResolutionM);
float salsSample = texelFetch(shadowtex0, icoord, 0).x; // read 28A3DK6
if (salsSample < 0.55) {
float sampledHeight = texture2D(shadowcolor1, coord).a;
if (sampledHeight > 0.0) {
sampledHeight = max0(sampledHeight - 0.25) / 0.05; // consistencyMEJHRI7DG
salsSampleSum += sampledHeight;
salsSampleCount++;
}
}
}
}
float salsCheck = salsSampleSum / salsSampleCount;
int reduceAmount = 2;
int skyCheck = 0;
for (float i = 0.1; i < 1.0; i += 0.2) {
skyCheck += int(texelFetch(depthtex0, ivec2(view.x * i, view.y * 0.9), 0).x == 1.0);
}
if (skyCheck >= 4) {
salsCheck = 0.0;
reduceAmount = 3;
}
if (salsCheck > heightThreshold) {
vlFactor = min(vlFactor + OSIEBCA, 1.0);
} else {
vlFactor = max(vlFactor - OSIEBCA * reduceAmount, 0.0);
}
}
} else vlFactor = 0.0;
//if (gl_FragCoord.y < 50) color.rgb = vec3(1,0,1) * float(salsCheck / heightThreshold > gl_FragCoord.x / 1920.0);
/*for (float i = 0.25; i < salsX; i++) {
for (float h = 0.45; h < salsY; h++) {
if (length(texCoord - (0.3 + 0.4 * viewM * vec2(i, h))) < 0.01) return vec4(1,0,1,1);
}
}*/
#endif
#ifdef OVERWORLD
vlColor = pow(vlColor, vec3(0.5 + (0.5 + LIGHTSHAFT_SUNSET_SATURATION * sunVisibility) * invNoonFactor * invRainFactor + 0.3 * rainFactor));
vlColor *= 1.0 - (0.3 + 0.3 * noonFactor) * rainFactor - 0.5 * rainyNight + sunVisibility * pow2(invNoonFactor) * invRainFactor;
#if LIGHTSHAFT_DAY_I != 100 || LIGHTSHAFT_NIGHT_I != 100 || LIGHTSHAFT_RAIN_I != 100
#define LIGHTSHAFT_DAY_IM LIGHTSHAFT_DAY_I * 0.01
#define LIGHTSHAFT_NIGHT_IM LIGHTSHAFT_NIGHT_I * 0.01
#define LIGHTSHAFT_RAIN_IM LIGHTSHAFT_RAIN_I * 0.01
if (isEyeInWater == 0) {
#if LIGHTSHAFT_DAY_I != 100 || LIGHTSHAFT_NIGHT_I != 100
vlColor.rgb *= mix(LIGHTSHAFT_NIGHT_IM, LIGHTSHAFT_DAY_IM, sunVisibility);
#endif
#if LIGHTSHAFT_RAIN_I != 100
vlColor.rgb *= mix(1.0, LIGHTSHAFT_RAIN_IM, rainFactor);
#endif
}
#endif
volumetricLight.rgb *= vlColor;
#endif
volumetricLight.rgb *= vlMult;
volumetricLight = max(volumetricLight, vec4(0.0));
#if defined DISTANT_HORIZONS && defined OVERWORLD
if (isEyeInWater == 0) {
float lViewPosM = lViewPos0;
if (z0 >= 1.0) {
float z0DH = texelFetch(dhDepthTex, texelCoord, 0).r;
vec4 screenPosDH = vec4(texCoord, z0DH, 1.0);
vec4 viewPosDH = dhProjectionInverse * (screenPosDH * 2.0 - 1.0);
viewPosDH /= viewPosDH.w;
lViewPosM = length(viewPosDH.xyz);
}
lViewPosM = min(lViewPosM, renderDistance * 0.6);
float dhVlStillIntense = max(max(vlSceneIntensity, rainFactor), nightFactor * 0.5);
volumetricLight *= mix(0.0003 * lViewPosM, 1.0, dhVlStillIntense);
}
#endif
#ifdef END
#ifndef DISTANT_HORIZONS
volumetricLight *= sqrt1(min1(lViewPos1 * 2.0 / 512.0));
#else
volumetricLight *= min1(lViewPos1 * 3.0 / renderDistance);
#endif
#endif
#if RETRO_LOOK == 1
volumetricLight *= vec4(0.0);
#elif RETRO_LOOK == 2
volumetricLight *= mix(vec4(1.0), vec4(0.0), nightVision);
#endif
return volumetricLight;
}