A chunk is a group of 16 x 384 x 16 blocks in 1.18 and above, and 16 x 256 x 16 blocks in 1.17 and below. They are used to divide the huge world of Minecraft into small pieces that can be loaded and unloaded as needed while keeping the resource usage as low as possible.
Shadow Leaking and Chunk Loading
Shadow leaking is a problem where sunlight sometimes appears on the edges of blocks underground. It can look a bit like this, this, or this. But to understand why it happens, we first need to know a little bit about how chunk loading works. Chunk loading can be triggered for a lot of different reasons, but for this explanation I am going to assume that chunk loading was triggered because the player crossed a chunk boundary. I am also assuming this is in singleplayer. I will get back to both of these assumptions later.
There are 4 main steps for chunk loading:
- The server thread tries to load that chunk from disk. If that fails, it will generate the chunk based on the world seed. After this is done, the chunk is "loaded server-side", and server-side processes can query what blocks exist in this chunk.
- The server will send the data of that chunk to the client. This happens in singleplayer too since even singleplayer worlds have their own "integrated" server. After the client receives and processes this information, the chunk is now "loaded client-side", and client-side processes can query what blocks exist in this chunk. But the story isn't over yet.
- After that, the chunk is queued to have its "meshes built". This basically means converting all the blocks in that chunk into a list of vertexes that the GPU can actually draw. This process is actually done for every "chunk section" (a chunk section is a 16x16x16 volume), not the entire chunk all at once. Also, this will only happen for sections which are within the player's view frustum, and have line of sight to the player. Any sections which do not meet these criteria are only built after that section becomes visible again.
- Once a chunk section has its mesh built, the final step is to upload that mesh to the GPU. Once this is done, the chunk section is now "uploaded", and it will appear on your screen.
So, back to shadow leaking then. Ultimately, the reason why shadow leaking happens is that shaders only know about chunks which are uploaded. If the player is underground, the chunk sections on the surface may be loaded client-side, but they might not be visible, and therefore might not have their meshes built or uploaded. In this case, the shader thinks there's nothing but air between the wall you're looking at and the sun. And the thing is, sunlight can travel through air.
There are 2 main ways to fix shadow leaking:
- Make sure the chunk sections on the surface are uploaded, and this usually means going to the surface and looking around to make sure everything has line of sight for a little while. Remember, if you go underground again after this, the surface sections are still uploaded until they exit your view distance. This is not a guaranteed fix, and things can still break at sunset because the only sections which could block the sun are so far away that they're outside your view distance, and are therefore guaranteed to not be uploaded. There's not really anything you can do in this case unfortunately. But at least now you know what's going wrong.
- Have the shader skip shadows when the sky light level is low. This means the sun will no longer illuminate surfaces which have low light levels at all, even if they have line-of-sight to the sun. So there are pros and cons to this solution. For that reason, most packs that do this have a config option for it, and that option is typically named "Light leak fix". So if this solution is acceptable, then go through your pack's options, and see if it has anything like that.
Additional Information
This isn't really necessary to understand for fixing shadow leaking, but if you're into technical details, here's some more facts about how chunk loading and unloading works.
Non-players loading chunks
If chunk loading was triggered by a non-player (for example, Redstone), then step 1 will be performed, but steps 2-4 might not be. This simply depends on whether or not the chunk is within the player's view distance. Or, on a multiplayer server, whether or not the chunk is in any player's view distance.
Changing an already-loaded chunk
If a block or light level changes while a chunk is still loaded, the server knows about this change immediately, and server-side processes can query the block to see that it did in fact change.
Then the server tells the client that the block changed. Once the client processes this message, client-side processes can query that change too.
Then the chunk sections are re-added to the queue to have their meshes built again. This uses the same logic as chunk loading, so if the sections aren't visible, then they will only be re-built once they become visible again.
After the new meshes are built, they are re-uploaded to the GPU, and the old meshes are forgotten. The chunk section now looks different on your screen to reflect the block or light level that changed.
The chunk does not unload on the client or the server at any point during this process, and the blocks inside the chunk can still be queried on both the client and the server while its meshes are being re-built on the client.
Loading an already-loaded chunk
If the player crosses a chunk border and "loads" a chunk which is already loaded on the server for any reason, then step 1 will be skipped in this case. The chunk will not be read from disk, nor will it be generated from the world seed. It will still get sent to the client, and it will still have its meshes built and uploaded.
Chunk Unloading
If the player turns around or moves in such a way that existing uploaded chunk sections are no longer visible, the meshes of those sections remain in VRAM, and will be re-used if the player looks at the section again. The chunk sections do not need to have their meshes re-built in this case. The chunk is not unloaded on the client or the server either, and both the client and the server can still query what blocks are in this chunk.
If the player crosses another chunk boundary and suddenly some chunks are outside the player's view distance, all of the chunk loading processes will be undone. The meshes are erased from VRAM, and the chunk is forgotten on both the client and the server. Nothing can query what blocks are in this chunk anymore unless chunk loading is triggered again.