cannon-es-control
Version:
A lightweight 3D physics engine written in JavaScript with control system tools
543 lines (457 loc) • 17.2 kB
HTML
<!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>