Issues simulating buoyancy with forces

PgrAm
Posts: 12
Joined: Sun Apr 15, 2012 3:34 pm

Issues simulating buoyancy with forces

Post by PgrAm »

So I'm trying to simulate buoyancy (and drag) by calculating and applying it's force every step. But I'm having some issues, I seem to be getting things exploding and bouncing everywhere when they hit the water (fluid_box in the code below). I'm approximating the displaced fluid using the AABB intersection between the fluid volume and the floating rigidbody. I seem to get better results when I either massively increase the mass of the object beyond realistic values or massively decrease the water density below realistic values. Can anyone see an issue with my approach or my calculations?

Code: Select all

btAABB box1{}, intersect{};
rigid_body->getAabb(box1.m_min, box1.m_max);
fluid_box.find_intersection(box1, intersect);

auto velocity = rigid_body->getLinearVelocity();

if (velocity.length() > 0.0f)
	velocity = velocity.normalized() * (velocity.length() * velocity.length());

auto dimensions = intersect.m_max - intersect.m_min;

auto volume = dimensions.x() * dimensions.y() * dimensions.z();
auto area = dimensions.x() * dimensions.z();

if (volume > 0.0f && area > 0.0f)
{
	const float density = 1000.0f; 	// density of water in kg/m^3
	const float drag_c = 1.05f; 	// drag coefficient of a box	

	auto drag = 0.5f * density * -velocity * drag_c * area;

	auto buoyancy = volume * density * -rigid_body->getGravity();

	rigid_body->applyCentralForce(buoyancy);
	rigid_body->applyCentralForce(drag);
}
User avatar
drleviathan
Posts: 849
Joined: Tue Sep 30, 2014 6:03 pm
Location: San Francisco

Re: Issues simulating buoyancy with forces

Post by drleviathan »

You're using the AABB of the Box for the buoyancy intersection. The AABB of a Box is much larger than the Box itself. It is the bounding box around sphere that contains the Box no matter its orientation. In other words... when the Box tumbles arbitrarily it will always be inside its bounding sphere... the AABB is the box around that. When using the AABB you will get buoyancy forces even when the Box and the water don't actually overlap.

More complex math is required to compute the correct intersection volume between two boxes of arbitrary orientations. The find_insersection(btAABB, btAABB) method does not do what you want here because it assumes the boxes are axis-aligned (e.g. it accepts arguments of type btAABB). The math for arbitrary Box overlap is complicated enough that people usually resort to approximate methods such as using multiple proxy spheres distributed throughout the floating objects body and applying non-centralized partial forces at their locations instead of one big force at the Box's center. This allows for non-zero torques to be applied to the floating object which makes for more interesting "boat wobble" behavior, especially when the water surface is dynamic.
PgrAm
Posts: 12
Joined: Sun Apr 15, 2012 3:34 pm

Re: Issues simulating buoyancy with forces

Post by PgrAm »

Yeah I thought the AABB approximation might have too much error so I tried it with a sphere instead, using the volume of the sphere cap cut off by the water plane. I'm gonna double check my math on that once I get a chance but it's also presenting the same issue. Things are very unstable, so i suspect the volume calculation is not the only problem. As for the torque and all that, I figure I'll make that to work once I get the basics working.
User avatar
drleviathan
Posts: 849
Joined: Tue Sep 30, 2014 6:03 pm
Location: San Francisco

Re: Issues simulating buoyancy with forces

Post by drleviathan »

I believe the general treatment for drag approximations is more of an infinite series:

drag_force = c0 * speed^0 + c1 * speed^1 + c2 * speed^2 + ...

and the empirical exercise is to measure what are the proper values for the various coefficients: c0, c1, c2, ...

Your calculation of drag has c0 and c1 both equal to zero: you only keep c2. Of course c0 is zero but c1 should not be. Note: c2 dominates only when the velocity gets high enough --> at slow speeds the c1 term should be stronger. The measurement of those coefficients are typically done in a steady state experiment where the object is put into a wind tunnel and the force + wind_velocity curve data is given a polynomial fit. In short: I believe the coefficient you are using (dunno where you got it) might not be the best value to use for a more dynamic interaction. My advice would be:

(0) try the system with zero drag: the floating object won't bounce on water forever because Bullet already has a non-zero damping effect enabled by default (unless you've explicitly disabled Bullet's default damping)

(1) add a non-zero c1 term and manually tune it until your floating object settles down fast enough

(2) If and only if your floating object tends to punch through the water too deep at high velocities: then add the c2 term. Make it very small at first and manually tune it larger until high-velocity splashes are slowing down better.

Finally, if you really want a strong c2 term then you will always have instabilities at high velocities... until you make smaller substeps such that the object does not have time to accelerate in and out of the water within one or two substeps. Basically, there is an inequality relating c2, max_object_speed, object_size, and substep_duration that determines the stability threshold of your system. It is something like:

c2 * max_object_speed^2 * substep_duration^2 < some_fraction * object_size

In other words: "the movement of your object after accelerating under drag for one substep must be less than some fraction of the object's dimensions" because otherwise the approximate assumption that "the drag force is relatively constant for the duration of the substep" is incorrect (the object can be both in the water and outside of it during one substep) --> you need to either (a) cap the max speed of the object or (b) take smaller substeps.
PgrAm
Posts: 12
Joined: Sun Apr 15, 2012 3:34 pm

Re: Issues simulating buoyancy with forces

Post by PgrAm »

Thanks. I ended up just using a linear drag function, specifically there's a good implementation in Game Programming Gems 6 (Can be borrowed for free on archive.org). Seems to be alot more stable.

Also I should add, the sphere approximation is actually really bad :cry:, unless your shape is already a sphere. So I think I will need to use a different approximation depending on each collision shape.