Zylann / godot_voxel

Voxel module for Godot Engine
MIT License
2.64k stars 249 forks source link

Adding non-flowing water (or other liquids) #608

Closed AimiIsFat closed 7 months ago

AimiIsFat commented 7 months ago

So I likely won't be adding this to my game for at least a month, but I've been wondering how you would make water. This is fairly important to me because I'm making an open world survival game with editable terrain and one of the most important things in many open world survival games is water, whether it's for drinking or just making a nice ocean area of the map.

Problem is, you can't just make water a part of the same terrain as grass, at least not with smooth terrain, or else I assume you'll be able to see through the terrain and walk on top of the water. I also understand the difficulties with flowing water. If I add that then it'll likely be a very long time later, but it doesn't bother me too much to have water that just sort of floats around even if you break the terrain under it. Much better than having no water at all.

Currently, my idea is to have two VoxelTerrains: one main VoxelTerrain and one liquid VoxelTerrain. The main VoxelTerrain will generate empty rivers, as well as any terrain below a certain height considered ocean, while the liquid VoxelTerrain will generate terrain inside rivers and oceans, and also round up to a full voxel every time so there aren't tiny air pockets where the water and land meet. However, the issue here is that it's generating the world twice, once on each terrain. I'm worried this will be bad for performance. Is there any better way to do this or should I just accept that this is the cost of adding water?

Zylann commented 7 months ago

I have no plans regarding this. In my own projects using smooth voxels, I just thought of doing what No Man's Sky does: just have a water plane separate from voxel terrain, eventually chunked if waving details are needed at close range. That's very cheap. Eventually it could be height-based as its own system. Any other solution sounds like a lot of work full of edge cases and constraints.

If you need water to be voxel based so badly, one way of doing it could be to have a custom mesher that runs transvoxel, and then runs a second mesher (which could also be transvoxel, or something more specialized) that looks into a different channel (storing "liquid" SDF separately from the "solid" SDF, or using straight cubic voxels) producing the "bodies" of water, and combines results in the output mesh as a separate surface. But in order to do this, you will have to write it in a C++ module, maybe even modify the module a little. This would bring you the same results you'd get with two terrains, minus the overhead of having two terrains. Of course that also increases memory usage due to having to store water bodies as voxels. And you still have to set these voxels properly, which can be its own challenge.

Other options include 2D flood-fill to detect edges of lakes, given a point in space and horizontal lookups, producing water planes. Easy for small lakes, But it gets complicated if what you thought was a "lake" actually has openings below it (cuz it's voxel terrain, you have to control whether overhangs occur). Also larger bodies would have to handle chunking and very large oceans that might not even fit in the loaded area. It might be easier if you manually author your world, but not if you procedurally generate it.

AimiIsFat commented 7 months ago

I do plan for water to be editable, sort of like a smooth terrain Minecraft minus the flowing of the water, so most likely I will need it to be voxel-based. There will also be swimming and caves which is why it needs more advanced 3D hit detection rather than using a simple plane.

Most likely I'll probably just try to optimize the terrain generator some more and then just go with the two generators idea. It is a fairly simple generator and render distance is pretty low so it shouldn't be too big of an issue. The game is mainly for middle to high end computers, and seems to run very well already, especially when it comes to terrain generation, so I believe it'll be fine.

Anyways, since there isn't much more to say here, I'll close the issue. I may reopen it in the future if I run into any issues when I finally implement it.