Aloft Dev Log 5: Revenge of the Finite Element Method
So I'm afraid I don't have a huge amount to report this week - I made a little progress the week before on the finite element simulation/destruction method I am using for rigid bodies (such are the girders that support larger airships) and I am getting pretty close to this being done, but I had the flu last week and as a result made no more progress. Here's a little gif preview of the me mistreating a girder, demonstrating elastic and mechanical failure - ignore for the moment that it is a bit "floppy", I still need to tune the material strength:
So for this week I'll finish the run down I started previously of the Finite Element Method gas simulation system. Last time I described the broader systems that support it - the data grids which contain information about each gas "element" in the simulation, and which are used to calculate essential things like the shape of the total gas area and enable a force feedback between the conventionally simulated "skin" nodes and the FEM gas sim.
The real core of the simulation happens in one of these grids, which I call the atmosphere grid. It is very simple, with each 2D grid space representing a 2x2 meter area of the game world (you'll notice I previously said 4 meters, but it is actually fully configurable). Each cell in this grid simply contains a value for the number of moles (a scientific unit for the amount) of simulated gas, in this case Hydrogen, which are currently in that grid square.
The above image shows a deliberately coarse atmospheric grid, each grid square displaying its mole value. This may seem extremely simple, but is is actually almost everything we need to simulate the behaviour of that gas under expected conditions using the Ideal Gas Law.
To do that simulation, we iterate through each populated node in that gas grid once every game frame (about 1/30 of a second). When processing an individual cell, the first thing we do is make a list of every cell that neighbours it, in both straight and diagonal directions; that gives us 9 in total. We then discard any neighbours that are invalid e.g. those outside of the gas bag skin.
According to Ideal Gas Law, a gas will always try to diffuse from areas of high pressure to areas of low pressure. We already know exactly what pressure our gas is at, as we know how much of it is in the cell (in moles) and we know what the volume of a cell is. We then also calculate the pressure in the same way for the neighbouring cells, giving us the difference in pressure between our own cell and each neighbour. We then calculate, for each neighbour, the amount of gas this pressure difference represents and that gives us how much gas (in moles) moves between the current cell and the neighbour being considered - this is done using the following form of the Ideal Gas Law:
m = PV\RT
m is the number of moles of gas
P is the pressure of the gas
V is the volume of the gas
R is the ideal gas constant
T is the temperature of the gas
If the value resulting from this is positive then the gas generally moves from our currently considered cell into our neighbour, if its is negative then gas flows the other direction. The basics are really quite that simple.
There are some caveats though, which I'll cover here. It is super important to randomise the order in which the cells and the neighbouring cells are considered for this diffusion; if you do not you introduce a static "grain" to your gas grid along which the gas prefers to flow. To combat this I have a list that stores the ID of every gas cell in random order; I use this list to go through each cell, and re-randomise the order of the list each frame - thus averaging out any directional effects.
You may also notice above the Ideal Gas Law requires a temperature, which I haven't mentioned. This temperature is currently set to sensible static value, which is fine, but it misses some important effects in airship flight to do with thermal heating of the gas in the airship (it expands, be careful!) - fortunately the calculations for this are even easier than the gas diffusion, so it's no problem to add later. Similarly I also need to add some simulation of gas momentum, but this is less pressing and also fairly straight forward.
There is one final piece of the puzzle, which is how the gas cells interact with the physically based skin. I covered this a bit in the previous post, but what happens is each gas cell at the border of the envelope gets assigned to the closest skin node (red dots on the skin in the pictures) - the pressure we calculated for that gas cell is then applied to that skin node as a force, and if it is large enough it will push the node away; if that happens with enough force then the skin will move far enough to include a new, empty, gas grid square in the envelope - when this happens the gas from the previous edge nodes rushes into the empty node, thus reducing the average pressure. At the same time, an opposite force is exerted back on the skin nodes by a simulated "atmospheric pressure" from outside the gas envelope. These competing pressures eventually lead the system to stabilise at 1 bar of atmospheric pressure, which is precisely correct (the first time that happened was a real Eureka moment).
Phew, and that was a lot of words again! I hope that was interesting to some of the more technically minded among you, and hopefully the next update I should have some of the concept art that is currently being worked on ready to show.