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