const engine = bitbybit.babylon.engine.getEngine();
const scene = bitbybit.babylon.scene.getScene();
const camera = scene.activeCamera as BABYLON.ArcRotateCamera;
camera.position = new BABYLON.Vector3(80, 45, 10);
camera.target = new BABYLON.Vector3(0, 25, 0);
const start = async () => {
const chainModel = await createChain();
const ballChain = await createBallChain();
chainModel.collisionMesh.isVisible = false;
ballChain.collisionMesh.isVisible = false;
bitbybit.babylon.scene.enablePhysics({ vector: [0, -9.81, 0] });
const boxMeshRes = await createBox();
const boxMeshCollision = boxMeshRes.getChildMeshes()[0] as BABYLON.Mesh;
const sphere = BABYLON.MeshBuilder.CreateSphere("sphere", { diameter: 8, segments: 32 }, scene);
const material = new BABYLON.PBRMetallicRoughnessMaterial("spheres", scene);
material.baseColor = new BABYLON.Color3(0, 0, 1);
material.metallic = 0.7;
material.roughness = 0.1;
sphere.position.y = 4;
sphere.material = material;
const step = 10;
const limit = 5;
for (let x = 0; x < limit; x++) {
for (let z = 0; z < limit; z++) {
const sph = sphere.clone(`${x}-${z}`);
sph.position = new BABYLON.Vector3(x * step - 60, 20, z * step - (step * limit / 2));
new BABYLON.PhysicsAggregate(sph, BABYLON.PhysicsShapeType.SPHERE, { mass: 0.01, restitution: 0.75 }, scene);
}
}
new BABYLON.PhysicsAggregate(sphere, BABYLON.PhysicsShapeType.SPHERE, { mass: 0.3, restitution: 0.75 }, scene);
new BABYLON.PhysicsAggregate(boxMeshCollision, BABYLON.PhysicsShapeType.MESH, { mass: 0 }, scene);
const positionStep = 4.5;
const times = 8;
for (let i = 0; i < times; i++) {
const cloneVisual = chainModel.visualMesh.clone(`m-${i}`);
cloneVisual.getChildMeshes().forEach(cm => {
if (cm instanceof BABYLON.LinesMesh) {
cm.enableEdgesRendering();
cm.edgesWidth = 1;
} else {
cm.material.zOffset = 2;
}
})
const cloneCollision = chainModel.collisionMesh.clone(`m-${i}`);
cloneVisual.position = new BABYLON.Vector3(i * positionStep, 45, 0);
cloneCollision.position = new BABYLON.Vector3(i * positionStep, 45, 0);
if (i % 2 === 0) {
cloneVisual.rotateAround(cloneVisual.position, new BABYLON.Vector3(1, 0, 0), Math.PI / 2);
cloneCollision.rotateAround(cloneCollision.position, new BABYLON.Vector3(1, 0, 0), Math.PI / 2);
}
cloneCollision.isVisible = false;
if (i !== 0) {
new BABYLON.PhysicsAggregate(cloneVisual, BABYLON.PhysicsShapeType.MESH, { mesh: cloneCollision, mass: 0.5, restitution: 0.75 }, scene)
} else {
new BABYLON.PhysicsAggregate(cloneVisual, BABYLON.PhysicsShapeType.MESH, { mesh: cloneCollision, mass: 0, restitution: 0.75 }, scene)
}
}
chainModel.visualMesh.getChildMeshes().forEach(m => m.isVisible = false);
ballChain.visualMesh.rotateAround(ballChain.visualMesh.position, new BABYLON.Vector3(1, 0, 0), Math.PI / 2);
ballChain.collisionMesh.rotateAround(ballChain.collisionMesh.position, new BABYLON.Vector3(1, 0, 0), Math.PI / 2);
ballChain.visualMesh.position = new BABYLON.Vector3(times * positionStep - 0.5, 45, 0);
ballChain.collisionMesh.position = new BABYLON.Vector3(times * positionStep - 0.5, 45, 0);
new BABYLON.PhysicsAggregate(ballChain.visualMesh, BABYLON.PhysicsShapeType.MESH, { mesh: ballChain.collisionMesh, mass: 2, restitution: 0.75 }, scene)
const light = new Bit.Inputs.BabylonScene.DirectionalLightDto();
light.intensity = 1;
light.direction = [200, -200, 200];
light.shadowGeneratorMapSize = 2056;
bitbybit.babylon.scene.drawDirectionalLight(light);
}
start();
async function createChain() {
const chainOCCT = await createOCCTChains();
const options = new Bit.Inputs.Draw.DrawOcctShapeOptions();
options.precision = 0.005;
const visualMesh = await bitbybit.draw.drawAnyAsync({
entity: chainOCCT.fillet,
options
});
options.precision = 0.1;
options.drawEdges = false;
const collisionMeshRes = await bitbybit.draw.drawAnyAsync({
entity: chainOCCT.extruded,
options
});
const collisionMesh = collisionMeshRes.getChildMeshes()[0] as BABYLON.Mesh;
return { visualMesh, collisionMesh }
}
async function createBallChain() {
const chainOCCT = await createOCCTChains();
const sphere = await bitbybit.occt.shapes.solid.createSphere({ radius: 4, center: [6, 0, 0] });
const shapeCollision = await bitbybit.occt.booleans.union({
shapes: [chainOCCT.extruded, sphere],
keepEdges: false
})
const shapeVisual = await bitbybit.occt.booleans.union({
shapes: [chainOCCT.fillet, sphere],
keepEdges: false
})
const options = new Bit.Inputs.Draw.DrawOcctShapeOptions();
options.precision = 0.005;
const visualMesh = await bitbybit.draw.drawAnyAsync({
entity: shapeVisual,
options
});
options.precision = 0.1;
options.drawEdges = false;
const collisionMeshRes = await bitbybit.draw.drawAnyAsync({
entity: shapeCollision,
options
});
const collisionMesh = collisionMeshRes.getChildMeshes()[0] as BABYLON.Mesh;
return { visualMesh, collisionMesh }
}
async function createBox() {
const box = await bitbybit.occt.shapes.solid.createBox({
width: 200,
length: 200,
height: 30,
center: [0, 13, 0],
})
const boxCutout = await bitbybit.occt.shapes.solid.createBox({
width: 190,
length: 190,
height: 30,
center: [0, 15, 0],
})
const diff = await bitbybit.occt.booleans.difference({
shape: box,
shapes: [boxCutout],
keepEdges: false
})
const boxDrawOptions = new Bit.Inputs.Draw.DrawOcctShapeOptions();
boxDrawOptions.precision = 0.1;
boxDrawOptions.faceColour = "#ff00ff";
const boxMesh = await bitbybit.draw.drawAnyAsync({
entity: diff,
options: boxDrawOptions
})
return boxMesh
}
async function createOCCTChains() {
const chainOffset = 0.5;
const chaingRadiusMinor = 1;
const chainRadiusMajor = 3;
const radiuses = [[chaingRadiusMinor, chainRadiusMajor - chainOffset], [chaingRadiusMinor + chainOffset, chainRadiusMajor + chainOffset]];
const contourEllipses = await Promise.all(radiuses.map((r) => {
return bitbybit.occt.shapes.wire.createEllipseWire({
radiusMinor: r[0],
radiusMajor: r[1],
center: [0, 0, -chainOffset / 2],
direction: [0, 0, 1],
})
}));
const loft = await bitbybit.occt.operations.loft({
shapes: contourEllipses,
makeSolid: false
});
const extruded = await bitbybit.occt.operations.extrude({
shape: loft,
direction: [0, 0, chainOffset],
});
const fillet = await bitbybit.occt.fillets.filletEdges({
shape: extruded,
radius: chainOffset / 3
});
return { extruded, fillet };
}