Hello fellow monkeys,
over time my project has turned into a huge mess and since i was quite busy the last month i feel like to find back into my code its a good idea to tidy up and redo some parts. and i would like to make sure i do it a reasonable way
ill try to sum up my approach and then ask for any idea about improvements / alternatives.
note: the terrain does not need to be “infinite” as in minecraft eg, still big enough to require some sort of paging. and about terminology: by “chunk” i mean 32x32x32 blocks, by “column” i mean a vertical stack of chunks (32x256x32 blocks = 8 chunks stacked on top of each other)
when a player spawns / moves etc i check which columns need to be loaded and mark them, then i tick the column the player is in.
the tick causes the column to “basic terrain generate”, that is create some rock strata, caves and overhangs (basically everything that does not need any information about neighbour chunks). this happens on column-level meaning all chunks in a column are basic-terrain-generated at the same time since it allowed for some optimizations.
when the column is done basic terrain generating, it ticks all 8 neighbours, which in return causes them to basic terrain generate if they are marked as “need load”.
some time later (that is, when the last of the 8 surrounding columns has finished basic terrain generation and ticks its neigbours) the column that was basic terrain generated first is ticked again, realizes that all surrounding columns are already basic terrain generated now and starts complex terrain generation.
complex terrain generation places structures like trees and buildings that might overlap chunk-borders / column-borders, which is why it needs the surrounding columns to be basic generated (so trees stop growing if they reach into a neighbour chunk and there is a rock stopping the tree eg)
those ticks happen whenever a column / chunk has finished some task.
after complex terrain generation there is a step called basic light calculation.
basic light calculation again does not require any surrounding columns to be complex terrain generated or even basic terrain generated, which is why it basically starts right after a column has finished complex terrain generation.
it starts to floodfill sunlight from the top and emits light from light emittting blocks, but never crosses a chunk border.
later, when a column is ticked which is basic light calculated already and it realizes that all 8 surrounding columns are basic light calculated too, it starts complex light calculation.
complex light calculation takes the outer most blocks of a column and floods their light into the corresponding touching neighbour column (north east south and west, 4 floodfills total), those flood their light into the diagonals of the original chunk (2 floodfills per north east south and west = 8 floodfills), those diagonals floodfill their light back into the north east south and west columns (again 8 floodfills) which then flood their light back into the center column (another 4 floodfills).
this is because the floodfilled light can go around corners and a chunk might have a wall of blocks reaching all the way to its chunk border, which means i have to floodfill the light out of the chunk, and then floodfill it back in, maybe even via the diagonal column.
when a column is done complex light calculating, it is considered fully loaded and can start meshing / collisionShaping in parallel
now although i feel like it works quite well, im sure there is a lot to optimize especially regarding the light calculation.
also my current approach requires me to have a loadrange that is at least 2 chunks higher than the viewrange (because to mesh a chunk it needs complex light which means its surrounding columns need basic light, so they are also complex terrain generated, which means their surrounding chunks needed to be basic terrain generated)
now i thought i could combine the 2 light calculation steps into 1 step and just fully floodfill the light thats emitted by blocks and not care about column borders because i know the surrounding columns are at least complex generated (meaning they got all their solid blocks placed and light cannot reach further than the length of a chunk-edge).
but thinking about it im not sure its an optimization because it might cause more calculations than needed: say i floodfill sunlight from the top in one column, but there is an overhang fully cutting the chunk horizontally. that causes the sunlight to floodfill into the neighbour column (losing strength because going sideways) then go down further (losing strength because its not at max strength anymore) and reach back into the original chunk underneach the overhang.
then the neighbour column is lit, sunlight is floodfilled from the top, and all the sunlight from the original chunk is basically overwritten because the new sunlight is brighter since it didnt need to go around such big corner
updating light upon block placements is no problem and im fine with the performance. im also fine with the performance of my current approach for light calculations upon generation but im sure the algorithm itsself is not efficient, i just dont have an idea to compare it to.
and in some article about occlusion culling in minecraft i read that 2 of their biggest improvements were occlusion culling and chunk scheduling (if im not mistaken) so i guess a good approach for loading chunks makes a good approach for scheduling that easier
i would like to base the chunk loading scheduling on the occlusion algorithm because that tells me which chunks are visible and thus which columns need to be loaded and i cannot fit my current approach with the ticks into this
as always, thanks a lot in advance for any input or idea, experience etc
many greetings from the shire,
samwise