Files

150 lines
4.6 KiB
GLSL

#include "/Lib/Settings.glsl"
#include "/Lib/Utilities.glsl"
// MinecraftPT — Precomputed Atmosphere (analytic)
// A compact analytic Rayleigh/Mie sky model with precomputed transmittance.
// Provides sun/sky irradiance for the scene and sky radiance for the panorama.
#ifndef PRECOMPUTED_ATMOSPHERE_GLSL
#define PRECOMPUTED_ATMOSPHERE_GLSL
// Earth-like atmosphere constants (scaled)
const float atmosphereModel_bottom_radius = 6360.0;
const float atmosphereModel_top_radius = 6420.0;
const vec3 wavelengths = vec3(680.0, 550.0, 440.0); // nm
const vec3 betaRayleigh = vec3(5.802, 13.558, 33.1) * 1e-6;
const float betaMie = 3.996e-6;
const float mieG = 0.8;
vec3 RayleighPhase(float cosTheta){
return 3.0 / (16.0 * 3.14159265) * (1.0 + cosTheta * cosTheta);
}
vec3 MiePhase(float cosTheta){
float g = mieG;
float g2 = g * g;
return 3.0 / (8.0 * 3.14159265) * ((1.0 - g2) * (1.0 + cosTheta * cosTheta)) /
((2.0 + g2) * pow(1.0 + g2 - 2.0 * g * cosTheta, 1.5));
}
// Ground intersection for ray from camera
float GroundIntersection(vec3 pos, vec3 dir){
float b = dot(pos, dir);
float c = dot(pos, pos) - atmosphereModel_bottom_radius * atmosphereModel_bottom_radius;
float h = b * b - c;
if (h > 0.0){
float t = -b - sqrt(h);
if (t > 0.0) return t;
}
return -1.0;
}
float AtmosphereIntersection(vec3 pos, vec3 dir){
float b = dot(pos, dir);
float c = dot(pos, pos) - atmosphereModel_top_radius * atmosphereModel_top_radius;
float h = b * b - c;
if (h > 0.0){
float t = -b + sqrt(h);
if (t > 0.0) return t;
}
return -1.0;
}
// Optical depth to space (transmittance approximation)
vec3 OpticalDepthToSpace(vec3 pos, vec3 dir){
float tMax = AtmosphereIntersection(pos, dir);
if (tMax < 0.0) return vec3(1e10);
const int steps = 16;
float dt = tMax / float(steps);
vec3 opticalDepth = vec3(0.0);
vec3 p = pos;
for (int i = 0; i < steps; i++){
float h = length(p) - atmosphereModel_bottom_radius;
vec3 density = exp(-h / 8.0) * betaRayleigh + exp(-h / 1.2) * betaMie;
opticalDepth += density * dt;
p += dir * dt;
}
return opticalDepth;
}
// Sun/sky irradiance at a camera position (simplified single scattering)
void GetSunAndSkyIrradiance(vec3 camera, vec3 sunDir, vec3 moonDir,
out vec3 colorSunlight, out vec3 colorMoonlight,
out vec3 colorSunSkylight, out vec3 colorMoonSkylight){
vec3 sunColor = vec3(1.0, 0.98, 0.92);
vec3 moonColor = vec3(0.5, 0.6, 0.8) * 0.1;
float sunElevation = sunDir.y;
float moonElevation = moonDir.y;
float sunStrength = curve(saturate(sunElevation * 15.0 + 0.5));
float moonStrength = curve(saturate(-sunElevation * 5.0 + 0.5));
// Sun disk color by elevation (sunset tint)
vec3 sunsetTint = mix(vec3(1.0, 0.3, 0.1), vec3(1.0), curve(saturate(sunElevation * 3.0)));
sunColor *= sunsetTint;
colorSunlight = sunColor * sunStrength * SUNLIGHT_INTENSITY;
colorMoonlight = moonColor * moonStrength;
// Sky irradiance: ambient hemisphere light
vec3 skyColorDay = vec3(0.55, 0.75, 1.0) * sunStrength * 0.8;
vec3 skyColorNight = vec3(0.05, 0.08, 0.15) * 0.3;
vec3 skyColorSunset = vec3(1.0, 0.5, 0.3) * curve(saturate(1.0 - abs(sunElevation) * 4.0)) * 0.3;
colorSunSkylight = skyColorDay + skyColorSunset;
colorMoonSkylight = skyColorNight;
}
// Sky radiance for a direction (used for the sky panorama and reflections)
vec3 GetSkyRadiance(vec3 dir, vec3 sunDir){
dir = normalize(dir);
sunDir = normalize(sunDir);
float cosTheta = dot(dir, sunDir);
// Horizon / elevation response
float elevation = dir.y;
// Day sky
vec3 skyDay = vec3(0.4, 0.62, 0.9) * 0.6;
skyDay = mix(skyDay, vec3(0.9, 0.95, 1.0), pow(saturate(elevation), 0.6));
skyDay *= 1.0 - exp(-max(elevation, 0.0) * 3.0);
// Rayleigh scattering glow around sun
vec3 rayleigh = RayleighPhase(cosTheta) * betaRayleigh * 1.2;
// Mie scattering (sun disk)
float mie = MiePhase(cosTheta) * betaMie * 20.0;
// Sun disk itself
float sunDisk = exp(-(1.0 - cosTheta) / (2.0 * SUN_ANGULAR_RADIUS * SUN_ANGULAR_RADIUS));
vec3 sunColor = vec3(1.0, 0.97, 0.9) * SUNLIGHT_INTENSITY;
// Sunset tint
float sunElevation = sunDir.y;
sunColor *= mix(vec3(1.0, 0.3, 0.1), vec3(1.0), curve(saturate(sunElevation * 3.0)));
float sunVisible = curve(saturate(sunElevation * 15.0 + 0.5));
vec3 radiance = skyDay;
radiance += sunColor * (rayleigh + mie) * sunVisible;
radiance += sunColor * sunDisk * sunVisible * 80.0;
// Night sky
float night = 1.0 - curve(saturate(sunElevation * 10.0 + 0.5));
radiance += vec3(0.02, 0.03, 0.06) * night;
// Horizon haze
float horizon = exp(-abs(elevation) * 4.0);
radiance += vec3(0.9, 0.7, 0.5) * horizon * sunVisible * 0.1;
return radiance;
}
#endif