In this blog post, I will explain changes to the atmospheric flight model that was introduced in patch 0.1.4.0. Warning: it’s going to get long and technical, so if you don’t like talks about physics, this is your last chance to preserve your brain from a headache !
Basic flight theory
Before I go explaining what the new version does, one needs to understand how the previous version ( prior to patch 0.1.4.0 ) was working.
First of all, thrust and gravity should be pretty self-explainatory, so I won’t speak of those here. There has been no change in the atmospheric flight model for these two forces.
In atmospheric flight, the dominant force is drag. Drag is the reason why you reach a terminal velocity either when falling, or when flying at max speed in air. Drag opposes to the movement of the object. As for lift, it comes from the wing profile and difference of air pressure between under and above the wing. A good airplane maximizes lift while minimizes drag.
The old atmospheric model used two equations for drag and lift. Both are kind of similar, but let’s have a look at drag first:
- Fd is the drag force
- p is the atmospheric density ( 1,225 kg/m^3 at sea level on Earth, decreases with altitude exponentially )
- A is the wing area
- Cd is the drag coefficient ( more on that later )
- v is the speed
The most important thing to understand is that drag grows with the square of the size ( aka wing area ) and speed. When drag reaches thrust capacity, your object cannot accelerate any further and you hit terminal velocity.
The drag coefficient is a factor that determines how aerodynamic your object is. The closer to a bulky box, the higher it is. For an airplane seen from the front, Cd is minimal. That’s why planes do not behave like bricks, heh. Cd is usually found experimentally.
Lift is a very similar formula:
… except that this time it uses a lift coefficient, instead of a drag coefficient. The lift coefficient is interesting, because it changes ( for wings ) based on the angle of attack. In other words, depending on the inclination of the wing compared to the travel direction, you get different values for Cl.
Old atmospheric flight model ( 1.0 )
In the old flight model, the two equations were implemented directly. To determine the lift and drag coefficients Cd and Cl, based on the angle of attack, I used the following curves:
As you can see, those simplify the object as an airfoil. Our ships aren’t wings, they’re actually more like bricks. So, in many ways, the old atmospheric flight model was incorrect. More importantly, the overall shape of the ship in the travel directory ( the “flow vector” ) wasn’t a factor.
In order to make everything work well in the game prototype, I had to add arbitrary coefficients both in the drag and lift equations.
New atmospheric flight model ( 2 .0 )
To better determine the drag coefficient, my idea was very practical. Every single frame, cast a bunch of rays in the direction of the flow movement vector, and determine which percentage of those hit the surface of the object and at which angle. Each ray simulates air molecules hitting the object and resulting in a force that causes linear and rotational acceleration. The idea is similar to doing an integral over the flow surface.
For performance reasons, the number of rays is quite limited. I settled for a value of 25,but I experimented lower values ( 10 ) or higher ( up to 500 ). I haven’t noticed much of a difference in the quality or stability of the simulation based on the number of rays. Keep in mind those are rays per frame ( for a given flying object ), so at 100 fps, if you have a hundred objects and cast 500 rays, that’s a total of 100 * 100 * 500 = 5 million rays. This shouldn’t be a problem with 25 rays though, especially as the code can be optimized later.
The shape of the object is approximated with a bounding box. Later on we can refine the shape with a set of convex volumes if needed, but I think a box is a good first approximation of our flying bricks, err… ships.
So, what the algorithm does for each ray is to cast a ray, determine if it hits that box, and if it does, generate a feedback force along the normal of the box surface. This will naturally generate drag and lift.
To explain this better, let’s have a look at a simple scenario, in a standalone testbed app which I developped just for that purpose:
Ouch ! Lots of vectors all over the place. They’re color coded and represent the following:
- The dark blue vector ( pointing downwards outside the screen ) is the gravity vector
- the yellow vector ( pointing downwards and right outside the screen ) is the velocity vector
- The brown vectors represent flow-casts that missed the object
- The green vectors represent flow-casts that hit the object
- Finallt, the important ones: the purple/pink vectors represent the output forces acting upon the object as a result of the flow-cast
The object is obviously represented by the box ( seen from the sides ). This approximates our ship. The “front” ( nose ) is actually pointing to the right of the screen, slightly pitched downwards.
In this scenario, the ship is falling through the atmosphere and generates a good amount of drag due to it. It’s pretty close to hitting its fall terminal velocity. The simulated ship is the fighter, and weights 26 tons. Its dimensions ( the box’s ) are 12m x 4.5m x 15m.
If you pitch the ship even more so that it’s nose matches the velocity / air flow, it minimizes drag since the “profile area” is now much smaller. The terminal velocity increases to 150 m/s or even higher…
Inversely, if you counter-pitch the ship to maximize its area, like it was free-falling like a sky diver in a belly position, the terminal velocity diminishes to less than 100 m/s:
As you can see, this model seems to work out pretty well for drag. The way your object / ship is oriented changes the amount of drag, which changes the maximum speed you can reach. In this testbed, the atmospheric density is a constant, but in the game prototype it varies with altitude ( not per planet though; all planets use 1,225 kg/m3 at ground level. I’ll probably change that in a later patch to give more variety to planets ).
The most interesting part of this new model is that I was able to get ride of the arbitrary coefficients of the old model. And when I did that, I was very curious to see what results I would obtain if I simulated a sky-diving human in free-fall. According to wikipedia, a sky-diver in belly position would hit terminal velocity at around 50 m/s, 90 m/s in head-diving and up to 120 m/s with special equipment to minimize drag.
Well, I tested these 3 scenarios, and surprise surprise… without any arbitrary factors, my 90 Kg man-sized box did hit pretty close to these terminal velocities. Not bad, not bad. At least as far as linear accelerations are concerned.
One thing I still haven’t solved are torque ( rotational accelerations ). Without introducing an arbitrary factor in the equation, I found that the amount of torque is very high. In fact, it makes a sky-diving human quickly lose its stability and start to rotate in all directions. I do not know if I’m missing something in the physics or if I can simply blame it on the method ( a low amount of ray casts means every frame, the flow vectors hit the object at random positions. It’s no problem for the linear acceleration, but this randomization in the surface positions causes a random amount of torque ). For the game prototype, I had to introduce a scalar factor in the torque ( linear accelerations are left 100% realistic though ) otherwise it quickly became unplayable during re-entry, or even flying above 100 m/s in the atmospheres.
Last thing: more factors can easily be introduced into the atmospheric flight model. Such is wind, the cyan vector in the following picture:
In this scenario, the wind force blows from the back of the ship and helps flying in the direction of movement. Of course, if the wind was coming from the front of the ship, it’d slow it down a little bit. In the old atmospheric flight model 1.0, I didn’t know how to correctly generate an acceleration force out of a wind velocity, which results in awkyard behavior. In the new model, wind is simply added to the flow vector, and is naturally taken into account in the simulation. It behaves a lot better / more realistically.
Also note the big red vector on the right, slighly upwards. This is is thrust. As you can see, this scenario shows a ship flying in an atmosphere with a low amount of thrust ( 10% of what it’s capable of ). It hits maximum air speed ( drag = thrust ) at around 160 m/s. Of course, that’s only for 10% of its maximum thrust. At 100%, it can fly much, muuuch faster. Let’s see how fast exactly:
In this picture, the fighter is flying at 100% of its thrust capabilities ( according to my doc, that’d be around 5.7 g’s ). It hits maximum air speed at around 445 m/s. The view is zoomed out a bit, but as you can see, the big pink vector pointing to the left has become huge compared to the object’s size. There’s a small amount of lift too ( pointing upwards ) but it’s not enough to maintain the ship in air due to the gravity. This is probably a good example of the lack of insufficient lift, since our ships are more like bricks than wings.
Another factor that can be taken into account is the sound speed barrier ( mach 1.0 ). For the implementation details, see this forum thread:
I implemented it with constant sound speed ( around 340 m/s ), which causes the drag coefficient to rise up to x5 of its normal value. Let’s see if our ship at 100% thrust can still reach 445 m/s…
… nope, no way. At around 320 to 330 m/s, the ship becomes unable to speed up more. The mach barrier is definitely here. I’d need a lot more power / thrust to breach it. Or a lower drag coefficient. The conclusion here is that if you’re flying a brick, you really need a lot of power if you want to breach the sound limit.
Feedback & conclusion
For those of you who have tested the new atmospheric flight model in game, feel free to post your feedback.
I believe the sound barrier is a problem, as flying at 340 m/s is actually pretty slow. The good thing is that it will probably make combat better, and give a better sense of scale to the planets. The bad thing however is that it can now take forever to fly anywhere, or to escape from a planet to get into warp. 4-5 minutes is not unexpected, and is much longer than what I’d personally like to see.
It seems likely that, moving forward, we’ll re-introduce a per-ship aerodynamic coefficient which will be used as a multiplier to nerf the drag coefficient. It should allow ships to fly faster in atmospheres, and take off into warp more quickly. The downside is that it might make re-entry harder ( atmosphere will slow you down slower ) so it might get more tricky if you don’t control your entry speed.
As for lift, it is possible to introduce a new lift model, or to increase some coefficients to artificially introduce a higher amount of lift. As this point we enter the realism versus gameplay discussion. What do you think is best ? Do you want your “bricks” to have a decent amount of lift in atmospheres ? Did you like the roll-then-pitch approach of the old versions ? Let us know !