<!DOCTYPE html>
<html>
<head>
<title>Buoyancy demo - p2.js physics engine</title>
<script src="../build/p2.js"></script>
<script src="../build/p2.renderer.js"></script>
<link href="css/demo.css" rel="stylesheet"/>
<meta name="description" content="Buoyancy aka boat simulation">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
</head>
<body>
<script>
// Create demo application
var app = new p2.WebGLRenderer(function(){
var world = new p2.World({
gravity : [0,-10]
});
this.setWorld(world);
// Create "water surface"
var planeShape = new p2.Plane();
var plane = new p2.Body({
position:[0,0],
collisionResponse: false
});
plane.addShape(planeShape);
world.addBody(plane);
body = new p2.Body({
mass: 1,
position: [0,2],
angularVelocity: 0.5
});
body.addShape(new p2.Circle({ radius: 0.5 }), [0.5,0], 0);
body.addShape(new p2.Circle({ radius: 0.5 }), [-0.5,0], 0);
world.addBody(body);
body2 = new p2.Body({
mass: 1,
position: [-3,2],
angularVelocity: 1
});
body2.addShape(new p2.Box({ width: 0.5, height: 2 }), [1,0], 0);
body2.addShape(new p2.Box({ width: 0.5, height: 2 }), [0.5,0], 0);
body2.addShape(new p2.Box({ width: 0.5, height: 2 }), [-0.5,0], 0);
body2.addShape(new p2.Box({ width: 0.5, height: 2 }), [-1,0], 0);
world.addBody(body2);
// Add forces every step
world.on('postStep', function(){
applyAABBBuoyancyForces(body, plane.position, k, c);
applyAABBBuoyancyForces(body2, plane.position, k, c);
});
var shapePosition = [0,0];
var centerOfBouyancy = [0,0];
var liftForce = [0,0];
var viscousForce = [0,0];
var shapeAngle = 0;
var k = 100; // up force per submerged "volume"
var c = 0.8; // viscosity
var v = [0,0];
var aabb = new p2.AABB();
function applyAABBBuoyancyForces(body, planePosition, k, c){
for (var i = 0; i < body.shapes.length; i++) {
var shape = body.shapes[i];
// Get shape world transform
body.vectorToWorldFrame(shapePosition, shape.position);
p2.vec2.add(shapePosition, shapePosition, body.position);
shapeAngle = shape.angle + body.angle;
// Get shape AABB
shape.computeAABB(aabb, shapePosition, shapeAngle);
var areaUnderWater;
if(aabb.upperBound[1] < planePosition[1]){
// Fully submerged
p2.vec2.copy(centerOfBouyancy,shapePosition);
areaUnderWater = shape.area;
} else if(aabb.lowerBound[1] < planePosition[1]){
// Partially submerged
var width = aabb.upperBound[0] - aabb.lowerBound[0];
var height = 0 - aabb.lowerBound[1];
areaUnderWater = width * height;
p2.vec2.set(centerOfBouyancy, aabb.lowerBound[0] + width / 2, aabb.lowerBound[1] + height / 2);
} else {
continue;
}
// Compute lift force
p2.vec2.subtract(liftForce, planePosition, centerOfBouyancy);
p2.vec2.scale(liftForce, liftForce, areaUnderWater * k);
liftForce[0] = 0;
// Make center of bouycancy relative to the body
p2.vec2.subtract(centerOfBouyancy,centerOfBouyancy,body.position);
// Viscous force
body.getVelocityAtPoint(v, centerOfBouyancy);
p2.vec2.scale(viscousForce, v, -c);
// Apply forces
body.applyForce(viscousForce,centerOfBouyancy);
body.applyForce(liftForce,centerOfBouyancy);
}
}
});
</script>
</body>
</html>
cedarcantab
Comments