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