Initial commit: Minecraft 光追着色器包(从零实现的 path tracing)

This commit is contained in:
WpyQwq
2026-09-19 12:06:22 +08:00
commit 59e30822f8
314 changed files with 9259 additions and 0 deletions
@@ -0,0 +1,37 @@
// MinecraftPT — Block Light
// Maps vanilla block light level to physical light, with per-block colors.
#ifndef BLOCKLIGHT_GLSL
#define BLOCKLIGHT_GLSL
// Convert lightmap blocklight (0-1) to physical light intensity
float BlocklightFromLightmap(float blocklight){
return pow(blocklight, 2.0) * BLOCKLIGHT_BRIGHTNESS;
}
// Get the block light color for a material
vec3 BlocklightColor(float materialID){
// Warm torch color by default
vec3 color = pow(vec3(COLOR_TORCH_R, COLOR_TORCH_G, COLOR_TORCH_B), vec3(2.2));
if (materialID == MATID_SOULTORCH || materialID == MATID_COPPER_LANTERN){
color = pow(vec3(COLOR_SOULTORCH_R, COLOR_SOULTORCH_G, COLOR_SOULTORCH_B), vec3(2.2));
}else if (materialID == MATID_AMETHYST){
color = pow(vec3(COLOR_AMETHYST_R, COLOR_AMETHYST_G, COLOR_AMETHYST_B), vec3(2.2));
}else if (materialID == MATID_FIRE){
color = pow(vec3(COLOR_FIRE_R, COLOR_FIRE_G, COLOR_FIRE_B), vec3(2.2));
}else if (materialID == MATID_ENDROD){
color = pow(vec3(COLOR_ENDROD_R, COLOR_ENDROD_G, COLOR_ENDROD_B), vec3(2.2));
}
return color * BlocklightFromLightmap(0.5);
}
// Physical block light for a lightmap value
vec3 Blocklight(vec2 lightmap){
// Blocklight color temperature
vec3 warmColor = pow(vec3(COLOR_TORCH_R, COLOR_TORCH_G, COLOR_TORCH_B), vec3(2.2));
return warmColor * pow(lightmap.x, 2.0) * BLOCKLIGHT_BRIGHTNESS;
}
#endif
+37
View File
@@ -0,0 +1,37 @@
// MinecraftPT — Held Light
// Torch in hand / flashlight illumination.
#ifndef HELDLIGHT_GLSL
#define HELDLIGHT_GLSL
// Physical held light: torches held in hand or flashlight
vec3 GetHeldLight(vec3 worldPos, vec3 worldNormal, out float heldLightShadow){
vec3 result = vec3(0.0);
heldLightShadow = 1.0;
#ifdef HELDLIGHT_MODE
#if HELDLIGHT_MODE >= 1
// Torch in hand position (roughly 0.4, -0.4, 0.6 relative to camera)
vec3 heldPos = gbufferModelViewInverse[3].xyz + cameraPosition;
vec3 toLight = heldPos - worldPos;
float dist = length(toLight);
vec3 dir = toLight / max(dist, 1e-4);
float intensity = exp(-dist * dist * HELDLIGHT_FALLOFF) * HELDLIGHT_BRIGHTNESS;
float NdotL = max(dot(worldNormal, dir), 0.0);
vec3 color = pow(vec3(COLOR_TORCH_R, COLOR_TORCH_G, COLOR_TORCH_B), vec3(2.2));
result = color * intensity * NdotL;
#ifdef HELDLIGHT_SHADOW
// Simple ray shadow for held light (short distance)
heldLightShadow = SimpleShadowTracing(WorldToVoxel(worldPos + worldNormal * 0.1), dir);
#endif
#endif
#endif
return result;
}
#endif
@@ -0,0 +1,91 @@
#include "/Lib/Settings.glsl"
#include "/Lib/Utilities.glsl"
// MinecraftPT — Lighting Constants
// Per-frame lighting values computed inline (no SSBO dependency).
// These are cheap functions of the sun angle and camera position; computed
// per-pass instead of via a shared buffer for maximum loader compatibility.
#ifndef LIGHTING_CONSTANTS_GLSL
#define LIGHTING_CONSTANTS_GLSL
#include "/Lib/BasicFunctions/PrecomputedAtmosphere.glsl"
// Sun direction in world space (matches the shadow camera direction)
vec3 GetSunDirWorld(){
#ifndef DIMENSION_NETHER
#ifndef DIMENSION_END
return normalize(shadowModelViewInverse2);
#else
return normalize(shadowModelViewInverse2) * fsign(0.5 - sunAngle);
#endif
#else
return normalize(shadowModelViewInverse2) * fsign(0.5 - sunAngle);
#endif
}
// Atmosphere camera position (scaled Earth radius + camera altitude)
vec3 GetAtmoCamera(){
return vec3(0.0, max(cameraPosition.y, 63.0) * 0.001 + atmosphereModel_bottom_radius, 0.0);
}
// Sun irradiance (direct light color/intensity)
vec3 GetSunIrradiance(){
vec3 sunDir = GetSunDirWorld();
vec3 moon, sunSky, moonSky;
return GetSunAndSkyIrradiance(GetAtmoCamera(), sunDir, -sunDir, moon, sunSky, moonSky);
}
vec3 GetMoonIrradiance(){
vec3 sunDir = GetSunDirWorld();
vec3 moon, sunSky, moonSky;
GetSunAndSkyIrradiance(GetAtmoCamera(), sunDir, -sunDir, moon, sunSky, moonSky);
return moon;
}
vec3 GetCelestialIrradiance(){
return GetSunIrradiance() + GetMoonIrradiance();
}
vec3 GetAtmoIrradiance(){
vec3 sunDir = GetSunDirWorld();
vec3 moon, sunSky, moonSky;
GetSunAndSkyIrradiance(GetAtmoCamera(), sunDir, -sunDir, moon, sunSky, moonSky);
return sunSky + moonSky;
}
// Cloud-altitude irradiances
vec3 GetCloudSunIrradiance(){
vec3 sunDir = GetSunDirWorld();
vec3 atmoCamera = vec3(0.0, mix(CLOUD_CLEAR_ALTITUDE, CLOUD_RAIN_ALTITUDE, wetness) * 0.001 + atmosphereModel_bottom_radius, 0.0);
vec3 moon, sunSky, moonSky;
return GetSunAndSkyIrradiance(atmoCamera, sunDir, -sunDir, moon, sunSky, moonSky);
}
vec3 GetCloudAtmoIrradiance(){
vec3 sunDir = GetSunDirWorld();
vec3 atmoCamera = vec3(0.0, mix(CLOUD_CLEAR_ALTITUDE, CLOUD_RAIN_ALTITUDE, wetness) * 0.001 + atmosphereModel_bottom_radius, 0.0);
vec3 moon, sunSky, moonSky;
GetSunAndSkyIrradiance(atmoCamera, sunDir, -sunDir, moon, sunSky, moonSky);
return sunSky + moonSky;
}
// Moon/sun phase for fog time factor
vec2 GetFogTimeFactor(){
vec3 sunDir = GetSunDirWorld();
float timeNoon = pow(1.0 - (clamp(sunDir.y, 0.2, 0.99) - 0.2) / 0.8, 6.0);
float moonlightStrength = curve(saturate(sunDir.y * -5.0));
return vec2(timeNoon, moonlightStrength);
}
// Dimension-aware irradiance override
vec3 GetDimensionAmbient(){
#ifdef DIMENSION_NETHER
return vec3(0.08, 0.02, 0.01) * NETHER_BRIGHTNESS;
#elif defined DIMENSION_END
return vec3(0.02, 0.02, 0.04);
#else
return GetAtmoIrradiance();
#endif
}
#endif
@@ -0,0 +1,17 @@
// MinecraftPT — Nether Color
// Dimension-specific color and lighting adjustments.
#ifndef NETHER_COLOR_GLSL
#define NETHER_COLOR_GLSL
vec3 GetDimensionSkylight(vec3 skyColor){
#ifdef DIMENSION_NETHER
return skyColor * 0.4;
#elif defined DIMENSION_END
return skyColor * 0.2;
#else
return skyColor;
#endif
}
#endif
@@ -0,0 +1,150 @@
#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
@@ -0,0 +1,72 @@
// MinecraftPT — Sunlight & Shadow
// Direct sunlight with RTWSM warped shadow map sampling and voxel shadow tracing.
#ifndef SUNLIGHT_SHADOW_GLSL
#define SUNLIGHT_SHADOW_GLSL
#include "/Lib/RTWSM/SampleWarp.glsl"
#include "/Lib/BasicFunctions/LightingConstants.glsl"
// Sample the warped shadow map
float SampleShadowMap(vec3 shadowPos){
vec2 shadowCoord = shadowPos.xy * 0.5 + 0.5;
vec3 shadowUv = vec3(UnshiftShadowScreenPos(shadowCoord), shadowPos.z * 0.5 + 0.5);
float shadow = 0.0;
float depth = shadowUv.z;
#ifdef SHADOW_QUALITY
#if SHADOW_QUALITY >= 2
// 3x3 PCF
for (int i = -1; i <= 1; i++){
for (int j = -1; j <= 1; j++){
vec2 sampleCoord = shadowUv.xy + vec2(i, j) * shadowPixelSize;
shadow += step(texelFetch(shadowcolor0, ivec2(sampleCoord * shadowSize), 0).a, depth) * (1.0 / 9.0);
}}
#else
shadow = step(texelFetch(shadowcolor0, ivec2(shadowUv.xy * shadowSize), 0).a, depth);
#endif
#else
shadow = step(texelFetch(shadowcolor0, ivec2(shadowUv.xy * shadowSize), 0).a, depth);
#endif
return shadow;
}
// Full sunlight evaluation: shadow map + optional voxel shadow tracing
float GetSunShadow(vec3 viewPos, vec3 worldPos, vec3 vertexNormal, float lightmap){
float shadow = 1.0;
#ifdef PT_SHADOW
vec3 shadowDir = normalize(shadowModelViewInverse2);
shadow = ShadowTracing(viewPos, worldPos, vertexNormal, shadowDir, lightmap);
#else
// Shadow map path
vec4 shadowPos = shadowProjection * shadowModelView * vec4(worldPos, 1.0);
if (shadowPos.w > 0.0){
vec3 shadowNdc = shadowPos.xyz / shadowPos.w;
if (all(lessThan(abs(shadowNdc.xy), vec2(1.0)))){
shadow = SampleShadowMap(shadowNdc);
}
}
#endif
return shadow;
}
// Direct sun light for a surface
vec3 GetSunlight(vec3 viewPos, vec3 worldPos, vec3 vertexNormal, vec3 worldNormal, float lightmap){
float shadow = GetSunShadow(viewPos, worldPos, vertexNormal, lightmap);
float NdotL = max(dot(worldNormal, GetSunDirWorld()), 0.0);
vec3 sunColor = GetSunIrradiance();
#ifdef COLORED_SHADOWS
// Sample shadow albedo for colored shadows (subtle)
vec3 shadowAlbedo = vec3(0.0);
sunColor *= 1.0 - shadowAlbedo * 0.3;
#endif
return sunColor * shadow * NdotL;
}
#endif
@@ -0,0 +1,29 @@
// MinecraftPT — Temporal Noise
// Blue noise sampling with temporal interleaving, used for dithering and ray offsets.
#ifndef TEMPORAL_NOISE_GLSL
#define TEMPORAL_NOISE_GLSL
float BlueNoiseTemporal(){
vec2 coord = (gl_FragCoord.xy + 0.5) / screenSize;
coord = fract(coord * vec2(128.0, 128.0) + 0.5);
vec2 texel = coord * vec2(127.0 / 128.0) + vec2(0.5 / 128.0);
float noise = textureLod(noisetex, texel, 0.0).r;
return fract(noise + frameCounter * 0.03125);
}
vec2 BlueNoiseTemporal2(){
vec2 coord = (gl_FragCoord.xy + 0.5) / screenSize;
coord = fract(coord * vec2(128.0, 128.0) + 0.5);
vec2 texel = coord * vec2(127.0 / 128.0) + vec2(0.5 / 128.0);
vec2 noise = textureLod(noisetex, texel, 0.0).rg;
return fract(noise + frameCounter * 0.03125);
}
// Interleaved gradient noise
float InterleavedNoise(vec2 pos){
vec3 magic = vec3(0.06711056, 0.00583715, 52.9829189);
return fract(magic.z * fract(dot(pos, magic.xy)));
}
#endif
@@ -0,0 +1,17 @@
// MinecraftPT — Vanilla Composite helpers
// Sky/cloud colors approximating vanilla for transitions and fog.
#ifndef VANILLA_COMPOSITE_GLSL
#define VANILLA_COMPOSITE_GLSL
vec3 GetVanillaSkyColor(vec3 dir){
vec3 skyColor = vec3(0.6, 0.8, 1.0);
float horizon = exp(-max(dir.y, 0.0) * 3.0);
return mix(skyColor * 0.3, skyColor, 1.0 - horizon);
}
vec3 GetVanillaFogColor(vec3 skyColor, float nightFactor){
return mix(skyColor, skyColor * vec3(0.2, 0.25, 0.4), nightFactor);
}
#endif