I'm a fairly experienced programmer, but new to both physics programming in general and to Bullet in particular. I'm presently working on a small, simple, project to teach myself. Essentially, it's a simplified sailing simulator. For now, I don't deal with buoyancy, for instance, and the rest is essentially done in 2d (the objects are locked so they can only move on the xz-plane and can only rotate around their y-axis).
I've only actually gotten to implementing water resistance on the hull, and a controllable rudder that's supposed to steer the thing. The hull will move through the water fine, and even comes to a halt due to the water resistance if no force is applied. As long as the rudder points straight backwards. If, however, the rudder is turned at all, it only ever results in the hull spinning uncontrollably around its y-axis. It seems reasonable to assume that's because there's no angular water friction implemented yet (though I've tried to do just that, to no avail), but it might very well be something else for all I know. So, having been stuck on this for a week or so, I figured I'd see if there was some kind soul around willing to help.
The general physics-structure so far:
- Objects are loaded from file, linked to a btRigidBody (which I've given a collision shape, mass, and local inertia) and added to my engine
- Each iteration of the main loop, an update method is called on every physics object. This method will set forces on the btRigidBodies linked to the object.
- Then, stepSimulation is called on the dynamics world
- Loop
And here's the code for the hull's update method:
Code: Select all
void Hull::update()
{
btTransform xform;
// mMotionState is the motion state of the btRigidBody linked to the hull
mMotionState->getWorldTransform(xform);
btVector3 v = mBody->getLinearVelocity();
float s = v.length();
if(s > 0.f)
{
v /= s;
// surfaceArea() returns the area of the submerged part of the hull
float subArea = surfaceArea();
/* This is a formula for water resistance I found somewhere
* Technically, I think there's supposed to be some residual forces as well, but for now
* I'm ignoring them */
float Rn = s*mCharactersticLength*waterDensity()/waterViscosity();
float Cf = 0.075f/pow(log(Rn)-2.f, 2.f);
float Rf = 0.5f*waterDensity()*s*s*Cf;
float RfH = subArea*Rf;
/* mRudderDir is a vector describing, in hull-local coordinates, where to the rudder points,
* so rud is supposed to be its world-space representation. mRudderDir is about half the
* length of the rudder, as seen from the top, to yield a good-enough spot to apply the
* turning force to
*/
btVector3 rud = xform*mRudderDir - xform*btVector3(0,0,0);
/* This I'm not sure about, but it seemed reasonable to make the force applied due to the
* rudder a sine function of the angle between the rudder and the direction of travel, so that
* if the rudder points directly backward, no force is applied, while otherwise there will be
* proportionally more force the more the rudder is angled.
*/
float RfR = abs(sin(acos(rud.normalized().dot(v))))*mRudderArea*Rf;
btVector3 f(-v.getX(), 0, -v.getZ());
// Water friction on hull
mBody->applyCentralForce(f*RfH);
btVector3 rF = f*RfR;
// mRudderAnchor is the point on the hull around which the rudder rotates
btVector3 rP = xform*mRudderAnchor + rud;
// Water friction on rudder
mBody->applyForce(rF, rP);
}
// That should have taken care of linear water resistance, but what do I do about angular?
// I haven't found any resources (that I can understand) on that... I have, however, tried some things along the lines of
v = mBody->getAngularVelocity();
s = v.length();
if(s > 0.f)
{
v /= s;
// Various calculations on the speed, submerged area, characteristic length etc, that I quite frankly don't know how to do
float magnitude = torque_to_apply;
mBody->applyTorque(btVector3(0, -v.y()*magnitude, 0));
}
// Test to see how the hull would behave if given forward propulsion (-z in hull-space is "forward")
mBody->applyCentralForce(xform*btVector3(0,0,-200)-xform*btVector3(0,0,0));
}