UNPKG

cannon-es-control

Version:

A lightweight 3D physics engine written in JavaScript with control system tools

543 lines (457 loc) 17.2 kB
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <title>cannon.js - stacks demo</title> <link rel="stylesheet" href="css/style.css" type="text/css" /> <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0" /> </head> <body> <script type="module"> import * as CANNON from '../dist/cannon-es-control.js' import { Demo } from './js/Demo.js' /** * For debugging different kinds of stacks */ const demo = new Demo() const size = 2 const mass = 5 function createTetra() { const vertices = [ new CANNON.Vec3(0, 0, 0), new CANNON.Vec3(2, 0, 0), new CANNON.Vec3(0, 2, 0), new CANNON.Vec3(0, 0, 2), ] const offset = -0.35 for (let i = 0; i < vertices.length; i++) { const v = vertices[i] v.x += offset v.y += offset v.z += offset } return new CANNON.ConvexPolyhedron({ vertices: vertices, faces: [ [0, 3, 2], // -x [0, 1, 3], // -y [0, 2, 1], // -z [1, 2, 3], // +xyz ], }) } function createBoxPolyhedron(size = 1) { const box = new CANNON.Box(new CANNON.Vec3(size, size, size)) return box.convexPolyhedronRepresentation } function createCompound(mass = 1) { const compoundBody = new CANNON.Body({ mass }) const shape = new CANNON.Box(new CANNON.Vec3(0.5 * size, 0.5 * size, 0.5 * size)) compoundBody.addShape(shape, new CANNON.Vec3(0, size, 0)) compoundBody.addShape(shape, new CANNON.Vec3(0, 0, 0)) compoundBody.addShape(shape, new CANNON.Vec3(0, -size, 0)) compoundBody.addShape(shape, new CANNON.Vec3(size, -size, 0)) return compoundBody } demo.addScene('sphere/sphere', () => { const world = setupWorld(demo) // Sphere 1 const sphereShape = new CANNON.Sphere(size) const body1 = new CANNON.Body({ mass }) body1.addShape(sphereShape) body1.position.set(0, size * 3, 0) world.addBody(body1) demo.addVisual(body1) // Sphere 2 const body2 = new CANNON.Body({ mass }) body2.addShape(sphereShape) body2.position.set(0, size, 0) world.addBody(body2) demo.addVisual(body2) }) demo.addScene('sphere/plane', () => { const world = setupWorld(demo) // Sphere const sphereShape = new CANNON.Sphere(size) const body = new CANNON.Body({ mass }) body.addShape(sphereShape) body.position.set(0, size * 3, 0) world.addBody(body) demo.addVisual(body) }) demo.addScene('sphere/box', () => { const world = setupWorld(demo) // Box const boxShape = new CANNON.Box(new CANNON.Vec3(size, size, size)) const body1 = new CANNON.Body({ mass }) body1.addShape(boxShape) body1.position.set(0, size, 0) world.addBody(body1) demo.addVisual(body1) // Sphere const sphereShape = new CANNON.Sphere(size) const body2 = new CANNON.Body({ mass }) body2.addShape(sphereShape) body2.position.set(0, size * 3, 0) world.addBody(body2) demo.addVisual(body2) }) demo.addScene('sphere/compound', () => { const world = setupWorld(demo) // Sphere const sphereShape = new CANNON.Sphere(size * 0.5) const body1 = new CANNON.Body({ mass }) body1.addShape(sphereShape) body1.position.set(size, size * 6, 0) world.addBody(body1) demo.addVisual(body1) // Compound const body2 = createCompound(mass) body2.position.set(0, size * 3, 0) world.addBody(body2) demo.addVisual(body2) }) demo.addScene('sphere/convex', () => { const world = setupWorld(demo) // Sphere const sphereShape = new CANNON.Sphere(size * 0.5) const body1 = new CANNON.Body({ mass }) body1.addShape(sphereShape) body1.position.set(0, size * 6, 0) world.addBody(body1) demo.addVisual(body1) // Convex tetra const tetraShape = createTetra() const body2 = new CANNON.Body({ mass }) body2.addShape(tetraShape) body2.position.set(0, size, 0) world.addBody(body2) demo.addVisual(body2) }) demo.addScene('sphere/cylinder', () => { const world = setupWorld(demo) // Sphere const sphereShape = new CANNON.Sphere(size * 0.5) const body1 = new CANNON.Body({ mass }) body1.addShape(sphereShape) body1.position.set(0, size * 6, 0) world.addBody(body1) demo.addVisual(body1) // Cylinder const cylinderShape = new CANNON.Cylinder(size, size, size * 2, 10) const body2 = new CANNON.Body({ mass }) body2.addShape(cylinderShape) body2.position.set(0, size * 3, 0) world.addBody(body2) demo.addVisual(body2) }) demo.addScene('sphere/particle', () => { const world = setupWorld(demo) // Sphere const sphereShape = new CANNON.Sphere(size * 0.5) const body = new CANNON.Body({ mass }) body.addShape(sphereShape) body.position.set(0, size, 0) world.addBody(body) demo.addVisual(body) // Particle const particle = new CANNON.Body({ mass: 1 }) particle.addShape(new CANNON.Particle()) particle.position.set(-0.02, size * 3, 0) world.addBody(particle) demo.addVisual(particle) }) demo.addScene('plane/box', () => { const world = setupWorld(demo) // Box const boxShape = new CANNON.Box(new CANNON.Vec3(size, size, size)) const body = new CANNON.Body({ mass }) body.addShape(boxShape) body.position.set(0, size, 0) world.addBody(body) demo.addVisual(body) }) demo.addScene('plane/compound', () => { const world = setupWorld(demo) // Compound const body = createCompound(5) body.position.set(0, size * 4, 0) world.addBody(body) demo.addVisual(body) }) demo.addScene('plane/convex', () => { const world = setupWorld(demo) // Convex tetra const tetraShape = createTetra() const body = new CANNON.Body({ mass }) body.addShape(tetraShape) body.position.set(0, size, 0) world.addBody(body) demo.addVisual(body) }) demo.addScene('plane/cylinder', () => { const world = setupWorld(demo) // Cylinder const cylinderShape = new CANNON.Cylinder(size, size, size * 2, 10) const body = new CANNON.Body({ mass }) body.addShape(cylinderShape) body.position.set(0, size * 3, 0) world.addBody(body) demo.addVisual(body) }) demo.addScene('plane/particle', () => { const world = setupWorld(demo) // Particle const particle = new CANNON.Body({ mass: 1 }) particle.addShape(new CANNON.Particle()) particle.position.set(-0.02, size * 3, 0) world.addBody(particle) demo.addVisual(particle) }) demo.addScene('box/box', () => { const world = setupWorld(demo) // Box 1 const boxShape = new CANNON.Box(new CANNON.Vec3(size * 0.5, size * 0.5, size * 0.5)) const body1 = new CANNON.Body({ mass }) body1.addShape(boxShape) body1.position.set(0, size, 0) world.addBody(body1) demo.addVisual(body1) // Box 2 const body2 = new CANNON.Body({ mass }) body2.addShape(boxShape) body2.position.set(-size * 0.5, size * 3, 0) world.addBody(body2) demo.addVisual(body2) }) demo.addScene('box/compound', () => { const world = setupWorld(demo) // Compound const body1 = createCompound(5) body1.position.set(-size * 0.5, size * 2, 0) world.addBody(body1) demo.addVisual(body1) // Box const boxShape = new CANNON.Box(new CANNON.Vec3(size * 0.5, size * 0.5, size * 0.5)) const body2 = new CANNON.Body({ mass }) body2.addShape(boxShape) body2.position.set(0, size * 7, 0) world.addBody(body2) demo.addVisual(body2) }) demo.addScene('box/convex', () => { const world = setupWorld(demo) // Box const boxShape = new CANNON.Box(new CANNON.Vec3(size * 0.5, size * 0.5, size * 0.5)) const body1 = new CANNON.Body({ mass }) body1.addShape(boxShape) body1.position.set(0, size * 2, 0) world.addBody(body1) demo.addVisual(body1) // Convex tetra const tetraShape = createTetra(size) const body2 = new CANNON.Body({ mass }) body2.addShape(tetraShape) body2.position.set(0, size * 5, 0) world.addBody(body2) demo.addVisual(body2) }) demo.addScene('box/cylinder', () => { const world = setupWorld(demo) // Box const boxShape = new CANNON.Box(new CANNON.Vec3(size * 0.5, size * 0.5, size * 0.5)) const body1 = new CANNON.Body({ mass }) body1.addShape(boxShape) body1.position.set(0, size * 5, 0) world.addBody(body1) demo.addVisual(body1) // Cylinder const cylinderShape = new CANNON.Cylinder(size, size, size * 2, 10) const body2 = new CANNON.Body({ mass }) body2.addShape(cylinderShape) body2.position.set(0, size * 2, 0) world.addBody(body2) demo.addVisual(body2) }) demo.addScene('box/particle', () => { const world = setupWorld(demo) // Box const boxShape = new CANNON.Box(new CANNON.Vec3(size * 0.5, size * 0.5, size * 0.5)) const body = new CANNON.Body({ mass }) body.addShape(boxShape) body.position.set(0, size, 0) world.addBody(body) demo.addVisual(body) // Particle const particle = new CANNON.Body({ mass: 1 }) particle.addShape(new CANNON.Particle()) particle.position.set(0, size * 3, 0) world.addBody(particle) demo.addVisual(particle) }) demo.addScene('compound/compound', () => { const world = setupWorld(demo) // Compound const body1 = createCompound(5) body1.position.set(-size * 0.5, size * 6, 0) world.addBody(body1) demo.addVisual(body1) // Compound const body2 = createCompound(5) body2.position.set(-size * 0.5, size * 2, 0) world.addBody(body2) demo.addVisual(body2) }) demo.addScene('compound/convex', () => { const world = setupWorld(demo) // Convex tetra const tetraShape = createTetra() const body1 = new CANNON.Body({ mass }) body1.addShape(tetraShape) body1.position.set(0, size * 3, 0) world.addBody(body1) demo.addVisual(body1) // Compound const body2 = createCompound(5) body2.position.set(0, size, 0) world.addBody(body2) demo.addVisual(body2) }) demo.addScene('compound/cylinder', () => { const world = setupWorld(demo) // Cylinder const cylinderShape = new CANNON.Cylinder(size, size, size * 2, 10) const body1 = new CANNON.Body({ mass }) body1.addShape(cylinderShape) body1.position.set(0, size * 5, 0) world.addBody(body1) demo.addVisual(body1) // Compound const body2 = createCompound(5) body2.position.set(0, size, 0) world.addBody(body2) demo.addVisual(body2) }) demo.addScene('compound/particle', () => { const world = setupWorld(demo) // Compound const body1 = createCompound(5) body1.position.set(0, size * 4, 0) world.addBody(body1) demo.addVisual(body1) // Particle const particle = new CANNON.Body({ mass: 1 }) particle.addShape(new CANNON.Particle()) particle.position.set(0, size * 7, 0) world.addBody(particle) demo.addVisual(particle) }) demo.addScene('convex/convex', () => { const world = setupWorld(demo) // Convex tetra const tetraShape = createTetra() const body1 = new CANNON.Body({ mass }) body1.addShape(tetraShape) body1.position.set(-0.1, size * 5, 0.1) world.addBody(body1) demo.addVisual(body1) // Convex box // const tetraShape = createTetra() const boxShape = createBoxPolyhedron(size) const body2 = new CANNON.Body({ mass }) body2.addShape(boxShape) body2.position.set(0, size * 3, 0) world.addBody(body2) demo.addVisual(body2) }) demo.addScene('convex/cylinder', () => { const world = setupWorld(demo) // Convex tetra const tetraShape = createTetra() const body1 = new CANNON.Body({ mass }) body1.addShape(tetraShape) body1.position.set(-0.1, size * 5, 0.1) world.addBody(body1) demo.addVisual(body1) // Cylinder const cylinderShape = new CANNON.Cylinder(size, size, size * 2, 10) const body2 = new CANNON.Body({ mass }) body2.addShape(cylinderShape) body2.position.set(0, size * 2, 0) world.addBody(body2) demo.addVisual(body2) }) demo.addScene('convex/particle', () => { const world = setupWorld(demo) // Convex tetra // const boxShape = createBoxPolyhedron(size) const tetraShape = createTetra() const body1 = new CANNON.Body({ mass }) body1.addShape(tetraShape) body1.position.set(0, size, 0) world.addBody(body1) demo.addVisual(body1) // Particle const particle = new CANNON.Body({ mass: 1 }) particle.addShape(new CANNON.Particle()) particle.position.set(0, size * 3, 0) world.addBody(particle) demo.addVisual(particle) }) demo.addScene('cylinder/cylinder', () => { const world = setupWorld(demo) // Cylinder const cylinderShape = new CANNON.Cylinder(size, size, size * 2, 10) const body1 = new CANNON.Body({ mass }) body1.addShape(cylinderShape) body1.position.set(0, size * 3, 0) world.addBody(body1) demo.addVisual(body1) // Cylinder const body2 = new CANNON.Body({ mass }) body2.addShape(cylinderShape) body2.position.set(0, size * 6, 0) body2.quaternion.setFromEuler(-Math.PI / 2, 0, 0) world.addBody(body2) demo.addVisual(body2) }) demo.addScene('cylinder/particle', () => { const world = setupWorld(demo) // Cylinder const cylinderShape = new CANNON.Cylinder(size, size, size * 2, 10) const body1 = new CANNON.Body({ mass }) body1.addShape(cylinderShape) body1.position.set(0, size * 2, 0) world.addBody(body1) demo.addVisual(body1) // Particle const particle = new CANNON.Body({ mass: 1 }) particle.addShape(new CANNON.Particle()) particle.position.set(0, size * 4, 0) world.addBody(particle) demo.addVisual(particle) }) demo.start() function setupWorld(demo) { const world = demo.getWorld() world.gravity.set(0, -10, 0) // Max solver iterations: Use more for better force propagation, but keep in mind that it's not very computationally cheap! world.solver.iterations = 20 // Tweak contact properties. // Contact stiffness - use to make softer/harder contacts world.defaultContactMaterial.contactEquationStiffness = 1e7 // Stabilization time in number of timesteps world.defaultContactMaterial.contactEquationRelaxation = 5 // Static ground plane const groundShape = new CANNON.Plane() const groundBody = new CANNON.Body({ mass: 0 }) groundBody.addShape(groundShape) groundBody.position.set(0, -1, 0) groundBody.quaternion.setFromEuler(-Math.PI / 2, 0, 0) world.addBody(groundBody) demo.addVisual(groundBody) return world } </script> </body> </html>