NVIDIA / gvdb-voxels

Sparse volume compute and rendering on NVIDIA GPUs
Other
673 stars 144 forks source link

Guidance on merging volumes/voxels #81

Closed digbeta closed 4 years ago

digbeta commented 4 years ago

Hi,

I could use some guidance on how best to go about merging two structures/sets of voxels.

The OpenVDB cookbook has a few examples of compositing and combining operations for multiple grids, but am only now beginning to explore how we could do something similar in GVDB.

Are there examples or functions that could be used to "easily" do this today? Or is there a recommended approach to this (e.g. iterating nodes like in the CPU approaches described by OpenVDB)?

Thank you in advance!

NBickford-NV commented 4 years ago

Unfortunately, GVDB doesn't have functions like OpenVDB's csg or comp functions in openvdb::tools, or Tree::combine yet! But if you're up for merging trees manually, it should definitely be possible to do with some knowledge of the internal data structure - and should be pretty fast, especially if the trees have the same brick sizes (though you can do this without equivalent brick sizes, though).

To merge one tree into another, say tree B into tree A, one method I can think of (though I haven't tested it!) would be to allocate space in tree A - e.g. by getting all of the bricks that are active in tree B but not in tree A, then calling something like AcumulateTopology (in this case, after copying the list of brick coordinates into AUX_PNTPOS) - then iterate over each brick in tree B, getting its corresponding brick (i.e. chunk of the atlas texture) in tree A, and combining the two using your preferred combining operation.

digbeta commented 4 years ago

Thanks! Today I just got something mostly working to do this. I had to hack up the allocator (adding AtlasCopy/AtlasMerge functions) and gvdb_volume to get it to work (had to pull out some Cuda initialization from the volume class and some other tidbits). Basically, now I can allocate multiple volumes and merge or copy by passing in different kernels to do specific operations.

I'm not doing it as elegantly as your suggestion, however... Essentially, I iterate over a source volume's nodes, activating new bricks and keeping track of the mapping between the src node ID and dst volume's node ID in a hash map. Then, I finish the topology, update the atlas, then call the AtlasMerge() functions to copy/blend the voxels via a kernel. Here's a bunny in a cube, each were separate volumes merged together (note there are still some small bugs and it's not super performant).

image

Happy to share my hacky-ish code if interested!