### Install npm packages and run examples Source: https://github.com/jrouwe/joltphysics.js/blob/main/README.md Install project dependencies and start the development server to run the examples. Ensure you are serving the HTML file using a web server, not opening it directly. ```bash npm install npm run examples ``` -------------------------------- ### Initialize JoltPhysics.js and Example Source: https://github.com/jrouwe/joltphysics.js/blob/main/Examples/character_virtual.html Initializes JoltPhysics.js and the example setup. Replace the URL if not building the library locally. ```javascript // In case you haven't built the library yourself, replace URL with: https://www.unpkg.com/jolt-physics/dist/jolt-physics.wasm-compat.js initJolt().then(function (Jolt) { // Initialize this example initExample(Jolt, null); ``` -------------------------------- ### Initialize JoltPhysics.js and Setup Example Source: https://github.com/jrouwe/joltphysics.js/blob/main/Examples/conveyor_belt.html Initializes JoltPhysics.js and sets up the camera and floor for the demo. Ensure the Jolt physics WASM module is correctly imported. ```javascript // In case you haven't built the library yourself, replace URL with: https://www.unpkg.com/jolt-physics/dist/jolt-physics.wasm-compat.js import initJolt from './js/jolt-physics.wasm-compat.js'; initJolt().then(function (Jolt) { // Initialize this example initExample(Jolt, null); camera.position.z += 60; camera.position.y += 20; camera.position.x += 50; // Create a basic floor createFloor(100); ``` -------------------------------- ### Initialize JoltPhysics and Example Source: https://github.com/jrouwe/joltphysics.js/blob/main/Examples/heightfield.html Initializes JoltPhysics and the example setup. Replace the URL with the JoltPhysics WASM file if not built locally. ```javascript import initJolt from './js/jolt-physics.wasm-compat.js'; // In case you haven't built the library yourself, replace URL with: https://www.unpkg.com/jolt-physics/dist/jolt-physics.wasm-compat.js initJolt().then(async function (Jolt) { // Initialize this example initExample(Jolt, null); // ... rest of the initialization code }); ``` -------------------------------- ### Initialize JoltPhysics.js and Example Source: https://github.com/jrouwe/joltphysics.js/blob/main/Examples/constraint_path.html Initializes JoltPhysics.js and sets up the example environment. Replace the URL if you haven't built the library yourself. ```javascript // In case you haven't built the library yourself, replace URL with: https://www.unpkg.com/jolt-physics/dist/jolt-physics.wasm-compat.js import initJolt from './js/jolt-physics.wasm-compat.js'; initJolt().then(function (Jolt) { // Initialize this example const updates = []; initExample(Jolt, () => { updates.forEach(func => func()); }); // Create a basic floor createFloor(); const rotation = Jolt.Quat.prototype.sIdentity(); const position = new Jolt.RVec3(); const size = new Jolt.Vec3(0.5, 0.1, 0.5); const pathPoints = []; const pointResolution = 100; for (let i = 0; i < pointResolution; i++) { const x = Math.cos(i * 2 * Math.PI / pointResolution) * 2; const y = Math.sin(i * 2 * Math.PI / pointResolution) * 2; pathPoints.push(new THREE.Vector3(x, 0, y)); } const pathGeo = new Line3DMesh(pathPoints, '#0000FF'); const pathMesh = pathGeo.getMesh(); const SetV3 = (joltV3, threeV3) => threeV3.set(joltV3.GetX(), joltV3.GetY(), joltV3.GetZ()); const path = new Jolt.PathConstraintPathJS(); path.GetPathMaxFraction = () => pointResolution; const tmp = new THREE.Vector3(); const tmp2 = new THREE.Vector3(); path.GetClosestPoint = (vecPtr, fractionHint) => { const jVec3 = Jolt.wrapPointer(vecPtr, Jolt.Vec3); SetV3(jVec3, tmp2); const body2Loc = tmp2; let closest = 31; let maxLen = Number.POSITIVE_INFINITY; pathPoints.forEach((p, i) => { tmp.subVectors(p, body2Loc); const len = tmp.length(); if (len < maxLen) { closest = i; maxLen = len; } }); return closest; } const normal = new THREE.Vector3(0, 1, 0); path.GetPointOnPath = (inFraction, outPathPositionPtr, outPathTangentPtr, outPathNormalPtr, outPathBinormalPtr) => { const outPathPosition = Jolt.wrapPointer(outPathPositionPtr, Jolt.Vec3); const outPathTangent = Jolt.wrapPointer(outPathTangentPtr, Jolt.Vec3); const outPathNormal = Jolt.wrapPointer(outPathNormalPtr, Jolt.Vec3); const outPathBinormal = Jolt.wrapPointer(outPathBinormalPtr, Jolt.Vec3); const pointAIdx = Math.floor(inFraction); const pointBIdx = Math.ceil(inFraction + 0.0001) % pointResolution; const percent = inFraction - pointAIdx; const pointA = pathPoints[pointAIdx]; const pointB = pathPoints[pointBIdx]; const pos = tmp.lerpVectors(pointA, pointB, percent); outPathNormal.Set(normal.x, normal.y, normal.z); outPathPosition.Set(pos.x, pos.y, pos.z); const tan = tmp.subVectors(pointB, pointA).normalize(); outPathTangent.Set(tan.x, tan.y, tan.z); const binormal = tmp.crossVectors(tan, normal).normalize(); outPathBinormal.Set(binormal.x, binormal.y, binormal.z); } Jolt.castObject(path, Jolt.PathConstraintPath).SetIsLooping(true); const _jPosition = new Jolt.Vec3(); const _jTangent = new Jolt.Vec3(); const _jNormal = new Jolt.Vec3(); const _jBinormal = new Jolt.Vec3(); const positionMaterial = new THREE.MeshPhongMaterial({ color: '#00ff00' }); const positionGeo = new THREE.SphereGeometry(0.25, 32, 32); function renderPathData(parent, constraint) { parent.add(pathMesh.clone()); const pos = new THREE.Mesh(positionGeo, positionMaterial); parent.add(pos); const tanLine = new Line3DMesh([new THREE.Vector3(), new THREE.Vector3()], '#FF0000'); pos.add(tanLine.getMesh()); const normLine = new Line3DMesh([new THREE.Vector3(), new THREE.Vector3()], '#00FF00'); pos.add(normLine.getMesh()); const binLine = new Line3DMesh([new THREE.Vector3(), new THREE.Vector3()], '#FF00FF'); pos.add(binLine.getMesh()); updates.push(() => { path.GetPointOnPath(constraint.GetPathFraction(), Jolt.getPointer(_jPosition), Jolt.getPointer(_jTangent), Jolt.getPointer(_jNormal), Jolt.getPointer(_jBinormal)); SetV3(_jPosition, pos.position); SetV3(_jTangent, tanLine._points[1]); tanLine.update(); SetV3(_jNormal, normLine._points[1]); normLine.update(); SetV3(_jBinormal, binLine._points[1]); binLine.update(); }) } let offsetX = -8; let offsetZ = 0; { position.Set(0 + offsetX, 5, 0 + offsetZ); const box1 = createBox(position, rotation, size, Jolt.EMotionType_Static, LAYER_NON_MOVING); const threeBox = dynamicObjects[dynamicObjects.length - 1]; position.Set(2.5 + offsetX, 5, 0 + offsetZ); const box2 = createBox(position, rotation, size, Jolt.EMotionType_Dynamic, LAYER_MOVING, '#ff0000'); const pathConstraintSettings = new Jolt.PathConstraintSettings(); pathConstraintSettings.mRotationConstraintType = Jolt.EPathRotationConstraintType.EPathRotationConstraintType_Free; ``` -------------------------------- ### Initialize Jolt Physics and Setup Source: https://github.com/jrouwe/joltphysics.js/blob/main/Examples/constraint_pulley.html Initializes Jolt Physics and sets up the example, including graphics updates for lines. Requires Three.js for visualization. ```javascript import initJolt from './js/jolt-physics.wasm-compat.js'; initJolt().then(function (Jolt) { const lineUpdates = []; // Initialize this example initExample(Jolt, () => { lineUpdates.forEach(func => func()); }); // ... rest of the code ``` -------------------------------- ### Initialize JoltPhysics and Example Source: https://github.com/jrouwe/joltphysics.js/blob/main/Examples/constraint_svg_path.html Initializes JoltPhysics and the example environment. Replace the URL with a CDN link if not building the library locally. ```javascript // In case you haven't built the library yourself, replace URL with: https://www.unpkg.com/jolt-physics/dist/jolt-physics.wasm-compat.js import initJolt from './js/jolt-physics.wasm-compat.js'; initJolt().then(function (Jolt) { // Initialize this example const updates = [] initExample(Jolt, () => { updates.forEach(func => func()) }); // Create a basic floor createFloor(); const rotation = Jolt.Quat.prototype.sIdentity(); const position = new Jolt.RVec3(); const size = new Jolt.Vec3(0.5, 0.1, 0.5); const SetV3 = (joltV3, threeV3) => threeV3.set(joltV3.GetX(), joltV3.GetY(), joltV3.GetZ()); const normal = new THREE.Vector3(0, 1, 0); class SVGJoltPath extends Jolt.PathConstraintPathJS { constructor(svgPath, velocity, scale, sampleRate) { super(); this._svgPath = svgPath; this._velocity = velocity; this._scale = scale || 1; this._sampleRate = sampleRate || 1; this._tmpVec = [new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3()]; // Emscripten require properties, not methods, for these functions, so we can not just declare them as normal class methods this.GetClosestPoint = this.getClosestPoint; this.GetPathMaxFraction = this.getPathMaxFraction; this.GetPointOnPath = this.getPointOnPath; this.points = []; // This SVG's native sampling is slow, so pre-calculate the needed points. Reduce sample-rate for this demo, since const pathLen = this._svgPath.getTotalLength(); for (let i = 0; i < pathLen; i += this._sampleRate) { this.points.push(this._getPos(i, new THREE.Vector3())); } // calculate center and size for later re-centering and scaling the SVG this._calcBoundingBox(); this.points.forEach(pos => { pos.set((pos.x - this.bbox.center.x) / this.bbox.width * this._scale, 0, (pos.y - this.bbox.center.y) / this.bbox.height * this._scale) }) this._length = this.points.length; } _calcBoundingBox() { const bbox = this.bbox = { min: { x: Number.POSITIVE_INFINITY, y: Number.POSITIVE_INFINITY }, max: { x: -Number.POSITIVE_INFINITY, y: -Number.POSITIVE_INFINITY } } this.points.forEach(p => { bbox.min.x = Math.min(bbox.min.x, p.x) bbox.min.y = Math.min(bbox.min.y, p.y) bbox.max.x = Math.max(bbox.max.x, p.x) bbox.max.y = Math.max(bbox.max.y, p.y) }); bbox.width = bbox.max.x - bbox.min.x; bbox.height = bbox.max.y - bbox.min.y; bbox.center = { x: 0, y: 0 }; bbox.center.x = (bbox.max.x + bbox.min.x) / 2; bbox.center.y = (bbox.max.y + bbox.min.y) / 2; } getMesh(color) { const pathGeo = new Line3DMesh(this.points, color); return pathGeo.getMesh(); } _searchRange(current, indexA, indexB, iterations) { const pointA = this.points[Math.floor((indexA + this.points.length) % this.points.length)]; const distA = this._tmpVec[3].subVectors(pointA, current).length(); const pointB = this.points[Math.floor((indexB + this.points.length) % this.points.length)]; const distB = this._tmpVec[3].subVectors(pointB, current).length(); const indexDelta = indexB - indexA; if (distA == 0) { return indexA; } if (distB == 0) { return indexB; } const weightA = distA / (distA + distB); const nextEstimate = indexA + weightA * indexDelta; if (iterations == 1 || Math.abs(indexA - indexB) < 1) { return nextEstimate; } return this._searchRange(current, nextEstimate - 0.125 * indexDelta, nextEstimate + 0.125 * indexDelta, iterations - 1); } getClosestPoint(vecPtr, fractionHint) { const jVec3 = Jolt.wrapPointer(vecPtr, Jolt.Vec3); const curPos = this._tmpVec[0]; SetV3(jVec3, curPos); const closest = this._searchRange(curPos, fractionHint - this._velocity, fractionHint + this._velocity, 6) return (closest + this.points.length) % this.points.length; } getPathMaxFraction() { return this._length; } _getPos(fraction, threeVec) { const pos = this._svgPath.getPointAtLength(fraction); threeVec.set(pos.x, pos.y, 0); return threeVec; } getPointOnPath(inFraction, outPathPositionPtr, outPathTangentPtr, outPathNormalPtr, outPathBinormalPtr) { const outPathPosition = Jolt.wrapPointer(outPathPositionPtr, Jolt.Vec3); const outPathTangent = Jolt.wrapPointer(outPathTangentPtr, Jolt.Vec3); const outPathNormal = Jolt.wrapPointer(outPathNormalPtr, Jolt.Vec3); const outPathBinormal = Jolt.wrapPointer(outPathBinormalPtr, Jolt.Vec3); const indexA = Math.floor(inFraction + this.points.length) % this.points.length; const indexB = Math.ceil(inFraction + 0.001 + this.points.length) % this.points.length; const pointA = this.points[indexA]; const pointB = this.points[indexB]; ``` -------------------------------- ### Initialize JoltPhysics.js and Setup Source: https://github.com/jrouwe/joltphysics.js/blob/main/Examples/constraints.html Initializes JoltPhysics.js and sets up the basic scene, including the camera, floor, and group filters for collision management. This code is essential for starting any JoltPhysics.js simulation. ```javascript import initJolt from './js/jolt-physics.wasm-compat.js'; initJolt().then(function (Jolt) { // Initialize this example initExample(Jolt, null); // Better position the camera camera.position.set(10, 30, 30); // Create a basic floor createFloor(); // Create group filter that filters out collisions between body N and N + 1 in the same chain let filter = new Jolt.GroupFilterTable(10); for (let z = 0; z < 9; ++z) filter.DisableCollision(z, z + 1); let shape = new Jolt.BoxShape(new Jolt.Vec3(0.5, 0.5, 0.5), 0.05, null); let creationSettings = new Jolt.BodyCreationSettings(shape, new Jolt.RVec3(-15, 20, 0), Jolt.Quat.prototype.sIdentity(), Jolt.EMotionType_Dynamic, LAYER_MOVING); creationSettings.mCollisionGroup.SetGroupFilter(filter); function createBody(creationSettings, z) { creationSettings.mMotionType = z == 0 ? Jolt.EMotionType_Static : Jolt.EMotionType_Dynamic; creationSettings.mObjectLayer = z == 0 ? LAYER_NON_MOVING : LAYER_MOVING; creationSettings.mPosition.SetZ(z); creationSettings.mCollisionGroup.SetSubGroupID(z); let body = bodyInterface.CreateBody(creationSettings); addToScene(body, 0xff0000); // Add an impulse (gravity is really boring, many constraints look the same) if (z == 9) body.AddImpulse(new Jolt.Vec3(1000, 0, 0)); return body; } // Fixed constraint creationSettings.mCollisionGroup.SetGroupID(0); { let constraintSettings = new Jolt.FixedConstraintSettings(); constraintSettings.mAutoDetectPoint = true; let prevBody = null; for (let z = 0; z < 10; ++z) { let body = createBody(creationSettings, z); if (prevBody != null) { physicsSystem.AddConstraint(constraintSettings.Create(prevBody, body)); } prevBody = body; } } // Point constraint creationSettings.mCollisionGroup.SetGroupID(creationSettings.mCollisionGroup.GetGroupID() + 1); creationSettings.mPosition.SetX(creationSettings.mPosition.GetX() + 5); { let constraintSettings = new Jolt.PointConstraintSettings(); constraintSettings.mPoint1 = constraintSettings.mPoint2 = creationSettings.mPosition; let prevBody = null; for (let z = 0; z < 10; ++z) { let body = createBody(creationSettings, z); if (prevBody != null) { constraintSettings.mPoint1.SetZ(z - 0.5); constraintSettings.mPoint2.SetZ(z - 0.5); physicsSystem.AddConstraint(constraintSettings.Create(prevBody, body)); } prevBody = body; } } // Distance constraint creationSettings.mCollisionGroup.SetGroupID(creationSettings.mCollisionGroup.GetGroupID() + 1); creationSettings.mPosition.SetX(creationSettings.mPosition.GetX() + 5); { let constraintSettings = new Jolt.DistanceConstraintSettings(); constraintSettings.mPoint1 = constraintSettings.mPoint2 = creationSettings.mPosition; constraintSettings.mMinDistance = 0; constraintSettings.mMaxDistance = 1; let prevBody = null; for (let z = 0; z < 10; ++z) { let body = createBody(creationSettings, z); if (prevBody != null) { constraintSettings.mPoint1.SetZ(z - 0.5); constraintSettings.mPoint2.SetZ(z - 0.5); physicsSystem.AddConstraint(constraintSettings.Create(prevBody, body)); } prevBody = body; } } // Hinge constraint creationSettings.mCollisionGroup.SetGroupID(creationSettings.mCollisionGroup.GetGroupID() + 1); creationSettings.mPosition.SetX(creationSettings.mPosition.GetX() + 5); { let constraintSettings = new Jolt.HingeConstraintSettings(); constraintSettings.mPoint1 = constraintSettings.mPoint2 = new Jolt.RVec3(creationSettings.mPosition.GetX(), creationSettings.mPosition.GetY() - 0.5, creationSettings.mPosition.GetZ()); constraintSettings.mHingeAxis1 = constraintSettings.mHingeAxis2 = new Jolt.Vec3(1, 0, 0); constraintSettings.mNormalAxis1 = constraintSettings.mNormalAxis2 = new Jolt.Vec3(0, 1, 0); let prevBody = null; for (let z = 0; z < 10; ++z) { let body = createBody(creationSettings, z); if (prevBody != null) { constraintSettings.mPoint1.SetZ(z - 0.5); constraintSettings.mPoint2.SetZ(z - 0.5); physicsSystem.AddConstraint(constraintSettings.Create(prevBody, body)); } prevBody = body; } } // Slider constraint creationSettings.mCollisionGroup.SetGroupID(creationSettings.mCollisionGroup.GetGroupID() + 1); creationSettings.mPosition.SetX(creationSettings.mPosition.GetX() + 5); { let constraintSettings = new Jolt.SliderConstraintSettings(); constraintSettings.mPoint1 = constraintSettings.mPoint2 = creationSettings.mPosition; constraintSettings.mSliderAxis1 = constraintSettings.mSliderAxis2 = new Jolt.Vec3(0, -1, 1).Normalized(); constraintSettings.mNormalAxis1 = constraintSettings.mNormalAxis2 = constraintSettings.mSliderAxis1.GetNormalizedPerpendicular(); constraintSettings.mLimitsMin = 0; constraintSettings.mLimitsMax = 1; let prevBody = null; for (let z = 0; z < 10; 0.5); physicsSystem.AddConstraint(constraintSettings.Create(prevBody, body)); } prevBody = body; } } }); ``` -------------------------------- ### Initialize JoltPhysics.js and Setup Demo Source: https://github.com/jrouwe/joltphysics.js/blob/main/Examples/falling_shapes.html Initializes JoltPhysics.js and sets up the falling shapes demo. Replace the URL if not building the library locally. The `onUpdate` function is called each frame. ```javascript // In case you haven't built the library yourself, replace URL with: https://www.unpkg.com/jolt-physics/dist/jolt-physics.wasm-compat.js import initJolt from './js/jolt-physics.wasm-compat.js'; initJolt().then(function (Jolt) { // Spawning variables var objectTimePeriod = 0.25; var timeNextSpawn = time + objectTimePeriod; var maxNumObjects = 100; // Initialize this example initExample(Jolt, onUpdate); // Create a basic floor createFloor(); // Create example mesh createMeshFloor(30, 1, 4, 0, 5, 0); function generateObject() { let numTypes = 10; let objectType = Math.ceil(Math.random() * numTypes); let shape = null; let colors = [0xff0000, 0xd9b1a3, 0x4d4139, 0xccad33, 0xf2ff40, 0x00ff00, 0x165943, 0x567371, 0x80d5ff, 0x69778c, 0xbeb6f2, 0x7159b3, 0x73004d, 0xd90074, 0xff8091, 0xbf3030, 0x592400, 0xa66c29, 0xb3aa86, 0x296600, 0x00e600, 0x66ccaa, 0x00eeff, 0x3d9df2, 0x000e33, 0x3d00e6, 0xb300a7, 0xff80d5, 0x330d17, 0x59332d, 0xff8c40, 0x33210d, 0x403c00, 0x89d96c, 0x0d3312, 0x0d3330, 0x005c73, 0x0066ff, 0x334166, 0x1b0066, 0x4d3949, 0xbf8faf, 0x59000c, 0x0000ff] switch (objectType) { case 1: { // Sphere let radius = 0.5 + Math.random(); shape = new Jolt.SphereShape(radius, null); break; } case 2: { // Box let sx = 1 + Math.random(); let sy = 1 + Math.random(); let sz = 1 + Math.random(); shape = new Jolt.BoxShape(new Jolt.Vec3(sx * 0.5, sy * 0.5, sz * 0.5), 0.05, null); break; } case 3: { // Cylinder let radius = 0.5 + Math.random(); let halfHeight = 0.5 + 0.5 * Math.random(); shape = new Jolt.CylinderShape(halfHeight, radius, 0.05, null); break; } case 4: { // Tapered cylinder let topRadius = 0.1 + Math.random(); let bottomRadius = 0.5 + Math.random(); let halfHeight = 0.5 * (topRadius + bottomRadius + Math.random()); shape = new Jolt.TaperedCylinderShapeSettings(halfHeight, topRadius, bottomRadius, null).Create().Get(); break; } case 5: { // Capsule let radius = 0.5 + Math.random(); let halfHeight = 0.5 + 0.5 * Math.random(); shape = new Jolt.CapsuleShape(halfHeight, radius, null); break; } case 6: { // Tapered capsule let topRadius = 0.1 + Math.random(); let bottomRadius = 0.5 + Math.random(); let halfHeight = 0.5 * (topRadius + bottomRadius + Math.random()); shape = new Jolt.TaperedCapsuleShapeSettings(halfHeight, topRadius, bottomRadius, null).Create().Get(); break; } case 7: { // Convex hull let hull = new Jolt.ConvexHullShapeSettings; for (let p = 0; p < 10; ++p) hull.mPoints.push_back(new Jolt.Vec3(-0.5 + 2 * Math.random(), -0.5 + 2 * Math.random(), -0.5 + 2 * Math.random())); shape = hull.Create().Get(); break; } case 8: { // Static compound shape let shapeSettings = new Jolt.StaticCompoundShapeSettings(); let l = 1.0 + Math.random(); let r2 = 0.5 + 0.5 * Math.random(); let r1 = 0.5 * r2; shapeSettings.AddShape(new Jolt.Vec3(-l, 0, 0), Jolt.Quat.prototype.sIdentity(), new Jolt.SphereShapeSettings(r2)); shapeSettings.AddShape(new Jolt.Vec3(l, 0, 0), Jolt.Quat.prototype.sIdentity(), new Jolt.SphereShapeSettings(r2)); shapeSettings.AddShape(new Jolt.Vec3(0, 0, 0), Jolt.Quat.prototype.sRotation(new Jolt.Vec3(0, 0, 1), 0.5 * Math.PI), new Jolt.CapsuleShapeSettings(l, r1)); shape = shapeSettings.Create().Get(); break; } case 9: { // Mutable compound shape let shapeSettings = new Jolt.MutableCompoundShapeSettings(); let l = 1.0 + Math.random(); let r2 = 0.5 + 0.5 * Math.random(); let r1 = 0.5 * r2; shapeSettings.AddShape(new Jolt.Vec3(-l, 0, 0), Jolt.Quat.prototype.sIdentity(), new Jolt.SphereShapeSettings(r2)); shapeSettings.AddShape(new Jolt.Vec3(l, 0, 0), Jolt.Quat.prototype.sIdentity(), new Jolt.BoxShapeSettings(Jolt.Vec3.prototype.sReplicate(r2))); shapeSettings.AddShape(new Jolt.Vec3(0, 0, 0), Jolt.Quat.prototype.sRotation(new Jolt.Vec3(0, 0, 1), 0.5 * Math.PI), new Jolt.CapsuleShapeSettings(l, r1)); shape = shapeSettings.Create().Get(); break; } case 10: { // Sphere with COM offset let radius = 0.5; shape = new Jolt.OffsetCenterOfMassShapeSettings(new Jolt.Vec3(0, -0.1 * radius, 0), new Jolt.SphereShapeSettings(radius, null)).Create().Get(); break; } } // Position and rotate body let pos = new Jolt.RVec3((Math.random() - 0.5) * 25, 15, (Math.random() - 0.5) * 25); let rot = getRandomQuat(); // Create physics body let creationSettings = new Jolt.BodyCreationSettings(shape, pos, rot, Jolt.EMotionType_Dynamic, LAYER_MOVING); creationSettings.mRestitution = 0.5; let body = bodyInterface.CreateBody(creationSettings); addToScene(body, colors[objectType - 1]); } function onUpdate(time, deltaTime) { // Check if its time to spawn a new object if (dynamicObjects.length < maxNumObjects && time > timeNextSpawn) { generateObject(); timeNextSpawn = time + objectTimePeriod; } } }); ``` -------------------------------- ### JoltPhysics.js Initialization and Setup Source: https://github.com/jrouwe/joltphysics.js/blob/main/Examples/conveyor_belt_threaded.html Initializes JoltPhysics.js, sets up the worker script for multi-threading, and configures initial scene parameters like camera position and floor creation. It also demonstrates creating static conveyor belt boxes. ```javascript import initJolt from './js/jolt-physics.multithread.wasm-compat.js'; initJolt().then(function (Jolt) { const contactListener = new Jolt.ContactListenerJS(); const workerUrl = URL.createObjectURL(new Blob([document.getElementById('workerScript').innerHTML], { type: 'text/javascript' })); const workerParams = { contactListenerPtr: Jolt.getPointer(contactListener), angularBelt: new Uint32Array(new SharedArrayBuffer(4)), linearBelts: new Uint32Array(new SharedArrayBuffer(20)) } Jolt.configureWorkerScripts(workerUrl, workerParams); // Initialize this example initExample(Jolt, null); camera.position.z += 60; camera.position.y += 20; camera.position.x += 50; // Create a basic floor createFloor(100); // Create conveyor belts const cBeltWidth = 10.0; const cBeltLength = 50.0; const linearBelts = []; for (let i = 0; i < 4; ++i) { const friction = 0.25 * (i + 1); const rot1 = new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(0, 1, 0), 0.5 * Math.PI * i); const rot2 = new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(1, 0, 0), DegreesToRadians(1.0)); const rotation = rot1.clone().multiply(rot2); const position = new THREE.Vector3(cBeltLength, 6.0, cBeltWidth).applyQuaternion(rotation); const belt = createBox(unwrapRVec3(position), unwrapQuat(rotation), new Jolt.Vec3(cBeltWidth, 0.1, cBeltLength), Jolt.EMotionType_Static, LAYER_NON_MOVING); be ``` -------------------------------- ### Create Pulley Constraint - Example 2 Source: https://github.com/jrouwe/joltphysics.js/blob/main/Examples/constraint_pulley.html Sets up a second pulley constraint with two dynamic boxes, demonstrating different ratios or weights. ```javascript { position.Set(xOffset - 0.6, 4, 0); const box1 = createBox(position, rotation, size, Jolt.EMotionType_Dynamic, LAYER_MOVING); box1.GetMotionProperties().SetInverseMass(1 / 111); const threeBox1 = dynamicObjects[dynamicObjects.length - 1]; position.Set(xOffset + 0.6, 4, 0); const box2 = createBox(position, rotation, size, Jolt.EMotionType_Dynamic, LAYER_MOVING); box1.GetMotionProperties().SetInverseMass(1 / 112); const threeBox2 = dynamicObjects[dynamicObjects.length - 1]; const pulley1 = new Jolt.PulleyConstraintSettings(); createPulleyGraphics(threeBox1, threeBox2, new THREE.Vector3(0, 0.1, 0), new THREE.Vector3(0, 0.1, 0), new THREE.Vector3(xOffset - 1, 9, 0), new THREE.Vector3(xOffset + 1, 9, 0), pulley1); physicsSystem.AddConstraint(pulley1.Create(box1, box2)) } ``` -------------------------------- ### Initialize Jolt Physics and Setup Animation Source: https://github.com/jrouwe/joltphysics.js/blob/main/Examples/rig/powered_rig.html Initializes Jolt Physics, sets up animation sampling for a ragdoll, and creates a dynamic floor. Requires Three.js and Jolt Physics library. ```javascript // In case you haven't built the library yourself, replace URL with: https://www.unpkg.com/jolt-physics/dist/jolt-physics.wasm-compat.js import initJolt from './../js/jolt-physics.wasm-compat.js'; const texLoader = new THREE.TextureLoader(); const texture = texLoader.load('data:image/gif;base64,R0lGODdhAgACAIABAAAAAP///ywAAAAAAgACAAACA0QCBQA7'); texture.wrapS = texture.wrapT = THREE.RepeatWrapping; texture.offset.set(0, 0); texture.repeat.set(20, 20); texture.magFilter = THREE.NearestFilter; initJolt().then(async function (Jolt) { const sAnimations = [ "Neutral", "Walk", "Sprint", "Dead_Pose1", "Dead_Pose2", "Dead_Pose3", "Dead_Pose4" ]; let sAnimationName = "Sprint"; let mAnimation, mPose, mRagdoll; let mAnimationTime = 0; const root_offset = new Jolt.RVec3(); const joint_rot = new Jolt.Quat(); // Initialize this example initExample(Jolt, (mTime, mDeltaTime) => { if (mAnimation && mPose && mRagdoll) { mAnimation.Sample(mAnimationTime, mPose); const joint = mPose.GetJoint(0); joint.mTranslation = Jolt.RVec3.prototype.sZero(); mRagdoll.GetRootTransform(root_offset, joint_rot); joint.mRotation = joint_rot; mPose.SetRootOffset(root_offset); mAnimationTime += mDeltaTime; mPose.CalculateJointMatrices(); mRagdoll.DriveToPoseUsingMotors(mPose); } }); scene.add(new THREE.AmbientLight(0xFFFFFF, 0.2)); // Create a basic floor createFloor(); const floorModel = dynamicObjects[dynamicObjects.length - 1]; floorModel.material.map = texture; let shape = new Jolt.BoxShape(new Jolt.Vec3(0.2, 0.2, 0.2)); const position = new Jolt.RVec3(); const rotation = Jolt.Quat.prototype.sIdentity(); let boxes = []; function buildBoxes() { boxes.forEach(box => { removeFromScene(box); }); boxes = []; for (let i = 0; i < 3; ++i) for (let j = i / 2; j < 10 - (i + 1) / 2; ++j) { position.Set(-2.0 + j * 0.4 + (i & 1 ? 0.2 : 0.0), 0.2 + i * 0.4, -2.0); let creationSettings = new Jolt.BodyCreationSettings(shape, position, rotation, Jolt.EMotionType_Dynamic, LAYER_MOVING); creationSettings.mFriction = 0.1; creationSettings.mOverrideMassProperties = Jolt.EOverrideMassProperties_CalculateInertia; creationSettings.mMassPropertiesOverride.mMass = 1; let body = bodyInterface.CreateBody(creationSettings); addToScene(body, 0x00ffff); boxes.push(dynamicObjects[dynamicObjects.length - 1]); } } const dropdown = document.getElementById('sAnimations'); sAnimations.forEach(type => { const option = document.createElement('option'); option.value = type; option.innerText = type; dropdown.appendChild(option); }); dropdown.value = sAnimationName; const mRagdollSettings = await RagdollLoader.load(Jolt, "../assets/Human/Human.tof", Jolt.EMotionType_Dynamic, "Ragdoll"); mRagdollSettings.DisableParentChildCollisions(); mRagdoll = mRagdollSettings.CreateRagdoll(0, 0, physicsSystem); mRagdoll.AddToPhysicsSystem(Jolt.EActivation_Activate); // Create ragdoll let bodyCount = mRagdoll.GetBodyCount(); for (let i = 0; i < bodyCount; i++) { const bodyID = mRagdoll.GetBodyID(i); let body = physicsSystem.GetBodyLockInterfaceNoLock().TryGetBody(bodyID); addToThreeScene(body, 0xFF00FF); } mPose = new Jolt.SkeletonPose(); mPose.SetSkeleton(mRagdollSettings.GetSkeleton()); async function loadAnimation() { if (mAnimation) { Jolt.destroy(mAnimation); mAnimation = undefined; } buildBoxes(); sAnimationName = dropdown.value; mAnimation = await RagdollLoader.loadAnimation(Jolt, "../assets/Human/animations/" + sAnimationName.toLocaleLowerCase() + ".tof"); mAnimationTime = 0; // Drive the ragdoll to the first frame of the animation using motors mAnimation.Sample(0.0, mPose); mPose.CalculateJointMatrices(); mRagdoll.SetPose(mPose); // Wake up, in case we tried to animate to a Pose and all bodies are sleeping mRagdoll.Activate(); } dropdown.onchange = () => loadAnimation(); loadAnimation(); // Position the camera camera.position.z = -8; camera.position.y = 3; }); ``` -------------------------------- ### Initialize JoltPhysics.js and Basic Setup Source: https://github.com/jrouwe/joltphysics.js/blob/main/Examples/proper_cleanup.html Initializes the Jolt physics engine and sets up basic collision layers and filters. Ensure the Jolt WASM module is correctly imported. ```javascript import initJolt from './js/jolt-physics.wasm-compat.js'; initJolt().then(function (Jolt) { // Record how much memory we have in the beginning const memoryFreeBefore = Jolt.JoltInterface.prototype.sGetFreeMemory()); // Create very simple object layer filter with only a single layer const MY_LAYER = 0; let objectFilter = new Jolt.ObjectLayerPairFilterTable(1); objectFilter.EnableCollision(MY_LAYER, MY_LAYER); // Create very simple broad phase layer interface with only a single layer const BP_LAYER = new Jolt.BroadPhaseLayer(0); let bpInterface = new Jolt.BroadPhaseLayerInterfaceTable(1, 1); bpInterface.MapObjectToBroadPhaseLayer(MY_LAYER, BP_LAYER); Jolt.destroy(BP_LAYER); // 'BP_LAYER' has been copied into bpInterface // Create broad phase filter let bpFilter = new Jolt.ObjectVsBroadPhaseLayerFilterTable(bpInterface, 1, objectFilter, 1); // Initialize Jolt let settings = new Jolt.JoltSettings(); settings.mObjectLayerPairFilter = objectFilter; settings.mBroadPhaseLayerInterface = bpInterface; settings.mObjectVsBroadPhaseLayerFilter = bpFilter; let jolt = new Jolt.JoltInterface(settings); // Everything in 'settings' has now been copied into 'jolt', the 3 interfaces above are now owned by 'jolt' Jolt.destroy(settings); // Typing shortcuts let physicsSystem = jolt.GetPhysicsSystem(); let bodyInterface = physicsSystem.GetBodyInterface(); ```