Is sector based PartialCulling really worth even having?
How often is an entire side of a thing opaque?
Culling needs to not be a world property; but really more something associated with the renderer; because only the renderer (and save file) is a consumer of cull data. It certainly makes sense how it currently is that nothing(except game container) knows about the renderer... I started passing the game environment as initializers so classes could get the renderer; and added some culling methods to renderer... but maybe ZVoxelCuller should be a utility class that's associated with/retrieved from the renderer, and then pass that. ZVoxelCuller would look more like an interface with
ZVoxelCuller( ZWorld &world );
InitFaceCullData( sector );
CullSector( sector, internal/edges);
-or-
CullSectorInternal( sector );
CullSectorEdges( sector );
and CullSingleVoxel( sector, (x,y,z/offset) );
...
-------------
Does culling must be done at world level ? In some parts, sectors need to be processed independently to the existence of a world. So, your proposition of an independent class is an efficient idea to clean the mess.
But we are tempted to say : don't mangle your head too much with that.
Because what is on our roadmap for future is making face culling completely integrated with rendering phase.
Yes, making that could be a very, very bad choice in some ways because it can add significant overhead to the main thread.
So, why we plan to do it ? Let's explain the actual system and why it could be better.
Keep in mind that Blackvoxel made very specific game choices. It's MVI engine cause massive load on rendering. Also, vehicles like airplane needs very quick refresh of sectors.
That's why avoiding bottleneck in rendering was vital for Blackvoxel. That's wasn't easy to make rendering fluid enough and balance rendering settings for getting fluid and quick.
To alleviate the task of rendering, work had been distributed on other threads. At sector loading/creation, main culling is done. It's completed on the MVI's thread for partial culling. Partial culling is also done on individual voxel refresh.
So you are asking, why partial culling ? Does it is really needed ?
Partial culling is not related to having an entire sector face culled, that's simply because voxels on the sides of a sectors needs to have culling like others. Unless that, it will make visible errors on side... or huge slowdowns if you make sides "all visibles".
The problem is simple : external faces of voxels on side can't be culled without data of the neighboring sectors.
At sector loading and creation, we can't rely on other sectors being in memory, so we made culling for all faces but the outside.
Further, MVI thread check if culling is needed on sectors and look if neighboring sectors are loaded. If so, culling is completed on the relevant side. Making these partial culling make less load on memory system than full culling.
All that stuff is complicated, but it's fast and working well.
So, why wanting to change that ?
In one word : because of MVI. What is optimized in one hand is bad on other.
The system rely on fact the faces are (nearly) always culled. So when MVI needs to move a voxel, it must redo culling on it's faces. Looking at the voxel changing routine will let you understand what we mean : it could be faster without need to keep faces culled.
Since the begining, we optimized rendering a lot with various stuff. It may compensate enough for what will be lost.
It will also be simpler, eliminate a lot of architectural complexity and make it more powerfull for future architectural change we are planing.
The Blackvoxel Team