Inactive Real Liquids

Cervator

Org Co-Founder & Project Lead
Contributor
Design
Logistics
SpecOps
The main trick still is dealing with unloaded chunks - but I wonder if we could use the sort of phantom object like with a partially loaded village with large streams of water as well. Say we go with that polygon-based World Map gen, then rivers generate along polygon edges. Simply notate the full path of said river, its starting point, give it a name (ooh, immersion!), and find a way to connect water in-world with said phantom object. Since there aren't a ton of rivers and a polygon edge will translate into a relatively narrow range of blocks in the world that shouldn't be too hard.

Now the water knows it is part of a river, and if you're simulating a border chunk with said river in it you can find out that yep, it is part of river x, its source is outputting y amount of flow, so keep running.

Harder then is keeping track of changes, like rerouting a river or somehow spawning a new one. But if the river object (I want to call it a meta-object so bad, as usual..) can just notate which chunks it exists in we should be able to keep water uniquely tagged very cheaply (if only river-type water gets tracked you could probably do it with a bit or two + the parent chunk info)
 

CapsE

New Member
Seems like we found a good balance between possibility and function :)

A while ago somebody asked me if I knew any AAA-game with "real" water physics that an average PC could handle. And I have to say no... but I know an Indie game that can :) just found it


I guess this proves that there is pretty much possible today... not that we need all this features and that it would be worth putting all the developing time in them... but hey it IS possible ;)

For the problem with not loaded areas: We could tell all water elements that are next to an unloaded block to remove all water that flows directly to them. With this we wont create a water world... Problem is when a riverend is generated the water would start to rise just in the moment the end was loaded so we wouldn't have a fully calculated river before all the blocks are loaded and the water will trevel through the land just like the player wich leads to huge changes in the landscape after the player first walks there. This might not be a problem technicly but its bad for the gameplay if the player builds a house without noticing that the water in the small lake rises and rises...
 

Skaldarnar

Development Lead
Contributor
Art
World
SpecOps
I've seen that some time before :) But its not really an Indie game I think (published by Ubisoft). For the Germans around her - a little test video from GameStar magazine: test video
 

Cervator

Org Co-Founder & Project Lead
Contributor
Design
Logistics
SpecOps
I'm not sure I would really call Ubisoft "indie" but yes, From Dust has some impressive effects - and probably about half that game was to showcase the liquid dynamics :D

"Vessel" is a nice indie game also focused around liquid dynamics

Key is, those games base themselves on stuff like fancy liquid dynamics. For us we base on a procedurally generated world and liquid is just one part of it that has to play nice with the main parts of the game. And there's the kicker - blocky (or even non-blocky!) voxels in a hugely expansive world with realistic liquid simulation? Aiieee!

None the less, I think we can find a happy balance :D
 

Immortius

Lead Software Architect
Contributor
Architecture
GUI
From Dust certainly isn't a AAA title. Maybe AA or A. I have played it through, nice little game.

From Dust is height-map based though, which simplifies things. It also deals with a strictly finite play area - if we similarly has a finite map I'ld be much more comfortable with saying that we could do increased liquid dynamics. But we have to balance it with an infinite map, loading and unloading of chunks, every other simulation, AI, etc.

One thing we could do to improve performance though - at the moment a change to a liquid requires rebuilding the entire mesh chunk - or chunks. But water actually use a separate chunk to other blocks, so we could just rebuild that in certain cases. The main issue there is that water causes sunlight to degrade, and that lighting wouldn't be updated, but may still be worth it. Structuring the chunk mesh so that lighting can be updated without rebuilding the entire mesh is another option.
 

Aperion

New Member
Contributor
well !@#!@#!@ I had a large reply written out now I lost it :( this is about 3x shorter, and thus probably easier to digest :)

Basically why not adopt a system similar to Dwarf fortress? Rivers have sources and sinks, when you load a chunk the the edge of the chunk that comes from upstream is an infinite source, all other water is finite. and all other edges are sinks. as the player gets close the new chunk edges are infinite water and the previously infinite water is now finite. When the source of the river is loaded the river is fed with water from the ground aka aquifers :)

BTWI found this to be an interesting read once upon a time: http://algorithmicbotany.org/papers/mountains.gi93.pdf
 

Cervator

Org Co-Founder & Project Lead
Contributor
Design
Logistics
SpecOps
Nice paper! I like how squiggly those rivers become.

It would be easy if we had a finite small map like in DF where there's a distinct entry and exit for a river, then yeah infinite source and sink would work. But with multiplayer, the possibilities for changing the terrain, and chunk load/unloads? We'd have to maintain the "integrity" of the river really well, and there might be edge cases that would be hard to address? Although with the whole treating rivers like meta objects and other water differently ...
 

Aperion

New Member
Contributor
Nice paper! I like how squiggly those rivers become.

