Havok Physics Physics engine called Havok gives our users powerful simulation features, let's learn how to use it in Bitbybit. In this tutorial video we learn how to use it in combination with our CAD algorithms. We will design a chain model shape, convert it to BabylonJS mesh and will simulate it's physical movement through Havok.
VIDEO
The Code You can copy paste this code to Monaco TypeScript editor and it should work without problems even if you do not have an account.
const start = async () => {
bitbybit.draw.drawGridMesh(new Bit.Inputs.Draw.SceneDrawGridMeshDto());
const resMeshes = await createPartMeshes();
bitbybit.babylon.scene.enablePhysics({
vector: [0, -9.81, 0]
});
const times = 8;
const step = 4.5;
for (let i = 0; i <= times; i++) {
const cloneVisual = resMeshes.visualMesh.clone(`clone-visual-${i}`);
const cloneCollision = resMeshes.collisionMesh.clone(`clone-collision-${i}`);
if (i % 2 === 0) {
cloneVisual.rotateAround(new BABYLON.Vector3(0, 0, 0), new BABYLON.Vector3(1, 0, 0), Math.PI / 2);
}
cloneVisual.position = new BABYLON.Vector3(i * step, 20, 0);
cloneCollision.position = new BABYLON.Vector3(i * step, 20, 0);
if (i === 0) {
new BABYLON.PhysicsAggregate(
cloneVisual,
BABYLON.PhysicsShapeType.MESH,
{ mesh: cloneCollision, mass: 0, restitution: 0.75 }
);
} else {
new BABYLON.PhysicsAggregate(
cloneVisual,
BABYLON.PhysicsShapeType.MESH,
{ mesh: cloneCollision, mass: 0.5, restitution: 0.75 }
);
}
}
resMeshes.visualMesh.getChildMeshes().forEach(m => m.isVisible = false);
}
start();
async function createPartMeshes() {
const res = await createChainPartShape();
const visualOptions = new Bit.Inputs.Draw.DrawOcctShapeOptions();
visualOptions.precision = 0.02;
const visualMesh = await bitbybit.draw.drawAnyAsync({
entity: res.visualShape,
options: visualOptions,
});
const collisionOptions = new Bit.Inputs.Draw.DrawOcctShapeOptions();
collisionOptions.drawEdges = false;
collisionOptions.precision = 0.5;
const collisionMeshRes = await bitbybit.draw.drawAnyAsync({
entity: res.collisionShape,
options: collisionOptions
});
const collisionMesh = collisionMeshRes.getChildMeshes()[0] as BABYLON.Mesh;
collisionMesh.isVisible = false;
return { visualMesh, collisionMesh };
}
async function createChainPartShape() {
const radiusOffset = 0.5;
const radiusMinor = 1;
const radiusMajor = 3;
const radiusArray = [
{
minor: radiusMinor,
major: radiusMajor - radiusOffset
},
{
minor: radiusMinor + radiusOffset,
major: radiusMajor + radiusOffset
}
];
const ellipses = await Promise.all(radiusArray.map(r => {
const ellipseOptions = new Bit.Inputs.OCCT.EllipseDto();
ellipseOptions.radiusMajor = r.major;
ellipseOptions.radiusMinor = r.minor;
ellipseOptions.direction = [0, 0, 1];
ellipseOptions.center = [0, 0, -radiusOffset / 2];
return bitbybit.occt.shapes.wire.createEllipseWire(ellipseOptions);
}));
const ellipseFace = await bitbybit.occt.operations.loft({
shapes: ellipses,
makeSolid: false
});
const collisionShape = await bitbybit.occt.operations.extrude({
shape: ellipseFace,
direction: [0, 0, radiusOffset],
});
const visualShape = await bitbybit.occt.fillets.filletEdges({
shape: collisionShape,
radius: 0.1,
});
return { visualShape, collisionShape };
}
< Previous Finish >