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