It would be easy if we had a finite small map like in DF where there's a distinct entry and exit for a river, then yeah infinite source and sink would work. But with multiplayer, the possibilities for changing the terrain, and chunk load/unloads? We'd have to maintain the "integrity" of the river really well, and there might be edge cases that would be hard to address? Although with the whole treating rivers like meta objects and other water differently ...
Doesn't DF supports that as well,think adventure mode. I'll have to make a small world with lots of streams then build a fort that messes with water to see the effect on the world when playing Adventure mode.
 

Cervator

Org Co-Founder & Project Lead
Contributor
Design
Logistics
SpecOps
I've never actually played adventure mode - fortress mode is too tempting :oops:
 

Yokmp

New Member
As far as i understand, an infinite river flows into an finite sea (seems logic to me btw ^^). So you need a sink in the sea equal to the amount of water comin from the river? Then the river must be switch to "infinite mode" when the sea is unloaded or doesn't even exist. Its maybe possible to use just some switches to accomplish that. I've read about a path system for NPCs anywhere on the forums (can't find it atm.) So you just have to create these two pathes, then create a riverbed along the path and end it in the sea. At the start of the path should be the mystical waterblock-source-thingy. The water fills the riverbed by using its 'physics'. At the end of the path will be the sink. Done ^^

With 'real' flowing water its maybe possible to create some kind of flowing rate for it. So the player must use different materials to build in it (let's say you can't use sand to build a bridge or a dam, you have to use planks or stone ...).
 

Cervator

Org Co-Founder & Project Lead
Contributor
Design
Logistics
SpecOps
Yeah we might want to go for having some sort of "meta object" storing information about a river segment (inflow + outflow, perhaps even a name for maps), then if the actual water flow hits an unloaded chunk it can check the river info to get flow stats. Probably more useful at the starting end - without the very first chunk loaded, wherever the first chunk is loaded just simulate using the appropriate flow value for the river at that point.

Say a player redirects a river mid-stream. Unloaded chunks further down the original path still think there should be water, but when they load they check the expected flow value, find it gone, then dissipate. The new river inherits the metadata of the original, simulate flow till it runs out of loaded chunks, then waits till those load or use some sort of light-weight simulation to find out what chunks it'll impact. By using prediction you could avoid having a situation where a second player way down the direction of the new river segment sees no water because some intermediate chunks haven't loaded (out of range of both players)

I think we have plenty of solid design at this point, we just need somebody to start implementing :)
 

Cervator

Org Co-Founder & Project Lead
Contributor
Design
Logistics
SpecOps
Alright, thought I'd expand on the concept a bit more and include some related topics :)

Say we introduce river entities to a redesigned liquid flow system. Not quite sure that's entirely the right way to do it, but easier to think about. We have a RiverComponent that stores a given name for a river as well as the strength and exact location of its source (might need more details later if we get fancy with the hydrological cycle). We also give it a list of chunks it exists in (using a LinkedList seems like it would have potential?)

The related chunk summary data concept as discussed in the height limit thread might come in handy here, as you could note there how many/which rivers exist per chunk. As the river is born it creates a source tile and starts simulating outflow from that source using its strength. If the water crosses a chunk barrier that chunk is added to the river's list of chunks, and the chunk's river counter is incremented by one. As long as there's only one body of water in that chunk we can assume all the water there belongs to the river. If a second body of water is added we do some magic.

If a player simple drops a bucket of water on the ground and the engine detects there are now two separate bodies of water it could generate an entity for the chunk with a simple list of what block position belong to what source of water (what entity). That way we prevent acting on "flow" in disconnected pools and such. Or maybe one entity per body of water (with a WaterComponent?) that is linked to the river entity if appropriate.

If the player (or terrain) instead causes the river to fork, we detect that and generate a new River entity with its source being its branching point from the parent river, which inherits the appropriate amount of flow from the parent and in return adds a sink to drain the parent's flow accordingly.

On the other hand if a river enters a chunk that holds an existing river and then joins it we end whichever River entity has the weaker flow (sink its entire flow into the more powerful river, or maybe the older river if it happens post-world gen) then re-simulate the added flow on the remaining river segment going wherever. Maps with accurate river names that can change over time, gasp! On the technical side of things you'd probably use ES events here to communicate between the entities to find out how a river splits or is merged, or how a new body of water inserted into the world reacts.

Similar flow mechanics could probably be used to simulate aquifers, just held under pressure until released somehow. Not totally sure how my crazy block dynamics and per-block pressure counters would factor into that

