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
+221
View File
@@ -0,0 +1,221 @@
#include "/Lib/Settings.glsl"
#include "/Lib/Utilities.glsl"
// MinecraftPT — GbufferData structures
#ifndef GBUFFER_DATA_GLSL
#define GBUFFER_DATA_GLSL
struct Material{
float roughness;
float metalness;
float emissiveness;
float scattering;
float reflectionStrength;
};
struct GbufferData{
vec3 albedo;
float albedoAlpha;
vec3 worldNormal;
vec3 vertexNormal;
vec2 lightmap;
float materialID;
float parallaxShadow;
Material material;
};
// Standard material defaults
#define material_air Material(1.0, 0.0, 0.0, 0.0, 0.0);
#define material_water Material(0.0, 0.018, 0.0, 0.0, 1.0);
#define material_glass Material(0.0, 0.04, 0.0, 0.0, 1.0);
// Material IDs (written to GBuffer)
#define MATID_DEFAULT 0.0
#define MATID_WATER 1.0
#define MATID_STAINEDGLASS 2.0
#define MATID_LEAVES 3.0
#define MATID_GRASS 4.0 // cross plant
#define MATID_HAND 5.0
#define MATID_ENTITIES 6.0
#define MATID_ENTITIES_PLAYER 7.0
#define MATID_ENTITIES_SNOW 8.0
#define MATID_LIGHTNING 9.0
#define MATID_SKY 10.0
#define MATID_TORCH 11.0
#define MATID_FIRE 12.0
#define MATID_ENDROD 13.0
#define MATID_AMETHYST 14.0
#define MATID_SOULTORCH 15.0
#define MATID_REDSTONE_TORCH 16.0
#define MATID_PARTICLE 17.0
#define MATID_END_PORTAL 18.0
#define MATID_SELECTION 19.0
#define MATID_COPPER_LANTERN 20.0
#define MATID_BEACON_BEAM 21.0
// Material from specular texture (LAB PBR)
Material MaterialFromTex(vec4 specTex){
Material material;
material.roughness = 1.0 - specTex.r;
material.roughness = material.roughness * material.roughness;
material.metalness = specTex.g;
material.reflectionStrength = saturate(material.roughness < 0.1 ? 1.0 : pow(specTex.r, 0.2));
material.reflectionStrength = saturate(material.reflectionStrength + material.metalness);
material.metalness = max(material.metalness, 0.04);
material.emissiveness = specTex.a;
material.scattering = 0.0;
return material;
}
// Predefined metal F0 values (from LAB PBR spec)
vec3 PredefinedMetalF0(float index){
vec3 f0 = vec3(0.0);
if (abs(index - 230.0 / 255.0) < 2e-4){
f0 = vec3(0.56, 0.58, 0.58); // Iron
}else if (abs(index - 231.0 / 255.0) < 2e-4){
f0 = vec3(1.00, 0.69, 0.28); // Gold
}else if (abs(index - 232.0 / 255.0) < 2e-4){
f0 = vec3(0.81, 0.82, 0.83); // Aluminum
}else if (abs(index - 233.0 / 255.0) < 2e-4){
f0 = vec3(0.50, 0.49, 0.49); // Chromium
}else if (abs(index - 234.0 / 255.0) < 2e-4){
f0 = vec3(0.95, 0.52, 0.35); // Copper
}else if (abs(index - 235.0 / 255.0) < 2e-4){
f0 = vec3(0.81, 0.83, 0.87); // Lead
}else if (abs(index - 236.0 / 255.0) < 2e-4){
f0 = vec3(0.66, 0.63, 0.58); // Platinum
}else if (abs(index - 237.0 / 255.0) < 2e-4){
f0 = vec3(0.95, 0.91, 0.81); // Silver
}
return f0;
}
// Read solid GBuffer data
GbufferData GetGbufferDataSoild(ivec2 texelCoord){
GbufferData data;
vec4 gbuffer2 = texelFetch(colortex2, texelCoord, 0);
vec4 gbuffer3 = texelFetch(colortex3, texelCoord, 0);
data.albedo = GammaToLinear(texelFetch(colortex0, texelCoord, 0).rgb);
data.albedoAlpha = 1.0;
data.worldNormal = DecodeNormal(texelFetch(colortex1, texelCoord, 0).xy);
data.vertexNormal = DecodeNormal(texelFetch(colortex1, texelCoord, 0).zw);
data.lightmap = gbuffer3.xy;
data.materialID = gbuffer2.a;
data.parallaxShadow = gbuffer3.b;
vec4 specTex = vec4(gbuffer2.r, gbuffer2.g, gbuffer2.b, 0.0);
data.material = MaterialFromTex(specTex);
return data;
}
// Read translucent GBuffer data
GbufferData GetGbufferDataTranslucent(ivec2 texelCoord, out bool isSmooth){
GbufferData data;
vec4 gbuffer5 = texelFetch(colortex5, texelCoord, 0);
vec4 gbuffer6 = texelFetch(colortex6, texelCoord, 0);
data.worldNormal = DecodeNormal(gbuffer6.xy);
data.vertexNormal = DecodeNormal(gbuffer6.zw);
data.lightmap = texelFetch(colortex7, texelCoord, 0).xy;
data.materialID = gbuffer6.a;
data.parallaxShadow = 1.0;
isSmooth = false;
if (data.materialID == MATID_WATER){
data.albedo = GammaToLinear(gbuffer5.rgb);
data.albedoAlpha = gbuffer5.a;
data.material = material_water;
isSmooth = true;
}else if (data.materialID == MATID_STAINEDGLASS){
data.albedo = GammaToLinear(gbuffer5.rgb);
data.albedoAlpha = gbuffer5.a;
data.material = material_glass;
isSmooth = true;
}else if (data.materialID == MATID_PARTICLE){
data.albedo = GammaToLinear(gbuffer5.rgb);
data.albedoAlpha = gbuffer5.a;
data.material = material_air;
}else{
data.albedo = GammaToLinear(texelFetch(colortex0, texelCoord, 0).rgb);
data.albedoAlpha = 1.0;
vec4 specTex = vec4(gbuffer2.r, gbuffer2.g, gbuffer2.b, 0.0);
data.material = MaterialFromTex(specTex);
}
return data;
}
// Material mask utilities
struct MaterialMask{
float sky;
float grass;
float leaves;
float hand;
float entityPlayer;
float water;
float stainedGlass;
float lightning;
float entitiesSnow;
float endrod;
float fire;
float torch;
float lightSource;
float redstoneTorch;
float soulTorch;
float amethyst;
float particle;
float endPortal;
float selection;
};
MaterialMask CalculateMasks(float materialIDs){
MaterialMask mask;
mask.sky = float(materialIDs == MATID_SKY);
mask.grass = float(materialIDs == MATID_GRASS || materialIDs == MATID_BEACON_BEAM);
mask.leaves = float(materialIDs == MATID_LEAVES);
mask.hand = float(materialIDs == MATID_HAND);
mask.water = float(materialIDs == MATID_WATER);
mask.stainedGlass = float(materialIDs == MATID_STAINEDGLASS);
mask.entityPlayer = float(materialIDs == MATID_ENTITIES_PLAYER);
mask.entitiesSnow = float(materialIDs == MATID_ENTITIES_SNOW || materialIDs == MATID_BEACON_BEAM);
mask.lightning = float(materialIDs == MATID_LIGHTNING);
mask.endrod = float(materialIDs == MATID_ENDROD);
mask.fire = float(materialIDs == MATID_FIRE);
mask.torch = float(materialIDs == MATID_TORCH);
mask.redstoneTorch = float(materialIDs == MATID_REDSTONE_TORCH);
mask.amethyst = float(materialIDs == MATID_AMETHYST);
mask.soulTorch = float(materialIDs == MATID_SOULTORCH || materialIDs == MATID_COPPER_LANTERN);
mask.particle = float(materialIDs == MATID_PARTICLE);
mask.endPortal = float(materialIDs == MATID_END_PORTAL);
mask.selection = float(materialIDs == MATID_SELECTION);
return mask;
}
void ApplyMaterial(inout Material material, in MaterialMask materialMask, inout bool isSmooth){
if (materialMask.water > 0.5){
material = material_water;
isSmooth = true;
}else if (materialMask.stainedGlass > 0.5){
material = material_glass;
isSmooth = true;
}
}
#endif
@@ -0,0 +1,13 @@
// MinecraftPT — Bloom CS (SIG)
// Bloom sprite / glare generation (compute shader utility).
#ifndef BLOOM_CS_SIG_GLSL
#define BLOOM_CS_SIG_GLSL
// Bloom glare from bright pixels
void EmitBloomGlare(ivec2 texel, vec3 color, float intensity){
// Simple bloom spike (cross pattern)
// This is a placeholder — actual implementation samples and adds to bloom buffer
}
#endif
@@ -0,0 +1,28 @@
#include "/Lib/Settings.glsl"
#include "/Lib/Utilities.glsl"
#include "/Lib/BasicFunctions/LightingConstants.glsl"
// MinecraftPT — Cloud Shadow
// Cloud shadow projection onto the ground from the cloud layer.
#ifndef CLOUD_SHADOW_GLSL
uniform sampler3D CloudNoise3D;
#define CLOUD_SHADOW_GLSL
float GetCloudShadow(vec3 worldPos){
float cloudAlt = mix(CLOUD_CLEAR_ALTITUDE, CLOUD_RAIN_ALTITUDE, wetness);
float cloudDensity = mix(CLOUD_CLEAR_DENSITY, CLOUD_RAIN_DENSITY, wetness);
// Project ground position onto cloud layer
vec3 shadowDir = normalize(GetSunDirWorld());
vec3 cloudPos = worldPos + shadowDir * (cloudAlt - worldPos.y) / shadowDir.y;
// Sample cloud density at that position
vec2 p = cloudPos.xz * CLOUD_BASE_NOISE_SCALE + frameTimeCounter * 0.001 * CLOUD_SPEED;
float n = textureLod(CloudNoise3D, vec3(p, 0.2), 0.0).r;
float shadow = 1.0 - saturate((n - 0.5) * cloudDensity * 2.0 * CLOUD_SHADOW);
return shadow;
}
#endif
+37
View File
@@ -0,0 +1,37 @@
// MinecraftPT — Depth of Field
// Circle of confusion computation and bokeh blur.
#ifndef DOF_GLSL
#define DOF_GLSL
// Compute CoC (circle of confusion) for a fragment
float GetCoC(float depth, float focalDepth){
float focus = focalDepth;
float aperture = DOF_BLUR;
float coc = abs(depth - focus) / focus * aperture * DOF_MAX_COC;
return clamp(coc, 0.0, DOF_MAX_COC);
}
// Simple bokeh blur (gather)
vec3 DofBlur(vec2 texelCoord, float coc){
vec3 color = vec3(0.0);
float weight = 0.0;
int radius = int(min(coc, 8.0)) + 1;
for (int i = -radius; i <= radius; i++){
for (int j = -radius; j <= radius; j++){
float dist = length(vec2(i, j));
if (dist > coc) continue;
vec2 coord = texelCoord + vec2(i, j);
vec3 sampleColor = texelFetch(colortex12, ivec2(coord), 0).rgb;
float w = max(0.0, 1.0 - dist / coc);
color += sampleColor * w;
weight += w;
}}
return weight > 0.0 ? color / weight : color;
}
#endif
@@ -0,0 +1,39 @@
#include "/Lib/Settings.glsl"
#include "/Lib/Utilities.glsl"
// MinecraftPT — End Sky
// End dimension sky: stars, planet, accretion disc around black hole.
#ifndef END_SKY_GLSL
#define END_SKY_GLSL
vec3 GetEndSky(vec3 dir, vec3 sunDir){
dir = normalize(dir);
// Dark base
vec3 color = vec3(0.01, 0.01, 0.02);
// Stars (hash-based)
float stars = 0.0;
vec3 starDir = dir;
for (int i = 0; i < 32; i++){
vec3 seed = vec3(i * 0.1, 0.5, 0.7);
vec3 starPos = normalize(hash3(seed.xy) - 0.5);
float star = exp(-(1.0 - dot(dir, starPos)) * 1000.0);
stars += star * hash1(seed.xy);
}
color += stars * 0.5;
// Planet (distant body)
vec3 planetDir = normalize(vec3(0.5, 0.3, 0.0));
float planet = exp(-(1.0 - dot(dir, planetDir)) * 200.0);
color += vec3(0.3, 0.4, 0.6) * planet * 0.8;
// Accretion disc (around planet)
float disc = exp(-abs(dot(normalize(dir.xz), normalize(planetDir.xz))) * 50.0);
disc *= step(abs(dir.y), 0.1);
color += vec3(1.0, 0.6, 0.2) * disc * 0.5;
return color;
}
#endif
@@ -0,0 +1,37 @@
// MinecraftPT — Parallax Occlusion Mapping
// Steep parallax mapping with PCF soft shadows.
#ifndef PARALLAX_GLSL
#define PARALLAX_GLSL
// Steep parallax mapping
vec2 ParallaxMapping(vec2 texcoord, vec3 viewDir){
float height = texture(tex, texcoord).a;
vec2 delta = viewDir.xy / viewDir.z * PARALLAX_DEPTH;
int numLayers = max(1, int(PARALLAX_QUALITY));
float layerDepth = 1.0 / float(numLayers);
float currentDepth = 0.0;
vec2 currentCoord = texcoord;
for (int i = 0; i < numLayers; i++){
currentCoord -= delta * layerDepth;
height = texture(tex, currentCoord).a;
currentDepth += layerDepth;
if (height < currentDepth) break;
}
// Parallax shadow
float shadow = 1.0;
#ifdef PARALLAX_SHADOW
// PCF shadow
for (int i = 0; i < PARALLAX_SHADOW_QUALITY; i++){
vec2 shadowCoord = currentCoord + delta * float(i) / float(PARALLAX_SHADOW_QUALITY);
shadow *= step(currentDepth - layerDepth * float(i) / float(PARALLAX_SHADOW_QUALITY), texture(tex, shadowCoord).a);
}
#endif
return currentCoord;
}
#endif
@@ -0,0 +1,38 @@
#include "/Lib/Settings.glsl"
#include "/Lib/Utilities.glsl"
#include "/Lib/BasicFunctions/LightingConstants.glsl"
// MinecraftPT — Planar Clouds
// Simple 2D cloud layer rendered as a plane at altitude.
#ifndef PLANAR_CLOUDS_GLSL
#define PLANAR_CLOUDS_GLSL
// Sample cloud density at a world XZ position (2D noise + coverage)
float GetPlanarCloudDensity(vec2 xz, float time, out vec3 cloudColor){
// Coverage by weather
float coverage = mix(PC_CLEAR_COVERAGE, PC_RAIN_COVERAGE, wetness);
float density = mix(PC_CLEAR_DENSITY, PC_RAIN_DENSITY, wetness);
float sunlighting = mix(PC_CLEAR_SUNLIGHTING, PC_RAIN_SUNLIGHTING, wetness);
float skylighting = mix(PC_CLEAR_SKYLIGHTING, PC_RAIN_SKYLIGHTING, wetness);
// FBM noise
vec2 p = xz * PC_NOISE_SCALE + vec2(time * 0.01, 0.0);
float n = 0.0;
float amp = 0.5;
for (int i = 0; i < 3; i++){
n += textureLod(CloudNoise3D, vec3(p, 0.5), 0.0).r * amp;
p *= 2.0;
amp *= 0.5;
}
float clouds = saturate((n - (1.0 - coverage)) * (1.0 / max(coverage, 0.01)));
// Cloud color: lit by sun and sky
float sunFactor = sunlighting;
cloudColor = mix(GetCloudAtmoIrradiance(), GetCloudSunIrradiance(), sunFactor) * clouds
+ vec3(1.0) * skylighting * clouds;
return clouds * density;
}
#endif
@@ -0,0 +1,14 @@
// MinecraftPT — Ripple
// Rain-induced ripple normal map for water surfaces.
#ifndef RIPPLE_GLSL
uniform sampler2D ripple2D;
#define RIPPLE_GLSL
vec2 GetRippleNormal(vec3 worldPos, float time){
vec2 coord = worldPos.xz * 0.1;
vec2 ripple = textureLod(ripple2D, fract(coord + time * 0.02), 0.0).rg;
return ripple * 2.0 - 1.0;
}
#endif
@@ -0,0 +1,47 @@
#include "/Lib/BasicFunctions/LightingConstants.glsl"
// MinecraftPT — Volumetric Fog
// Height-based volumetric fog with 3D noise, ray marched in the volumetric pass.
#ifndef VOLUMETRIC_FOG_GLSL
uniform sampler3D CloudNoise3D;
#define VOLUMETRIC_FOG_GLSL
// Fog density at a world position (height + noise)
float GetVolumetricFogDensity(vec3 worldPos, float time){
float height = worldPos.y;
// Two-layer height fog
float density = VFOG_DENSITY_BASE;
density += exp(-(height - VFOG_HEIGHT) * VFOG_FALLOFF) * VFOG_DENSITY;
density += exp(-(height - VFOG_HEIGHT_2) * VFOG_FALLOFF * 2.0) * VFOG_DENSITY * 0.5;
// Noise variation
#ifdef VFOG_NOISE_TYPE
if (VFOG_NOISE_TYPE > 0){
vec3 p = worldPos * vec3(VFOG_NOISE_HORIZONTAL_SCALE, VFOG_NOISE_VERTICAL_SCALE, VFOG_NOISE_HORIZONTAL_SCALE) + vec3(time * 0.01, 0.0, time * 0.008);
float n = 0.0;
float amp = 0.5;
for (int i = 0; i < VFOG_NOISE_OCTAVE; i++){
n += textureLod(CloudNoise3D, fract(p), 0.0).r * amp;
p *= 2.0;
amp *= 0.5;
}
density *= 1.0 + (n - 0.5) * VFOG_NOISE_COVERAGE * 2.0;
}
#endif
// Rain fog boost
density *= 1.0 + wetness * VFOG_RAIN_DENSITY_MUL;
return max(density, 0.0);
}
// In-scattering color for fog (sun + sky)
vec3 GetFogColor(vec3 worldPos, vec3 sunDir){
vec3 sunColor = GetSunIrradiance() * VFOG_SUNLIGHT_DENSITY;
vec3 skyColor = GetAtmoIrradiance();
return skyColor + sunColor * 0.5;
}
#endif
@@ -0,0 +1,15 @@
// MinecraftPT — Water Fog
// Underwater volumetric fog with scattering colors.
#ifndef WATER_FOG_GLSL
#define WATER_FOG_GLSL
vec3 GetWaterFogColor(vec3 worldPos){
return vec3(WATER_SCATTERING_R, WATER_SCATTERING_G, WATER_SCATTERING_B) * WATER_SCATTERING_DENSITY;
}
float GetWaterFogDensity(vec3 worldPos){
return WATER_SCATTERING_DENSITY;
}
#endif
@@ -0,0 +1,28 @@
// MinecraftPT — Water Waves
// Gerstner-style water wave normals with multi-octave detail.
#ifndef WATER_WAVES_GLSL
#define WATER_WAVES_GLSL
vec3 GetWaveNormal(vec3 worldPos, float lightmap){
vec2 pos = worldPos.xz;
float time = frameTimeCounter * 0.05 * WAVE_SPEED;
// Multi-octave sine waves
float wave1 = sin(pos.x * 0.1 * WAVE_SCALE + time) * cos(pos.y * 0.08 * WAVE_SCALE + time * 0.7);
float wave2 = sin(pos.x * 0.2 * WAVE_SCALE + time * 1.3) * cos(pos.y * 0.15 * WAVE_SCALE - time * 0.9);
float wave3 = sin((pos.x + pos.y) * 0.35 * WAVE_SCALE + time * 1.7) * 0.5;
// Height field derivatives for normal
float dx = cos(pos.x * 0.1 * WAVE_SCALE + time) * 0.1 * WAVE_SCALE * 0.5 * 0.05
+ cos(pos.x * 0.2 * WAVE_SCALE + time * 1.3) * 0.2 * WAVE_SCALE * 0.5 * 0.04;
float dz = -sin(pos.x * 0.1 * WAVE_SCALE + time) * sin(pos.y * 0.08 * WAVE_SCALE + time * 0.7) * 0.08 * WAVE_SCALE * 0.5 * 0.05
- sin(pos.x * 0.2 * WAVE_SCALE + time * 1.3) * sin(pos.y * 0.15 * WAVE_SCALE - time * 0.9) * 0.15 * WAVE_SCALE * 0.5 * 0.04;
vec3 normal = normalize(vec3(-dx, 1.0, -dz) * WAVE_NORMAL_STRENGTH + vec3(0.0, 1.0 - WAVE_NORMAL_STRENGTH, 0.0));
return normal;
}
#endif
@@ -0,0 +1,39 @@
#include "/Lib/Settings.glsl"
#include "/Lib/Utilities.glsl"
// MinecraftPT — Waving Plants
// Wind animation for grass, plants, leaves.
#ifndef WAVING_PLANTS_GLSL
#define WAVING_PLANTS_GLSL
void WavingPlants(inout vec4 worldPos, float lightLevel){
float time = frameTimeCounter * 0.05 * WAVING_SPEED;
// Wind direction
vec2 wind = vec2(0.5, 0.3) * sin(time) + vec2(0.2);
// Amplitude by plant type
float amplitude = GRASS_AMPLITUDE;
#ifdef IS_LEAVES
amplitude = LEAVES_AMPLITUDE;
#endif
float dist = length(worldPos.xyz - gbufferModelViewInverse[3].xyz);
float fade = 1.0 - saturate(dist / WAVING_RANGE);
vec3 vertexPos = worldPos.xyz;
// Vertex-based wave
vec3 offset = vec3(wind * sin(vertexPos.x * 0.3 + vertexPos.z * 0.2 + time * 2.0), 0.0);
offset *= vertexPos.y * amplitude * fade;
// Random per-vertex jitter (height-based)
float heightFactor = vertexPos.y;
float noise = sin(vertexPos.x * 12.9898 + vertexPos.z * 78.233 + time) * 0.5 + 0.5;
offset.x += noise * amplitude * 0.5 * heightFactor * fade;
offset.z += noise * amplitude * 0.3 * heightFactor * fade;
worldPos.xyz += offset;
}
#endif
@@ -0,0 +1,64 @@
#include "/Lib/Settings.glsl"
#include "/Lib/Utilities.glsl"
// MinecraftPT — Diffuse Spatial Filter
// Edge-avoiding A-trous wavelet spatial filter. Multi-pass (detail levels).
#ifndef DIFFUSE_SPATIAL_FILTER_GLSL
#define DIFFUSE_SPATIAL_FILTER_GLSL
#include "/Lib/Utilities.glsl"
// Single A-trous pass at the given step size
vec3 DiffuseSpatialPass(vec3 center, vec2 texelCoord, int step){
vec3 result = center * 0.25;
// Center depth and normal for edge detection
float depth = texelFetch(depthtex0, texelCoord * 2.0, 0).r;
vec3 normal = DecodeNormal(texelFetch(colortex1, texelCoord * 2.0, 0).xy);
vec3 centerAlbedo = texelFetch(colortex0, texelCoord * 2.0, 0).rgb;
// Reconstruct view position for depth edge weight
vec4 viewPos = gbufferProjectionInverse * vec4(texelCoord * 2.0 / screenSize * 2.0 - 1.0, depth * 2.0 - 1.0, 1.0);
viewPos.xyz /= viewPos.w;
float weightSum = 0.25;
vec2 offsets[4] = vec2[4](vec2(1.0, 0.0), vec2(-1.0, 0.0), vec2(0.0, 1.0), vec2(0.0, -1.0));
for (int i = 0; i < 4; i++){
vec2 coord = texelCoord + offsets[i] * float(step);
vec3 sampleColor = texelFetch(colortex7, ivec2(coord), 0).rgb;
float sampleDepth = texelFetch(depthtex0, coord * 2.0, 0).r;
vec3 sampleNormal = DecodeNormal(texelFetch(colortex1, coord * 2.0, 0).xy);
// Edge-avoiding weights
float depthWeight = exp(-abs(depth - sampleDepth) * PT_DIFFUSE_SPATIAL_FILTER_DEPTH_WEIGHT * 100.0);
float normalWeight = pow(max(dot(normal, sampleNormal), 0.0), 8.0 * PT_DIFFUSE_SPATIAL_FILTER_NORMAL_WEIGHT + 1.0);
float luminanceWeight = exp(-abs(luminance(center) - luminance(sampleColor)) * PT_DIFFUSE_SPATIAL_FILTER_LUMINANCE_WEIGHT * 10.0);
float weight = depthWeight * normalWeight * luminanceWeight;
result += sampleColor * weight;
weightSum += weight;
}
return result / weightSum;
}
// Run the spatial filter chain (detail levels)
vec3 DiffuseSpatialFilter(vec2 texelCoord){
vec3 color = texelFetch(colortex7, ivec2(texelCoord), 0).rgb;
int levels = 1 + int(PT_DIFFUSE_SPATIAL_FILTER_DETAIL);
int step = 1;
for (int i = 0; i < levels; i++){
color = DiffuseSpatialPass(color, texelCoord, step);
step *= 2;
}
return color;
}
#endif
@@ -0,0 +1,42 @@
// MinecraftPT — Diffuse Temporal Filter
// Reprojects the previous frame's denoised diffuse result using motion vectors
// and accumulates with the current noisy frame.
#ifndef DIFFUSE_TEMPORAL_FILTER_GLSL
#define DIFFUSE_TEMPORAL_FILTER_GLSL
#include "/Lib/Utilities.glsl"
vec3 DiffuseTemporalAccumulate(vec3 current, vec2 texelCoord, vec3 prevColor){
vec2 motionVec = texelFetch(colortex10, ivec2(texelCoord), 0).xy;
vec2 prevCoord = (texelCoord + 0.5) - motionVec;
// Validate reprojection: depth comparison
float depth = texelFetch(depthtex0, texelCoord * 2.0, 0).r;
float prevDepth = textureLod(prevDepth2D, prevCoord / (screenSize * 0.5), 0.0).r;
float depthValid = step(abs(depth - prevDepth), 0.05 * depth + 0.001);
// History confidence based on accumulation count
float accum = 1.0 / float(PT_DIFFUSE_TEMPORAL_MAX_ACCUM);
// Sample previous
vec3 history = textureLod(colortex7, prevCoord / (screenSize * 0.5), 0.0).rgb;
// Neighborhood clamp to reduce ghosting
vec3 minColor = history;
vec3 maxColor = history;
for (int i = -1; i <= 1; i++){
for (int j = -1; j <= 1; j++){
vec3 c = textureLod(colortex7, (prevCoord + vec2(i, j)) / (screenSize * 0.5), 0.0).rgb;
minColor = min(minColor, c);
maxColor = max(maxColor, c);
}}
history = clamp(history, minColor, maxColor);
float blend = mix(accum, 1.0, depthValid * PT_DIFFUSE_TEMPORAL_HISTORY_FIX * 0.5);
return mix(current, history, blend * (1.0 - accum));
}
#endif
@@ -0,0 +1,32 @@
#include "/Lib/Settings.glsl"
#include "/Lib/Utilities.glsl"
// MinecraftPT — Diffuse Variance Estimation
// Computes luminance moments to drive temporal accumulation and firefly rejection.
#ifndef DIFFUSE_VARIANCE_ESTIMATION_GLSL
#define DIFFUSE_VARIANCE_ESTIMATION_GLSL
#include "/Lib/Utilities.glsl"
vec2 DiffuseEstimateVariance(vec3 color, vec2 texelCoord){
float lum = luminance(color);
float lum2 = lum * lum;
// Local variance from neighbors (5-tap)
float variance = 0.0;
for (int i = -1; i <= 1; i++){
for (int j = -1; j <= 1; j++){
if (i == 0 && j == 0) continue;
vec3 c = texelFetch(colortex7, ivec2(texelCoord) + ivec2(i, j), 0).rgb;
float l = luminance(c);
variance += (l - lum) * (l - lum);
}}
variance /= 8.0;
// Clamp fireflies
float firefly = step(1.0, lum / max(variance * 4.0, 0.001));
return vec2(lum, firefly);
}
#endif
@@ -0,0 +1,55 @@
#include "/Lib/Settings.glsl"
#include "/Lib/Utilities.glsl"
// MinecraftPT — Specular Spatial Filter
// Edge-avoiding spatial filter for specular reflections (fewer passes than diffuse).
#ifndef SPECULAR_SPATIAL_FILTER_GLSL
#define SPECULAR_SPATIAL_FILTER_GLSL
#include "/Lib/Utilities.glsl"
vec3 SpecularSpatialPass(vec3 center, vec2 texelCoord, int step){
vec3 result = center * 0.25;
float depth = texelFetch(depthtex0, texelCoord * 2.0, 0).r;
vec3 normal = DecodeNormal(texelFetch(colortex1, texelCoord * 2.0, 0).xy);
float weightSum = 0.25;
vec2 offsets[4] = vec2[4](vec2(1.0, 0.0), vec2(-1.0, 0.0), vec2(0.0, 1.0), vec2(0.0, -1.0));
for (int i = 0; i < 4; i++){
vec2 coord = texelCoord + offsets[i] * float(step);
vec3 sampleColor = texelFetch(colortex11, ivec2(coord), 0).rgb;
float sampleDepth = texelFetch(depthtex0, coord * 2.0, 0).r;
vec3 sampleNormal = DecodeNormal(texelFetch(colortex1, coord * 2.0, 0).xy);
float depthWeight = exp(-abs(depth - sampleDepth) * PT_DIFFUSE_SPATIAL_FILTER_DEPTH_WEIGHT * 100.0);
float normalWeight = pow(max(dot(normal, sampleNormal), 0.0), 8.0 * PT_DIFFUSE_SPATIAL_FILTER_NORMAL_WEIGHT + 1.0);
float luminanceWeight = exp(-abs(luminance(center) - luminance(sampleColor)) * PT_DIFFUSE_SPATIAL_FILTER_LUMINANCE_WEIGHT * 10.0);
float weight = depthWeight * normalWeight * luminanceWeight;
result += sampleColor * weight;
weightSum += weight;
}
return result / weightSum;
}
vec3 SpecularSpatialFilter(vec2 texelCoord){
vec3 color = texelFetch(colortex11, ivec2(texelCoord), 0).rgb;
int levels = 1 + int(PT_DIFFUSE_SPATIAL_FILTER_DETAIL) / 2;
int step = 1;
for (int i = 0; i < levels; i++){
color = SpecularSpatialPass(color, texelCoord, step);
step *= 2;
}
return color;
}
#endif
@@ -0,0 +1,38 @@
// MinecraftPT — Specular Temporal Filter
// Temporal accumulation for specular reflections with reprojection.
#ifndef SPECULAR_TEMPORAL_FILTER_GLSL
#define SPECULAR_TEMPORAL_FILTER_GLSL
#include "/Lib/Utilities.glsl"
vec3 SpecularTemporalAccumulate(vec3 current, vec2 texelCoord){
vec2 motionVec = texelFetch(colortex10, ivec2(texelCoord), 0).xy;
vec2 prevCoord = (texelCoord + 0.5) - motionVec;
float depth = texelFetch(depthtex0, texelCoord * 2.0, 0).r;
float prevDepth = textureLod(prevDepth2D, prevCoord / (screenSize * 0.5), 0.0).r;
float depthValid = step(abs(depth - prevDepth), 0.05 * depth + 0.001);
float accum = 1.0 / float(PT_DIFFUSE_TEMPORAL_MAX_ACCUM);
vec3 history = textureLod(colortex11, prevCoord / (screenSize * 0.5), 0.0).rgb;
// Neighborhood clamp
vec3 minColor = history;
vec3 maxColor = history;
for (int i = -1; i <= 1; i++){
for (int j = -1; j <= 1; j++){
vec3 c = textureLod(colortex11, (prevCoord + vec2(i, j)) / (screenSize * 0.5), 0.0).rgb;
minColor = min(minColor, c);
maxColor = max(maxColor, c);
}}
history = clamp(history, minColor, maxColor);
float blend = mix(accum, 1.0, depthValid * PT_DIFFUSE_TEMPORAL_HISTORY_FIX * 0.5);
return mix(current, history, blend * (1.0 - accum));
}
#endif
@@ -0,0 +1,54 @@
#include "/Lib/BasicFunctions/LightingConstants.glsl"
// MinecraftPT — SampleIRC
// Sampling the irradiance cache: a 3D grid of pre-computed diffuse irradiance
// used to cheaply evaluate indirect diffuse light.
#ifndef SAMPLE_IRC_GLSL
#define SAMPLE_IRC_GLSL
// Sample irradiance cache at a world position (trilinear)
vec3 SampleIRC(vec3 worldPos){
vec3 voxelPos = WorldToVoxel(worldPos);
vec3 coord = voxelPos / float(ircResolution);
if (clamp(coord, vec3(0.0), vec3(1.0)) == coord){
coord *= float(ircResolution) - 1.0;
vec3 base = floor(coord);
vec3 frac = coord - base;
ivec3 i0 = ivec3(base);
ivec3 i1 = min(i0 + 1, ivec3(ircResolution - 1));
vec3 c000 = texelFetch(irradianceCache3D, i0, 0).rgb;
vec3 c100 = texelFetch(irradianceCache3D, ivec3(i1.x, i0.y, i0.z), 0).rgb;
vec3 c010 = texelFetch(irradianceCache3D, ivec3(i0.x, i1.y, i0.z), 0).rgb;
vec3 c110 = texelFetch(irradianceCache3D, ivec3(i1.x, i1.y, i0.z), 0).rgb;
vec3 c001 = texelFetch(irradianceCache3D, ivec3(i0.x, i0.y, i1.z), 0).rgb;
vec3 c101 = texelFetch(irradianceCache3D, ivec3(i1.x, i0.y, i1.z), 0).rgb;
vec3 c011 = texelFetch(irradianceCache3D, ivec3(i0.x, i1.y, i1.z), 0).rgb;
vec3 c111 = texelFetch(irradianceCache3D, i1, 0).rgb;
vec3 x00 = mix(c000, c100, frac.x);
vec3 x10 = mix(c010, c110, frac.x);
vec3 x01 = mix(c001, c101, frac.x);
vec3 x11 = mix(c011, c111, frac.x);
vec3 y0 = mix(x00, x10, frac.y);
vec3 y1 = mix(x01, x11, frac.y);
return mix(y0, y1, frac.z);
}
// Outside the cache — fall back to sky ambient
return GetCelestialIrradiance() + GetAtmoIrradiance();
}
// Normal-aware IRC sampling (bias by surface normal facing)
vec3 SampleIRCNormal(vec3 worldPos, vec3 normal){
vec3 irc = SampleIRC(worldPos);
// Simple hemisphere shading via normal alignment with up
float upFactor = normal.y * 0.5 + 0.5;
return irc * (0.5 + 0.5 * upFactor);
}
#endif
@@ -0,0 +1,130 @@
#include "/Lib/Settings.glsl"
#include "/Lib/Utilities.glsl"
// MinecraftPT — Shadow Tracing
// Direct sunlight shadow rays: march from surface toward the sun through the
// voxel grid. Soft penumbra via distance-weighted ray length.
#ifndef SHADOW_TRACING_GLSL
#define SHADOW_TRACING_GLSL
#include "/Lib/PathTracing/Tracer/TracingUtilities.glsl"
float ShadowTracing(vec3 viewPos, vec3 worldPos, vec3 vertexNormal, vec3 lightVector, float lightMap){
float shadow = 1.0;
vec3 voxelPos = WorldToVoxel(worldPos);
voxelPos += vertexNormal * (-viewPos.z * 0.0003);
if (clamp(voxelPos, vec3(0.0), vec3(voxelResolution)) == voxelPos){
lightMap = saturate(1.0 - lightMap * 2.0);
vec2 shadowWeight = vec2(
4.0 - 2.0 * saturate(lightMap - viewPos.z * 0.01),
0.2 + 0.5 * saturate(lightMap - viewPos.z * 0.01)
);
Ray ray = PackRay(voxelPos, lightVector);
vec3 voxelCoord = floor(ray.ori);
vec3 totalStep = (ray.sdir * (voxelCoord - ray.ori + 0.5) + 0.5) * abs(ray.rdir);
float rayLength = 0.0;
vec3 tracingNext;
bool hit = false;
for (int i = 0; i < 64; i++){
if (clamp(voxelCoord, vec3(0.0), vec3(voxelResolution - 0.5)) != voxelCoord) break;
vec4 voxelData = texelFetch(voxelData3D, ivec3(voxelCoord), 0);
float voxelID = DecodeVoxelID(voxelData.z);
// Full block or cutout shape
if (voxelID >= 999.0){
hit = rayLength > 0.0;
}else if (voxelID < 1000.0 && voxelID > 1.0){
float rawID = 1000.0 - voxelID;
rayLength = minVec3(totalStep);
hit = HitShape_Lite(ray, voxelCoord, rawID, rayLength);
}
if (hit){
shadow = saturate((rayLength - shadowWeight.y) * shadowWeight.x);
break;
}
// Sparse skip
float marker = voxelData.z;
if (marker > 0.60 && marker < 0.92){
float skipSize = marker > 0.90 ? 8.0 : (marker > 0.70 ? 4.0 : 2.0);
vec3 nextBoundary = floor((voxelCoord + 1.0) / skipSize) * skipSize;
vec3 distToBoundary = (nextBoundary - voxelCoord) * abs(ray.rdir);
float tSkip = minVec3(distToBoundary) + 1e-4;
rayLength += tSkip;
vec3 stepVec = ray.sdir * abs(ray.rdir) * tSkip;
ray.ori += stepVec;
voxelCoord = floor(ray.ori);
totalStep = (ray.sdir * (voxelCoord - ray.ori + 0.5) + 0.5) * abs(ray.rdir);
continue;
}
rayLength = minVec3(totalStep);
tracingNext = step(totalStep, vec3(rayLength));
voxelCoord += tracingNext * ray.sdir;
totalStep += tracingNext * abs(ray.rdir);
}
}
return shadow;
}
// Simplified version for IRC / light sampling (no soft penumbra)
float SimpleShadowTracing(vec3 voxelPos, vec3 lightVector){
Ray ray = PackRay(voxelPos, lightVector);
vec3 voxelCoord = floor(ray.ori);
vec3 totalStep = (ray.sdir * (voxelCoord - ray.ori + 0.5) + 0.5) * abs(ray.rdir);
float rayLength = 0.0;
vec3 tracingNext;
bool hit = false;
for (int i = 0; i < 64; i++){
if (clamp(voxelCoord, vec3(0.0), vec3(voxelResolution - 0.5)) != voxelCoord) break;
vec4 voxelData = texelFetch(voxelData3D, ivec3(voxelCoord), 0);
float voxelID = DecodeVoxelID(voxelData.z);
if (voxelID >= 999.0){
hit = rayLength > 0.0;
}else if (voxelID < 1000.0 && voxelID > 1.0){
float rawID = 1000.0 - voxelID;
rayLength = minVec3(totalStep);
hit = HitShape_Lite(ray, voxelCoord, rawID, rayLength);
}
if (hit) break;
// Sparse skip
float marker = voxelData.z;
if (marker > 0.60 && marker < 0.92){
float skipSize = marker > 0.90 ? 8.0 : (marker > 0.70 ? 4.0 : 2.0);
vec3 nextBoundary = floor((voxelCoord + 1.0) / skipSize) * skipSize;
vec3 distToBoundary = (nextBoundary - voxelCoord) * abs(ray.rdir);
float tSkip = minVec3(distToBoundary) + 1e-4;
rayLength += tSkip;
vec3 stepVec = ray.sdir * abs(ray.rdir) * tSkip;
ray.ori += stepVec;
voxelCoord = floor(ray.ori);
totalStep = (ray.sdir * (voxelCoord - ray.ori + 0.5) + 0.5) * abs(ray.rdir);
continue;
}
rayLength = minVec3(totalStep);
tracingNext = step(totalStep, vec3(rayLength));
voxelCoord += tracingNext * ray.sdir;
totalStep += tracingNext * abs(ray.rdir);
}
return float(!hit);
}
#endif
@@ -0,0 +1,149 @@
#include "/Lib/Settings.glsl"
#include "/Lib/Utilities.glsl"
// MinecraftPT — Specular Tracer
// Traces GGX-sampled reflection/refraction rays through the voxel grid and
// accumulates the reflected radiance (incl. light sphere contributions).
#ifndef SPECULAR_TRACER_GLSL
#define SPECULAR_TRACER_GLSL
#include "/Lib/PathTracing/Tracer/TracingUtilities.glsl"
#include "/Lib/BasicFunctions/LightingConstants.glsl"
#include "/Lib/PathTracing/Tracer/ShadowTracing.glsl"
#include "/Lib/PathTracing/Tracer/SampleIRC.glsl"
// Panorama: 3:2 cubemap cross. Map direction to face UV.
float absX = abs(dir.x), absY = abs(dir.y), absZ = abs(dir.z);
float maxAxis = max(absX, max(absY, absZ));
vec2 uv;
vec3 tdir = dir / maxAxis;
if (maxAxis == absX){
uv = vec2(tdir.y * 0.5 + 0.5, tdir.z * 0.5 + 0.5) / vec2(3.0, 2.0) + vec2(0.0, 0.5) * vec2(1.0/3.0, 1.0/2.0);
if (tdir.x > 0.0){
uv = vec2(tdir.y * 0.5 + 0.5, tdir.z * 0.5 + 0.5) / vec2(3.0, 2.0) + vec2(1.0/3.0, 0.5/2.0);
}
}else if (maxAxis == absY){
uv = vec2(tdir.x * 0.5 + 0.5, tdir.z * 0.5 + 0.5) / vec2(3.0, 2.0) + vec2(2.0/3.0, 0.5/2.0);
if (tdir.y > 0.0){
uv = vec2(tdir.x * 0.5 + 0.5, tdir.z * 0.5 + 0.5) / vec2(3.0, 2.0) + vec2(1.0/3.0, 0.5/2.0);
}
}else{
uv = vec2(tdir.x * 0.5 + 0.5, tdir.y * 0.5 + 0.5) / vec2(3.0, 2.0) + vec2(2.0/3.0, 1.5/2.0);
if (tdir.z > 0.0){
uv = vec2(tdir.x * 0.5 + 0.5, tdir.y * 0.5 + 0.5) / vec2(3.0, 2.0) + vec2(1.0/3.0, 1.5/2.0);
}
}
return textureLod(skyBox2D, uv, 0.0).rgb;
}
// Trace a single specular ray and accumulate radiance.
// origin: world pos (voxel space handled inside), dir: normalized direction
vec3 SpecularTrace(vec3 voxelPos, vec3 dir, float maxDist, vec2 noise){
vec3 result = vec3(0.0);
Ray ray = PackRay(voxelPos, dir);
vec3 voxelCoord = floor(ray.ori);
vec3 totalStep = (ray.sdir * (voxelCoord - ray.ori + 0.5) + 0.5) * abs(ray.rdir);
float rayLength = 0.0;
vec3 tracingNext;
bool hit = false;
for (int i = 0; i < 128; i++){
if (clamp(voxelCoord, vec3(0.0), vec3(voxelResolution - 0.5)) != voxelCoord){
// Escaped the voxel grid — sample sky
result = SampleSkyBox(dir);
break;
}
if (rayLength > maxDist){
result = SampleSkyBox(dir);
break;
}
vec4 voxelData = texelFetch(voxelData3D, ivec3(voxelCoord), 0);
float voxelID = DecodeVoxelID(voxelData.z);
// Light source: accumulate sphere light
if (IsLightSphere(voxelID)){
result += HitLightShpereReflection(ray, voxelCoord, voxelID, rayLength);
rayLength = minVec3(totalStep);
tracingNext = step(totalStep, vec3(rayLength));
voxelCoord += tracingNext * ray.sdir;
totalStep += tracingNext * abs(ray.rdir);
continue;
}
if (voxelID >= 999.0){ // Full block
// Shade the hit point: sample albedo from atlas, apply lighting
vec3 hitPos = ray.ori + ray.dir * rayLength;
vec3 hitNormal = -step(vec3(rayLength), totalStep - abs(ray.rdir)) * ray.sdir;
vec2 midCoord = voxelData.xy;
vec3 albedo = SampleVoxelAlbedo(midCoord, hitPos, hitNormal);
// Direct light from sun
vec3 sunColor = GetSunIrradiance();
float sunShadow = SimpleShadowTracing(hitPos + hitNormal * 0.01, GetSunDirWorld());
vec3 direct = albedo * sunColor * sunShadow * max(dot(hitNormal, GetSunDirWorld()), 0.0);
// Sky ambient from IRC
vec3 irc = SampleIRC(hitPos);
result += direct + irc * albedo * 0.5;
hit = true;
break;
}else if (voxelID < 1000.0 && voxelID > 1.0){
// Cutout shape
float rawID = 1000.0 - voxelID;
rayLength = minVec3(totalStep);
vec3 n;
if (HitShape(ray, voxelCoord, rawID, rayLength, n)){
vec3 hitPos = ray.ori + ray.dir * rayLength;
vec2 midCoord = voxelData.xy;
vec3 albedo = SampleVoxelAlbedo(midCoord, hitPos, n);
vec3 sunColor = GetSunIrradiance();
float sunShadow = SimpleShadowTracing(hitPos + n * 0.01, GetSunDirWorld());
vec3 direct = albedo * sunColor * sunShadow * max(dot(n, GetSunDirWorld()), 0.0);
vec3 irc = SampleIRC(hitPos);
result += direct + irc * albedo * 0.5;
hit = true;
break;
}
}
// Sparse skip
float marker = voxelData.z;
if (marker > 0.60 && marker < 0.92){
float skipSize = marker > 0.90 ? 8.0 : (marker > 0.70 ? 4.0 : 2.0);
vec3 nextBoundary = floor((voxelCoord + 1.0) / skipSize) * skipSize;
vec3 distToBoundary = (nextBoundary - voxelCoord) * abs(ray.rdir);
float tSkip = minVec3(distToBoundary) + 1e-4;
rayLength += tSkip;
vec3 stepVec = ray.sdir * abs(ray.rdir) * tSkip;
ray.ori += stepVec;
voxelCoord = floor(ray.ori);
totalStep = (ray.sdir * (voxelCoord - ray.ori + 0.5) + 0.5) * abs(ray.rdir);
continue;
}
rayLength = minVec3(totalStep);
tracingNext = step(totalStep, vec3(rayLength));
voxelCoord += tracingNext * ray.sdir;
totalStep += tracingNext * abs(ray.rdir);
}
if (!hit){
result = SampleSkyBox(dir);
}
return result;
}
#endif
@@ -0,0 +1,33 @@
// MinecraftPT — Tracing Noise
// Noise functions for ray tracing (hash-based, temporally stable).
#ifndef TRACING_NOISE_GLSL
#define TRACING_NOISE_GLSL
// Per-pixel temporal noise, stable across frames
float GetTracingNoise(vec2 screenPos, int frame, int offset){
// Blue noise from texture + temporal interleave
vec2 coord = (screenPos + 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 + (frame + offset) * 0.03125);
}
vec2 GetTracingNoise2(vec2 screenPos, int frame, int offset){
// 2D noise for ray directions
vec2 coord = (screenPos + 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 + (frame + offset) * 0.03125);
}
// Golden-ratio based sample rotation (for progressive sampling)
vec2 RotateNoise(vec2 uv, int sampleIndex, int totalSamples){
float angle = 6.28318 * float(sampleIndex) / float(totalSamples);
mat2 rot = mat2(cos(angle), sin(angle), -sin(angle), cos(angle));
return rot * uv;
}
#endif
@@ -0,0 +1,187 @@
#include "/Lib/Settings.glsl"
#include "/Lib/Utilities.glsl"
// MinecraftPT — Tracing Utilities
// Core voxel ray marching helpers used by all tracers.
// Custom resource declarations (bound via shaders.properties)
uniform sampler2D atlas2D;
uniform sampler3D voxelData3D;
uniform sampler2D skyBox2D;
// Sample the sky box panorama for a direction (for reflections / sky miss).
// Layout must match SkyImage_CS: 3x2 tiles:
// row 0: +X -X +Y row 1: -Y +Z -Z
vec3 SampleSkyBox(vec3 dir){
dir = normalize(dir);
float absX = abs(dir.x), absY = abs(dir.y), absZ = abs(dir.z);
float maxAxis = max(absX, max(absY, absZ));
vec3 tdir = dir / maxAxis;
vec2 uv;
vec2 tileOrigin;
vec2 tile = vec2(1.0 / 3.0, 1.0 / 2.0);
if (maxAxis == absX){
// +X (col 0) or -X (col 1), row 0
tileOrigin = vec2(dir.x > 0.0 ? 0.0 : 1.0, 0.0);
uv = vec2(tdir.y * 0.5 + 0.5, tdir.z * 0.5 + 0.5);
}else if (maxAxis == absY){
// +Y (col 2, row 0) or -Y (col 0, row 1)
tileOrigin = dir.y > 0.0 ? vec2(2.0, 0.0) : vec2(0.0, 1.0);
uv = vec2(tdir.x * 0.5 + 0.5, tdir.z * 0.5 + 0.5);
}else{
// +Z (col 1, row 1) or -Z (col 2, row 1)
tileOrigin = vec2(dir.z > 0.0 ? 1.0 : 2.0, 1.0);
uv = vec2(tdir.x * 0.5 + 0.5, tdir.y * 0.5 + 0.5);
}
uv = uv * tile + tileOrigin * tile;
return textureLod(skyBox2D, uv, 0.0).rgb;
}
#ifndef TRACING_UTILITIES_GLSL
#define TRACING_UTILITIES_GLSL
#include "/Lib/PathTracing/Voxelizer/VoxelProfile.glsl"
#include "/Lib/PathTracing/Voxelizer/BlockShape.glsl"
// Convert world position to voxel grid coordinates
vec3 WorldToVoxel(vec3 worldPos){
return worldPos + cameraPositionFract + (voxelResolution * 0.5);
}
// Sample the atlas for a hit voxel, returns albedo
vec3 SampleVoxelAlbedo(vec2 midCoord, vec3 hitVoxelPos, vec3 hitNormal){
// Reconstruct the face UV from hit position within voxel
vec3 local = fract(hitVoxelPos);
vec2 uv;
if (abs(hitNormal.x) > 0.5){
uv = vec2(local.z, local.y);
}else if (abs(hitNormal.y) > 0.5){
uv = vec2(local.x, local.z);
}else{
uv = vec2(local.x, local.y);
}
// midCoord is the tile-aligned center UV; reconstruct pixel within tile
vec2 tileCoord = midCoord;
vec2 atlasSizeF = vec2(atlasSize);
float tileW = 1.0 / atlasSizeF.x; // approximate; resolved via textureResolution
vec2 pixelUV = tileCoord + (uv - 0.5) * tileW * 4.0;
return textureLod(atlas2D, pixelUV, 0.0).rgb;
}
// Read a voxel's data
vec4 ReadVoxel(ivec3 voxelCoord){
return texelFetch(voxelData3D, voxelCoord, 0);
}
// Test whether a voxel is empty (air or empty marker)
bool IsVoxelEmpty(vec4 voxelData){
float voxelID = DecodeVoxelID(voxelData.z);
return voxelID <= 1.0;
}
// Test whether a voxel is a light source (sphere light)
bool IsLightSphere(float voxelID){
return voxelID >= 239.0 && voxelID <= 290.0;
}
// Core 3D-DDA march. Calls the callback-style inline logic via return.
// Returns: 0 = no hit, 1 = hit, 2 = hit light
int TraceRay(Ray ray, float maxDist, out float rayLength, out ivec3 hitVoxel, out float voxelID, out vec3 hitNormal){
vec3 voxelPos = ray.ori;
vec3 voxelCoord = floor(voxelPos);
vec3 totalStep = (ray.sdir * (voxelCoord - voxelPos + 0.5) + 0.5) * abs(ray.rdir);
rayLength = 0.0;
vec3 tracingNext;
hitNormal = vec3(0.0);
int result = 0;
vec3 prevCoord = voxelCoord;
for (int i = 0; i < 128; i++){
if (clamp(voxelCoord, vec3(0.0), vec3(voxelResolution - 0.5)) != voxelCoord) break;
vec4 voxelData = texelFetch(voxelData3D, ivec3(voxelCoord), 0);
float id = DecodeVoxelID(voxelData.z);
if (id <= 1.0){
// empty or full-block marker
if (id >= 0.99 && id <= 1.0){
// Full block
if (rayLength > 0.0){
hitVoxel = ivec3(voxelCoord);
voxelID = 1.0;
hitNormal = -step(vec3(rayLength), totalStep - abs(ray.rdir)) * ray.sdir;
result = 1;
break;
}
}
}else if (id >= 1000.0){
// Encoded as full block: id = rawID + 1000
float rawID = id - 1000.0;
if (rawID <= 1.0){
hitVoxel = ivec3(voxelCoord);
voxelID = rawID;
hitNormal = -step(vec3(rayLength), totalStep - abs(ray.rdir)) * ray.sdir;
result = 1;
break;
}
}else if (id > 1.0 && id < 1000.0){
// Cutout shape: id = 1000 - rawID
float rawID = 1000.0 - id;
float t = minVec3(totalStep);
rayLength = t;
vec3 n;
if (HitShape(ray, voxelCoord, rawID, rayLength, n)){
hitVoxel = ivec3(voxelCoord);
voxelID = rawID;
hitNormal = n;
result = 1;
break;
}
}else if (id >= 200.0 && id <= 290.0){
// Light source — contribute and continue
// (handled by caller; here just note it)
hitVoxel = ivec3(voxelCoord);
voxelID = id;
result = 2;
break;
}
// Sparse tracing: skip empty markers
float marker = voxelData.z;
if (marker > 0.60 && marker < 0.92){
// Hierarchical skip — approximate by stepping over the block size
float skipSize = marker > 0.90 ? 8.0 : (marker > 0.70 ? 4.0 : 2.0);
// find next boundary
vec3 nextBoundary = floor((voxelCoord + 1.0) / skipSize) * skipSize;
vec3 distToBoundary = (nextBoundary - voxelCoord) * abs(ray.rdir);
float tSkip = minVec3(distToBoundary) + 1e-4;
rayLength += tSkip;
vec3 stepVec = ray.sdir * abs(ray.rdir) * tSkip;
voxelPos += stepVec;
voxelCoord = floor(voxelPos);
totalStep = (ray.sdir * (voxelCoord - voxelPos + 0.5) + 0.5) * abs(ray.rdir);
if (rayLength > maxDist) break;
continue;
}
rayLength = minVec3(totalStep);
tracingNext = step(totalStep, vec3(rayLength));
voxelCoord += tracingNext * ray.sdir;
totalStep += tracingNext * abs(ray.rdir);
if (rayLength > maxDist) break;
}
return result;
}
#endif
@@ -0,0 +1,223 @@
#include "/Lib/Settings.glsl"
#include "/Lib/Utilities.glsl"
// MinecraftPT — Block Shape reconstruction
// Exact AABB-based shapes for non-full-block voxel IDs, used during ray marching.
#ifndef BLOCK_SHAPE_GLSL
#define BLOCK_SHAPE_GLSL
float SphereIntersectionLength(Ray ray, vec3 blockOrigin, vec3 sphereOrigin, float sphereRadius){
sphereOrigin = -blockOrigin - sphereOrigin;
float b = dot(ray.dir, sphereOrigin);
float c = dot(sphereOrigin, sphereOrigin) - sphereRadius * sphereRadius;
float d = b * b - c;
float intersectionLength = 0.0;
if (d > 0.0){
d = sqrt(d);
intersectionLength = saturate(min(-b + d, d * 2.0));
}
return intersectionLength;
}
float BoxIntersectionLength(Ray ray, vec3 blockOrigin){
vec3 boxMax = blockOrigin + 1.0;
vec3 t1 = ray.rdir * blockOrigin;
vec3 t2 = ray.rdir * boxMax;
vec3 tMin = min(t1, t2);
vec3 tMax = max(t1, t2);
float tEnter = maxVec3(tMin);
float tExit = minVec3(tMax);
return max(tExit - tEnter, 0.0);
}
// Light sphere colors for emissive blocks (IDs 200-270 range)
vec3 LightShpereColor(float voxelID){
const vec3 torchColor = pow(vec3(COLOR_TORCH_R, COLOR_TORCH_G, COLOR_TORCH_B), vec3(2.2)) * BRIGHTNESS_TORCH * SPHERELIGHT_BRIGHTNESS;
const vec3 fireColor = pow(vec3(COLOR_FIRE_R, COLOR_FIRE_G, COLOR_FIRE_B), vec3(2.2)) * BRIGHTNESS_FIRE * SPHERELIGHT_BRIGHTNESS;
const vec3 redstoneTorchColor = pow(vec3(COLOR_REDSTONETORCH_R, COLOR_REDSTONETORCH_G, COLOR_REDSTONETORCH_B), vec3(2.2)) * BRIGHTNESS_REDSTONETORCH * SPHERELIGHT_BRIGHTNESS;
const vec3 amethystColor = pow(vec3(COLOR_AMETHYST_R, COLOR_AMETHYST_G, COLOR_AMETHYST_B), vec3(2.2)) * BRIGHTNESS_AMETHYST * SPHERELIGHT_BRIGHTNESS;
const vec3 soultorchColor = pow(vec3(COLOR_SOULTORCH_R, COLOR_SOULTORCH_G, COLOR_SOULTORCH_B), vec3(2.2)) * BRIGHTNESS_SOULTORCH * SPHERELIGHT_BRIGHTNESS;
const vec3 lightblockColor = pow(vec3(COLOR_LIGHTBLOCK_R, COLOR_LIGHTBLOCK_G, COLOR_LIGHTBLOCK_B), vec3(2.2)) * BRIGHTNESS_LIGHTBLOCK * SPHERELIGHT_BRIGHTNESS;
const vec3 endrodColor = pow(vec3(COLOR_ENDROD_R, COLOR_ENDROD_G, COLOR_ENDROD_B), vec3(2.2)) * BRIGHTNESS_ENDROD * SPHERELIGHT_BRIGHTNESS;
vec3 shpereColor = vec3(0.0);
if (voxelID <= 244.0){
if (voxelID == 242.0){ // Torch
shpereColor = torchColor;
}else if (voxelID == 243.0){ // Redstone Torch
shpereColor = redstoneTorchColor;
}else if (abs(voxelID - 240.0) < 1.5){ // Campfire 239 240
shpereColor = fireColor;
}else{
shpereColor = soultorchColor;
}
}else{
if (voxelID == 245.0){ // Amethyst Cluster
shpereColor = amethystColor;
}else if (voxelID == 246.0){ // Soul Torch
shpereColor = soultorchColor;
}else if (voxelID == 247.0){ // Copper Lantern
shpereColor = torchColor;
}else if (abs(voxelID - 250.5) < 2.0){ // Candle & Sea Pickle
shpereColor = torchColor * 0.8;
}else if (abs(voxelID - 263.0) < 7.5){ // Light Block
shpereColor = lightblockColor * (voxelID * (1.0 / 15.0) - (255.0 / 15.0));
}else if (abs(voxelID - 280.0) < 1.5){ // End Rod
shpereColor = endrodColor;
}else{
// Generic emissive (from vanilla light level blocks)
shpereColor = torchColor * 0.5;
}
}
return shpereColor;
}
vec3 HitLightShpere(Ray ray, vec3 voxelCoord, float voxelID, float rayLength){
vec3 shpereLighting = vec3(0.0);
vec3 blockOrigin = voxelCoord - ray.ori;
float intersectionLength = SphereIntersectionLength(ray, blockOrigin, vec3(0.5), 0.5);
if (intersectionLength > 0.0)
intersectionLength = intersectionLength * intersectionLength;
shpereLighting = LightShpereColor(voxelID) * (intersectionLength * BLOCKLIGHT_BRIGHTNESS);
return shpereLighting;
}
vec3 HitLightShpereReflection(Ray ray, vec3 voxelCoord, float voxelID, float rayLength){
vec3 shpereLighting = vec3(0.0);
vec3 blockOrigin = voxelCoord - ray.ori;
float intersectionLength = SphereIntersectionLength(ray, blockOrigin, vec3(0.5), 0.25);
if (intersectionLength > 0.0)
intersectionLength = intersectionLength * intersectionLength;
intersectionLength = intersectionLength * intersectionLength * 50.0;
shpereLighting = LightShpereColor(voxelID) * (intersectionLength * BLOCKLIGHT_BRIGHTNESS);
return shpereLighting;
}
bool IsHitBox(Ray ray, vec3 blockOrigin, vec3 boxOrigin, vec3 boxSize, inout float rayLength, inout vec3 hitNormal){
vec3 boxMin = blockOrigin + boxOrigin;
vec3 boxMax = boxMin + boxSize;
vec3 t1 = ray.rdir * boxMin;
vec3 t2 = ray.rdir * boxMax;
vec3 tMin = min(t1, t2);
vec3 tMax = max(t1, t2);
float tEnter = maxVec3(tMin);
float tExit = minVec3(tMax);
bool hit = min(rayLength, tExit) >= tEnter && tExit >= 0.0;
if (hit){
hitNormal = -step(vec3(tEnter), tMin) * ray.sdir;
rayLength = tEnter;
}
return hit;
}
// Full shape reconstruction for cutout blocks. voxelID here is the raw block ID
// from block.properties (0-100 range).
bool HitShape(Ray ray, vec3 voxelCoord, float voxelID, inout float rayLength, out vec3 hitNormal){
vec3 blockOrigin = voxelCoord - ray.ori;
hitNormal = vec3(0.0);
bool hit = false;
const float rotIndex[8] = float[8](1.0, 0.0, -1.0, 0.0, 0.0, 1.0, 0.0, -1.0);
if (voxelID == 2.0){ // Leaves — full block
hit = IsHitBox(ray, blockOrigin, vec3(0.0), vec3(1.0), rayLength, hitNormal);
}else if (voxelID == 4.0){ // Cross plant (X shape)
vec3 ori0 = vec3(0.5);
vec3 size0 = vec3(-1.0, 1.0, 0.25 / 16.0);
vec3 ori1 = vec3(0.5);
vec3 size1 = vec3(0.25 / 16.0, 1.0, -1.0);
hit = IsHitBox(ray, blockOrigin, vec3(ori0.x, 0.0, ori0.z), vec3(size0.x, 1.0, size0.z), rayLength, hitNormal);
hit = IsHitBox(ray, blockOrigin, vec3(ori1.x, 0.0, ori1.z), vec3(size1.x, 1.0, size1.z), rayLength, hitNormal) || hit;
}else if (voxelID == 5.0){ // Torch
hit = IsHitBox(ray, blockOrigin, vec3(0.4375, 0.0, 0.4375), vec3(0.125, 0.5625, 0.125), rayLength, hitNormal);
}else if (voxelID == 6.0){ // Lantern
hit = IsHitBox(ray, blockOrigin, vec3(0.25, 0.1875, 0.25), vec3(0.5, 0.5625, 0.5), rayLength, hitNormal);
hit = IsHitBox(ray, blockOrigin, vec3(0.4375, 0.0, 0.4375), vec3(0.125, 0.1875, 0.125), rayLength, hitNormal) || hit;
}else if (voxelID == 10.0 || voxelID == 11.0){ // Glass pane / Iron bars
hit = IsHitBox(ray, blockOrigin, vec3(7.0 / 16.0, 0.0, 7.0 / 16.0), vec3(2.0 / 16.0, 1.0, 2.0 / 16.0), rayLength, hitNormal);
}else if (voxelID >= 12.0 && voxelID <= 13.0){ // Stairs & slabs simplified as full-ish
hit = IsHitBox(ray, blockOrigin, vec3(0.0), vec3(1.0), rayLength, hitNormal);
}else if (voxelID >= 14.0 && voxelID <= 16.0){ // Walls, fences, fence gates
hit = IsHitBox(ray, blockOrigin, vec3(0.25, 0.0, 0.25), vec3(0.5, 1.0, 0.5), rayLength, hitNormal);
hit = IsHitBox(ray, blockOrigin, vec3(0.0, 0.375, 0.0), vec3(1.0, 0.25, 1.0), rayLength, hitNormal) || hit;
}else if (voxelID == 17.0){ // Door
hit = IsHitBox(ray, blockOrigin, vec3(0.0, 0.0, 13.0 / 16.0), vec3(1.0, 1.0, 3.0 / 16.0), rayLength, hitNormal);
}else if (voxelID == 20.0){ // End rod
hit = IsHitBox(ray, blockOrigin, vec3(0.4375, 0.0, 0.4375), vec3(0.125, 1.0, 0.125), rayLength, hitNormal);
}else if (voxelID == 21.0){ // Chain
hit = IsHitBox(ray, blockOrigin, vec3(0.4375, 0.0, 0.4375), vec3(0.125, 1.0, 0.125), rayLength, hitNormal);
}else if (voxelID == 22.0){ // Amethyst cluster
hit = IsHitBox(ray, blockOrigin, vec3(0.25, 0.0, 0.25), vec3(0.5, 0.5, 0.5), rayLength, hitNormal);
}else if (voxelID == 27.0){ // Ladder
hit = IsHitBox(ray, blockOrigin, vec3(0.0, 0.0, 0.0), vec3(1.0, 1.0, 1.0), rayLength, hitNormal);
}else if (voxelID == 28.0 || voxelID == 29.0 || voxelID == 31.0){ // Sugar cane / Bamboo / Chorus
hit = IsHitBox(ray, blockOrigin, vec3(0.375, 0.0, 0.375), vec3(0.25, 1.0, 0.25), rayLength, hitNormal);
}else if (voxelID == 32.0){ // Coral
hit = IsHitBox(ray, blockOrigin, vec3(0.25, 0.0, 0.25), vec3(0.5, 0.625, 0.5), rayLength, hitNormal);
}else if (voxelID == 33.0){ // Pointed dripstone
hit = IsHitBox(ray, blockOrigin, vec3(0.375, 0.0, 0.375), vec3(0.25, 1.0, 0.25), rayLength, hitNormal);
}else if (voxelID == 35.0){ // Lightning rod
hit = IsHitBox(ray, blockOrigin, vec3(0.375, 0.0, 0.375), vec3(0.25, 1.0, 0.25), rayLength, hitNormal);
}else if (voxelID == 37.0){ // Snow layers
hit = IsHitBox(ray, blockOrigin, vec3(0.0, 0.0, 0.0), vec3(1.0, 0.125, 1.0), rayLength, hitNormal);
}else if (voxelID == 80.0){ // Cobweb
hit = IsHitBox(ray, blockOrigin, vec3(0.0), vec3(1.0), rayLength, hitNormal);
}else{
// Default: full block
hit = IsHitBox(ray, blockOrigin, vec3(0.0), vec3(1.0), rayLength, hitNormal);
}
return hit;
}
// Lightweight hit test (no normal) for shadow rays
bool HitShape_Lite(Ray ray, vec3 voxelCoord, float voxelID, float rayLength){
vec3 blockOrigin = voxelCoord - ray.ori;
vec3 unused = vec3(0.0);
return HitShape(ray, voxelCoord, voxelID, rayLength, unused);
}
#endif
@@ -0,0 +1,338 @@
// MinecraftPT — Shadow + Voxelization pass
// Renders the RTWSM shadow map (shadowcolor0) AND the voxel atlas (shadowcolor1),
// which is then copied into the 3D voxel texture by VoxelData_Copy_CS.
#include "/Lib/Settings.glsl"
#include "/Lib/Utilities.glsl"
#include "/Lib/PathTracing/Voxelizer/VoxelProfile.glsl"
#include "/Lib/RTWSM/SampleWarp.glsl"
//////////////////////////////////////////////////////////////////////////////
// Vertex Shader
//////////////////////////////////////////////////////////////////////////////
#ifdef PROGRAM_VSH
uniform mat4 shadowModelViewInverse;
uniform mat4 shadowProjection;
uniform vec3 cameraPositionFract;
uniform float frameTimeCounter;
uniform float wetness;
uniform sampler2D noisetex;
in vec4 mc_Entity;
in vec4 at_midBlock;
in vec2 mc_midTexCoord;
out vec3 g_color;
out vec3 g_worldPos;
out vec2 g_texcoord;
#ifdef PROGRAM_VOXEL
flat out float g_voxelID;
out float g_mcLightLevel;
out vec3 g_voxelCoord;
out float g_notInVoxel;
out float g_normalInvalid;
#endif
#include "/Lib/PathTracing/Voxelizer/VoxelProfile.glsl"
#include "/Lib/RTWSM/SampleWarp.glsl"
#ifdef WAVING_PLANTS
#include "/Lib/IndividualFunctions/WavingPlants.glsl"
#endif
void main(){
vec4 worldPos = shadowModelViewInverse * gl_ModelViewMatrix * gl_Vertex;
float skylightmap = saturate(float(gl_MultiTexCoord1.y - 8) / 232.0);
#ifdef WAVING_PLANTS
#ifdef SHADOW_WAVING_PLANTS
WavingPlants(worldPos, skylightmap);
#endif
#endif
g_worldPos = worldPos.xyz;
g_color = gl_Color.rgb;
g_texcoord.xy = mat2(gl_TextureMatrix[0]) * gl_MultiTexCoord0.xy + gl_TextureMatrix[0][3].xy;
#ifdef PROGRAM_VOXEL
vec3 worldNormal = mat3(shadowModelViewInverse) * normalize(gl_NormalMatrix * gl_Normal);
g_voxelID = mc_Entity.x;
g_mcLightLevel = skylightmap;
g_notInVoxel = step(5999.5, g_voxelID);
g_notInVoxel += step(g_voxelID, 0.5);
g_notInVoxel *= float(abs(g_voxelID - 8400.0) > 400.5);
g_normalInvalid = step(maxVec3(abs(worldNormal)), 0.99);
g_voxelCoord = vec3(-2.0);
if (g_notInVoxel < 0.5){
// Full block detection: verify vertices are on the block grid
if (g_voxelID <= 1.0){
vec3 vertexPos = gl_Vertex.xyz + cameraPositionFract;
vertexPos = abs(vertexPos - round(vertexPos));
float posInvalid = vertexPos.x + vertexPos.y + vertexPos.z;
posInvalid = step(0.001, posInvalid);
g_notInVoxel = posInvalid + g_normalInvalid;
}
#ifdef PT_MIDBLOCK_TEMPFIX
g_voxelCoord = g_worldPos + cameraPositionFract + (voxelResolution * 0.5) - worldNormal * 0.01;
#else
g_voxelCoord = g_worldPos + cameraPositionFract + (voxelResolution * 0.5) + at_midBlock.xyz * 0.015625;
#endif
}
#endif
gl_Position = vec4(1.0); // set by geometry shader
}
#endif
//////////////////////////////////////////////////////////////////////////////
// Geometry Shader
//////////////////////////////////////////////////////////////////////////////
#ifdef PROGRAM_GSH
layout(triangles) in;
layout(triangle_strip, max_vertices = 6) out;
uniform mat4 shadowProjection;
uniform ivec2 atlasSize;
uniform int renderStage;
in vec3 g_color[];
in vec3 g_worldPos[];
in vec2 g_texcoord[];
#ifdef PROGRAM_VOXEL
flat in float g_voxelID[];
in float g_mcLightLevel[];
in vec3 g_voxelCoord[];
in float g_notInVoxel[];
in float g_normalInvalid[];
#endif
out vec3 v_color;
out vec4 v_worldPos_voxelData_isWater_isVoxel;
out vec2 v_texcoord_mcLightLevel;
flat out vec2 v_midTexCoord;
#include "/Lib/PathTracing/Voxelizer/VoxelProfile.glsl"
void main(){
v_midTexCoord = vec2(0.0);
vec3 posDiff = vec3(
distance(g_worldPos[0], g_worldPos[1]),
distance(g_worldPos[1], g_worldPos[2]),
distance(g_worldPos[2], g_worldPos[0])
);
// Emit the shadow map triangle (for RTWSM shadow sampling)
{
float bias = saturate(maxVec3(posDiff) * 0.5 - 1.0) * shadowProjection[0][0] * 0.3;
for (int i = 0; i < 3; i++){
vec4 worldPos = shadowModelViewInverse * gl_in[i].gl_Position;
gl_Position = gl_in[i].gl_Position;
gl_Position.z += bias;
// Shift into the right square shadow region, then apply warp
ShiftShadowNdcPos(gl_Position.xy);
gl_Position.xy += SampleRTWWarpSmooth(gl_Position.xy * 0.5 + 0.5) * 2.0;
v_color = g_color[i];
v_worldPos_voxelData_isWater_isVoxel = vec4(g_worldPos[i], 0.0);
v_texcoord_mcLightLevel = g_texcoord[i];
EmitVertex();
}
EndPrimitive();
}
#ifdef PROGRAM_VOXEL
vec3 voxelCoord = floor(g_voxelCoord[0] * 0.33333333 + g_voxelCoord[1] * 0.33333333 + g_voxelCoord[2] * 0.33333333);
if (all(bvec3(
clamp(voxelCoord, vec3(0.0), vec3(voxelResolution - 1.0)) == voxelCoord,
g_notInVoxel[0] + g_notInVoxel[1] + g_notInVoxel[2] < 0.5,
renderStage == MC_RENDER_STAGE_TERRAIN_SOLID || renderStage == MC_RENDER_STAGE_TERRAIN_TRANSLUCENT
))){
vec2 atlasResolution = vec2(atlasSize);
vec2 maxTexCoord = max(g_texcoord[0].xy, max(g_texcoord[1].xy, g_texcoord[2].xy));
vec2 minTexCoord = min(g_texcoord[0].xy, min(g_texcoord[1].xy, g_texcoord[2].xy));
v_midTexCoord = (maxTexCoord + minTexCoord) * 0.5;
vec2 coordSize = (maxTexCoord - minTexCoord) * atlasResolution;
#if TEXTURE_RESOLUTION == 0
float coordMaxSize = maxVec3(vec3(
maxVec2(abs(g_texcoord[0].xy - g_texcoord[1].xy) * atlasResolution) / max(posDiff.x, 1e-4),
maxVec2(abs(g_texcoord[1].xy - g_texcoord[2].xy) * atlasResolution) / max(posDiff.y, 1e-4),
maxVec2(abs(g_texcoord[0].xy - g_texcoord[2].xy) * atlasResolution) / max(posDiff.z, 1e-4)
));
float textureResolution = floor(coordMaxSize + 0.5);
#else
float textureResolution = TEXTURE_RESOLUTION;
#endif
float voxelID = g_voxelID[0];
float roundedResolution = round(log2(textureResolution));
vec2 atlasTiles = vec2(atlasSize) * exp2(-roundedResolution);
// Tile-aligned texel sampling for accurate atlas UV
v_midTexCoord = (floor(v_midTexCoord * atlasTiles) + 0.5) / atlasTiles;
float skylight = saturate(SkyLightmapCurve(g_mcLightLevel[0] * 0.33333333 + g_mcLightLevel[1] * 0.33333333 + g_mcLightLevel[2] * 0.33333333));
float zOffset = g_normalInvalid[0] + g_normalInvalid[1] + g_normalInvalid[2];
coordSize /= textureResolution;
zOffset += saturate(coordSize.x * coordSize.y) * -0.2;
bool isCutout = voxelID == 2.0;
// Light blocks (8000-8400): encode block light level
if (abs(voxelID - 8400.0) < 400.5){
voxelID -= 8000.0;
if (voxelID > 499.5){
// hardcoded light level block
voxelID = 1.0;
}
}
// Encode: cutout shapes get 1000 - id, full blocks get id + 1000
bool isShape = bool(
uint(voxelID == 2.0) | // leaves
uint(voxelID == 4.0) | // cross plants
uint(voxelID == 5.0) | // torch
uint(voxelID == 6.0) | // lantern
uint(voxelID == 10.0) | // glass pane
uint(voxelID == 11.0) | // iron bars
uint(voxelID == 12.0) | // stairs
uint(voxelID == 13.0) | // slabs
uint(voxelID == 14.0) | // walls
uint(voxelID == 15.0) | // fences
uint(voxelID == 16.0) | // fence gates
uint(voxelID == 17.0) | // doors
uint(voxelID == 20.0) | // end rod
uint(voxelID == 21.0) | // chain
uint(voxelID == 22.0) | // amethyst
uint(voxelID == 27.0) | // ladder
uint(voxelID == 28.0) | // sugar cane
uint(voxelID == 29.0) | // bamboo
uint(voxelID == 31.0) | // chorus
uint(voxelID == 32.0) | // coral
uint(voxelID == 33.0) | // dripstone
uint(voxelID == 35.0) | // lightning rod
uint(voxelID == 36.0) | // pot
uint(voxelID == 37.0) | // snow layers
uint(voxelID == 80.0) // cobweb
);
voxelID = isShape ? 1000.0 - voxelID : voxelID + 1000.0;
#ifdef PT_FULLBLOCK_VERIFICATION
if (voxelID == 1001.0){
if (abs(posDiff.x + posDiff.y + posDiff.z - 3.41421356) > 0.001){
voxelID = 65536.0;
zOffset = -0.49;
}
}
#endif
vec2 voxelTexel = VoxelTexel_From_VoxelCoord(voxelCoord);
const vec2[3] vertexOffset = vec2[3](vec2(0.0, 0.0), vec2(1.0, 0.0), vec2(0.5, 1.0));
for (int i = 0; i < 3; i++){
gl_Position = vec4((voxelTexel + vertexOffset[i]) * shadowPixelSize * 2.0 - 1.0, zOffset * 0.5 - 0.75, 1.0);
v_color = g_color[i];
v_worldPos_voxelData_isWater_isVoxel = vec4(voxelID, roundedResolution, 0.0, 1.0);
v_texcoord_mcLightLevel = vec2(skylight, 0.0);
EmitVertex();
}
EndPrimitive();
}
#endif
}
#endif
//////////////////////////////////////////////////////////////////////////////
// Fragment Shader
//////////////////////////////////////////////////////////////////////////////
#ifdef PROGRAM_FSH
#include "/Lib/PathTracing/Voxelizer/VoxelProfile.glsl"
layout(location = 0) out vec4 shadowbuffer0;
layout(location = 1) out vec4 shadowbuffer1;
uniform mat4 shadowModelViewInverse;
uniform vec3 cameraPosition;
uniform ivec2 atlasSize;
uniform int isEyeInWater;
uniform vec2 screenSize;
uniform vec2 pixelSize;
uniform int frameCounter;
uniform int renderStage;
uniform sampler2D tex;
uniform sampler2D noisetex;
uniform sampler2D pixelData2D;
#include "/Lib/BasicFunctions/TemporalNoise.glsl"
#include "/Lib/RTWSM/SampleWarp.glsl"
in vec3 v_color;
in vec4 v_worldPos_voxelData_isWater_isVoxel;
in vec2 v_texcoord_mcLightLevel;
flat in vec2 v_midTexCoord;
void main(){
// Shadow map fragment
if (v_worldPos_voxelData_isWater_isVoxel.w < 0.5){
vec4 albedoTex = textureLod(tex, v_texcoord_mcLightLevel.xy, 0.0);
// Keep shadow fragments only in the right square region [W, 2W] x [0, W]
if (gl_FragCoord.x < float(voxelWidth) || gl_FragCoord.x >= shadowSize || gl_FragCoord.y >= float(voxelWidth)
|| albedoTex.a < 0.004) discard;
albedoTex.rgb *= v_color;
shadowbuffer0 = vec4(albedoTex);
shadowbuffer1 = vec4(0.0);
}
// Voxel atlas fragment
if (v_worldPos_voxelData_isWater_isVoxel.w > 0.2){
shadowbuffer0 = vec4(v_color.rgb, v_texcoord_mcLightLevel.x);
vec2 midCoord = saturate(v_midTexCoord * (65536.0 / 65535.0));
float voxelID = saturate(v_worldPos_voxelData_isWater_isVoxel.x / 65535.0);
float textureResolution = saturate(v_worldPos_voxelData_isWater_isVoxel.y / 255.0);
float skylight = saturate(SkyLightmapCurve(v_texcoord_mcLightLevel.x * 1.07));
shadowbuffer1 = vec4(midCoord, voxelID, Pack2xU8_to_U16(vec2(textureResolution, skylight)));
}
}
#endif
@@ -0,0 +1,139 @@
#include "/Lib/Settings.glsl"
#include "/Lib/Utilities.glsl"
// MinecraftPT — Voxel Profile
// Voxel grid parameters derived from settings.
//
// The shadow framebuffer (shadowcolor0/1) is square, size S x S, and holds:
// - the VOXEL ATLAS in the bottom-left region: texels [0, W) x [0, H)
// where W = voxelWidth and H = ceil(N / W), N = Rx*Ry*Rz voxels.
// Each voxel is one texel; linear packing: n = x + y*Rx + z*Rx*Ry.
// - the SHADOW MAP in the right square region: texels [W, 2W) x [0, W).
// The shadow camera NDC is shifted into this region (square -> square,
// no aspect distortion). Effective shadow resolution = W.
#ifndef VOXEL_PROFILE_GLSL
#define VOXEL_PROFILE_GLSL
// Shadow render distance -> shadow coverage
#if SHADOW_RENDER_DISTANCE == 4
const float shadowDistance = 64.1;
#elif SHADOW_RENDER_DISTANCE == 6
const float shadowDistance = 96.1;
#elif SHADOW_RENDER_DISTANCE == 8
const float shadowDistance = 128.1;
#elif SHADOW_RENDER_DISTANCE == 12
const float shadowDistance = 192.1;
#elif SHADOW_RENDER_DISTANCE == 16
const float shadowDistance = 256.1;
#elif SHADOW_RENDER_DISTANCE == 24
const float shadowDistance = 384.1;
#elif SHADOW_RENDER_DISTANCE == 32
const float shadowDistance = 512.1;
#elif SHADOW_RENDER_DISTANCE == 48
const float shadowDistance = 768.1;
#elif SHADOW_RENDER_DISTANCE == 64
const float shadowDistance = 1024.1;
#elif SHADOW_RENDER_DISTANCE == 96
const float shadowDistance = 1536.1;
#elif SHADOW_RENDER_DISTANCE == 128
const float shadowDistance = 2048.1;
#else
const float shadowDistance = 256.1;
#endif
// Voxel grid resolution and coverage (blocks)
#if PT_VOXEL_RESOLUTION == 4004
const ivec3 voxelResolutionInt = ivec3(128);
const float voxelDistance = 64.0;
const int voxelWidth = 2048;
#elif PT_VOXEL_RESOLUTION == 6004
const ivec3 voxelResolutionInt = ivec3(192, 128, 192);
const float voxelDistance = 96.0;
const int voxelWidth = 2048;
#elif PT_VOXEL_RESOLUTION == 8004
const ivec3 voxelResolutionInt = ivec3(256, 128, 256);
const float voxelDistance = 128.0;
const int voxelWidth = 2048;
#elif PT_VOXEL_RESOLUTION == 8006
const ivec3 voxelResolutionInt = ivec3(256, 192, 256);
const float voxelDistance = 128.0;
const int voxelWidth = 4096;
#elif PT_VOXEL_RESOLUTION == 8008
const ivec3 voxelResolutionInt = ivec3(256);
const float voxelDistance = 128.0;
const int voxelWidth = 4096;
#elif PT_VOXEL_RESOLUTION == 12004
const ivec3 voxelResolutionInt = ivec3(384, 128, 384);
const float voxelDistance = 192.0;
const int voxelWidth = 4096;
#elif PT_VOXEL_RESOLUTION == 12006
const ivec3 voxelResolutionInt = ivec3(384, 192, 384);
const float voxelDistance = 192.0;
const int voxelWidth = 4096;
#elif PT_VOXEL_RESOLUTION == 12008
const ivec3 voxelResolutionInt = ivec3(384, 256, 384);
const float voxelDistance = 192.0;
const int voxelWidth = 6144;
#elif PT_VOXEL_RESOLUTION == 16004
const ivec3 voxelResolutionInt = ivec3(512, 128, 512);
const float voxelDistance = 256.0;
const int voxelWidth = 6144;
#elif PT_VOXEL_RESOLUTION == 16008
const ivec3 voxelResolutionInt = ivec3(512, 256, 512);
const float voxelDistance = 256.0;
const int voxelWidth = 6144;
#elif PT_VOXEL_RESOLUTION == 16016
const ivec3 voxelResolutionInt = ivec3(512);
const float voxelDistance = 256.0;
const int voxelWidth = 8192;
#else
const ivec3 voxelResolutionInt = ivec3(256, 192, 256);
const float voxelDistance = 128.0;
const int voxelWidth = 4096;
#endif
const vec3 voxelResolution = vec3(voxelResolutionInt);
// Irradiance cache resolution (clamped to voxel grid)
const int ircResolution = min(PT_IRC_RESOLUTION, voxelResolutionInt.x);
// Shadow framebuffer size (square)
const int shadowMapResolution = voxelWidth * 2;
const float shadowSize = float(shadowMapResolution);
const float shadowPixelSize = 1.0 / shadowSize;
const float shadowRatio = 0.5; // W / S
// Map 3D voxel coordinate to 2D atlas texel (linear packing)
vec2 VoxelTexel_From_VoxelCoord(vec3 voxelCoord){
float n = voxelCoord.x + voxelCoord.y * voxelResolution.x + voxelCoord.z * voxelResolution.x * voxelResolution.y;
return vec2(mod(n, float(voxelWidth)), floor(n / float(voxelWidth)));
}
// Shift shadow map NDC into the right square region [W, 2W] x [0, W]
void ShiftShadowNdcPos(inout vec2 coord){
coord = coord * shadowRatio + vec2(1.0 - shadowRatio, shadowRatio - 1.0);
}
// Shift shadow map screen uv into the right square region
void ShiftShadowScreenPos(inout vec2 coord){
coord = coord * shadowRatio + vec2(1.0 - shadowRatio, 0.0);
}
// Shift back from shadow region uv to standard shadow uv
vec2 UnshiftShadowScreenPos(vec2 coord){
return (coord - vec2(1.0 - shadowRatio, 0.0)) / shadowRatio;
}
// Block ID encoding (16-bit range)
// Full block: voxelID + 1000
// Cutout shape: 1000 - voxelID
// Empty markers: 0.91 (8^3), 0.71 (4^3), 0.61 (2^3)
float EncodeVoxelID(float voxelID){
return saturate((voxelID + 1000.0) / 65535.0);
}
float DecodeVoxelID(float encoded){
return abs(floor(encoded * 65535.0 - 999.9));
}
#endif
@@ -0,0 +1,37 @@
// MinecraftPT — CausticsTex_CS
// Generates a caustics normal field texture (pixelData2D) used by water voxels.
#include "/Lib/Settings.glsl"
#include "/Lib/Utilities.glsl"
const ivec3 workGroups = ivec3(16, 16, 1);
layout (local_size_x = 32, local_size_y = 32) in;
layout (rg16f) uniform writeonly image2D img_pixelData2D;
void main(){
ivec2 texel = ivec2(gl_GlobalInvocationID.xy);
vec2 uv = (vec2(texel) + 0.5) / vec2(512.0, 513.0);
float time = frameTimeCounter * 0.05;
// Analytic caustics field (sum of moving sine waves)
vec2 coord = uv * 32.0;
float n1 = sin(coord.x * 2.0 + time * 3.0) * cos(coord.y * 1.7 - time * 2.0);
float n2 = sin(coord.x * 1.3 - time * 1.5) * cos(coord.y * 2.4 + time * 2.5);
float n3 = sin((coord.x + coord.y) * 3.1 + time * 4.0) * 0.5;
float field = n1 * 0.5 + n2 * 0.3 + n3 * 0.2;
// Normal from field gradient
float eps = 0.01;
float fx = sin((coord.x + eps) * 2.0 + time * 3.0) * cos(coord.y * 1.7 - time * 2.0);
float fxx = sin((coord.x - eps) * 2.0 + time * 3.0) * cos(coord.y * 1.7 - time * 2.0);
float fy = sin(coord.x * 2.0 + time * 3.0) * cos((coord.y + eps) * 1.7 - time * 2.0);
float fyy = sin(coord.x * 2.0 + time * 3.0) * cos((coord.y - eps) * 1.7 - time * 2.0);
vec2 normal = vec2((fx - fxx) * 0.5 / eps, (fy - fyy) * 0.5 / eps) * 0.2;
normal = tanh(normal);
imageStore(img_pixelData2D, texel, vec4(normal * 0.5 + 0.5, 0.0, 0.0));
}
@@ -0,0 +1,100 @@
// MinecraftPT — Bloom_CS
// Bloom compute passes: two downsample levels + axial blur X/Y.
// Uses two alternating images (bloomA/bloomB) to avoid read-write conflicts.
#include "/Lib/Settings.glsl"
#include "/Lib/Utilities.glsl"
const ivec3 workGroups = ivec3(int(ceil(viewWidth * 0.03125)), int(ceil(viewHeight * 0.03125)), 1);
layout (local_size_x = 8, local_size_y = 8) in;
layout (rgba16f) uniform writeonly image2D img_bloomA;
layout (rgba16f) uniform writeonly image2D img_bloomB;
uniform sampler2D colortex12;
uniform sampler2D bloomA;
uniform sampler2D bloomB;
// Downsample pass
#ifdef PROGRAM_BLOOM_DOWNSAMPLE
void main(){
ivec2 texel = ivec2(gl_GlobalInvocationID.xy);
vec3 color = vec3(0.0);
#if PROGRAM_BLOOM_DOWNSAMPLE_LEVEL == 1
// Level 1: 2x2 box from the HDR scene -> bloomA
for (int i = 0; i < 2; i++){
for (int j = 0; j < 2; j++){
color += texelFetch(colortex12, texel * 2 + ivec2(i, j), 0).rgb;
}}
color *= 0.25;
float brightness = luminance(color);
color *= saturate(brightness * BLOOM_CLAMP_STRENGTH);
ivec2 imgSize = imageSize(img_bloomA);
if (all(lessThan(texel, imgSize))){
imageStore(img_bloomA, texel, vec4(color, 1.0));
}
#else
// Level 2: 2x2 box from bloomA -> bloomB
for (int i = 0; i < 2; i++){
for (int j = 0; j < 2; j++){
color += texelFetch(bloomA, texel * 2 + ivec2(i, j), 0).rgb;
}}
color *= 0.25;
float brightness = luminance(color);
color *= saturate(brightness * BLOOM_CLAMP_STRENGTH);
ivec2 imgSize = imageSize(img_bloomB);
if (all(lessThan(texel, imgSize))){
imageStore(img_bloomB, texel, vec4(color, 1.0));
}
#endif
}
#endif
// Axial blur pass (X or Y depending on defines)
#ifdef PROGRAM_BLOOM_AXIALBLUR
void main(){
ivec2 texel = ivec2(gl_GlobalInvocationID.xy);
ivec2 imgSize = imageSize(img_bloomA);
if (any(greaterThanEqual(texel, imgSize))) return;
vec2 uv = (vec2(texel) + 0.5) / vec2(imgSize);
// Which buffer to read (BLOOM_AXIAL_READ_A defined for the pass reading bloomA)
#ifdef BLOOM_AXIAL_READ_A
sampler2D src = bloomA;
#else
sampler2D src = bloomB;
#endif
#ifdef PROGRAM_BLOOM_AXIALBLUR_X
vec2 axis = vec2(1.0, 0.0);
#else
vec2 axis = vec2(0.0, 1.0);
#endif
vec3 color = vec3(0.0);
float weightSum = 0.0;
for (int i = -8; i <= 8; i++){
vec2 coord = uv + axis * float(i) / vec2(imgSize);
float w = exp(-float(i * i) * 0.05);
color += textureLod(src, coord, 0.0).rgb * w;
weightSum += w;
}
// Write to the opposite buffer of the read source
#ifdef BLOOM_AXIAL_READ_A
imageStore(img_bloomB, texel, vec4(color / weightSum, 1.0));
#else
imageStore(img_bloomA, texel, vec4(color / weightSum, 1.0));
#endif
}
#endif
@@ -0,0 +1,23 @@
// MinecraftPT — Bloom_FS
// Final bloom composite onto the scene.
// bloomB is a fixed 1024x1024 image; the valid bloom region for this screen
// is its top-left (viewWidth/4 x viewHeight/4) texels, so UV = screen / 4096.
#include "/Lib/Settings.glsl"
#include "/Lib/Utilities.glsl"
uniform sampler2D colortex12;
uniform sampler2D bloomB;
layout(location = 0) out vec4 colorOut;
void main(){
vec2 texelCoord = gl_FragCoord.xy;
vec3 scene = texelFetch(colortex12, ivec2(texelCoord), 0).rgb;
vec3 bloom = textureLod(bloomB, clamp(texelCoord / 4096.0, vec2(0.0), vec2(1.0)), 0.0).rgb;
vec3 color = scene + bloom * BLOOM_AMOUNT;
colorOut = vec4(color, 1.0);
}
@@ -0,0 +1,19 @@
// MinecraftPT — DepthCopy_CS
// Copies the current frame depth to prevDepth2D at the end of the frame,
// so temporal filters in the next frame have the previous depth for
// reprojection validation.
#include "/Lib/Settings.glsl"
#include "/Lib/Utilities.glsl"
const ivec3 workGroups = ivec3(int(ceil(viewWidth * 0.0625)), int(ceil(viewHeight * 0.0625)), 1);
layout (local_size_x = 8, local_size_y = 8) in;
layout (r32f) uniform writeonly image2D img_prevDepth2D;
uniform sampler2D depthtex0;
void main(){
ivec2 texel = ivec2(gl_GlobalInvocationID.xy);
imageStore(img_prevDepth2D, texel, vec4(texelFetch(depthtex0, texel * 2, 0).r));
}
@@ -0,0 +1,25 @@
// MinecraftPT — DiffuseSpatial (single pass, step parameterized by composite index)
#include "/Lib/Settings.glsl"
#include "/Lib/Utilities.glsl"
#include "/Lib/PathTracing/Denoiser/DiffuseSpatialFilter.glsl"
layout(location = 0) out vec4 colorOut;
void main(){
vec2 texelCoord = gl_FragCoord.xy;
vec3 color = texelFetch(colortex7, ivec2(texelCoord), 0).rgb;
// Step size determined by whic composite pass we are
int step = 1;
#ifdef SPATIAL_STEP_2
step = 2;
#elif defined SPATIAL_STEP_4
step = 4;
#elif defined SPATIAL_STEP_8
step = 8;
#endif
color = DiffuseSpatialPass(color, texelCoord, step);
colorOut = vec4(color, 1.0);
}
@@ -0,0 +1,16 @@
// MinecraftPT — DiffuseTemporal_FS
#include "/Lib/Settings.glsl"
#include "/Lib/Utilities.glsl"
#include "/Lib/PathTracing/Denoiser/DiffuseTemporalFilter.glsl"
layout(location = 0) out vec4 colorOut;
void main(){
vec2 texelCoord = gl_FragCoord.xy;
vec3 current = texelFetch(colortex6, ivec2(texelCoord), 0).rgb;
vec3 prev = texelFetch(colortex7, ivec2(texelCoord), 0).rgb;
vec3 result = DiffuseTemporalAccumulate(current, texelCoord, prev);
colorOut = vec4(result, 1.0);
}
@@ -0,0 +1,158 @@
// MinecraftPT — DiffuseTracing_FS
// One diffuse path-tracing ray per pixel at half resolution.
// Output: colortex6 = noisy diffuse irradiance, colortex10 = motion vectors.
#include "/Lib/Settings.glsl"
#include "/Lib/Utilities.glsl"
#include "/Lib/BasicFunctions/LightingConstants.glsl"
#include "/Lib/GbufferData.glsl"
#include "/Lib/PathTracing/Tracer/TracingNoise.glsl"
#include "/Lib/PathTracing/Tracer/TracingUtilities.glsl"
#include "/Lib/PathTracing/Tracer/ShadowTracing.glsl"
#include "/Lib/PathTracing/Tracer/SampleIRC.glsl"
#include "/Lib/PathTracing/Tracer/SpecularTracer.glsl"
#include "/Lib/BasicFunctions/TemporalNoise.glsl"
uniform sampler2D colortex0; // albedo
uniform sampler2D colortex1; // normals
uniform sampler2D colortex3; // lightmap
layout(location = 0) out vec4 diffuseOut; // colortex6
layout(location = 1) out vec4 motionOut; // colortex10
vec3 TraceDiffuseRay(vec3 origin, vec3 dir, float maxDist){
vec3 result = vec3(0.0);
Ray ray = PackRay(origin, dir);
vec3 voxelCoord = floor(ray.ori);
vec3 totalStep = (ray.sdir * (voxelCoord - ray.ori + 0.5) + 0.5) * abs(ray.rdir);
float rayLength = 0.0;
vec3 tracingNext;
for (int i = 0; i < 128; i++){
if (clamp(voxelCoord, vec3(0.0), vec3(voxelResolution - 0.5)) != voxelCoord){
// Miss: sample sky
result += SampleSkyBox(dir) * (1.0 / 3.14159265);
break;
}
if (rayLength > maxDist){
result += SampleSkyBox(dir) * (1.0 / 3.14159265);
break;
}
vec4 voxelData = texelFetch(voxelData3D, ivec3(voxelCoord), 0);
float voxelID = DecodeVoxelID(voxelData.z);
// Light sphere contribution
if (IsLightSphere(voxelID)){
result += HitLightShpere(ray, voxelCoord, voxelID, rayLength);
rayLength = minVec3(totalStep);
tracingNext = step(totalStep, vec3(rayLength));
voxelCoord += tracingNext * ray.sdir;
totalStep += tracingNext * abs(ray.rdir);
continue;
}
bool hit = false;
vec3 hitNormal = vec3(0.0);
if (voxelID >= 999.0){
hit = rayLength > 0.0;
hitNormal = -step(vec3(rayLength), totalStep - abs(ray.rdir)) * ray.sdir;
}else if (voxelID < 1000.0 && voxelID > 1.0){
float rawID = 1000.0 - voxelID;
rayLength = minVec3(totalStep);
hit = HitShape(ray, voxelCoord, rawID, rayLength, hitNormal);
}
if (hit){
vec3 hitPos = ray.ori + ray.dir * rayLength;
vec2 midCoord = voxelData.xy;
vec3 albedo = SampleVoxelAlbedo(midCoord, hitPos, hitNormal);
float skylight = Unpack2xU8_Y_from_U16(voxelData.w);
// Direct sun at hit point
vec3 sun = GetSunIrradiance();
float shadow = SimpleShadowTracing(hitPos + hitNormal * 0.01, GetSunDirWorld());
float NdotL = max(dot(hitNormal, GetSunDirWorld()), 0.0);
result += albedo * sun * shadow * NdotL;
// Sky light at hit point (from voxel skylight)
result += albedo * GetAtmoIrradiance() * skylight * 0.5;
// One-bounce: sample IRC
result += albedo * SampleIRC(hitPos) * 0.5;
break;
}
// Sparse skip
float marker = voxelData.z;
if (marker > 0.60 && marker < 0.92){
float skipSize = marker > 0.90 ? 8.0 : (marker > 0.70 ? 4.0 : 2.0);
vec3 nextBoundary = floor((voxelCoord + 1.0) / skipSize) * skipSize;
vec3 distToBoundary = (nextBoundary - voxelCoord) * abs(ray.rdir);
float tSkip = minVec3(distToBoundary) + 1e-4;
rayLength += tSkip;
vec3 stepVec = ray.sdir * abs(ray.rdir) * tSkip;
ray.ori += stepVec;
voxelCoord = floor(ray.ori);
totalStep = (ray.sdir * (voxelCoord - ray.ori + 0.5) + 0.5) * abs(ray.rdir);
continue;
}
rayLength = minVec3(totalStep);
tracingNext = step(totalStep, vec3(rayLength));
voxelCoord += tracingNext * ray.sdir;
totalStep += tracingNext * abs(ray.rdir);
}
return result;
}
void main(){
// Half resolution texel
ivec2 texelCoord = ivec2(gl_FragCoord.xy);
ivec2 fullCoord = texelCoord * 2;
// Skip sky
float depth = texelFetch(depthtex0, fullCoord, 0).r;
if (depth >= 1.0){
diffuseOut = vec4(0.0);
motionOut = vec4(0.0);
return;
}
vec4 albedoData = texelFetch(colortex0, fullCoord, 0);
vec4 normalData = texelFetch(colortex1, fullCoord, 0);
vec3 worldNormal = DecodeNormal(normalData.xy);
vec3 viewNormal = mat3(gbufferModelView) * worldNormal;
// Reconstruct view position
vec4 viewPos = gbufferProjectionInverse * vec4(vec2(fullCoord) / screenSize * 2.0 - 1.0, depth * 2.0 - 1.0, 1.0);
viewPos.xyz /= viewPos.w;
vec3 worldPos = gbufferModelViewInverse[3].xyz + viewPos.xyz;
vec2 noise = GetTracingNoise2(vec2(texelCoord), frameCounter, 0);
// Cosine-weighted hemisphere sampling
vec3 dir = SampleHemisphere(noise, worldNormal);
// Only trace if there's anything to bounce (skip pure black)
vec3 traceResult = TraceDiffuseRay(WorldToVoxel(worldPos + worldNormal * 0.05), dir, PT_DIFFUSE_TRACING_DISTANCE);
diffuseOut = vec4(traceResult, 1.0);
// Motion vectors (full res reprojection)
vec4 prevViewPos = gbufferPreviousProjection * gbufferPreviousModelView * vec4(worldPos, 1.0);
prevViewPos.xyz /= prevViewPos.w;
vec2 prevScreen = (prevViewPos.xy * 0.5 + 0.5) * screenSize;
vec2 motion = vec2(texelCoord) - prevScreen * 0.5;
motionOut = vec4(motion, 0.0, 1.0);
}
@@ -0,0 +1,14 @@
// MinecraftPT — DiffuseVariance_FS
#include "/Lib/Settings.glsl"
#include "/Lib/Utilities.glsl"
#include "/Lib/PathTracing/Denoiser/DiffuseVarianceEstimation.glsl"
layout(location = 0) out vec4 varOut;
void main(){
vec2 texelCoord = gl_FragCoord.xy;
vec3 color = texelFetch(colortex7, ivec2(texelCoord), 0).rgb;
vec2 variance = DiffuseEstimateVariance(color, texelCoord);
varOut = vec4(variance, 0.0, 1.0);
}
@@ -0,0 +1,44 @@
// MinecraftPT — Dof_FS
// Depth of field with circle of confusion bokeh.
#include "/Lib/Settings.glsl"
#include "/Lib/Utilities.glsl"
#include "/Lib/IndividualFunctions/DOF.glsl"
uniform sampler2D colortex12;
layout(location = 0) out vec4 colorOut;
void main(){
vec2 texelCoord = gl_FragCoord.xy;
vec3 color = texelFetch(colortex12, ivec2(texelCoord), 0).rgb;
#ifdef DOF
if (DOF > 0){
float depth = texelFetch(depthtex0, ivec2(texelCoord), 0).r;
// Focal distance (from center depth or manual)
float focalDepth = CAMERA_FOCAL_POINT;
#ifdef CAMERA_FOCUS_MODE
if (CAMERA_FOCUS_MODE == 1){
vec2 center = screenSize * 0.5;
focalDepth = texelFetch(depthtex0, ivec2(center), 0).r;
}
#endif
float coc = GetCoC(depth, focalDepth);
#ifdef DISABLE_HAND_DOF
// Skip hand (close depth)
if (depth < 0.1) coc = 0.0;
#endif
if (coc > 0.5){
color = DofBlur(texelCoord, coc);
}
}
#endif
colorOut = vec4(color, 1.0);
}
@@ -0,0 +1,54 @@
// MinecraftPT — Exposure_CS
// Computes the average scene luminance and smooths the exposure over time.
// Writes the result into a 1x1 R16F image (exposureTex) read by the final pass.
#include "/Lib/Settings.glsl"
#include "/Lib/Utilities.glsl"
const ivec3 workGroups = ivec3(8, 8, 1);
layout (local_size_x = 16, local_size_y = 16) in;
layout (r16f) uniform writeonly image2D img_exposureTex;
uniform sampler2D colortex12;
shared float luminanceSum[256];
void main(){
ivec2 texel = ivec2(gl_GlobalInvocationID.xy);
// Downsample luminance from the HDR scene
float lum = 0.0;
vec2 base = vec2(texel * 4);
for (int i = 0; i < 4; i++){
for (int j = 0; j < 4; j++){
vec3 color = texelFetch(colortex12, ivec2(base + vec2(i, j)), 0).rgb;
lum += luminance(color);
}}
lum /= 16.0;
// Shared reduction
uint local = gl_LocalInvocationID.x + gl_LocalInvocationID.y * 16u;
luminanceSum[local] = lum;
barrier();
if (local == 0u){
float avg = 0.0;
for (uint i = 0u; i < 256u; i++){
avg += luminanceSum[i];
}
avg /= 256.0;
// Target exposure (inverse of average luminance)
float targetExposure = 1.0 / max(avg, 0.001);
// Read previous exposure for temporal smoothing (single thread)
float prevExposure = imageLoad(img_exposureTex, ivec2(0, 0)).r;
if (prevExposure <= 0.0) prevExposure = 1.0;
float adapted = mix(prevExposure, targetExposure, SMOOTH_EXPOSURE);
adapted = clamp(adapted, 0.01, 100.0);
imageStore(img_exposureTex, ivec2(0, 0), vec4(adapted));
}
}
@@ -0,0 +1,86 @@
// MinecraftPT — IRC_CS (Irradiance Cache Update)
// Updates the 3D irradiance cache: traces a few rays per cell toward the sky,
// stores ambient + direct light contributions, blends over time.
#include "/Lib/Settings.glsl"
#include "/Lib/Utilities.glsl"
#include "/Lib/BasicFunctions/LightingConstants.glsl"
#include "/Lib/PathTracing/Voxelizer/VoxelProfile.glsl"
#include "/Lib/PathTracing/Tracer/ShadowTracing.glsl"
#include "/Lib/BasicFunctions/PrecomputedAtmosphere.glsl"
#ifdef PT_IRC
const ivec3 workGroups = ivec3(int(ceil(float(ircResolution) / 4.0)));
layout (local_size_x = 4, local_size_y = 4, local_size_z = 4) in;
layout (rgba16f) uniform writeonly image3D img_irradianceCache3D;
layout (rgba16f) uniform readonly image3D img_irradianceCache3D_Alt;
uniform sampler3D voxelData3D;
void main(){
ivec3 texel = ivec3(gl_GlobalInvocationID.xyz);
if (any(greaterThanEqual(texel, ivec3(ircResolution)))){
return;
}
// World position of this cache cell
vec3 cellPos = (vec3(texel) + 0.5) / float(ircResolution);
vec3 worldPos = (cellPos - 0.5) * voxelDistance + cameraPosition;
// Voxel occupancy check — don't cache inside solid blocks
vec3 voxelCoord = cellPos * voxelResolution;
vec4 voxelData = texelFetch(voxelData3D, ivec3(clamp(voxelCoord, vec3(0.0), vec3(voxelResolution - 1.0))), 0);
float voxelID = DecodeVoxelID(voxelData.z);
if (voxelID > 1.0 && voxelID < 999.0){
// Solid — keep old value
return;
}
// Sample sky irradiance from multiple directions (hemisphere)
vec3 irradiance = vec3(0.0);
for (int i = 0; i < PT_IRC_SPP; i++){
// Deterministic sample directions over hemisphere
float phi = 6.28318 * hash1(vec3(texel) + float(i) * 1.7);
float cosTheta = hash1(vec3(texel) * 2.0 + float(i) * 3.1);
float sinTheta = sqrt(1.0 - cosTheta * cosTheta);
vec3 dir = vec3(cos(phi) * sinTheta, cosTheta, sin(phi) * sinTheta);
// Trace toward sky — if not blocked, add sky light
vec3 voxelPos = WorldToVoxel(worldPos) + dir * 0.5;
float visibility = SimpleShadowTracing(voxelPos, dir);
// Sky radiance in this direction (analytic)
vec3 skyRadiance = GetSkyRadiance(dir, GetSunDirWorld());
irradiance += skyRadiance * visibility;
}
irradiance /= float(PT_IRC_SPP);
// Sun contribution (direct)
vec3 sunDir = GetSunDirWorld();
float sunVis = SimpleShadowTracing(WorldToVoxel(worldPos), sunDir);
irradiance += GetSunIrradiance() * sunVis * max(sunDir.y, 0.0);
// Blend with previous (temporal smoothing), ping-pong by frame parity
bool evenFrame = (frameCounter % 2) == 0;
vec3 prev = evenFrame
? texelFetch(img_irradianceCache3D_Alt, texel, 0).rgb
: texelFetch(img_irradianceCache3D, texel, 0).rgb;
irradiance = mix(prev, irradiance, PT_IRC_BLENDWEIGHT);
if (evenFrame){
imageStore(img_irradianceCache3D, texel, vec4(irradiance, 1.0));
}else{
imageStore(img_irradianceCache3D_Alt, texel, vec4(irradiance, 1.0));
}
}
#endif
@@ -0,0 +1,45 @@
// MinecraftPT — MotionBlur_FS
// Per-pixel camera motion blur using motion vectors.
#include "/Lib/Settings.glsl"
#include "/Lib/Utilities.glsl"
#include "/Lib/BasicFunctions/TemporalNoise.glsl"
uniform sampler2D colortex12;
uniform sampler2D colortex10;
layout(location = 0) out vec4 colorOut;
void main(){
vec2 texelCoord = gl_FragCoord.xy;
vec3 color = texelFetch(colortex12, ivec2(texelCoord), 0).rgb;
#ifdef MOTION_BLUR
if (MOTION_BLUR > 0){
vec2 motion = texelFetch(colortex10, ivec2(texelCoord * 0.5), 0).xy * 2.0;
float speed = length(motion);
if (speed > 0.5){
// Shutter angle sampling
float shutterAngle = mix(90.0, 360.0, MOTION_BLUR_SUTTER_SPEED);
float samples = float(MOTION_BLUR_QUALITY);
float dither = BlueNoiseTemporal();
vec2 dir = normalize(motion);
float length = min(speed, 32.0) * 0.5;
vec3 acc = vec3(0.0);
for (int i = 0; i < MOTION_BLUR_QUALITY; i++){
float t = (float(i) + dither) / samples - 0.5;
vec2 sampleCoord = texelCoord + dir * length * t;
acc += textureLod(colortex12, sampleCoord / screenSize, 0.0).rgb;
}
color = acc / samples;
}
}
#endif
colorOut = vec4(color, 1.0);
}
@@ -0,0 +1,64 @@
// MinecraftPT — SH_Tracing_CS
// Low-order spherical-harmonics sky tracing: evaluates sky radiance on a small
// SH basis and stores it for ambient light estimation (used by IRC seeding).
#include "/Lib/Settings.glsl"
#include "/Lib/Utilities.glsl"
#include "/Lib/BasicFunctions/LightingConstants.glsl"
#include "/Lib/BasicFunctions/PrecomputedAtmosphere.glsl"
#include "/Lib/PathTracing/Tracer/ShadowTracing.glsl"
#include "/Lib/PathTracing/Voxelizer/VoxelProfile.glsl"
#ifdef PT_IRC
const ivec3 workGroups = ivec3(int(ceil(float(ircResolution) / 4.0)));
layout (local_size_x = 4, local_size_y = 4, local_size_z = 4) in;
layout (rgba16f) uniform writeonly image3D img_irradianceCache3D;
layout (rgba16f) uniform readonly image3D img_irradianceCache3D_Alt;
uniform sampler3D voxelData3D;
// SH basis Y1 (linear, 3 components) coefficients for sky radiance at a cell
void main(){
ivec3 texel = ivec3(gl_GlobalInvocationID.xyz);
if (any(greaterThanEqual(texel, ivec3(ircResolution)))){
return;
}
vec3 cellPos = (vec3(texel) + 0.5) / float(ircResolution);
vec3 worldPos = (cellPos - 0.5) * voxelDistance + cameraPosition;
vec3 voxelCoord = cellPos * voxelResolution;
vec4 voxelData = texelFetch(voxelData3D, ivec3(clamp(voxelCoord, vec3(0.0), vec3(voxelResolution - 1.0))), 0);
float voxelID = DecodeVoxelID(voxelData.z);
if (voxelID > 1.0 && voxelID < 999.0){
return;
}
// Trace N directions, accumulate SH coefficients
vec3 sh = vec3(0.0);
for (int i = 0; i < 6; i++){
float phi = 6.28318 * hash1(vec3(texel) * 1.3 + float(i) * 0.7);
float cosTheta = hash1(vec3(texel) * 0.7 + float(i) * 1.9);
float sinTheta = sqrt(1.0 - cosTheta * cosTheta);
vec3 dir = vec3(cos(phi) * sinTheta, cosTheta, sin(phi) * sinTheta);
float visibility = SimpleShadowTracing(WorldToVoxel(worldPos) + dir * 0.5, dir);
vec3 radiance = GetSkyRadiance(dir, GetSunDirWorld());
sh += radiance * visibility * cosTheta; // cos-weighted
}
sh /= 6.0;
imageStore(img_irradianceCache3D, texel, vec4(sh, 1.0));
}
#endif
@@ -0,0 +1,76 @@
// MinecraftPT — SkyImage_CS
// Precomputes the sky panorama (skyBox2D, 3:2 cubemap cross) using the analytic
// atmosphere model, for sampling by the path tracer and reflections.
#include "/Lib/Settings.glsl"
#include "/Lib/Utilities.glsl"
#include "/Lib/BasicFunctions/LightingConstants.glsl"
#include "/Lib/BasicFunctions/PrecomputedAtmosphere.glsl"
#include "/Lib/IndividualFunctions/EndSky.glsl"
#include "/Lib/IndividualFunctions/PlanarClouds.glsl"
const ivec3 workGroups = ivec3(int(ceil(float(SKYBOX_RESOLUTION_X) / 8.0)), int(ceil(float(SKYBOX_RESOLUTION_Y) / 8.0)), 1);
layout (local_size_x = 8, local_size_y = 8) in;
layout (rgba16f) uniform writeonly image2D img_skyBox2D;
void main(){
ivec2 texel = ivec2(gl_GlobalInvocationID.xy);
// Panorama layout: 3:2 cross (like a cubemap cross folded)
vec2 resolution = vec2(SKYBOX_RESOLUTION_X, SKYBOX_RESOLUTION_Y);
vec2 uv = (vec2(texel) + 0.5) / resolution;
// Determine face and local UV
float tileX = SKYBOX_RESOLUTION / resolution.x; // 1/3
float tileY = SKYBOX_RESOLUTION / resolution.y; // 1/2
int face = int(floor(uv.x / tileX));
vec2 faceUV = vec2(
(uv.x - float(face) * tileX) / tileX,
(uv.y - float(face < 3 ? 0 : 1) * tileY) / tileY
);
faceUV = faceUV * 2.0 - 1.0;
// Cubemap cross mapping (Standard OpenGL cross layout, 4x3 grid):
// faces: 0=+X, 1=-X, 2=+Y, 3=-Y, 4=+Z, 5=-Z (top row: +X -X +Y; bottom row: -Y +Z -Z)
// This panorama is a 3x2 layout, so: top row = +X, -X, +Y; bottom row = -Y, +Z, -Z
vec3 dir;
if (face == 0){ // +X
dir = vec3(1.0, -faceUV.y, -faceUV.x);
}else if (face == 1){ // -X
dir = vec3(-1.0, -faceUV.y, faceUV.x);
}else if (face == 2){ // +Y
dir = vec3(faceUV.x, 1.0, -faceUV.y);
}else if (face == 3){ // -Y
dir = vec3(faceUV.x, -1.0, faceUV.y);
}else if (face == 4){ // +Z
dir = vec3(faceUV.x, -faceUV.y, 1.0);
}else{ // -Z
dir = vec3(-faceUV.x, -faceUV.y, -1.0);
}
dir = normalize(dir);
vec3 sunDir = GetSunDirWorld();
// Sky radiance from analytic atmosphere
vec3 color = GetSkyRadiance(dir, sunDir);
// Stars at night
float night = 1.0 - curve(saturate(sunDir.y * 10.0 + 0.5));
if (night > 0.5){
float stars = 0.0;
vec3 starSeed = floor(dir * 64.0);
float star = hash1(starSeed);
stars = step(0.998, star) * 2.0;
color += vec3(1.0, 1.0, 1.0) * stars * night;
}
// End dimension sky
#ifdef DIMENSION_END
color = GetEndSky(dir, sunDir);
#endif
imageStore(img_skyBox2D, texel, vec4(color, 0.0));
}
@@ -0,0 +1,28 @@
// MinecraftPT — Sky_End_FS
// End dimension sky rendering pass.
#include "/Lib/Settings.glsl"
#include "/Lib/BasicFunctions/LightingConstants.glsl"
#include "/Lib/Utilities.glsl"
#include "/Lib/IndividualFunctions/EndSky.glsl"
uniform sampler2D depthtex0;
layout(location = 0) out vec4 colorOut;
void main(){
ivec2 texelCoord = ivec2(gl_FragCoord.xy);
float depth = texelFetch(depthtex0, texelCoord, 0).r;
if (depth < 1.0){
discard;
}
vec4 viewPos = gbufferProjectionInverse * vec4(vec2(texelCoord) / screenSize * 2.0 - 1.0, 1.0, 1.0);
vec3 viewDir = normalize(viewPos.xyz / viewPos.w);
vec3 worldDir = normalize(mat3(gbufferModelViewInverse) * viewDir);
vec3 color = GetEndSky(worldDir, GetSunDirWorld());
colorOut = vec4(color, 1.0);
}
@@ -0,0 +1,66 @@
// MinecraftPT — Sky_Overworld_FS
// Renders the sky into the background (colortex12) where no geometry was drawn.
#include "/Lib/Settings.glsl"
#include "/Lib/Utilities.glsl"
#include "/Lib/BasicFunctions/LightingConstants.glsl"
#include "/Lib/BasicFunctions/PrecomputedAtmosphere.glsl"
#include "/Lib/IndividualFunctions/EndSky.glsl"
#include "/Lib/IndividualFunctions/PlanarClouds.glsl"
#include "/Lib/IndividualFunctions/CloudShadow.glsl"
uniform sampler2D depthtex0;
layout(location = 0) out vec4 colorOut;
void main(){
ivec2 texelCoord = ivec2(gl_FragCoord.xy);
float depth = texelFetch(depthtex0, texelCoord, 0).r;
if (depth < 1.0){
// Not sky — preserve scene
discard;
}
// Reconstruct view ray
vec4 viewPos = gbufferProjectionInverse * vec4(vec2(texelCoord) / screenSize * 2.0 - 1.0, 1.0, 1.0);
vec3 viewDir = normalize(viewPos.xyz / viewPos.w);
vec3 worldDir = normalize(mat3(gbufferModelViewInverse) * viewDir);
vec3 sunDir = GetSunDirWorld();
// Sky radiance
vec3 color = GetSkyRadiance(worldDir, sunDir);
#ifdef DIMENSION_END
color = GetEndSky(worldDir, sunDir);
#elif defined DIMENSION_NETHER
// Nether: dark smoky red-brown atmosphere
color = vec3(0.18, 0.06, 0.03) * 1.2;
color += vec3(0.5, 0.2, 0.1) * 0.3 * (1.0 - abs(worldDir.y) * 0.5);
#endif
// Planar clouds
#ifdef PLANAR_CLOUDS
if (PLANAR_CLOUDS > 0){
// Ray-plane intersection with cloud layer
float cloudAlt = mix(PC_ALTITUDE, CLOUD_CLEAR_ALTITUDE, wetness * 0.5);
if (worldDir.y > 0.001){
float t = (cloudAlt - cameraPosition.y) / worldDir.y;
if (t > 0.0){
vec3 cloudPos = cameraPosition + worldDir * t;
vec3 cloudColor;
float cloudDensity = GetPlanarCloudDensity(cloudPos.xz, frameTimeCounter * CLOUD_SPEED, cloudColor);
if (cloudDensity > 0.01){
// Soft cloud edge
vec3 cloudLight = mix(GetCloudAtmoIrradiance(), GetCloudSunIrradiance(), 0.8);
color = mix(color, cloudLight, cloudDensity * 0.8);
}
}
}
}
#endif
colorOut = vec4(color, 1.0);
}
@@ -0,0 +1,114 @@
// MinecraftPT — Soild_FS (Main Lighting Composite)
// Combines GBuffer data with path-traced diffuse + specular, direct sun,
// held light, emission, and ambient to produce the final HDR scene.
#include "/Lib/Settings.glsl"
#include "/Lib/Utilities.glsl"
#include "/Lib/BasicFunctions/LightingConstants.glsl"
#include "/Lib/GbufferData.glsl"
#include "/Lib/BasicFunctions/Blocklight.glsl"
#include "/Lib/BasicFunctions/HeldLight.glsl"
#include "/Lib/BasicFunctions/Sunlight_Shadow.glsl"
#include "/Lib/BasicFunctions/NetherColor.glsl"
#include "/Lib/PathTracing/Tracer/SampleIRC.glsl"
uniform sampler2D colortex7; // diffuse PT (denoised)
uniform sampler2D colortex11; // specular PT (denoised)
uniform sampler2D colortex8; // previous diffuse (for blending)
uniform sampler2D colortex12; // combined HDR (for historical blend)
layout(location = 0) out vec4 colorOut; // colortex12
void main(){
ivec2 texelCoord = ivec2(gl_FragCoord.xy);
// Skip sky — sky was written by composite20 (Sky_Overworld_FS) into colortex12
float depth = texelFetch(depthtex0, texelCoord, 0).r;
if (depth >= 1.0){
discard;
}
// Read GBuffer
GbufferData gbuffer = GetGbufferDataSoild(texelCoord);
MaterialMask mask = CalculateMasks(gbuffer.materialID);
vec3 worldNormal = gbuffer.worldNormal;
vec3 vertexNormal = gbuffer.vertexNormal;
vec3 albedo = gbuffer.albedo;
vec2 lightmap = gbuffer.lightmap;
// Reconstruct world position
vec4 viewPos = gbufferProjectionInverse * vec4(vec2(texelCoord) / screenSize * 2.0 - 1.0, depth * 2.0 - 1.0, 1.0);
viewPos.xyz /= viewPos.w;
vec3 worldPos = gbufferModelViewInverse[3].xyz + viewPos.xyz;
// Path-traced diffuse (from half-res colortex6, sampled at full res)
vec2 halfCoord = vec2(texelCoord) * 0.5;
vec3 diffusePT = textureLod(colortex7, halfCoord / (screenSize * 0.5), 0.0).rgb;
// Path-traced specular
vec3 specularPT = textureLod(colortex11, halfCoord / (screenSize * 0.5), 0.0).rgb;
// Direct sunlight
vec3 sunLight = GetSunlight(viewPos.xyz, worldPos, vertexNormal, worldNormal, lightmap.x);
// Block light
vec3 blockLight = Blocklight(lightmap) * gbuffer.material.emissiveness;
// Emission from GBuffer
vec3 emission = vec3(0.0);
emission = texelFetch(colortex0, texelCoord, 0).a * 2.0;
// Held light
float heldShadow = 1.0;
vec3 heldLight = GetHeldLight(worldPos, worldNormal, heldShadow);
// IRC ambient
vec3 irc = SampleIRC(worldPos) * 0.3;
// Combine:
// diffuse = albedo * (sun + block + irc + held) + diffusePT
// specular = specularPT
// emission = emission
// HDR output
vec3 color = vec3(0.0);
// Diffuse
color += albedo * (sunLight + blockLight + irc) * (1.0 - gbuffer.material.metalness);
color += albedo * heldLight * heldShadow * gbuffer.material.roughness;
// Path-traced diffuse contribution (indirect GI)
color += diffusePT * albedo * 0.5;
// Specular
color += specularPT * gbuffer.material.reflectionStrength;
// Emission
color += emission;
// Fresnel-based specular from direct light
float NdotV = max(dot(worldNormal, normalize(-viewPos.xyz)), 0.0);
float F0 = gbuffer.material.metalness;
vec3 fresnel = FresnelSchlick(NdotV, vec3(F0));
// Direct specular (sun)
float NdotL = max(dot(worldNormal, GetSunDirWorld()), 0.0);
if (NdotL > 0.0){
float roughness = gbuffer.material.roughness;
vec3 halfVec = normalize(GetSunDirWorld() + normalize(-viewPos.xyz));
float NdotH = max(dot(worldNormal, halfVec), 0.0);
float D = GGX_D(NdotH, roughness);
float G = Smith_G(NdotV, NdotL, roughness);
vec3 specular = fresnel * D * G / (4.0 * NdotV * NdotL + 0.0001);
color += GetSunIrradiance() * specular * NdotL * 0.5;
}
// Apply parallax shadow
color *= gbuffer.parallaxShadow;
// Sky mask: if sky, output 0
if (mask.sky > 0.5) color = vec3(0.0);
colorOut = vec4(color, 1.0);
}
@@ -0,0 +1,22 @@
// MinecraftPT — SpecularSpatial_FS
#include "/Lib/Settings.glsl"
#include "/Lib/Utilities.glsl"
#include "/Lib/PathTracing/Denoiser/SpecularSpatialFilter.glsl"
layout(location = 0) out vec4 colorOut;
void main(){
vec2 texelCoord = gl_FragCoord.xy;
vec3 color = texelFetch(colortex11, ivec2(texelCoord), 0).rgb;
int step = 1;
#ifdef SPATIAL_STEP_2
step = 2;
#elif defined SPATIAL_STEP_4
step = 4;
#endif
color = SpecularSpatialPass(color, texelCoord, step);
colorOut = vec4(color, 1.0);
}
@@ -0,0 +1,16 @@
// MinecraftPT — SpecularTemporal_FS
#include "/Lib/Settings.glsl"
#include "/Lib/Utilities.glsl"
#include "/Lib/PathTracing/Denoiser/SpecularTemporalFilter.glsl"
layout(location = 0) out vec4 colorOut;
void main(){
vec2 texelCoord = gl_FragCoord.xy;
vec3 current = texelFetch(colortex9, ivec2(texelCoord), 0).rgb;
vec3 prev = texelFetch(colortex11, ivec2(texelCoord), 0).rgb;
vec3 result = SpecularTemporalAccumulate(current, texelCoord);
colorOut = vec4(result, 1.0);
}
@@ -0,0 +1,63 @@
// MinecraftPT — SpecularTracing_FS
// Specular reflection path tracing at half resolution.
// Output: colortex9 = noisy specular, colortex11 = history (ping-pong)
#include "/Lib/Settings.glsl"
#include "/Lib/Utilities.glsl"
#include "/Lib/BasicFunctions/LightingConstants.glsl"
#include "/Lib/GbufferData.glsl"
#include "/Lib/PathTracing/Tracer/TracingNoise.glsl"
#include "/Lib/PathTracing/Tracer/TracingUtilities.glsl"
#include "/Lib/PathTracing/Tracer/SpecularTracer.glsl"
#include "/Lib/BasicFunctions/TemporalNoise.glsl"
layout(location = 0) out vec4 specularOut;
void main(){
ivec2 texelCoord = ivec2(gl_FragCoord.xy);
ivec2 fullCoord = texelCoord * 2;
float depth = texelFetch(depthtex0, fullCoord, 0).r;
if (depth >= 1.0){
specularOut = vec4(0.0);
return;
}
vec4 normalData = texelFetch(colortex1, fullCoord, 0);
vec3 worldNormal = DecodeNormal(normalData.xy);
vec4 materialData = texelFetch(colortex2, fullCoord, 0);
float roughness = 1.0 - materialData.r;
roughness = roughness * roughness;
float metalness = materialData.g;
// Skip rough non-metal surfaces when rough specular is disabled
#if ENABLE_ROUGH_SPECULAR == 0
if (roughness > 0.5 && metalness < 0.04){
specularOut = vec4(0.0);
return;
}
#endif
// Reconstruct view position
vec4 viewPos = gbufferProjectionInverse * vec4(vec2(fullCoord) / screenSize * 2.0 - 1.0, depth * 2.0 - 1.0, 1.0);
viewPos.xyz /= viewPos.w;
vec3 worldPos = gbufferModelViewInverse[3].xyz + viewPos.xyz;
vec3 viewDir = normalize(-viewPos.xyz);
vec2 noise = GetTracingNoise2(vec2(texelCoord), frameCounter, 1);
// Importance-sample GGX reflection direction
vec3 reflDir = ImportanceSampleGGX(noise, worldNormal, roughness);
// Or use pure reflection for smooth surfaces
if (roughness < 0.05){
reflDir = reflect(-viewDir, worldNormal);
}
// Trace the specular ray
vec3 result = SpecularTrace(WorldToVoxel(worldPos + worldNormal * 0.02), reflDir, PT_SPECULAR_TRACING_DISTANCE, noise);
specularOut = vec4(result, 1.0);
}
+46
View File
@@ -0,0 +1,46 @@
// MinecraftPT — TAA
// Temporal anti-aliasing with jittered accumulation and neighborhood clamping.
#include "/Lib/Settings.glsl"
#include "/Lib/Utilities.glsl"
#include "/Lib/BasicFunctions/TemporalNoise.glsl"
uniform sampler2D colortex12; // HDR scene (current)
uniform sampler2D colortex13; // previous frame HDR
layout(location = 0) out vec4 colorOut;
layout(location = 1) out vec4 historyOut; // same result, stored for next frame
void main(){
vec2 texelCoord = gl_FragCoord.xy;
vec3 current = texelFetch(colortex12, ivec2(texelCoord), 0).rgb;
// Motion vector
vec2 motion = texelFetch(colortex10, ivec2(texelCoord * 0.5), 0).xy * 2.0;
vec2 prevCoord = texelCoord + motion;
// Sample previous
vec3 history = textureLod(colortex13, prevCoord / screenSize, 0.0).rgb;
// Neighborhood clamp
vec3 minColor = history;
vec3 maxColor = history;
for (int i = -1; i <= 1; i++){
for (int j = -1; j <= 1; j++){
vec3 c = textureLod(colortex13, (prevCoord + vec2(i, j)) / screenSize, 0.0).rgb;
minColor = min(minColor, c);
maxColor = max(maxColor, c);
}}
history = clamp(history, minColor, maxColor);
// Subpixel sharpening
float sharpening = TAA_SUBPIXEL_SHARPNING;
current = current + (current - history) * sharpening * TAA_AGGRESSION;
float blend = TAA_BLENDWEIGHT;
vec3 color = mix(current, history, blend);
colorOut = vec4(color, 1.0);
historyOut = vec4(color, 1.0);
}
@@ -0,0 +1,84 @@
// MinecraftPT — Translucent_FS
// Composites translucent geometry (water, glass, particles) on top of solid.
#include "/Lib/Settings.glsl"
#include "/Lib/Utilities.glsl"
#include "/Lib/BasicFunctions/LightingConstants.glsl"
#include "/Lib/GbufferData.glsl"
#include "/Lib/BasicFunctions/Sunlight_Shadow.glsl"
#include "/Lib/BasicFunctions/Blocklight.glsl"
#include "/Lib/PathTracing/Tracer/SampleIRC.glsl"
#include "/Lib/PathTracing/Tracer/ShadowTracing.glsl"
uniform sampler2D colortex12; // combined HDR solid scene
uniform sampler2D colortex4; // translucent albedo
uniform sampler2D colortex5; // translucent normal
layout(location = 0) out vec4 colorOut;
void main(){
ivec2 texelCoord = ivec2(gl_FragCoord.xy);
float depth = texelFetch(depthtex0, texelCoord, 0).r;
if (depth >= 1.0){
colorOut = texelFetch(colortex12, texelCoord, 0);
return;
}
// Check if there is translucent data
vec4 gbuffer5 = texelFetch(colortex5, texelCoord, 0);
float matID = gbuffer5.a * 255.0;
if (matID < 0.5){
colorOut = texelFetch(colortex12, texelCoord, 0);
return;
}
bool isSmooth;
GbufferData gbuffer = GetGbufferDataTranslucent(texelCoord, isSmooth);
vec4 viewPos = gbufferProjectionInverse * vec4(vec2(texelCoord) / screenSize * 2.0 - 1.0, depth * 2.0 - 1.0, 1.0);
viewPos.xyz /= viewPos.w;
vec3 worldPos = gbufferModelViewInverse[3].xyz + viewPos.xyz;
vec3 solidColor = texelFetch(colortex12, texelCoord, 0).rgb;
// Water: blend with refraction
vec3 color = solidColor;
if (matID == MATID_WATER){
vec3 waterColor = gbuffer.albedo;
float alpha = gbuffer.albedoAlpha;
// Fresnel
vec3 viewDir = normalize(-viewPos.xyz);
float NdotV = max(dot(gbuffer.worldNormal, viewDir), 0.0);
float fresnel = 0.02 + 0.98 * pow(1.0 - NdotV, 5.0);
// Light contribution (sun + sky) on water
vec3 sunLight = GetSunlight(viewPos.xyz, worldPos, gbuffer.vertexNormal, gbuffer.worldNormal, gbuffer.lightmap.x);
vec3 waterLight = waterColor * (sunLight + Blocklight(gbuffer.lightmap) * 0.5);
// Water tint / depth color
vec3 deepColor = waterColor * 0.3;
color = mix(solidColor, waterLight + deepColor, fresnel * 0.8 + 0.2);
}else if (matID == MATID_STAINEDGLASS){
vec3 glassColor = gbuffer.albedo;
float alpha = gbuffer.albedoAlpha;
vec3 viewDir = normalize(-viewPos.xyz);
float NdotV = max(dot(gbuffer.worldNormal, viewDir), 0.0);
float fresnel = 0.04 + 0.96 * pow(1.0 - NdotV, 5.0);
color = mix(solidColor, solidColor * glassColor, fresnel);
color += glassColor * 0.1;
}else{
// Particles etc — additively blend
color = solidColor + gbuffer.albedo * gbuffer.albedoAlpha * 0.5;
}
colorOut = vec4(color, 1.0);
}
@@ -0,0 +1,81 @@
// MinecraftPT — Volumetric_FS
// Volumetric fog + volumetric clouds ray marched per-pixel and composited.
#include "/Lib/Settings.glsl"
#include "/Lib/Utilities.glsl"
#include "/Lib/BasicFunctions/LightingConstants.glsl"
#include "/Lib/BasicFunctions/TemporalNoise.glsl"
#include "/Lib/IndividualFunctions/VolumetricFog.glsl"
#include "/Lib/IndividualFunctions/WaterFog.glsl"
#include "/Lib/IndividualFunctions/PlanarClouds.glsl"
#include "/Lib/IndividualFunctions/CloudShadow.glsl"
uniform sampler2D colortex12; // HDR scene
layout(location = 0) out vec4 colorOut;
void main(){
vec2 texelCoord = gl_FragCoord.xy;
vec3 sceneColor = texelFetch(colortex12, ivec2(texelCoord), 0).rgb;
float depth = texelFetch(depthtex0, ivec2(texelCoord), 0).r;
// Reconstruct view position
vec4 viewPos = gbufferProjectionInverse * vec4(texelCoord / screenSize * 2.0 - 1.0, depth * 2.0 - 1.0, 1.0);
viewPos.xyz /= viewPos.w;
vec3 worldPos = gbufferModelViewInverse[3].xyz + viewPos.xyz;
// Dithering for the ray march
float dither = BlueNoiseTemporal();
// Volumetric fog accumulation
vec3 fogColor = vec3(0.0);
float transmittance = 1.0;
// Ray march toward the surface
int steps = VFOG_QUALITY;
float dist = length(viewPos.xyz);
float stepSize = dist / float(steps);
vec3 rayDir = normalize(viewPos.xyz);
vec3 marchPos = worldPos;
float time = frameTimeCounter * 0.05;
for (int i = 0; i < steps; i++){
float t = (float(i) + dither) * stepSize;
vec3 samplePos = marchPos - rayDir * t;
float density = GetVolumetricFogDensity(samplePos, time);
density *= stepSize;
// Sun scattering
float phase = 0.5 + 0.5 * dot(normalize(GetSunDirWorld()), -rayDir);
vec3 inscatter = GetFogColor(samplePos, GetSunDirWorld()) * density * phase;
fogColor += transmittance * inscatter;
transmittance *= exp(-density);
}
// Cloud shadow on fog
#ifdef VFOG_CLOUD_SHADOW
float cloudShadow = GetCloudShadow(worldPos);
fogColor *= cloudShadow;
#endif
// Combine
vec3 finalColor = sceneColor * transmittance + fogColor;
// Water fog (underwater)
#ifdef UNDERWATER_VFOG
if (isEyeInWater > 0){
vec3 waterColor = GetWaterFogColor(worldPos);
float waterFog = 1.0 - exp(-dist * GetWaterFogDensity(worldPos) * UNDERWATER_VFOG_DENSITY);
finalColor = mix(finalColor, waterColor * 3.0, waterFog);
}
#endif
colorOut = vec4(finalColor, 1.0);
}
@@ -0,0 +1,92 @@
// MinecraftPT — VoxelData_Copy compute shader
// Copies the 2D voxel atlas (shadowcolor1) into the 3D voxel texture,
// computing sparse-tracing empty markers for hierarchical ray skipping.
#include "/Lib/Settings.glsl"
#include "/Lib/Utilities.glsl"
#include "/Lib/PathTracing/Voxelizer/VoxelProfile.glsl"
#if PT_VOXEL_RESOLUTION == 4004
const ivec3 workGroups = ivec3(16, 16, 16);
#elif PT_VOXEL_RESOLUTION == 6004
const ivec3 workGroups = ivec3(24, 16, 24);
#elif PT_VOXEL_RESOLUTION == 8004
const ivec3 workGroups = ivec3(32, 16, 32);
#elif PT_VOXEL_RESOLUTION == 8006
const ivec3 workGroups = ivec3(32, 24, 32);
#elif PT_VOXEL_RESOLUTION == 8008
const ivec3 workGroups = ivec3(32, 32, 32);
#elif PT_VOXEL_RESOLUTION == 12004
const ivec3 workGroups = ivec3(48, 16, 48);
#elif PT_VOXEL_RESOLUTION == 12006
const ivec3 workGroups = ivec3(48, 24, 48);
#elif PT_VOXEL_RESOLUTION == 12008
const ivec3 workGroups = ivec3(48, 32, 48);
#elif PT_VOXEL_RESOLUTION == 16004
const ivec3 workGroups = ivec3(64, 16, 64);
#elif PT_VOXEL_RESOLUTION == 16008
const ivec3 workGroups = ivec3(64, 32, 64);
#elif PT_VOXEL_RESOLUTION == 16016
const ivec3 workGroups = ivec3(64, 64, 64);
#else
const ivec3 workGroups = ivec3(32, 24, 32);
#endif
layout (local_size_x = 8, local_size_y = 8, local_size_z = 8) in;
layout (rgba16) uniform writeonly image3D img_voxelData3D;
#ifdef PT_SPARE_TRACING
shared uint isOccupied_8;
shared uint isOccupied_4[8];
shared uint isOccupied_2[64];
#endif
uniform sampler2D shadowcolor1;
void main(){
#ifdef PT_SPARE_TRACING
int id_4 = int((gl_LocalInvocationID.x >> 2u) + (gl_LocalInvocationID.y >> 2u) * 2u + (gl_LocalInvocationID.z >> 2u) * 4u);
int id_2 = int((gl_LocalInvocationID.x >> 1u) + (gl_LocalInvocationID.y >> 1u) * 4u + (gl_LocalInvocationID.z >> 2u) * 16u);
isOccupied_8 = 0u;
isOccupied_4[id_4] = 0u;
isOccupied_2[id_2] = 0u;
barrier();
#endif
ivec3 drawTexel = ivec3(gl_GlobalInvocationID.xyz);
ivec2 voxelTexel = ivec2(VoxelTexel_From_VoxelCoord(vec3(drawTexel)));
vec4 voxelData = texelFetch(shadowcolor1, voxelTexel, 0);
// A texel with z >= 1.0 is empty (clear color)
if (voxelData.z >= 1.0){
voxelData = vec4(0.0, 0.0, 1.0, 1.0); // empty voxel: encoded ID = 1.0 (air)
}
#ifdef PT_SPARE_TRACING
uint occupied = uint(voxelData.z < 0.999);
atomicMax(isOccupied_8, occupied);
barrier();
if (isOccupied_8 == 0u){
voxelData.z = 0.91; // 8^3 empty marker
}else{
atomicMax(isOccupied_4[id_4], occupied);
barrier();
if (isOccupied_4[id_4] == 0u){
voxelData.z = 0.71; // 4^3 empty marker
}else{
atomicMax(isOccupied_2[id_2], occupied);
barrier();
if (isOccupied_2[id_2] == 0u)
voxelData.z = 0.61; // 2^3 empty marker
}
}
#endif
imageStore(img_voxelData3D, drawTexel, voxelData);
}
@@ -0,0 +1,53 @@
// MinecraftPT — WaterRefraction_FS
// Water refraction pass: sample the solid scene with wave-based offset.
#include "/Lib/Settings.glsl"
#include "/Lib/Utilities.glsl"
#include "/Lib/GbufferData.glsl"
#include "/Lib/IndividualFunctions/WaterWaves.glsl"
uniform sampler2D colortex12; // solid scene
uniform sampler2D colortex4; // translucent albedo
layout(location = 0) out vec4 colorOut;
void main(){
ivec2 texelCoord = ivec2(gl_FragCoord.xy);
float depth = texelFetch(depthtex0, texelCoord, 0).r;
if (depth >= 1.0){
colorOut = texelFetch(colortex12, texelCoord, 0);
return;
}
vec4 gbuffer5 = texelFetch(colortex5, texelCoord, 0);
float matID = gbuffer5.a * 255.0;
if (matID != MATID_WATER){
colorOut = texelFetch(colortex12, texelCoord, 0);
return;
}
// Reconstruct world position
vec4 viewPos = gbufferProjectionInverse * vec4(vec2(texelCoord) / screenSize * 2.0 - 1.0, depth * 2.0 - 1.0, 1.0);
viewPos.xyz /= viewPos.w;
vec3 worldPos = gbufferModelViewInverse[3].xyz + viewPos.xyz;
// Wave normal-based refraction offset
vec3 waveNormal = GetWaveNormal(worldPos, 0.5);
vec3 viewDir = normalize(-viewPos.xyz);
vec3 refracted = refract(viewDir, waveNormal, 0.75);
// Sample the solid scene with the refraction offset
vec3 refractedDir = mat3(gbufferModelView) * refracted;
vec2 refractedCoord = viewPos.xy / viewPos.z * refractedDir.xy / refractedDir.z * 0.5 + 0.5;
vec2 sampleCoord = refractedCoord * screenSize;
vec3 color = textureLod(colortex12, sampleCoord / screenSize, 0.0).rgb;
// Water depth color fade
vec3 waterColor = texelFetch(colortex4, texelCoord, 0).rgb;
color = mix(color, waterColor, 0.3);
colorOut = vec4(color, 1.0);
}
+108
View File
@@ -0,0 +1,108 @@
// MinecraftPT — Final_FS
// HDR tonemapping, color grading, dithering, and output to screen.
#include "/Lib/Settings.glsl"
#include "/Lib/Utilities.glsl"
#include "/Lib/BasicFunctions/TemporalNoise.glsl"
uniform sampler2D exposureTex;
#if defined PROGRAM_FINAL_0
layout(location = 0) out vec4 colorOut;
#elif defined PROGRAM_FINAL_1
layout(location = 0) out vec4 colorOut;
#endif
// Tonemapping operators
vec3 TonemapACES(vec3 color){
// ACES filmic
float a = 2.51;
float b = 0.03;
float c = 2.43;
float d = 0.59;
float e = 0.14;
return saturate((color * (a * color + b)) / (color * (c * color + d) + e));
}
vec3 TonemapAGX(vec3 color){
// AGX-inspired: log-shaping curve
vec3 logColor = log2(max(color, 1e-6));
vec3 mid = vec3(AGX_HDR_MIDGREY);
vec3 shaped = logColor - mid;
shaped = tanh(shaped * 0.5) * 0.5 + 0.5;
vec3 result = exp2(shaped + mid);
return result;
}
vec3 TonemapFilmic(vec3 color){
// Uncharted 2 filmic
vec3 x = max(color, 0.0);
return (x * (6.2 * x + 0.5)) / (x * (6.2 * x + 1.7) + 0.06);
}
// Color grading
vec3 ApplyColorGrading(vec3 color){
// White/black point
color = (color - BLACK_POINT) / (WHITE_POINT - BLACK_POINT + 1e-6);
// Saturation
float lum = luminance(color);
color = mix(vec3(lum), color, SATURATION);
// Gamma
color = pow(color, vec3(GAMMA));
// Hue shifts (simplified)
#ifdef ADVANCED_COLOR
vec3 midtone = color * MIDTONE_HUE * MIDTONE_STRENGTH;
vec3 highlight = color * HIGHLIGHT_HUE * HIGHLIGHT_STRENGTH;
vec3 shadow = color * SHADOW_HUE * SHADOW_STRENGTH;
color += midtone + highlight + shadow;
#endif
return color;
}
void main(){
vec3 color = texelFetch(colortex12, ivec2(gl_FragCoord.xy), 0).rgb;
// Exposure
#ifdef MANUAL_EXPOSURE
float exposure = MANUAL_EXPOSURE * pow(2.0, EV_VALUE);
#else
float exposure = textureLod(exposureTex, vec2(0.5), 0.0).r;
#endif
color *= exposure;
// Bloom composite
#ifdef BLOOM
vec3 bloom = vec3(0.0);
// Simple bloom: sample from bloom buffer
bloom = textureLod(colortex15, gl_FragCoord.xy / screenSize, 0.0).rgb;
color += bloom * BLOOM_AMOUNT;
#endif
// Tonemapping
#if TONEMAP_OPERATOR == 0
color = TonemapACES(color);
#elif TONEMAP_OPERATOR == 1
color = TonemapAGX(color);
#elif TONEMAP_OPERATOR == 2
color = TonemapFilmic(color);
#else
// Vanilla-like: Reinhard
color = color / (color + 1.0);
#endif
// Color grading
color = ApplyColorGrading(color);
// Dithering
vec2 noise = BlueNoiseTemporal2();
color += (noise - 0.5) / 255.0;
// Gamma correction
color = LinearToGamma(color);
colorOut = vec4(color, 1.0);
}
@@ -0,0 +1,33 @@
// MinecraftPT — Armor Glint Fragment Shader (enchanted armor shimmer)
#include "/Lib/Settings.glsl"
#include "/Lib/Utilities.glsl"
in vec2 texcoord;
in vec3 worldPos;
in vec3 worldNormal;
in vec3 vertexNormal;
in vec4 color;
in vec2 lightmap;
layout(location = 0) out vec4 colortex0Out;
layout(location = 1) out vec4 colortex1Out;
layout(location = 2) out vec4 colortex2Out;
layout(location = 3) out vec4 colortex3Out;
layout(location = 4) out vec4 colortex4Out;
layout(location = 5) out vec4 colortex5Out;
void main(){
vec4 albedo = texture(tex, texcoord) * color;
if (albedo.a < 0.004) discard;
// Glint is additive-ish; store with high specular
colortex0Out = vec4(albedo.rgb, 0.0);
colortex1Out = vec4(EncodeNormal(worldNormal), EncodeNormal(vertexNormal));
colortex2Out = vec4(0.0, 0.0, 0.0, 6.0 / 255.0);
colortex3Out = vec4(lightmap, 1.0, 1.0);
colortex4Out = vec4(0.0);
colortex5Out = vec4(0.0);
}
@@ -0,0 +1,37 @@
// MinecraftPT — Basic Fragment Shader (untextured geometry, e.g. clouds, selection)
#include "/Lib/Settings.glsl"
#include "/Lib/Utilities.glsl"
in vec2 texcoord;
in vec3 worldPos;
in vec3 worldNormal;
in vec3 vertexNormal;
in vec4 color;
in vec2 lightmap;
flat in int blockId;
layout(location = 0) out vec4 colortex0Out;
layout(location = 1) out vec4 colortex1Out;
layout(location = 2) out vec4 colortex2Out;
layout(location = 3) out vec4 colortex3Out;
layout(location = 4) out vec4 colortex4Out;
layout(location = 5) out vec4 colortex5Out;
void main(){
vec4 albedo = color;
#ifdef IS_SELECTION
float matID = 19.0 / 255.0; // MATID_SELECTION
#else
float matID = 0.0;
#endif
colortex0Out = vec4(albedo.rgb, 0.0);
colortex1Out = vec4(EncodeNormal(worldNormal), EncodeNormal(vertexNormal));
colortex2Out = vec4(0.0, 0.0, 0.0, matID);
colortex3Out = vec4(1.0, 1.0, 1.0, 1.0);
colortex4Out = vec4(0.0);
colortex5Out = vec4(0.0);
}
@@ -0,0 +1,32 @@
// MinecraftPT — Beacon Beam Fragment Shader (emissive beam)
#include "/Lib/Settings.glsl"
#include "/Lib/Utilities.glsl"
in vec2 texcoord;
in vec3 worldPos;
in vec3 worldNormal;
in vec3 vertexNormal;
in vec4 color;
in vec2 lightmap;
layout(location = 0) out vec4 colortex0Out;
layout(location = 1) out vec4 colortex1Out;
layout(location = 2) out vec4 colortex2Out;
layout(location = 3) out vec4 colortex3Out;
layout(location = 4) out vec4 colortex4Out;
layout(location = 5) out vec4 colortex5Out;
void main(){
vec4 albedo = texture(tex, texcoord) * color;
if (albedo.a < 0.004) discard;
colortex0Out = vec4(albedo.rgb, 1.0); // fully emissive
colortex1Out = vec4(EncodeNormal(worldNormal), EncodeNormal(vertexNormal));
colortex2Out = vec4(0.0, 0.0, 0.0, 0.0);
colortex3Out = vec4(1.0, 1.0, 1.0, 1.0);
colortex4Out = vec4(0.0);
colortex5Out = vec4(0.0);
}
@@ -0,0 +1,19 @@
// MinecraftPT — Composite_Copy_CS
// Copies the full-res GBuffer into the half-res working buffers used by the
// path tracing passes (simplified: keeps full-res, pass-through for layout parity).
#include "/Lib/Settings.glsl"
#include "/Lib/Utilities.glsl"
layout (local_size_x = 8, local_size_y = 8) in;
uniform sampler2D colortex0;
uniform sampler2D colortex1;
uniform sampler2D colortex3;
void main(){
ivec2 texel = ivec2(gl_GlobalInvocationID.xy);
// Pass-through (identity copy for pipeline parity)
// In a full implementation this would downsample to half-res buffers.
}
@@ -0,0 +1,6 @@
// MinecraftPT — Damaged Block Fragment Shader
// Handles block damage cracks — same as terrain but with damage texture overlay
#include "/Lib/Settings.glsl"
#include "/Lib/Utilities.glsl"
#include "/Lib/Programs/Gbuffers/Terrain_FS.glsl"
@@ -0,0 +1,60 @@
// MinecraftPT — Entities Fragment Shader
// Handles entities (players, mobs), hands are in Hand_FS
#include "/Lib/Settings.glsl"
#include "/Lib/Utilities.glsl"
in vec2 texcoord;
in vec3 worldPos;
in vec3 worldNormal;
in vec3 vertexNormal;
in vec4 color;
in vec2 lightmap;
flat in int blockId;
flat in float blockLightLevel;
layout(location = 0) out vec4 colortex0Out;
layout(location = 1) out vec4 colortex1Out;
layout(location = 2) out vec4 colortex2Out;
layout(location = 3) out vec4 colortex3Out;
layout(location = 4) out vec4 colortex4Out;
layout(location = 5) out vec4 colortex5Out;
uniform bool isPlayer;
void main(){
vec4 albedo = texture(tex, texcoord) * color;
if (albedo.a < 0.004) discard;
// Entity material ID — default entity
float matID = 6.0; // MATID_ENTITIES
// Player special handling (OptiFine provides isPlayer uniform in entities pass)
if (isPlayer){
matID = 7.0; // MATID_ENTITIES_PLAYER
}
vec4 specTex = vec4(0.0);
#ifdef TEXTURE_PBR_FORMAT
if (TEXTURE_PBR_FORMAT >= 1){
specTex = texture(atlasSpecular2D, texcoord);
}
#endif
vec2 lm = lightmap;
lm.y = SkyLightmapCurve(lightmap.y);
float emissive = 0.0;
#ifdef VANILLA_EMISSIVE
emissive = step(13.5, blockLightLevel) * blockLightLevel / 15.0;
#endif
colortex0Out = vec4(albedo.rgb, emissive);
colortex1Out = vec4(EncodeNormal(worldNormal), EncodeNormal(vertexNormal));
colortex2Out = vec4(specTex.r, specTex.g, specTex.b, matID / 255.0);
colortex3Out = vec4(lm, 1.0, 1.0);
colortex4Out = vec4(0.0);
colortex5Out = vec4(0.0);
}
@@ -0,0 +1,34 @@
// MinecraftPT — Entities Vertex Shader
#include "/Lib/Settings.glsl"
#include "/Lib/Utilities.glsl"
out vec2 texcoord;
out vec3 worldPos;
out vec3 worldNormal;
out vec3 vertexNormal;
out vec4 color;
out vec2 lightmap;
flat out int blockId;
flat out float blockLightLevel;
void main(){
vec4 viewPos = gl_ModelViewMatrix * gl_Vertex;
vec4 wPos = gbufferModelViewInverse * viewPos;
worldPos = wPos.xyz;
vertexNormal = normalize(gl_NormalMatrix * gl_Normal);
worldNormal = normalize(mat3(gbufferModelViewInverse) * vertexNormal);
lightmap = gl_MultiTexCoord1.xy / 240.0;
lightmap = saturate(lightmap);
blockId = int(mc_Entity.x + 0.5);
blockLightLevel = at_midBlock.w;
texcoord = (gl_TextureMatrix[0] * gl_MultiTexCoord0).xy;
color = gl_Color;
gl_Position = gl_ProjectionMatrix * viewPos;
gl_Position.xy += taaJitter * gl_Position.w;
}
@@ -0,0 +1,34 @@
// MinecraftPT — Generic Vertex Shader (entities, textured, line, weather, glints)
#include "/Lib/Settings.glsl"
#include "/Lib/Utilities.glsl"
out vec2 texcoord;
out vec3 worldPos;
out vec3 worldNormal;
out vec3 vertexNormal;
out vec4 color;
out vec2 lightmap;
flat out int blockId;
flat out float blockLightLevel;
void main(){
vec4 viewPos = gl_ModelViewMatrix * gl_Vertex;
vec4 wPos = gbufferModelViewInverse * viewPos;
worldPos = wPos.xyz;
vertexNormal = normalize(gl_NormalMatrix * gl_Normal);
worldNormal = normalize(mat3(gbufferModelViewInverse) * vertexNormal);
lightmap = gl_MultiTexCoord1.xy / 240.0;
lightmap = saturate(lightmap);
blockId = int(mc_Entity.x + 0.5);
blockLightLevel = at_midBlock.w;
texcoord = (gl_TextureMatrix[0] * gl_MultiTexCoord0).xy;
color = gl_Color;
gl_Position = gl_ProjectionMatrix * viewPos;
gl_Position.xy += taaJitter * gl_Position.w;
}
@@ -0,0 +1,29 @@
// MinecraftPT — Water Hand Vertex Shader (hand when submerged)
#include "/Lib/Settings.glsl"
#include "/Lib/Utilities.glsl"
out vec2 texcoord;
out vec3 worldPos;
out vec3 worldNormal;
out vec3 vertexNormal;
out vec4 color;
out vec2 lightmap;
void main(){
vec4 viewPos = gl_ModelViewMatrix * gl_Vertex;
vec4 wPos = gbufferModelViewInverse * viewPos;
worldPos = wPos.xyz;
vertexNormal = normalize(gl_NormalMatrix * gl_Normal);
worldNormal = normalize(mat3(gbufferModelViewInverse) * vertexNormal);
lightmap = gl_MultiTexCoord1.xy / 240.0;
lightmap = saturate(lightmap);
texcoord = (gl_TextureMatrix[0] * gl_MultiTexCoord0).xy;
color = gl_Color;
gl_Position = gl_ProjectionMatrix * viewPos;
gl_Position.xy += taaJitter * gl_Position.w;
}
@@ -0,0 +1,29 @@
// MinecraftPT — Line Fragment Shader (debug lines, selection box)
#include "/Lib/Settings.glsl"
#include "/Lib/Utilities.glsl"
in vec2 texcoord;
in vec3 worldPos;
in vec3 worldNormal;
in vec3 vertexNormal;
in vec4 color;
in vec2 lightmap;
flat in int blockId;
layout(location = 0) out vec4 colortex0Out;
layout(location = 1) out vec4 colortex1Out;
layout(location = 2) out vec4 colortex2Out;
layout(location = 3) out vec4 colortex3Out;
layout(location = 4) out vec4 colortex4Out;
layout(location = 5) out vec4 colortex5Out;
void main(){
colortex0Out = vec4(color.rgb, 0.0);
colortex1Out = vec4(EncodeNormal(worldNormal), EncodeNormal(vertexNormal));
colortex2Out = vec4(0.0, 0.0, 0.0, 19.0 / 255.0); // MATID_SELECTION
colortex3Out = vec4(1.0, 1.0, 1.0, 1.0);
colortex4Out = vec4(0.0);
colortex5Out = vec4(0.0);
}
+19
View File
@@ -0,0 +1,19 @@
// MinecraftPT — Sky Vertex Shader
#include "/Lib/Settings.glsl"
#include "/Lib/Utilities.glsl"
out vec2 texcoord;
out vec3 worldPos;
out vec4 color;
void main(){
vec4 viewPos = gl_ModelViewMatrix * gl_Vertex;
vec4 wPos = gbufferModelViewInverse * viewPos;
worldPos = wPos.xyz;
texcoord = (gl_TextureMatrix[0] * gl_MultiTexCoord0).xy;
color = gl_Color;
gl_Position = gl_ProjectionMatrix * viewPos;
}
@@ -0,0 +1,30 @@
// MinecraftPT — Sky Fragment Shader
// Writes sky color into GBuffer with MATID_SKY so composite can identify it.
// Custom sky is drawn in composite20 (Sky_Overworld_FS) over this.
#include "/Lib/Settings.glsl"
#include "/Lib/Utilities.glsl"
in vec2 texcoord;
in vec3 worldPos;
in vec4 color;
layout(location = 0) out vec4 colortex0Out;
layout(location = 1) out vec4 colortex1Out;
layout(location = 2) out vec4 colortex2Out;
layout(location = 3) out vec4 colortex3Out;
layout(location = 4) out vec4 colortex4Out;
layout(location = 5) out vec4 colortex5Out;
void main(){
vec4 albedo = texture(tex, texcoord) * color;
// Sky: mark with MATID_SKY
colortex0Out = vec4(albedo.rgb, 0.0);
colortex1Out = vec4(0.5);
colortex2Out = vec4(0.0, 0.0, 0.0, 10.0 / 255.0); // MATID_SKY
colortex3Out = vec4(1.0, 1.0, 1.0, 1.0);
colortex4Out = vec4(0.0);
colortex5Out = vec4(0.0);
}
@@ -0,0 +1,32 @@
// MinecraftPT — Spider Eyes Fragment Shader (emissive eyes)
#include "/Lib/Settings.glsl"
#include "/Lib/Utilities.glsl"
in vec2 texcoord;
in vec3 worldPos;
in vec3 worldNormal;
in vec3 vertexNormal;
in vec4 color;
in vec2 lightmap;
layout(location = 0) out vec4 colortex0Out;
layout(location = 1) out vec4 colortex1Out;
layout(location = 2) out vec4 colortex2Out;
layout(location = 3) out vec4 colortex3Out;
layout(location = 4) out vec4 colortex4Out;
layout(location = 5) out vec4 colortex5Out;
void main(){
vec4 albedo = texture(tex, texcoord) * color;
if (albedo.a < 0.004) discard;
colortex0Out = vec4(albedo.rgb, albedo.r > 0.5 ? 1.0 : 0.0);
colortex1Out = vec4(EncodeNormal(worldNormal), EncodeNormal(vertexNormal));
colortex2Out = vec4(0.0, 0.0, 0.0, 6.0 / 255.0);
colortex3Out = vec4(lightmap, 1.0, 1.0);
colortex4Out = vec4(0.0);
colortex5Out = vec4(0.0);
}
@@ -0,0 +1,157 @@
// MinecraftPT — Terrain Fragment Shader
// Writes the solid and translucent GBuffer
#include "/Lib/Settings.glsl"
#include "/Lib/Utilities.glsl"
in vec2 texcoord;
in vec3 worldPos;
in vec3 worldNormal;
in vec3 vertexNormal;
in vec4 color;
in vec2 lightmap;
flat in int blockId;
flat in float blockLightLevel;
layout(location = 0) out vec4 colortex0Out; // albedo + emissive
layout(location = 1) out vec4 colortex1Out; // normals
layout(location = 2) out vec4 colortex2Out; // spec + matID
layout(location = 3) out vec4 colortex3Out; // lightmap
layout(location = 4) out vec4 colortex4Out; // translucent albedo + alpha
layout(location = 5) out vec4 colortex5Out; // translucent normal + matID
// Material IDs from block.properties
#define BLOCK_LEAVES 1
#define BLOCK_TRANSLUCENT 2
#define BLOCK_WATER 3
#define BLOCK_CROSS 4
#define BLOCK_TORCH 5
#define BLOCK_LANTERN 6
#define BLOCK_FIRE 7
#define BLOCK_CAMPFIRE 8
#define BLOCK_LAVA 9
#define BLOCK_GLASS_PANE 10
#define BLOCK_IRON_BARS 11
#define BLOCK_STAIRS 12
#define BLOCK_SLAB 13
#define BLOCK_WALL 14
#define BLOCK_FENCE 15
#define BLOCK_FENCE_GATE 16
#define BLOCK_DOOR 17
#define BLOCK_RAIL 18
#define BLOCK_REDSTONE 19
#define BLOCK_ENDROD 20
#define BLOCK_CHAIN 21
#define BLOCK_AMETHYST 22
#define BLOCK_CANDLE 23
#define BLOCK_GLOWSTONE 24
#define BLOCK_LIGHT 25
#define BLOCK_PORTAL 26
#define BLOCK_LADDER 27
#define BLOCK_SUGARCANE 28
#define BLOCK_BAMBOO 29
#define BLOCK_CACTUS 30
#define BLOCK_CHORUS 31
#define BLOCK_CORAL 32
#define BLOCK_DRIPSTONE 33
#define BLOCK_CONDUIT 34
#define BLOCK_LIGHTNING_ROD 35
#define BLOCK_POT 36
#define BLOCK_SNOW_LAYERS 37
#define BLOCK_COBWEB 80
void main(){
vec4 albedo = texture(tex, texcoord) * color;
// Cutout (alpha test)
if (albedo.a < 0.004) discard;
// Material ID determination
float matID = 0.0; // MATID_DEFAULT
#ifdef IS_HAND
matID = 5.0; // MATID_HAND
#endif
bool isTranslucent = false;
if (blockId == BLOCK_LEAVES){
matID = 3.0; // MATID_LEAVES
}else if (blockId == BLOCK_TRANSLUCENT){
matID = 2.0; // MATID_STAINEDGLASS
isTranslucent = true;
}else if (blockId == BLOCK_WATER){
matID = 1.0; // MATID_WATER (should be handled by gbuffers_water)
isTranslucent = true;
}else if (blockId == BLOCK_CROSS){
matID = 4.0; // MATID_GRASS
}else if (blockId == BLOCK_TORCH){
matID = 11.0; // MATID_TORCH
}else if (blockId == BLOCK_LANTERN){
matID = 20.0; // MATID_COPPER_LANTERN
}else if (blockId == BLOCK_FIRE || blockId == BLOCK_CAMPFIRE){
matID = 12.0; // MATID_FIRE
}else if (blockId == BLOCK_LAVA){
matID = 12.0;
}else if (blockId == BLOCK_GLASS_PANE){
matID = 2.0; // MATID_STAINEDGLASS
isTranslucent = true;
}else if (blockId == BLOCK_ENDROD){
matID = 13.0; // MATID_ENDROD
}else if (blockId == BLOCK_AMETHYST){
matID = 14.0; // MATID_AMETHYST
}else if (blockId == BLOCK_PORTAL){
matID = 18.0; // MATID_END_PORTAL
}else if (blockId == BLOCK_COBWEB){
matID = 17.0; // MATID_PARTICLE-like
isTranslucent = true;
}
// Emissive detection
float emissive = 0.0;
#ifdef HARDCODED_EMISSIVENESS_MODE
if (blockId == BLOCK_LAVA || blockId == BLOCK_FIRE || blockId == BLOCK_CAMPFIRE ||
blockId == BLOCK_GLOWSTONE || blockId == BLOCK_ENDROD || blockId == BLOCK_LANTERN ||
blockId == BLOCK_AMETHYST || blockId == BLOCK_TORCH || blockId == BLOCK_CANDLE ||
blockId == BLOCK_LIGHT || blockId == BLOCK_CONDUIT){
emissive = 1.0;
}
#endif
#ifdef VANILLA_EMISSIVE
// Emissive blocks from vanilla light level (at_midBlock.w = 0-15)
emissive = max(emissive, step(13.5, blockLightLevel) * blockLightLevel / 15.0);
#endif
// LAB PBR specular
vec4 specTex = vec4(0.0);
#ifdef TEXTURE_PBR_FORMAT
if (TEXTURE_PBR_FORMAT >= 1 && blockId != BLOCK_WATER){
specTex = texture(atlasSpecular2D, texcoord);
}
#endif
// Lightmap
vec2 lm = lightmap;
lm.y = SkyLightmapCurve(lightmap.y);
// Parallax shadow (POM)
float parallaxShadow = 1.0;
// Encode normals (octahedral)
vec2 worldNormalEnc = EncodeNormal(worldNormal);
vec2 vertexNormalEnc = EncodeNormal(vertexNormal);
// Solid write
colortex0Out = vec4(albedo.rgb, emissive);
colortex1Out = vec4(worldNormalEnc, vertexNormalEnc);
colortex2Out = vec4(specTex.r, specTex.g, specTex.b, matID / 255.0);
colortex3Out = vec4(lm, parallaxShadow, 1.0);
// Translucent write (glass, panes, cobweb)
if (isTranslucent){
colortex4Out = vec4(albedo.rgb, albedo.a);
colortex5Out = vec4(worldNormalEnc, matID / 255.0, specTex.r);
}else{
colortex4Out = vec4(0.0);
colortex5Out = vec4(0.0);
}
}
@@ -0,0 +1,51 @@
// MinecraftPT — Terrain Vertex Shader
// Handles terrain, block entities, damaged blocks
#include "/Lib/Settings.glsl"
#include "/Lib/Utilities.glsl"
out vec2 texcoord;
out vec3 worldPos;
out vec3 worldNormal;
out vec3 vertexNormal;
out vec4 color;
out vec2 lightmap;
flat out int blockId;
flat out float blockLightLevel;
#ifdef WAVING_PLANTS
#include "/Lib/IndividualFunctions/WavingPlants.glsl"
#endif
void main(){
// World position
vec4 viewPos = gl_ModelViewMatrix * gl_Vertex;
vec4 wPos = gbufferModelViewInverse * viewPos;
worldPos = wPos.xyz;
// Normals
vertexNormal = normalize(gl_NormalMatrix * gl_Normal);
worldNormal = normalize(mat3(gbufferModelViewInverse) * vertexNormal);
worldNormal = normalize(worldNormal);
// Lightmap (blocklight, skylight)
lightmap = gl_MultiTexCoord1.xy / 240.0;
lightmap = saturate(lightmap);
// Block ID from mc_Entity
blockId = int(mc_Entity.x + 0.5);
blockLightLevel = at_midBlock.w;
// Waving plants
#ifdef WAVING_PLANTS
if (blockId == 4){
WavingPlants(wPos, lightmap.y);
}
#endif
texcoord = (gl_TextureMatrix[0] * gl_MultiTexCoord0).xy;
color = gl_Color;
gl_Position = gl_ProjectionMatrix * viewPos;
gl_Position.xy += taaJitter * gl_Position.w;
}
@@ -0,0 +1,36 @@
// MinecraftPT — Textured Fragment Shader (textured non-terrain geometry)
#include "/Lib/Settings.glsl"
#include "/Lib/Utilities.glsl"
in vec2 texcoord;
in vec3 worldPos;
in vec3 worldNormal;
in vec3 vertexNormal;
in vec4 color;
in vec2 lightmap;
flat in int blockId;
layout(location = 0) out vec4 colortex0Out;
layout(location = 1) out vec4 colortex1Out;
layout(location = 2) out vec4 colortex2Out;
layout(location = 3) out vec4 colortex3Out;
layout(location = 4) out vec4 colortex4Out;
layout(location = 5) out vec4 colortex5Out;
void main(){
vec4 albedo = texture(tex, texcoord) * color;
if (albedo.a < 0.004) discard;
vec2 lm = lightmap;
lm.y = SkyLightmapCurve(lightmap.y);
colortex0Out = vec4(albedo.rgb, 0.0);
colortex1Out = vec4(EncodeNormal(worldNormal), EncodeNormal(vertexNormal));
colortex2Out = vec4(0.0, 0.0, 0.0, 6.0 / 255.0); // MATID_ENTITIES
colortex3Out = vec4(lm, 1.0, 1.0);
colortex4Out = vec4(0.0);
colortex5Out = vec4(0.0);
}
@@ -0,0 +1,50 @@
// MinecraftPT — Water Fragment Shader
// Writes the water GBuffer with waves, caustics data
#include "/Lib/Settings.glsl"
#include "/Lib/Utilities.glsl"
in vec2 texcoord;
in vec3 worldPos;
in vec3 worldNormal;
in vec3 vertexNormal;
in vec4 color;
in vec2 lightmap;
layout(location = 0) out vec4 colortex0Out; // albedo + emissive
layout(location = 1) out vec4 colortex1Out; // normals
layout(location = 2) out vec4 colortex2Out; // spec + matID
layout(location = 3) out vec4 colortex3Out; // lightmap
layout(location = 4) out vec4 colortex4Out; // translucent albedo + alpha
layout(location = 5) out vec4 colortex5Out; // translucent normal + matID
#include "/Lib/IndividualFunctions/WaterWaves.glsl"
void main(){
vec4 albedo = texture(tex, texcoord) * color;
// Water surface height / waves
vec3 wPos = worldPos;
#ifdef WAVE_PARALLAX
vec3 waveNormal = GetWaveNormal(wPos, lightmap.y);
#else
vec3 waveNormal = GetWaveNormal(wPos, lightmap.y);
#endif
// Water color — deep water tint
vec3 waterColor = mix(vec3(0.05, 0.15, 0.2), vec3(0.1, 0.3, 0.4), wetness * 0.5);
// Water lightmap
vec2 lm = lightmap;
lm.y = SkyLightmapCurve(lightmap.y);
// Water is translucent
colortex0Out = vec4(waterColor, 0.0);
colortex1Out = vec4(EncodeNormal(waveNormal), EncodeNormal(vertexNormal));
colortex2Out = vec4(0.0, 0.018, 0.0, 1.0 / 255.0); // matID = MATID_WATER
colortex3Out = vec4(lm, 1.0, 1.0);
// Translucent buffer: water albedo is mostly transparent, we store depth tint
colortex4Out = vec4(waterColor, 0.6);
colortex5Out = vec4(EncodeNormal(waveNormal), 1.0 / 255.0, 0.0);
}
@@ -0,0 +1,29 @@
// MinecraftPT — Water Vertex Shader
#include "/Lib/Settings.glsl"
#include "/Lib/Utilities.glsl"
out vec2 texcoord;
out vec3 worldPos;
out vec3 worldNormal;
out vec3 vertexNormal;
out vec4 color;
out vec2 lightmap;
void main(){
vec4 viewPos = gl_ModelViewMatrix * gl_Vertex;
vec4 wPos = gbufferModelViewInverse * viewPos;
worldPos = wPos.xyz;
vertexNormal = normalize(gl_NormalMatrix * gl_Normal);
worldNormal = normalize(mat3(gbufferModelViewInverse) * vertexNormal);
lightmap = gl_MultiTexCoord1.xy / 240.0;
lightmap = saturate(lightmap);
texcoord = (gl_TextureMatrix[0] * gl_MultiTexCoord0).xy;
color = gl_Color;
gl_Position = gl_ProjectionMatrix * viewPos;
gl_Position.xy += taaJitter * gl_Position.w;
}
@@ -0,0 +1,34 @@
// MinecraftPT — Weather Fragment Shader (rain/snow)
#include "/Lib/Settings.glsl"
#include "/Lib/Utilities.glsl"
in vec2 texcoord;
in vec3 worldPos;
in vec3 worldNormal;
in vec3 vertexNormal;
in vec4 color;
in vec2 lightmap;
flat in int blockId;
layout(location = 0) out vec4 colortex0Out;
layout(location = 1) out vec4 colortex1Out;
layout(location = 2) out vec4 colortex2Out;
layout(location = 3) out vec4 colortex3Out;
layout(location = 4) out vec4 colortex4Out;
layout(location = 5) out vec4 colortex5Out;
void main(){
vec4 albedo = texture(tex, texcoord) * color;
if (albedo.a < 0.004) discard;
// Weather drops are thin — mark as particle-ish translucent
colortex0Out = vec4(albedo.rgb, 0.0);
colortex1Out = vec4(EncodeNormal(worldNormal), EncodeNormal(vertexNormal));
colortex2Out = vec4(0.0, 0.0, 0.0, 17.0 / 255.0); // MATID_PARTICLE
colortex3Out = vec4(1.0, 1.0, 1.0, 1.0);
colortex4Out = vec4(0.0);
colortex5Out = vec4(0.0);
}
+12
View File
@@ -0,0 +1,12 @@
// MinecraftPT — Post_VS
// Fullscreen triangle vertex shader for composite passes.
void main(){
// Fullscreen triangle
vec2 pos = vec2(
gl_VertexID == 0 ? -1.0 : (gl_VertexID == 1 ? 3.0 : -1.0),
gl_VertexID == 0 ? -1.0 : (gl_VertexID == 1 ? -1.0 : 3.0)
);
gl_Position = vec4(pos, 1.0, 1.0);
}
+45
View File
@@ -0,0 +1,45 @@
// MinecraftPT — RTWSM Backward Analysis
// Computes the importance map from the shadow map depth: which shadow map texels
// need more resolution (near-field geometry, steep normals).
#include "/Lib/Settings.glsl"
#include "/Lib/Utilities.glsl"
#include "/Lib/PathTracing/Voxelizer/VoxelProfile.glsl"
const ivec3 workGroups = ivec3(32, 16, 1);
layout (local_size_x = 32, local_size_y = 32) in;
layout (r32f) uniform writeonly image2D img_rtwImportance2D;
uniform sampler2D shadowcolor0;
void main(){
ivec2 texel = ivec2(gl_GlobalInvocationID.xy);
vec2 uv = (vec2(texel) + 0.5) / vec2(RTW_RESOLUTION, RTW_RESOLUTION_Y);
// Sample shadow map depth (in the shadow region)
vec2 shadowUv = vec2(uv.x * 0.5 + 0.5, uv.y * 0.5); // map to right region
vec2 shadowTexel = shadowUv * shadowSize;
vec4 shadowData = texelFetch(shadowcolor0, ivec2(shadowTexel), 0);
float depth = shadowData.a;
float importance = 0.0;
if (depth < 1.0){
// Depth-based importance: closer = more important
float dist = 1.0 - depth;
importance = pow(dist, 2.0) * RTW_BACKWARD_DIST_FACTOR;
// Depth gradient importance (edges)
float dLeft = texelFetch(shadowcolor0, ivec2(shadowTexel) + ivec2(-1, 0), 0).a;
float dRight = texelFetch(shadowcolor0, ivec2(shadowTexel) + ivec2(1, 0), 0).a;
float dUp = texelFetch(shadowcolor0, ivec2(shadowTexel) + ivec2(0, -1), 0).a;
float dDown = texelFetch(shadowcolor0, ivec2(shadowTexel) + ivec2(0, 1), 0).a;
float gradient = abs(dLeft - dRight) + abs(dUp - dDown);
importance += gradient * 0.5 * RTW_BACKWARD_NORMAL_FACTOR;
}
imageStore(img_rtwImportance2D, texel, vec4(importance));
}
+31
View File
@@ -0,0 +1,31 @@
// MinecraftPT — RTWSM Blur Importance
// Gaussian-blurs the importance map to make the warp smooth.
#include "/Lib/Settings.glsl"
#include "/Lib/Utilities.glsl"
const ivec3 workGroups = ivec3(32, 16, 1);
layout (local_size_x = 32, local_size_y = 32) in;
layout (r32f) uniform writeonly image2D img_rtwImportance2D;
uniform sampler2D rtwImportance2D;
void main(){
ivec2 texel = ivec2(gl_GlobalInvocationID.xy);
float importance = 0.0;
float weightSum = 0.0;
int radius = int(RTW_BLUR_FACTOR);
for (int i = -radius; i <= radius; i++){
for (int j = -radius; j <= radius; j++){
vec2 coord = vec2(texel + ivec2(i, j)) / vec2(RTW_RESOLUTION, RTW_RESOLUTION_Y);
float w = exp(-(i * i + j * j) / (2.0 * RTW_BLUR_FACTOR * RTW_BLUR_FACTOR));
importance += textureLod(rtwImportance2D, coord, 0.0).r * w;
weightSum += w;
}}
imageStore(img_rtwImportance2D, texel, vec4(importance / weightSum));
}
+52
View File
@@ -0,0 +1,52 @@
// MinecraftPT — RTWSM Building Warp
// Builds the final warp curve (cumulative importance) from the importance map.
#include "/Lib/Settings.glsl"
#include "/Lib/Utilities.glsl"
const ivec3 workGroups = ivec3(32, 1, 1);
layout (local_size_x = 32) in;
layout (rg16) uniform writeonly image2D img_rtwWarp1D;
uniform sampler2D rtwImportance2D;
void main(){
int y = int(gl_GlobalInvocationID.y);
// Compute the cumulative importance curve for this row
float total = 0.0;
for (int x = 0; x < RTW_RESOLUTION; x++){
total += textureLod(rtwImportance2D, vec2(float(x) / float(RTW_RESOLUTION), float(y) / float(RTW_RESOLUTION_Y)), 0.0).r;
}
// Write warp curve: row 0 = cumulative, row 1 = inverse
if (total > 0.0){
float cum = 0.0;
for (int x = 0; x < RTW_RESOLUTION; x++){
cum += textureLod(rtwImportance2D, vec2(float(x) / float(RTW_RESOLUTION), float(y) / float(RTW_RESOLUTION_Y)), 0.0).r;
imageStore(img_rtwWarp1D, ivec2(x, 0), vec4(cum / total, 0.0, 0.0, 0.0));
}
// Inverse: for each output position find input position
for (int x = 0; x < RTW_RESOLUTION; x++){
float target = float(x) / float(RTW_RESOLUTION - 1);
int lo = 0;
int hi = RTW_RESOLUTION - 1;
for (int i = 0; i < 10; i++){
int mid = (lo + hi) / 2;
float v = textureLod(rtwImportance2D, vec2(float(mid) / float(RTW_RESOLUTION), float(y) / float(RTW_RESOLUTION_Y)), 0.0).r;
if (v < target) lo = mid; else hi = mid;
}
float inv = float(lo) / float(RTW_RESOLUTION);
imageStore(img_rtwWarp1D, ivec2(x, 1), vec4(inv, 0.0, 0.0, 0.0));
}
}else{
// Identity warp
for (int x = 0; x < RTW_RESOLUTION; x++){
float v = float(x) / float(RTW_RESOLUTION);
imageStore(img_rtwWarp1D, ivec2(x, 0), vec4(v, 0.0, 0.0, 0.0));
imageStore(img_rtwWarp1D, ivec2(x, 1), vec4(v, 0.0, 0.0, 0.0));
}
}
}
+33
View File
@@ -0,0 +1,33 @@
// MinecraftPT — RTWSM Collapse Importance
// Collapses the 2D importance map into a 1D cumulative curve per row.
#include "/Lib/Settings.glsl"
#include "/Lib/Utilities.glsl"
const ivec3 workGroups = ivec3(RTW_RESOLUTION, 1, 1);
layout (local_size_x = 1) in;
layout (r32f) uniform writeonly image2D img_rtwImportance2D;
layout (rg16) uniform writeonly image2D img_rtwWarp1D;
uniform sampler2D rtwImportance2D;
void main(){
int y = int(gl_GlobalInvocationID.y);
// Sum importance across rows -> 1D profile
float sum = 0.0;
for (int x = 0; x < RTW_RESOLUTION; x++){
sum += textureLod(rtwImportance2D, vec2(float(x) / float(RTW_RESOLUTION), float(y) / float(RTW_RESOLUTION_Y)), 0.0).r;
}
// Build cumulative distribution
float cumulative = 0.0;
for (int x = 0; x < RTW_RESOLUTION; x++){
float imp = textureLod(rtwImportance2D, vec2(float(x) / float(RTW_RESOLUTION), float(y) / float(RTW_RESOLUTION_Y)), 0.0).r;
cumulative += imp;
float normalized = sum > 0.0 ? cumulative / sum : float(x) / float(RTW_RESOLUTION);
imageStore(img_rtwWarp1D, ivec2(x, y), vec4(normalized, 1.0 - normalized, 0.0, 0.0));
}
}
+65
View File
@@ -0,0 +1,65 @@
#include "/Lib/Settings.glsl"
#include "/Lib/Utilities.glsl"
// MinecraftPT — RTWSM SampleWarp
// Samples the warp map to redistribute shadow map coordinates.
#ifndef SAMPLE_WARP_GLSL
uniform sampler2D rtwWarp1D;
#define SAMPLE_WARP_GLSL
// Warp curve sampling: rtwWarp1D is a RG16 texture, RTW_RESOLUTION x 2
// Row 0: warp curve (cumulative importance), Row 1: inverse warp curve
vec2 SampleWarp(float value){
vec2 coord = vec2(value * (RTW_RESOLUTION - 1.0) + 0.5, 0.5) / vec2(RTW_RESOLUTION, 2.0);
return textureLod(rtwWarp1D, coord, 0.0).rg;
}
// Smooth warp sampling with lerp
vec2 SampleRTWWarpSmooth(vec2 shadowScreenPos){
// The warp is 1D along the shadow map's X axis (sun direction)
float u = saturate(shadowScreenPos.x);
// Sample warp curve
vec2 warp = SampleWarp(u);
// Apply warp: remap x based on cumulative importance
float warpedX = warp.x;
// Also apply to y for 2D warping (using second channel)
float warpedY = warp.y;
return vec2(warpedX - u, warpedY - shadowScreenPos.y);
}
// Full warp application for shadow map sampling
vec2 WarpShadowCoord(vec2 shadowScreenPos){
float u = saturate(shadowScreenPos.x);
vec2 warp = SampleWarp(u);
vec2 warped = vec2(warp.x, warp.y);
// The warp curve maps [0,1] -> [0,1] cumulative
// Inverse: sample with the inverse curve
return warped;
}
// Unwarp (for reconstructing world positions)
vec2 UnwarpShadowCoord(vec2 warpedCoord){
// Binary search on the warp curve (forward map)
float low = 0.0;
float high = 1.0;
for (int i = 0; i < 8; i++){
float mid = (low + high) * 0.5;
vec2 sample = SampleWarp(mid);
if (sample.x < warpedCoord.x){
low = mid;
}else{
high = mid;
}
}
return vec2((low + high) * 0.5, warpedCoord.y);
}
#endif
+390
View File
@@ -0,0 +1,390 @@
// MinecraftPT — Settings
// All configurable options. Change values here or via the in-game GUI.
#ifndef SETTINGS_GLSL
#define SETTINGS_GLSL
// =============================== Path Tracing: Voxel ===============================
// Voxelization resolution (width x height x width)
// 4004=128³, 6004=192x128x192, 8004=256x128x256, 8006=256x192x256, 8008=256³
// 12004=384x128x384, 12006=384x192x384, 12008=384x256x384, 16004=512x128x512, 16008=512x256x512, 16016=512³
#define PT_VOXEL_RESOLUTION 8006
// Full block verification (more accurate, slightly slower)
#define PT_FULLBLOCK_VERIFICATION 0
// Full block detection from geometry (helps modded blocks)
#define PT_FULLBLOCK_DETECTION 0
// Sparse tracing — hierarchical empty-voxel skipping (much faster, recommended)
#define PT_SPARE_TRACING 1
// Detect emissive blocks from vanilla light level
#define VANILLA_EMISSIVE 1
// Trace through alpha pixels of blocks
#define PT_TRACING_ALPHA 0
// =============================== Path Tracing: Diffuse ===============================
// Max tracing distance for diffuse rays (blocks)
#define PT_DIFFUSE_TRACING_DISTANCE 32.0
// Samples per pixel for diffuse tracing (1 = 1 ray)
#define PT_DIFFUSE_SPP 1
// Screen space tracing for diffuse (SST) — helps short-range detail
#define PT_DIFFUSE_SST 1
// Diffuse refraction through translucent blocks
#define PT_DIFFUSE_REFRACTION 1
#define PT_DIFFUSE_REFRACTION_IOR 1.3
// ---- Diffuse denoiser ----
// Max temporal accumulation (frames)
#define PT_DIFFUSE_TEMPORAL_MAX_ACCUM 8
// Spatial filter detail (0=low,1=medium,2=high,3=ultra)
#define PT_DIFFUSE_SPATIAL_FILTER_DETAIL 2
#define PT_DIFFUSE_SPATIAL_FILTER_LUMINANCE_WEIGHT 0.4
#define PT_DIFFUSE_SPATIAL_FILTER_DEPTH_WEIGHT 0.8
#define PT_DIFFUSE_SPATIAL_FILTER_NORMAL_WEIGHT 0.4
// Fix history bleeding (0=off,1=on)
#define PT_DIFFUSE_TEMPORAL_HISTORY_FIX 1
// =============================== Path Tracing: Specular ===============================
// Enable rough specular (GGX) reflections
#define ENABLE_ROUGH_SPECULAR 1
// Clamp minimum roughness
#define ROUGHNESS_CLAMP 0
// Max tracing distance for specular rays
#define PT_SPECULAR_TRACING_DISTANCE 64.0
// Screen space reflection mode (0=off,1=combined,2=only screen space)
#define PT_SSR_MODE 1
// SSR quality (steps)
#define PT_SSR_QUALITY 32
// Reuse screen-space data in specular tracing
#define PT_SPECULAR_SCREEN_REUSE 1
// Smooth IRC specular
#define PT_SPECULAR_IRC_SMOOTH 0
// Skybox resolution for reflections (32/48/64/96/128)
#define SKYBOX_RESOLUTION 64
// =============================== Path Tracing: IRC ===============================
// Irradiance cache resolution (16/32/48/64)
#define PT_IRC_RESOLUTION 32
// Samples per IRC update
#define PT_IRC_SPP 8
// IRC blend weight (0-1)
#define PT_IRC_BLENDWEIGHT 0.5
// Self-bounce attenuation
#define PT_IRC_SELFBOUNCE_ATTENUATION 1.0
// =============================== Lighting ===============================
#define BLOCKLIGHT_BRIGHTNESS 1.0
#define SPHERELIGHT_BRIGHTNESS 1.0
#define BLOCKLIGHT_TEMPERATURE 1.5
#define PARTICLELIGHT_BRIGHTNESS 1.0
#define NOLIGHT_BRIGHTNESS 0.05
#define NIGHT_BRIGHTNESS 0.35
#define NETHER_BRIGHTNESS 1.0
#define COLD_MOONLIGHT 1
#define SUNRISE_ROTATION 0.0
#define SUN_ANGULAR_RADIUS 0.00465
#define SUNLIGHT_INTENSITY 1.0
// Light colors
#define BRIGHTNESS_TORCH 1.0
#define COLOR_TORCH_R 1.0
#define COLOR_TORCH_G 0.64
#define COLOR_TORCH_B 0.32
#define BRIGHTNESS_ENDROD 1.0
#define COLOR_ENDROD_R 1.0
#define COLOR_ENDROD_G 0.75
#define COLOR_ENDROD_B 0.6
#define BRIGHTNESS_FIRE 1.8
#define COLOR_FIRE_R 1.0
#define COLOR_FIRE_G 0.45
#define COLOR_FIRE_B 0.13
#define BRIGHTNESS_LIGHTBLOCK 1.0
#define COLOR_LIGHTBLOCK_R 1.0
#define COLOR_LIGHTBLOCK_G 1.0
#define COLOR_LIGHTBLOCK_B 1.0
#define BRIGHTNESS_SOULTORCH 0.4
#define COLOR_SOULTORCH_R 0.4
#define COLOR_SOULTORCH_G 0.98
#define COLOR_SOULTORCH_B 1.0
#define BRIGHTNESS_AMETHYST 0.3
#define COLOR_AMETHYST_R 0.84
#define COLOR_AMETHYST_G 0.52
#define COLOR_AMETHYST_B 1.28
#define BRIGHTNESS_REDSTONETORCH 0.1
#define COLOR_REDSTONETORCH_R 1.0
#define COLOR_REDSTONETORCH_G 0.48
#define COLOR_REDSTONETORCH_B 0.39
// Held light (torch in hand)
#define HELDLIGHT_BRIGHTNESS 1.0
#define HELDLIGHT_MODE 1
#define HELDLIGHT_FALLOFF 0.2
#define HELDLIGHT_COLOR_TEMPERATURE 1.5
#define SPECULAR_HELDLIGHT 0
#define HELDLIGHT_SHADOW 1
// =============================== Shadows ===============================
// Shadow map render distance (4/6/8/12/16/24/32/48/64/96/128)
#define SHADOW_RENDER_DISTANCE 16
// Variable penumbra shadows
#define VARIABLE_PENUMBRA_SHADOWS 1
#define VPS_SPREAD 1.0
// Shadow map quality (1/2/3)
#define SHADOW_QUALITY 2
#define SHADOW_BASIC_BLUR 0.0
// Use voxel shadow tracing instead of shadow map
#define PT_SHADOW 1
// Screen space shadows
#define SCREEN_SPACE_SHADOWS 1
// Colored shadows (from shadow map albedo)
#define COLORED_SHADOWS 1
#define HAND_SCREEN_SHADOW 1
// Prevent light leaking at sun-grazing angles
#define SUNLIGHT_LEAK_FIX 1
// RTWSM (warped shadow map)
#define RTW_RESOLUTION 512
#define RTW_BACKWARD_DIST_FACTOR 1.0
#define RTW_BACKWARD_NORMAL_FACTOR 0.8
#define RTW_BLUR_FACTOR 2.0
// =============================== Surface ===============================
// Block atlas texture resolution (0=auto)
#define TEXTURE_RESOLUTION 0
// LAB PBR texture format (0=legacy,1=LAB-PBR 1.3,2=LAB-PBR 1.4)
#define TEXTURE_PBR_FORMAT 1
// Emissiveness from LAB PBR
#define LABPBR_EMISSIVENESS 1
// Hardcoded emissive blocks
#define HARDCODED_EMISSIVENESS_MODE 1
// Subsurface scattering
#define LABPBR_SSS 1
#define SSS_QUALITY 4
#define SSS_STRENGTH 0.4
#define SSS_STRENGTH_OFFSET 0.0
#define SSS_BRIGHTNESS 1.0
// Porosity (wetness)
#define LABPBR_POROSITY 1
#define TEXTURE_DEFAULT_POROSITY 0.2
#define POROSITY_ABSORPTION 0.3
#define SURFACE_WETNESS 0.5
// Predefined metals
#define LABPBR_PREDEFINED_METAL 1
#define METAL_MINIMAL_F0 0.04
#define METAL_ORIGIN_COLOR 1.0
#define METALMASK_STRENGTH 1.0
// Parallax occlusion mapping
#define PARALLAX_MODE 0
#define ENTITIES_PARALLAX 0
#define PARALLAX_DEPTH 0.08
#define PARALLAX_QUALITY 6
// Waving plants
#define WAVING_PLANTS 1
#define SHADOW_WAVING_PLANTS 0
#define WAVING_RANGE 24.0
#define WAVING_SPEED 1.0
#define GRASS_AMPLITUDE 0.05
#define LEAVES_AMPLITUDE 0.08
// =============================== Water ===============================
#define WAVE_SCALE 8.0
#define WAVE_SPEED 1.0
#define WAVE_NORMAL_STRENGTH 0.4
#define WAVE_PARALLAX 1
#define WAVE_PARALLAX_DEPTH 0.4
#define WATER_FOG 1
#define WATER_SCATTERING_DENSITY 0.3
#define WATER_SCATTERING_R 0.3
#define WATER_SCATTERING_G 0.6
#define WATER_SCATTERING_B 0.8
#define WATER_ATTENUATION_R 0.6
#define WATER_ATTENUATION_G 0.4
#define WATER_ATTENUATION_B 0.3
#define UNDERWATER_VFOG 1
#define UNDERWATER_VFOG_QUALITY 8
#define UNDERWATER_VFOG_DENSITY 1.0
// Rain / wetness
#define drynessHalflife 0.25
#define wetnessHalflife 2.0
#define RAIN_SHADOW 0.98
#define RAIN_VISIBILITY 1.0
#define RAIN_SPLASH_EFFECT 1
#define RAIN_SPLASH_SPEED 1.0
#define RAIN_SPLASH_STRENGTH 1.0
#define RAIN_SPLASH_SCALE 1.0
#define RAIN_WIND_X 1.0
#define RAIN_WIND_Z 1.0
#define RAIN_DISTURBANCE 1.0
#define DISABLE_LOCAL_PRECIPITATION 0
// =============================== Sky / Atmosphere ===============================
#define ATMO_HORIZON 1
#define ATMO_REFLECTION_HORIZON 1
#define SKY_TEXTURE_BRIGHTNESS 1.0
#define HASHSTARS_BRIGHTNESS 1.0
#define STAR_TYPE 0
#define MOON_TEXTURE 1
#define BILINEAR_MOON_TEXTURE 1
#define END_PLANET_CYCLE 0
#define ACCRETIONDISC_ANGLE 0.0
#define BLACKHOLE_LQ 0
// =============================== Clouds ===============================
#define PLANAR_CLOUDS 1
#define VOLUMETRIC_CLOUDS 1
#define PC_ALTITUDE 128.0
#define PC_NOISE_SCALE 0.001
#define PC_CLEAR_COVERAGE 0.4
#define PC_CLEAR_DENSITY 0.5
#define PC_CLEAR_SUNLIGHTING 1.0
#define PC_CLEAR_SKYLIGHTING 0.6
#define PC_RAIN_COVERAGE 0.9
#define PC_RAIN_DENSITY 0.8
#define PC_RAIN_SUNLIGHTING 1.0
#define PC_RAIN_SKYLIGHTING 0.3
#define CLOUD_QUALITY 4
#define CLOUD_DETAILED_NOISE_STRENGTH 0.5
#define CLOUD_BASE_NOISE_SCALE 0.004
#define CLOUD_DETAILED_NOISE_SCALE 0.016
#define CLOUD_COVERAGE_NOISE_OFFSET 0.5
#define CLOUD_FADE 0.2
#define CLOUD_BOTTOM_BRIGHTNESS 0.6
#define CLOUD_OUTSCATTER_FACTOR 0.4
#define CLOUD_SHADOW 1
#define CLOUD_SPEED 1.0
#define CLOUD_CLEAR_ALTITUDE 192.0
#define CLOUD_CLEAR_THICKNESS 64.0
#define CLOUD_CLEAR_COVERY 0.5
#define CLOUD_CLEAR_DENSITY 0.35
#define CLOUD_CLEAR_SUNLIGHTING 1.0
#define CLOUD_CLEAR_SKYLIGHTING 0.7
#define CLOUD_CLEAR_SCALE 1.0
// =============================== Volumetric fog ===============================
#define VFOG 1
#define VFOG_REFLECTION 1
#define VFOG_REFRACTION 1
#define VFOG_HEIGHT 160.0
#define VFOG_HEIGHT_2 40.0
#define VFOG_FALLOFF 0.002
#define VFOG_DENSITY 1.0
#define VFOG_DENSITY_BASE 0.001
#define VFOG_QUALITY 24
#define VFOG_IGNORE_WORLDTIME 0
#define VFOG_SUNLIGHT_ABSORPTION 1.0
#define VFOG_RAIN_DENSITY_MUL 1.0
#define VFOG_SUNLIGHT_DENSITY 1.0
#define VFOG_STAINED 1
#define VFOG_FOG_DENSITY 0.05
#define VFOG_CLOUD_SHADOW 1
#define VFOG_NOISE_TYPE 1
#define VFOG_NOISE_OCTAVE 3
#define VFOG_NOISE_COVERAGE 0.3
#define VFOG_NOISE_HORIZONTAL_SCALE 0.004
#define VFOG_NOISE_VERTICAL_SCALE 0.01
#define LANDSCATTERING 1
#define LANDSCATTERING_STRENGTH 1.0
#define LANDSCATTERING_SHADOW 1
#define LANDSCATTERING_SHADOW_QUALITY 8
#define LANDSCATTERING_REFLECTION 1
#define LANDSCATTERING_REFRACTION 1
#define INDOOR_FOG 0
#define CAVE_FOG 1
#define CAVE_FOG_BRIGHTNESS 0.8
#define NETHERFOG_DENSITY 1.0
// =============================== Post-processing ===============================
// TAA
#define TAA_BLENDWEIGHT 0.9
#define TAA_AGGRESSION 0.05
#define TAA_SUBPIXEL_SHARPNING 0.8
// DOF
#define DOF 1
#define DISABLE_HAND_DOF 1
#define DOF_BLUR 0.5
#define DOF_QUALITY 12
#define DOF_COCSPREAD_QUALITY 12
#define DOF_MAX_COC 12.0
#define DOF_CATSEYE 0
#define DOF_CATSEYE_STRENGTH 1.0
#define DOF_CATSEYE_MIDPOINT 0.5
#define CAMERA_FOCUS_MODE 0
#define CAMERA_FOCAL_POINT 50.0
#define DOF_DEPTH_SMMOOTH_HALFLIFE 0.1
#define DOF_FOCUS_IGNORE_HAND_PARTICLE 0
// Exposure
#define AE_MODE 0
#define SMOOTH_EXPOSURE 0.3
#define AE_CURVE 0.6
#define AE_OFFSET 0.0
#define EXPOSURE_TIME 0.1
#define MANUAL_EXPOSURE 1.0
#define LUMINANCE_WEIGHT_MODE 0
#define LUMINANCE_WEIGHT_STRENGTH 1.0
#define EV_VALUE 0.0
// Motion blur
#define MOTION_BLUR 1
#define MOTION_BLUR_DITHER 1
#define MOTION_BLUR_QUALITY 8
#define MOTION_BLUR_SUTTER_MODE 0
#define MOTION_BLUR_SUTTER_ANGLE 0.0
#define MOTION_BLUR_SUTTER_SPEED 1.0
// Vignette
#define VIGNETTE 0
#define VIGNETTE_FALLOFF 1.0
#define VIGNETTE_ROUNDNESS 1.0
#define SNEAKING_VIGNETTE 1
// Bloom
#define BLOOM 1
#define BLOOM_AMOUNT 0.3
#define BLOOM_CLAMP_STRENGTH 1.0
#define NETHER_END_BLOOM_BOOST 1.0
// Color
#define TONEMAP_OPERATOR 0 // 0=ACES, 1=AGX, 2=filmic, 3=Vanilla
#define AGX_EV 0.0
#define AGX_HDR_EV 0.0
#define ABNEY_EFFECT_CORRECTION 1
#define AGX_HDR_MIDGREY 0.18
#define ADVANCED_COLOR 1
#define HIGHLIGHT_CURVE 1.0
#define SHADOW_CURVE 1.0
#define WHITE_POINT 1.0
#define BLACK_POINT 0.0
#define MIDTONE_HUE 0.0
#define MIDTONE_STRENGTH 0.0
#define HIGHLIGHT_HUE 0.0
#define HIGHLIGHT_STRENGTH 0.0
#define SHADOW_HUE 0.0
#define SHADOW_STRENGTH 0.0
#define KEEP_LUMINANCE 0
#define SATURATION 1.0
#define GAMMA 1.0
// =============================== Misc ===============================
#define CAVE_MODE 0
#define PT_HALF_RES 1
#define DEBUG_COUNTER 0
#define DEBUG_IRC 0
#define DISABLE_NIGHTVISION 0
#define DISABLE_BLINDNESS_DARKNESS 0
#define WHITE_DEBUG_WORLD 0
// RTWSM resolution
#if RTW_RESOLUTION == 256
#define RTW_RESOLUTION_Y 258
#elif RTW_RESOLUTION == 512
#define RTW_RESOLUTION_Y 514
#elif RTW_RESOLUTION == 1024
#define RTW_RESOLUTION_Y 1026
#endif
#endif
+34
View File
@@ -0,0 +1,34 @@
// MinecraftPT — Custom resource declarations
// The shader loader auto-declares standard uniforms, colortex/depthtex/shadowcolor
// samplers, noisetex and tex. This file only declares CUSTOM samplers and images
// (bound via shaders.properties customTexture / image declarations).
#ifndef UNIFORM_DECLARE_GLSL
#define UNIFORM_DECLARE_GLSL
// Custom textures (from customTexture.* in shaders.properties)
uniform sampler2D atlas2D;
uniform sampler2D atlasSpecular2D;
uniform sampler3D CloudNoise3D;
uniform sampler3D CloudDetailedNoise3D;
uniform sampler2D ripple2D;
// Custom image samplers (from image.img_* in shaders.properties)
uniform sampler3D voxelData3D;
uniform sampler2D skyBox2D;
uniform sampler2D prevDepth2D;
uniform sampler2D rtwImportance2D;
uniform sampler2D rtwWarp1D;
uniform sampler2D pixelData2D;
// Custom image bindings (write access)
layout(rgba16) uniform writeonly image3D img_voxelData3D;
layout(rgba16f) uniform writeonly image3D img_irradianceCache3D;
layout(rgba16f) uniform writeonly image3D img_irradianceCache3D_Alt;
layout(rgba16f) uniform writeonly image2D img_skyBox2D;
layout(r32f) uniform writeonly image2D img_prevDepth2D;
layout(r32f) uniform writeonly image2D img_rtwImportance2D;
layout(rg16) uniform writeonly image2D img_rtwWarp1D;
layout(rg16f) uniform writeonly image2D img_pixelData2D;
#endif
+213
View File
@@ -0,0 +1,213 @@
#include "/Lib/Settings.glsl"
// MinecraftPT — Utilities
// Math helpers, noise functions, packing/unpacking, color space conversions
#ifndef UTILITIES_GLSL
#define UTILITIES_GLSL
// --- Math helpers ---
#define saturate(x) clamp(x, 0.0, 1.0)
#define maxVec2(v) max(v.x, v.y)
#define maxVec3(v) max(max(v.x, v.y), v.z)
#define minVec3(v) min(min(v.x, v.y), v.z)
#define fsign(x) ((x) >= 0.0 ? 1.0 : -1.0)
#define sq(x) ((x) * (x))
#define cube(x) ((x) * (x) * (x))
// Gamma correction
vec3 LinearToGamma(vec3 linear){
return pow(linear, vec3(1.0 / 2.2));
}
vec3 GammaToLinear(vec3 gamma){
return pow(gamma, vec3(2.2));
}
float LinearToGamma(float linear){
return pow(linear, 1.0 / 2.2);
}
float GammaToLinear(float gamma){
return pow(gamma, 2.2);
}
// Normal packing (octahedral encoding)
vec2 EncodeNormal(vec3 n){
n /= abs(n.x) + abs(n.y) + abs(n.z);
n.xy = n.z >= 0.0 ? n.xy : (1.0 - abs(n.yx)) * fsign(n.xy);
return n.xy * 0.5 + 0.5;
}
vec3 DecodeNormal(vec2 e){
e = e * 2.0 - 1.0;
vec3 n = vec3(e.x, e.y, 1.0 - abs(e.x) - abs(e.y));
float t = max(-n.z, 0.0);
n.x += t * fsign(n.x);
n.y += t * fsign(n.y);
return normalize(n);
}
// Pack two 8-bit values into a 16-bit uint
float Pack2xU8_to_U16(vec2 v){
v = floor(v * 255.0 + 0.5);
return v.x * 256.0 + v.y;
}
vec2 Unpack2xU8_from_U16(float v){
return vec2(floor(v / 256.0), mod(v, 256.0)) / 255.0;
}
// Pack two 8-bit values with ID (8-bit + 8-bit) into float
vec2 Unpack2xU8_ID_from_U16(float v){
return vec2(mod(v, 9362.0) / 9361.0, floor(v / 9362.0) / 10.0);
}
float Unpack2xU8_ID_Y_from_U16(float v){
return floor(v / 9362.0) / 10.0;
}
// Luminance
float luminance(vec3 color){
return dot(color, vec3(0.2126, 0.7152, 0.0722));
}
// Hash functions
float hash1(vec2 p){
p = fract(p * vec2(443.8975, 397.2973));
p += dot(p, p + 19.19);
return fract(p.x * p.y);
}
float hash1(vec3 p){
p = fract(p * vec3(443.8975, 397.2973, 491.1871));
p += dot(p, p + 19.19);
return fract(p.x * p.y);
}
vec2 hash2(vec2 p){
vec3 p3 = fract(vec3(p.xyx) * vec3(443.8975, 397.2973, 491.1871));
p3 += dot(p3, p3.yxz + 19.19);
return fract(p3.xy);
}
vec2 hash2(vec3 p){
vec3 p3 = fract(p * vec3(443.8975, 397.2973, 491.1871));
p3 += dot(p3, p3.yxz + 19.19);
return fract(p3.xy);
}
vec3 hash3(vec2 p){
vec3 p3 = fract(vec3(p.xyx) * vec3(443.8975, 397.2973, 491.1871));
p3 += dot(p3, p3.yxz + 19.19);
return fract(p3);
}
// Interleaved gradient noise (temporal)
float InterleavedGradientNoise(vec2 pos, float index){
vec3 magic = vec3(0.06711056, 0.00583715, 52.9829189);
return fract(magic.z * fract(dot(pos, magic.xy)) + index * 0.03125);
}
// Blue noise temporal (from noise.png)
// Used as dithering / ray offset
float BlueNoiseTemporal(vec2 screenPos, float frame){
vec2 coord = (screenPos + 0.5) / vec2(viewWidth, viewHeight);
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;
// Temporal interleaving
return fract(noise + frame * 0.03125);
}
// Sky lightmap curve (vanilla sky light attenuation)
float SkyLightmapCurve(float skylight){
return skylight * skylight * (3.0 - 2.0 * skylight);
}
// Packing a ray for DDA traversal
struct Ray{
vec3 ori;
vec3 dir;
vec3 rdir;
vec3 sdir;
};
Ray PackRay(vec3 origin, vec3 direction){
Ray ray;
ray.ori = origin;
ray.dir = direction;
ray.rdir = 1.0 / direction;
ray.sdir = fsign(direction);
return ray;
}
// Smooth min/max
float smoothMin(float a, float b, float k){
float h = max(k - abs(a - b), 0.0) / k;
return min(a, b) - h * h * h * k * (1.0 / 6.0);
}
// Curve function for smooth transitions
float curve(float x){
return x * x * (3.0 - 2.0 * x);
}
// Fresnel Schlick
float FresnelSchlick(float cosTheta, float f0){
return f0 + (1.0 - f0) * pow(1.0 - cosTheta, 5.0);
}
vec3 FresnelSchlick(vec3 cosTheta, vec3 f0){
return f0 + (1.0 - f0) * pow(1.0 - cosTheta, vec3(5.0));
}
// GGX normal distribution
float GGX_D(float NdotH, float roughness){
float a = roughness * roughness;
float a2 = a * a;
float denom = NdotH * NdotH * (a2 - 1.0) + 1.0;
return a2 / (3.14159 * denom * denom);
}
// Smith geometry (GGX)
float Smith_G(float NdotV, float NdotL, float roughness){
float a = roughness * roughness;
float k = a * 0.5;
float g1 = NdotV / (NdotV * (1.0 - k) + k);
float g2 = NdotL / (NdotL * (1.0 - k) + k);
return g1 * g2;
}
// Importance sample GGX
vec3 ImportanceSampleGGX(vec2 uv, vec3 N, float roughness){
float a = roughness * roughness;
float phi = uv.x * 6.283185;
float cosTheta = sqrt((1.0 - uv.y) / (1.0 + (a * a - 1.0) * uv.y));
float sinTheta = sqrt(1.0 - cosTheta * cosTheta);
vec3 H = vec3(cos(phi) * sinTheta, sin(phi) * sinTheta, cosTheta);
// Tangent space to world
vec3 up = abs(N.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0);
vec3 T = normalize(cross(up, N));
vec3 B = cross(N, T);
return normalize(T * H.x + B * H.y + N * H.z);
}
// Cosine-weighted hemisphere sampling (for diffuse)
vec3 SampleHemisphere(vec2 uv, vec3 N){
float phi = uv.x * 6.283185;
float cosTheta = sqrt(uv.y);
float sinTheta = sqrt(1.0 - uv.y);
vec3 dir = vec3(cos(phi) * sinTheta, sin(phi) * sinTheta, cosTheta);
vec3 up = abs(N.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0);
vec3 T = normalize(cross(up, N));
vec3 B = cross(N, T);
return normalize(T * dir.x + B * dir.y + N * dir.z);
}
#endif