
I'm just about finished with floating objects using Novodex so I figured I'd share what I came up with.
The buoyant force on an object in a fluid, according to Archimedes' Principle, is
F = M * G, where
M is the mass of liquid displaced by the object and
G is the acceleration due to gravity. To simulate buoyancy then, we need to figure out how much water the floating object displaces at any given time. For this we take our model (of a marshmallow peep) and "voxelize" it, generating sample points throughout the peep.

Each point is assigned a fraction of the peep's total volume, and when under water, each point receives a fraction of the buoyant force. Gravity is constantly pulling the peep under water and the peep floats when the buoyant forces from the submerged sample points cancel out the gravitational force. The mass of the water displaced is found by taking the volume of dispacement times the density of water (1 gram per cubic centimeter). That times the negative gravity vector gives us the buoyant force at any given sample point.

Sounds simple and straight-forward, and it works great with enough sample points and a high framerate. Problems arise, however, when realtime physics simulation rears it's ghetto head. The biggest problem I had to battle was framerate. If the simulation framerate is too low, in one frame the peep can be given enough force to toss it straight out of the water. Once entirely out of the water in the next frame, the peep now has no submerged sample points, and gravity will pull it deep under water once again, and the cycle repeats. This causes the peep to jump up and down in the water, sometimes several feet into the air!
To account for this sort of crap (which shows up all over the place in physics simulation), Novodex uses a constant time-step. In a given frame, Novodex calls it's solver function a variable number of times. If a frame lasts 0.1 seconds and the time-step is set to 60 Hertz, the solver is run 6 times. This allows for more consistent, framerate independent results.
Again, sounds great in theory, but there are still issues with our water. Ideally, you would want to check for the number of submerged points and apply the appropriate buoyant forces at every time-step. The Novodex trigger callback will
tell you all about the submerged points, but will not let you apply any forces between time-steps. Apparently there are some threading issues internal to Novodex that prevent you from changing the state of the physics simulation in any callback or between time-steps.
Someone on the Novodex forums promised a special way to create force fields in a future release which will hopefully resolve all these problems. Meanwhile you have to find a hacky stabilizing solution. The biggest fix which gets you 90% of the way there is fluid friction; there is lots of it in water. It's not even a hack really, I just forgot about it at first, and without it, things would indeed bounce in and out of water. I didn't even bother to figure out the frictional force based on water density and peep surface area, I just hacked it with the linear and angular damping constants in Novodex. It took so much tweaking to get things to stablize, I wasn't going to sweat physical accuracy. I based the amount of damping on the number of submerged points. I increased the damping logarithmically so the amount of damping climbed rapidly even with a few points in the water, this just seemed to give better results.
Even with fluid friction, there is a lot of room for the peep to jump up and down on the surface, especially with a low density at low framerates (~10 fps things got really bad). I tried several things: clamping the velocity of the peep when partially submerged works really well. But when the peep is released from deep under water, there is a noticeable sluggish jerk as it breaks the surface and it's movement gets clamped.
I ended up with the following hack: given the sample point position
P, the point-velocity
V at point
P, length of the frame
dT, some constant
C>1, the buoyant force
F, and some multiplier
0<m<1,
if( P + V * dT * C is above water level ) F = F * M. This tries to predict if the current velocity will shoot the sample point out of the water within the next frame. If so, scale down the buoyant force applied at the point severely. I added the
C and
M constants in there so I could tweak the equation. I found
C=2.5, M=0.1 to be good values.
And the results? Good enough for me. Things still wobble a bit more at lower framerates but it looks like the wind is picking up, no more trampolining peeps though! I'm still testing other ideas (I also want to take force into consideration in the hack equation) and I have to test more shapes than just the marshmallow peep, but this seems like a good enough solution for now.