Chunks holding what we define as ocean (at world gen time) consider its ocean body of water (you could still have disconnected bodies of water in the same chunk) as having infinite sink ability so any inflow terminates there. However, if due to player intervention something causes an ocean body to outflow (don't mine through the ceiling under an ocean!) then we create a river object with outflow set to the size of the breach. In some cases we might want a new body of water that gets large enough (think a whole valley below sea level but a fair distance from the ocean) connected with a narrow enough river to the higher ocean like that to start simulating outflow that goes nowhere (evaporation and sinking into soil) so you end up with a balance where the inflow equals outflow without the two bodies of water necessarily being at the same level. Heck, you could end up with a subterranean cave ocean that itself could be a near infinite sink for underground rivers.

Simulating rivers into areas where chunks aren't loaded could use the height map of the world (a naive approach, more detail later) to figure out which chunks it should hit without having to load the chunks at all, just adding to their summary data / water body counter. If the chunks haven't previously generated then on generation the presence of water could be considered (avoid putting a walled goblin compound in the way if you've decided there's a river going through it - or place it next to the river, goofy!). There might be a bit of a disconnect here between since-dawn-of-time major rivers (that should probably belong to world gen phase) vs local rivers and player-caused events (that are based on more accurate simulations).

A big problem with using a height map is that you only have one surface - that also came up in the height limit thread (or a world gen thread?). Rather than working with a magic surface (or two, like a separate but equal skyworld) we probably should look into intelligently working out what is a surface local to a large amount of chunks (a mini height map specific to a layer of chunks that may go up or down? Chunk metadata?). That could then also be used for displaying a minimap, assigning region names, doing lighting calculations, running growth simulation, and calculating pre-emptive water generation. Although for water that's easier to imagine if you already generated the caves, not sure exactly when we'd do that in a world with stacked chunks.

Okay, I'm done for now. Back to work!

Edit: Come to think of it, you could probably use the pressure system in parallel to the liquid simulation. Pressure in blocks (think aquifer) or special bodies of liquid (think magma chamber) could be the sources for starting flow for a river simulation. Mmm, lava rivers.
 

Wernesgruner

New Member
If a player simple drops a bucket of water on the ground and the engine detects there are now two separate bodies of water it could generate an entity for the chunk with a simple list of what block position belong to what source of water (what entity). That way we prevent acting on "flow" in disconnected pools and such. Or maybe one entity per body of water (with a WaterComponent?) that is linked to the river entity if appropriate.
I don't think that's the right way to do it. I mean, from what I've experimented, the engines doesn't need to be aware of anything that doesn't come from an infinite source at some point.

I know its probably more of design preference , but I think its always better to go for short simulation instead of constant scanning/event listening when it comes to occasional events (For instance break the lid of a pond/lake on top of a mountain).


On the technical side of things you'd probably use ES events here to communicate between the entities to find out how a river splits or is merged, or how a new body of water inserted into the world reacts.
I like that approach.

All in all I think we are starting to have a pretty good idea of how we should theoricaly implement proper water systems and I think its time to start at the practical ramification and adjust our design as we implement new features.
 

Cervator

Org Co-Founder & Project Lead
Contributor
Design
Logistics
SpecOps
I don't think that's the right way to do it. I mean, from what I've experimented, the engines doesn't need to be aware of anything that doesn't come from an infinite source at some point.
I'm not at all sure on that, so more ideas are great. I was thinking about basic water propagation and how the engine would know how to tell apart "powered" water and basic "boring" water

Player dumps a bucket of water on the floor = engine sees "boring" water and just lets it splash out to whatever extent it can reach before it slowly soaks into the ground (the placed block dissipates)

Aquifer near the surface with solid blocks holding water pressure escapes as a block is removed = engine knows to perpetuate the water source - but how, on a block-to-block basis?

Right now we have a nibble (half-byte) that tracks how far from a source block water should flow (to not flood the world), but water isn't "moved" from a source at all. If you have an exposed aquifer you need to be moving a volume of water and simulate how that flows over the landscape.

Now, until whatever river that ends up as actually is impacted by external forces, no, you don't need to re-simulate from start to finish every frame. But I'm not sure how the per-block details work out to get you there in the first place, or re-simulate when something changes. I've only thought of it at the chunk level so far, along with prediction of rivers without even loading chunks

When you get into something like that I wonder if you'd need to know the source of any body of water (which could be one block or multiple) in a chunk. And maybe the direction, were we to animate river water (without every block going down a level - that could infer direction)
 

Double_A

Member
Contributor
Art
Hi,

I don't think I understand much about those things... But I still tried to figure something out. ^^

Each liquid block could have a volume value (e.g. 0-1), and 5 flow direction (down, front, back, left, right) with a volume stream value for each direction.

Then depending on what is around that liquid block (air, earth, other liquids) the stream values should change, and update the volume of all regarding blocks.

To solve the unloaded chucks problem, I thought that every liquid block at the border of the loaded region should have a constant volume. that should prevent unwanted drains.

Also Oceans blocks should have a constant volume.

I hope that I didn't just write nonsense :confused: and that maybe you can do something with it.
Thanks
 

ahoehma

New Member
Contributor
I think at the end the liquid simulator is like the organic growth simulation, some "structures" moving or growing or shrinking. For my liking its good to separate the voxel information from the structural entity information. It would be nice to have a separated data handling and only for interaction the voxel world should read/changed. Is the current entity system ready to manage "entity-networks"?
 

Cervator

Org Co-Founder & Project Lead
Contributor
Design
Logistics
SpecOps
I'm not sure if we truly need entity networks as much as a single entity (a "river") that is aware of what locations it affects. Those locations then have the primitive block data needed for simulating. Dunno if that's the most efficient way, we need to see some code and benchmarks already :D
 
Top