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,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