Hi all! I’m working on a 3D project using Three.js along with Cannon.js for physics. I’m trying to make a spherical world (imagine a mini-planet) where a car can be driven around the sphere.
I want the car to be able to drive anywhere on this sphere with the gravity keeping it attached to the sphere’s surface, regardless of where it is. In physics terms I want gravity to be spherical.
Initially, I tried this for gravity:
this.physicsworld.gravity.set(0, -10, 0)
This helps the car stay on the North Pole, but as soon as the car starts moving, it falls off.
I then tried this within my update method:
this.physicsworld.bodies.forEach(b => {
if (b.mass !== 0) {
const v = new CANNON.Vec3()
v.set(-b.position.x, -b.position.y, -b.position.z).normalize()
v.scale(98, b.force)
console.log(v)
b.applyLocalForce(v)
}
})
This makes the car stick to the sphere, but moving it around is really challenging.
Any ideas on how to make the car move smoothly?
Here is the MRE:
import * as CANNON from 'cannon-es'
import * as THREE from 'three'
export default class Physics {
constructor() {
// Setup
this.setPhysicsWorld();
this.setPhysicsFloor();
// Time tick event
this.time.on('tick', () => {
this.update();
});
}
setPhysicsWorld() {
this.physicsworld = new CANNON.World();
this.physicsworld.gravity.set(0, -10, 0); // Initially set to 0 since we'll be computing gravity dynamically
this.physicsworld.broadphase = new CANNON.SAPBroadphase(this.physicsworld);
this.physicsworld.solver.iterations = 10;
// Materials
this.defaultMaterial = new CANNON.Material('default');
this.defaultContactMaterial = new CANNON.ContactMaterial(
this.defaultMaterial,
this.defaultMaterial,
{
friction: 0.4,
restitution: 0.1
}
);
this.physicsworld.addContactMaterial(this.defaultContactMaterial);
}
setPhysicsFloor() {
const radius = this.physicsfloor.geometry.parameters.radius;
const groundShape = new CANNON.Sphere(radius);
this.groundBody = new CANNON.Body({
mass: 0,
position: new CANNON.Vec3(0, 0, 0), // Position at the center.
shape: groundShape
});
this.physicsworld.addBody(this.groundBody);
}
update() {
// Updating gravity dynamically (code commented out)
// this.physicsworld.bodies.forEach(b => {
// if (b.mass !== 0) {
// const v = new CANNON.Vec3();
// v.set(-b.position.x, -b.position.y, -b.position.z).normalize();
// v.scale(98, b.force);
// b.applyLocalForce(v);
// }
// });
this.physicsworld.step(1 / 60, this.time.delta, 3);
// Code for updating positions and orientations of the dummy vehicle (simplified)
this.bodyMesh.position.copy(this.chassisBody.position);
this.bodyMesh.quaternion.copy(this.chassisBody.quaternion);
// ... further code for updating vehicle's mesh ...
}
}