// MinecraftPT — Shadow + Voxelization pass // Renders the RTWSM shadow map (shadowcolor0) AND the voxel atlas (shadowcolor1), // which is then copied into the 3D voxel texture by VoxelData_Copy_CS. #include "/Lib/Settings.glsl" #include "/Lib/Utilities.glsl" #include "/Lib/PathTracing/Voxelizer/VoxelProfile.glsl" #include "/Lib/RTWSM/SampleWarp.glsl" ////////////////////////////////////////////////////////////////////////////// // Vertex Shader ////////////////////////////////////////////////////////////////////////////// #ifdef PROGRAM_VSH uniform mat4 shadowModelViewInverse; uniform mat4 shadowProjection; uniform vec3 cameraPositionFract; uniform float frameTimeCounter; uniform float wetness; uniform sampler2D noisetex; in vec4 mc_Entity; in vec4 at_midBlock; in vec2 mc_midTexCoord; out vec3 g_color; out vec3 g_worldPos; out vec2 g_texcoord; #ifdef PROGRAM_VOXEL flat out float g_voxelID; out float g_mcLightLevel; out vec3 g_voxelCoord; out float g_notInVoxel; out float g_normalInvalid; #endif #include "/Lib/PathTracing/Voxelizer/VoxelProfile.glsl" #include "/Lib/RTWSM/SampleWarp.glsl" #ifdef WAVING_PLANTS #include "/Lib/IndividualFunctions/WavingPlants.glsl" #endif void main(){ vec4 worldPos = shadowModelViewInverse * gl_ModelViewMatrix * gl_Vertex; float skylightmap = saturate(float(gl_MultiTexCoord1.y - 8) / 232.0); #ifdef WAVING_PLANTS #ifdef SHADOW_WAVING_PLANTS WavingPlants(worldPos, skylightmap); #endif #endif g_worldPos = worldPos.xyz; g_color = gl_Color.rgb; g_texcoord.xy = mat2(gl_TextureMatrix[0]) * gl_MultiTexCoord0.xy + gl_TextureMatrix[0][3].xy; #ifdef PROGRAM_VOXEL vec3 worldNormal = mat3(shadowModelViewInverse) * normalize(gl_NormalMatrix * gl_Normal); g_voxelID = mc_Entity.x; g_mcLightLevel = skylightmap; g_notInVoxel = step(5999.5, g_voxelID); g_notInVoxel += step(g_voxelID, 0.5); g_notInVoxel *= float(abs(g_voxelID - 8400.0) > 400.5); g_normalInvalid = step(maxVec3(abs(worldNormal)), 0.99); g_voxelCoord = vec3(-2.0); if (g_notInVoxel < 0.5){ // Full block detection: verify vertices are on the block grid if (g_voxelID <= 1.0){ vec3 vertexPos = gl_Vertex.xyz + cameraPositionFract; vertexPos = abs(vertexPos - round(vertexPos)); float posInvalid = vertexPos.x + vertexPos.y + vertexPos.z; posInvalid = step(0.001, posInvalid); g_notInVoxel = posInvalid + g_normalInvalid; } #ifdef PT_MIDBLOCK_TEMPFIX g_voxelCoord = g_worldPos + cameraPositionFract + (voxelResolution * 0.5) - worldNormal * 0.01; #else g_voxelCoord = g_worldPos + cameraPositionFract + (voxelResolution * 0.5) + at_midBlock.xyz * 0.015625; #endif } #endif gl_Position = vec4(1.0); // set by geometry shader } #endif ////////////////////////////////////////////////////////////////////////////// // Geometry Shader ////////////////////////////////////////////////////////////////////////////// #ifdef PROGRAM_GSH layout(triangles) in; layout(triangle_strip, max_vertices = 6) out; uniform mat4 shadowProjection; uniform ivec2 atlasSize; uniform int renderStage; in vec3 g_color[]; in vec3 g_worldPos[]; in vec2 g_texcoord[]; #ifdef PROGRAM_VOXEL flat in float g_voxelID[]; in float g_mcLightLevel[]; in vec3 g_voxelCoord[]; in float g_notInVoxel[]; in float g_normalInvalid[]; #endif out vec3 v_color; out vec4 v_worldPos_voxelData_isWater_isVoxel; out vec2 v_texcoord_mcLightLevel; flat out vec2 v_midTexCoord; #include "/Lib/PathTracing/Voxelizer/VoxelProfile.glsl" void main(){ v_midTexCoord = vec2(0.0); vec3 posDiff = vec3( distance(g_worldPos[0], g_worldPos[1]), distance(g_worldPos[1], g_worldPos[2]), distance(g_worldPos[2], g_worldPos[0]) ); // Emit the shadow map triangle (for RTWSM shadow sampling) { float bias = saturate(maxVec3(posDiff) * 0.5 - 1.0) * shadowProjection[0][0] * 0.3; for (int i = 0; i < 3; i++){ vec4 worldPos = shadowModelViewInverse * gl_in[i].gl_Position; gl_Position = gl_in[i].gl_Position; gl_Position.z += bias; // Shift into the right square shadow region, then apply warp ShiftShadowNdcPos(gl_Position.xy); gl_Position.xy += SampleRTWWarpSmooth(gl_Position.xy * 0.5 + 0.5) * 2.0; v_color = g_color[i]; v_worldPos_voxelData_isWater_isVoxel = vec4(g_worldPos[i], 0.0); v_texcoord_mcLightLevel = g_texcoord[i]; EmitVertex(); } EndPrimitive(); } #ifdef PROGRAM_VOXEL vec3 voxelCoord = floor(g_voxelCoord[0] * 0.33333333 + g_voxelCoord[1] * 0.33333333 + g_voxelCoord[2] * 0.33333333); if (all(bvec3( clamp(voxelCoord, vec3(0.0), vec3(voxelResolution - 1.0)) == voxelCoord, g_notInVoxel[0] + g_notInVoxel[1] + g_notInVoxel[2] < 0.5, renderStage == MC_RENDER_STAGE_TERRAIN_SOLID || renderStage == MC_RENDER_STAGE_TERRAIN_TRANSLUCENT ))){ vec2 atlasResolution = vec2(atlasSize); vec2 maxTexCoord = max(g_texcoord[0].xy, max(g_texcoord[1].xy, g_texcoord[2].xy)); vec2 minTexCoord = min(g_texcoord[0].xy, min(g_texcoord[1].xy, g_texcoord[2].xy)); v_midTexCoord = (maxTexCoord + minTexCoord) * 0.5; vec2 coordSize = (maxTexCoord - minTexCoord) * atlasResolution; #if TEXTURE_RESOLUTION == 0 float coordMaxSize = maxVec3(vec3( maxVec2(abs(g_texcoord[0].xy - g_texcoord[1].xy) * atlasResolution) / max(posDiff.x, 1e-4), maxVec2(abs(g_texcoord[1].xy - g_texcoord[2].xy) * atlasResolution) / max(posDiff.y, 1e-4), maxVec2(abs(g_texcoord[0].xy - g_texcoord[2].xy) * atlasResolution) / max(posDiff.z, 1e-4) )); float textureResolution = floor(coordMaxSize + 0.5); #else float textureResolution = TEXTURE_RESOLUTION; #endif float voxelID = g_voxelID[0]; float roundedResolution = round(log2(textureResolution)); vec2 atlasTiles = vec2(atlasSize) * exp2(-roundedResolution); // Tile-aligned texel sampling for accurate atlas UV v_midTexCoord = (floor(v_midTexCoord * atlasTiles) + 0.5) / atlasTiles; float skylight = saturate(SkyLightmapCurve(g_mcLightLevel[0] * 0.33333333 + g_mcLightLevel[1] * 0.33333333 + g_mcLightLevel[2] * 0.33333333)); float zOffset = g_normalInvalid[0] + g_normalInvalid[1] + g_normalInvalid[2]; coordSize /= textureResolution; zOffset += saturate(coordSize.x * coordSize.y) * -0.2; bool isCutout = voxelID == 2.0; // Light blocks (8000-8400): encode block light level if (abs(voxelID - 8400.0) < 400.5){ voxelID -= 8000.0; if (voxelID > 499.5){ // hardcoded light level block voxelID = 1.0; } } // Encode: cutout shapes get 1000 - id, full blocks get id + 1000 bool isShape = bool( uint(voxelID == 2.0) | // leaves uint(voxelID == 4.0) | // cross plants uint(voxelID == 5.0) | // torch uint(voxelID == 6.0) | // lantern uint(voxelID == 10.0) | // glass pane uint(voxelID == 11.0) | // iron bars uint(voxelID == 12.0) | // stairs uint(voxelID == 13.0) | // slabs uint(voxelID == 14.0) | // walls uint(voxelID == 15.0) | // fences uint(voxelID == 16.0) | // fence gates uint(voxelID == 17.0) | // doors uint(voxelID == 20.0) | // end rod uint(voxelID == 21.0) | // chain uint(voxelID == 22.0) | // amethyst uint(voxelID == 27.0) | // ladder uint(voxelID == 28.0) | // sugar cane uint(voxelID == 29.0) | // bamboo uint(voxelID == 31.0) | // chorus uint(voxelID == 32.0) | // coral uint(voxelID == 33.0) | // dripstone uint(voxelID == 35.0) | // lightning rod uint(voxelID == 36.0) | // pot uint(voxelID == 37.0) | // snow layers uint(voxelID == 80.0) // cobweb ); voxelID = isShape ? 1000.0 - voxelID : voxelID + 1000.0; #ifdef PT_FULLBLOCK_VERIFICATION if (voxelID == 1001.0){ if (abs(posDiff.x + posDiff.y + posDiff.z - 3.41421356) > 0.001){ voxelID = 65536.0; zOffset = -0.49; } } #endif vec2 voxelTexel = VoxelTexel_From_VoxelCoord(voxelCoord); const vec2[3] vertexOffset = vec2[3](vec2(0.0, 0.0), vec2(1.0, 0.0), vec2(0.5, 1.0)); for (int i = 0; i < 3; i++){ gl_Position = vec4((voxelTexel + vertexOffset[i]) * shadowPixelSize * 2.0 - 1.0, zOffset * 0.5 - 0.75, 1.0); v_color = g_color[i]; v_worldPos_voxelData_isWater_isVoxel = vec4(voxelID, roundedResolution, 0.0, 1.0); v_texcoord_mcLightLevel = vec2(skylight, 0.0); EmitVertex(); } EndPrimitive(); } #endif } #endif ////////////////////////////////////////////////////////////////////////////// // Fragment Shader ////////////////////////////////////////////////////////////////////////////// #ifdef PROGRAM_FSH #include "/Lib/PathTracing/Voxelizer/VoxelProfile.glsl" layout(location = 0) out vec4 shadowbuffer0; layout(location = 1) out vec4 shadowbuffer1; uniform mat4 shadowModelViewInverse; uniform vec3 cameraPosition; uniform ivec2 atlasSize; uniform int isEyeInWater; uniform vec2 screenSize; uniform vec2 pixelSize; uniform int frameCounter; uniform int renderStage; uniform sampler2D tex; uniform sampler2D noisetex; uniform sampler2D pixelData2D; #include "/Lib/BasicFunctions/TemporalNoise.glsl" #include "/Lib/RTWSM/SampleWarp.glsl" in vec3 v_color; in vec4 v_worldPos_voxelData_isWater_isVoxel; in vec2 v_texcoord_mcLightLevel; flat in vec2 v_midTexCoord; void main(){ // Shadow map fragment if (v_worldPos_voxelData_isWater_isVoxel.w < 0.5){ vec4 albedoTex = textureLod(tex, v_texcoord_mcLightLevel.xy, 0.0); // Keep shadow fragments only in the right square region [W, 2W] x [0, W] if (gl_FragCoord.x < float(voxelWidth) || gl_FragCoord.x >= shadowSize || gl_FragCoord.y >= float(voxelWidth) || albedoTex.a < 0.004) discard; albedoTex.rgb *= v_color; shadowbuffer0 = vec4(albedoTex); shadowbuffer1 = vec4(0.0); } // Voxel atlas fragment if (v_worldPos_voxelData_isWater_isVoxel.w > 0.2){ shadowbuffer0 = vec4(v_color.rgb, v_texcoord_mcLightLevel.x); vec2 midCoord = saturate(v_midTexCoord * (65536.0 / 65535.0)); float voxelID = saturate(v_worldPos_voxelData_isWater_isVoxel.x / 65535.0); float textureResolution = saturate(v_worldPos_voxelData_isWater_isVoxel.y / 255.0); float skylight = saturate(SkyLightmapCurve(v_texcoord_mcLightLevel.x * 1.07)); shadowbuffer1 = vec4(midCoord, voxelID, Pack2xU8_to_U16(vec2(textureResolution, skylight))); } } #endif