Open davids91 opened 5 months ago
I understand the need for different density information quality (and cost) for different LOD levels, and didn't think about this before. Your proposition raises some concerns to me, though, after a very quick consideration:
In my mind, VoxelData was to be kind of inert and just the result of evaluating a field at a given position. Would it work for your use case, if the field itself was responsible for handling the LOD / density details ? You would keep in VoxelData only things that transvoxel_rs cares about, and where today you might have something like:
fn f(x, y, z) -> VoxelData;
extract_from_fn(f, ...);
You would wrap f in a (LOD-customizable) field object, and do something like:
let field_for_current_lod = MyField::new(f, Lod::VERY_DETAILED); // Or some less static value like Lod::new(3);
extract_from_field(field_for_current_lod, ...);
Do you think that could work, and makes sense?
I think your proposition makes sense!
In that case the responsibility to align the generated meshes so there are no unintentional holes would fall into the implemented of VoxelData, which brings some additional questions into play though...
Thank you for considering it!
Did you manage to get something ?
It's going to be hard any way, if the f(x,y,z)->density function depends on the LOD, but I really feel like the "voxel source" is the right place to handle this. That said, I'm not sure the current implementation provides you enough information to do it properly: to avoid holes, you need all densities to coincide between neighboring blocks, for a given queried point in space. The issue is that the algorithm will sometimes call VoxelSource::get_regular_voxel even for a high-res face (assuming it saves memory potentially, but that's maybe not smart). In this case for example:
LOD N+1 LOD N with transition
┌───────┬──────a A───A────────────D
│ │ │ │ │ │
│ │ │ │ │ │
│ │ │ │ │ │
│ │ │ │ │ │
├───────┼──────b B │ │
│ │ │ │ │ │
│ │ │ │ │ │
│ │ │ │ │ │
│ │ │ │ │ │
└───────┴──────c C───C────────────E
You want a==A, b==B, c==C. But the density for A and C will be queried through get_regular_voxel, so you have no way of knowing that you need to match the higher LOD precision, in this case.
Maybe I should just drop this "optimization", or create a 3rd function (or pass down some flag telling you which resolution is queried). Would any of these help ?
Out of curiosity, are you doing this because you hit a point where generating density is a bottleneck ? What kind of application are you making ?
I've been thinking about this problem and for sure the information is available to the user through the subdivisions
field from block:
https://github.com/Gnurfos/transvoxel_rs/blob/9043633b82f40c44230202d233e380443853dde4/src/voxel_source.rs#L34
If I as a user am calling the extract function I have explicit control over the number of subdivisions there will be inside a field; Which correlates directly with LOD, as for smaller subdivisions lower LOD values match.
I managed to work around most of the limitations by having a reference to the field included inside the mesh builder, so it is possible to query the field itself, and the interpolated positions are available in the call of add_vertex_between
.
As for the usage, I generate terrain mesh from voxel information, and currently I am able to generate a panorama for a 256256256 block ( one voxel has 101010 size, so it's a 256025602560 landscape), but it's not nearly enough to have the immersion I was looking for so I'm looking to 10x that with optimizations, and pre-rendering ( in progress ), and one of the optimization possibilities is to have the field in different LODs. I was also experimenting with https://crates.io/crates/meshopt, but it messes up the connecting vertex positions so I'm not sure if that's a plausible use here.
I think reading subdivisions is not enough to avoid holes, as it is constant across the block. But it won't tell you what resolution of voxel is being queried by the algorithm. In my example above, voxels A/B/C, despite being used within the block of lod N, have to produce densities equal to the ones produced by a/b/c (in a block of lod N+1).
Well in itself it's a really complex unsolved problem; All one can do is approximate I think
To help with deciding on how detailed the density information should be, the VoxelData trait could be updated: https://github.com/Gnurfos/transvoxel_rs/blob/9043633b82f40c44230202d233e380443853dde4/src/traits.rs#L39
The function usage inside the library contains this information in
let rot = self.current_rotation;
: https://github.com/Gnurfos/transvoxel_rs/blob/9043633b82f40c44230202d233e380443853dde4/src/implementation/algorithm.rs#L469This would make it possible to provide better representative density information through VoxelData by enabling the trait implementers to use the size of the iterating cube.