Calculating buoyancy force

I am trying to simulate a buoyancy force for objects submerged/suspended in a fluid in a 2D environment.

According to Game Physics: Engine Development: How to Build a Robust Commercial-Grade Physics Engine for Your Game by Ian Millington (Chapter 6, page 99) (ISBN 987-0-12-381976-5) AND the wikipedia article on buoyancy the actual calculation is: PVG where P is the density of the fluid. V is the submerged volume (area) and G is the gravitational acceleration (0.00980665 Kilo-Newtons for Earth, but is variable in the code) and always acts in the opposite direction to gravity.

The code I have, below, produces a clean-looking result, but obviously the density of either the object in question or the fluid is not effecting the calculation, only the mass. If I insert the density of the fluid, say, water, at 1000.0 kg/m^3 the whole system explodes.

Is it something simple that I missed or did I screw up entirely?

The code I have so far:

//area_ratio is a scalar ratio of the area inside the defined fluid area (Volume submerged) and the entire object's bounding area (entire volume).
//area_ratio is equal to a value in the interval [0.0, 1.0]
//gravity is a force vector in Kilo-Newtons.
Vector2D current_weight(mass * area_ratio * gravity);

//current_area = The area inside the fluid. (Volume submerged)
Vector2D buoyancy(gravity.Normalize() * -current_weight * current_area);

//Forces and Impulses are automatically converted to Netwons by multiplying the values passed in by 1000.0
object->ApplyImpulse(buoyancy);

• In case anyone is interested, you can use the "Look Inside" feature to see page 99 on Amazon – MichaelHouse May 7 '13 at 20:44
• @Byte56 I can't see page 99 for some reason... only pages 1-20 and 505 onwards. – jrsala May 7 '13 at 21:25
• I searched for "buoyancy" and found the formula mentioned. – MichaelHouse May 7 '13 at 21:30
• Regarding what you said: "G is the gravitational acceleration (0.00980665 Kilo-Newtons for Earth..." An acceleration is in meters per second, not newtons or kilo-newtons. It's not a force. It's a parameter for a force (the weight) which depends on the mass of the object in question. – jrsala May 7 '13 at 21:42

Here's the correct code :

Vector2D weight(mass * gravity);
Vector2D buoyancy(immersedArea * fluidDensity * -gravity);
Vector2D totalForces(weight + buoyancy);

object->applyImpulse(totalForces);


In your code, you calculate mass * area_ratio * gravity but the weight does not depend on the immersed volume (area_ratio).

I think you misunderstood the law of physic you mentioned. I don't quite see what you were trying to do with

gravity.Normalize() * -current_weight * current_area


but the buoyancy of the object is simply the opposite of the weight of the volume of fluid it displaces. Therefore, it's equal to the displaced volume times the density of the fluid, times gravity, times -1. Note that the density of the object and that of the fluid are different in most cases so you can't reuse current_weight, as the buoyancy has nothing to do with the weight of the object. Also, multiplying by current_area will yield Newtons multiplied by squared meters, but we want Newtons! That's where you may have wanted to use area_ratio (assuming the rest was correct in the first place).

Finally, you must apply an impulse equal to the total of the forces, not just the buoyancy! So, weight + buoyancy!!

As a side remark, I suggest you always work with newtons (and standard units in general) unless your use of kilo newtons is justified. That way, you and whoever uses your code will have less needless thinking to do. Also, no more conversion to make in your constructor for Vector2D.

• I'm no expert, but is applying an impulse the right thing to do? An impulse is an instantaneous change in velocity, used for discontinuous rigid body collision response. Wouldn't applying forces be proper/better? – DaleyPaley May 7 '13 at 22:37
• Well, to be honest, I supposed when answering that his "ApplyImpulse" function meant adding F/m*dt to the current known speed (where F is the total applied force, m the mass and dt the timestep). Hopefully that's what it is, or else it's no wonder the system diverges... – jrsala May 7 '13 at 23:14
• To your comment, yes, that's what I'm doing. To your question, it was an attempt to apply a force directly opposite to gravity. ie. Normalize it to get its direction, then multiply by -1.0 or in this case -1.0 * current_weight * current_area I just simplified the calculation by changing one of the values to negative. – Casey May 7 '13 at 23:26
• @Casey Ok. What matters is that you understand the principle. Two forces apply: the weight and the buoyancy, and their sum is what appears is Newton's second law. The buoyancy is not a function of the weight of the object. Please take into account the remarks made by eBusiness as he is definitely right about 1000kg/m3 not being appropriate if you use the area. You must link the area to the volume somehow (e.g. the volume of a ball is 4/3*R times the area of the associated diametral disk), or use a density in kg/m². – jrsala May 7 '13 at 23:33

"current_weight" isn't a function of area_ratio. Weight is just the force of the mass affected by gravity, F=ma or W=mg. The boat will always have the same weight in the direction opposite gravity, but that force is counteracted by buoyancy.

http://www.engineeringtoolbox.com/mass-weight-d_589.html

Try removing area_ratio from your current_weight calculation.

Friction

You probably missed friction, in water that is a velocity dependent force working in the opposite direction of the velocity. For light voluminous objects the friction will counteract buoyancy very quickly.

Try pushing a beach-ball either a half or a whole metre under water and let go, you'd think the whole metre would give double the jump height, but the difference is almost non-existent, that is because the beach ball have almost reached terminal velocity in less than half a metre, most of the energy you spent pushing it down is lost to friction before the ball hit the surface.

Long story short, you'll have to deal with friction if you want to make a realistic simulation.

2D vs 3D

Also, you are mixing 2D and 3D, so your units don't match, you have a 3-dimensional density, so you need to multiply that by a 3-dimensional volume, in other words factor in a depth for any object or all your real world units will be for nothing.

Cheating

Finally, don't forget that you are making a game, no one will care how you did it as long as the result seem good, no object needs more than a buoyancy force and some soft speed cap to simulate friction. If I were making the game I would probably not bother with calculating buoyancy, I'd just type in a number and see if the resulting simulation behave to my satisfaction.

• How would I convert the 3d volume kg/m^3 to a 2d area kg/m^2 ? – Casey May 7 '13 at 23:22
• he said it! "factor in a depth" ! Either you keep real-world constants and you multiply (or divide, when necessary) all the areas by the same depth constant or you tweak each real-world constant individually. For instance, with a depth of 1 meter, you can keep your 1000kg/m3 constant because 1m * 1000kg/m3 = 1000kg/m². – jrsala May 7 '13 at 23:51