Initial commit: Minecraft 光追着色器包(从零实现的 path tracing)
This commit is contained in:
@@ -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
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user