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,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);
}