Notes on buoyancy
Buoyancy notes by Julio from the forums :
Note: Bouyancy on sphere is not working but it will be corrected with the new SDK (1.35).
A clarification may be useful. The buoyancy is based on the Archimedes principle with state: The force asserted over body immersed in a fluid is equal to the weight of the fluid displaced by the body and point of the direction opposite to the gravity.
Which this means is that to calculate the force that the fluid apply to the body we must determine the volume of the part of the body immerse in the fluid. For that we ask the application to specify the average plane of the surface of the body at the body origin.
Then part of the volume below the plane is the volume of the displaced liquid. To get the mass of the liquid we used the formula
1) liquidMass = liquidDensity * bodyVolume
Now to get this to work properly you need to do some proper calibration of the density and the mass.
Say for example you have a test box. With dimension a * a * a Say the box has mass of m (Note that units are irrelevant)
Say you want to set your values such that when the body is in water is like a submarine completely immersed but at equilibrium. If this is truth the following condition will hold:
BodyMass = liquidMass = liquidDensity * BodyVolume
liquidDensity = BodyMass / BodyVolume;
This is the density for your liquid.
Now let see what happens if you change the liquid density around that base value and keeping everything else fixed.
First making the density larger: say two times denser, obviously the body should float but let's find out. Using formula one if the body is fully immersed we get:
liquidMass = 2.0 * liquidDensity * bodyVolume
A mass twice as heavy, so when this mass is multiplied by the gravity you get a force twice the weight of the test body pointing in the opposite direction of the gravity. The body will move up. But each time less and less part of the body will be under the liquid until the part under the liquid exactly matches the weight of the body. Similarly should happen if you make the density lower.
The first case is not a realistic situation, after all when you have objects immersed in water the water density does not change too much (make that no change) depending on the object that is in it. A more practical example will be having two different bodies in the liquid.
Say now you add a body that is only half the mass of the test case. Again using formula 1, when the body is fully immersed you get
liquidMass = liquidDensity * bodyVolume
A mass equal to the test body, but the body is only half the weight, so also a next force point up will result.
The moral is that to get good result you need to do a proper calibration, the units involved in the calculation are irrelevant.
After you do you calibration you will find that to get realistic result the bodies masses will have to be very different from body to body, for example:
Say the test body have dimensions a x a x a and mass m Say you have another body that is 4 times bigger made out of the same material. You will find that for this body to react the same way as the test body you will have to set the mass to: using formula 1
liquidMass = newBodyMass = liquidDensity * newBodyVlume = liquidDensity * 4a x 4a x 4a
newBodyMass = 64 testBodyMass !!!!
However rigid body simulators do not like big masses ratios, so there is a dilemma here. You want the objects in water react realistically, and you want to keep the physics engine happy.
Fortunately there is a solution (after all it is virtual world)
This is what to do (remember you do this after you calibrate the density for a test body, and is working satisfactory for similar size, similar masses bodies) The objective now is to weigh the fluid density relative to the base values is such a way it produced the same realistic result. Explanation:
Say the mass of the large body is K times the mass of the test body instead of the 64 time required for realistic buoyancy behavior. How do you modify the density to accomplish this? The answer is you do not. You leave the fluid density alone and you store a weight factor with the rigid body. For that you write a formula:
fluidDensity = baseDensity * weighFactor
Where the base density is stored with the fluid volume and the weight is stored with the rigid body
Now if we substitute this new formula into equation 1 we get
2) liquidMass = basefluidDensity * weighFactor * bodyVolume
Now in this new formula we want to know what weight value you need to store with the rigid body such that I behave like the test body when is fully immerse.
So you get: weighFactor = liquidMass / (basefluidDensity * bodyVolume)
liquidMass = K * testMass = K * testVolume * basefluidDensity
Then you get the relation
weighFactor = K * testVolume * basefluidDensity / (basefluidDensity * bodyVolume)
weighFactor = K * testVolume / bodyVolume
Now is the call back instead of passing the fluid density of the liquid, you return the fluid density multiply by the weigh factor stored with the rigid body.
Going back to the example with the body 3 times the mass of the test body but is 64 time bigger, we get:
liquidMass = basefluidDensity * weighFactor * bodyVolume liquidMass = basefluidDensity * (3/64) * 64 testVolume liquidMass = basefluidDensity * 3 * testVolume = 3 * testMass
Now the fluid will apply a force equal to the testBody weight and the body is 3 times that weight. And the body stays in equilibrium, which is realistic
If you do not weight the value you would have
liquidMass = basefluidDensity * bodyVolume liquidMass = basefluidDensity * 64 * testVolume = 64 * testMass
and the body only weighs 3 times as much, so the next force will be 61 times the weight pointing up, which is unrealistic.