I am doing some research into how feasible it is to use voxels to represent largish (256x256x256 voxels) battlegrounds with destructible terrain for server-hosted multiplayer games. Only one battleground will exist for any game at a time. However, to be able to broadcast rooms and changes to their terrain, I am trying to find an algorithm that can group the voxels into the fewest rectangular blocks as possible.
As a simplistic example, if the bottom half of the level was completely filled with voxels of one type and the top half with voxels of another type, the level should be divided into two blocks, one representing the bottom half of the level, and the other representing the top. Ideally, this algorithm should be able to run in real time so any deformation in the terrain could be accounted for on a per-frame basis and broadcast to the clients. This should enable the clients to render the terrain efficiently without worrying about duplicating terrain destruction logic in the clients.
Here are the approaches I have tried and the problems I find with them. The block counts reported are for filling a 256^3 space by randomly dropping more than 4,194,304 "EARTH" voxels into as far close to the bottom as they can go for the randomly selected (x,z) coordinate. Only "EARTH" blocks are counted.
- Octrees: very fast, but if I split at the middle of a space, it produces a ridiculously large number of blocks (800,000+).
- k-D trees splitting to minimize weighted entropy after a split: slightly slower than octrees, but much fewer blocks (~350,000).
- k-D trees splitting to maximize information gain ratio: twice as fast as than the previous k-D trees method, generating far fewer blocks (~167,000), but still to slow.
- k-D trees splitting to minimize Gower similarity: very slow, but generates fewer blocks than any other k-D tree method (~155,000).
- Greedily grabbing the largest subset of non-intersecting, largest volume blocks available when considering each unclaimed "EARTH" block as the block's defining point: even threaded, this algorithm is obscenely slow (~16 minutes with 8 threads on an 8-core system), but it generates the fewest blocks of all (<65,536).
- Greedily grabbing the largest subset of non-intersecting blocks while treating a block's dimensions as objective scores to maximize: much slower than the other greedy approach and generates a few thousand more blocks, too.
Considering that a maximum acceptable number of blocks is one block per (x,y) coordinate to represent a single column, only the greedy volume is having results that could be considered even close to optimal.
I do not know how to compute the minimum block count without using a brute force approach that never ends, so I do not know whether it is possible to do better than the greedy volume approach. Furthermore, I do not know how I can make it any faster. Can anyone give me an algorithm to try or at least point me in the right direction? I'd like to another way to approach my problem if this cannot be done any better.