Zylann / godot_voxel

Voxel module for Godot Engine
MIT License
2.59k stars 244 forks source link

Using per-voxel texturing with more than 16 textures #560

Open Oh-Nothing opened 11 months ago

Oh-Nothing commented 11 months ago

Disclaimer: I'm very new to the plugin, Godot, gamedev, and everything else really, so apologies if this is a dumb question.

I've been wanting to make something akin to what is effectively smooth Minecraft using the transvoxel mesher, in the sense that any voxel can be harvested and placed somewhere else, with the texture of the original voxel carrying over to wherever it's placed next. 4-blend over 16 textures would presumably be the play here, but as the docs mentions it's limited to 16 textures per terrain, which means only 16 variations of dirt, stone, ores, etc if I'm not mistaken.

Is there any way of increasing the limit of this particular method (unlikely, probably), or any known workarounds to getting more per-voxel textures in terrain? I did see some discourse in previous issues on the topic, but all of them predate the addition of the 4-blend so I'm not sure if they're outdated or if anything new has come up since then. Blending also isn't really important in this case, if that makes things any easier.

Zylann commented 11 months ago

If you don't want any transition between textures (and by that I really mean that it won't even be anti-aliased), then it might be possible to store an ID in vertices that could be used as a texture index in a big texture array in your shader. That would require modifying the mesher to transfer voxel data into vertices nearby, although I'm not sure of the details. It might be doable as a second stage after transvoxel (the code of the algorithm is already quite complicated). But I'm unsure how well that would look like, because you'd have to turn off interpolation otherwise those IDs would vary between all values in pixels between vertices (transvoxel shares vertices instead of creating new ones in every cell).

Solutions with blending are more complicated and expensive. The 16 textures is already doubling the cost of meshing, and on top of that, it has situations where it just can't render all textures at once, because it can only pick the 4 most used ones in a 2x2x2 cell, so some of them will necessarily get thrown away. Adding more possible textures makes sorting even more expensive, and requires changing voxel format (and all the functions allowing you to edit them). In theory it can go up to 256 before requiring the doubling in size of vertex data (which is already quite fat). But I believe it would become too slow to mesh at this point.

Other ideas involve having some sort of palette per chunk, so the 16-texture limit would be per chunk and not per terrain, but I'm unsure how to do that properly because of course chunks share vertices with neighbors, and that also touches a lot more parts of the engine just to carry over this extra data. Or the subset would have to be recomputed on everey meshing. Also it sounds like it would not suit you because of course you could expect to place up to 4096 different voxels in a given chunk, which can always exceed 16. On top of this, LOD comes into play to make this even more complicated, because then how do you render a voxel from far away that actually represents a cluster of a hundred of chunks? So many IDs to sort from...

So currently, maybe only the first idea doesnt sound too hard to experiment, but for now it's unlikely to see more, I dont have time to work on this at the moment.

Oh-Nothing commented 11 months ago

Apologies for the late reply, but thanks for the detailed response!