schteppe / cannon.js

A lightweight 3D physics engine written in JavaScript.
http://schteppe.github.com/cannon.js
MIT License
4.63k stars 700 forks source link

Raycaster Vehicle not working in the positive Z axis #466

Closed JackBiofryd closed 2 years ago

JackBiofryd commented 2 years ago

Hey! So, I managed to make the Raycaster vehicle work properly, except for one huge bug. Whenever I try to drive with the vehicle in the positive z axis it glitches through the floor a bit down (about half of the wheels are below the plane) and slides to infinity. I have had this bug for a very very long time and I have no idea how to fix it. I don't think my code is the problem because I followed the examples completely. Any ideas? It might be because of the materials. Changing the default contact material changes how much the car slides (how fast), but no value fixes the bug.

Here is what the glitch looks like before it starts sliding: 123

Here's my code: ` const canvas = document.querySelector('canvas.webgl'); // Scene const scene = new THREE.Scene();

// Physics world const world = new CANNON.World(); world.gravity.set(0, -9.81, 0); world.defaultContactMaterial.friction = 0; const groundMaterial = new CANNON.Material('groundMaterial'); const wheelMaterial = new CANNON.Material('wheelMaterial'); const wheelGroundContactMaterial = new CANNON.ContactMaterial( wheelMaterial, groundMaterial, { friction: 0.3, restitution: 0, contactEquationStiffness: 1000 } ); world.addContactMaterial(wheelGroundContactMaterial); // Performance world.broadphase = new CANNON.SAPBroadphase(world); world.allowSleep = true;

// Cameras const camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 0.1, 1000 ); camera.position.set(10, 10, 10);

// Lights const ambientLight = new THREE.AmbientLight(0xffffff, 0.7); const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8); directionalLight.position.set(10, 12, 0);

scene.add(ambientLight, directionalLight);

// Planes const plane = new THREE.Mesh( new THREE.PlaneBufferGeometry(100, 100), new THREE.MeshStandardMaterial({ metalness: 0.3, roughness: 0.4, color: '#777777' }) ); plane.rotation.x = Math.PI * -0.5;

const planeBody = new CANNON.Body({ shape: new CANNON.Plane(), mass: 0, material: groundMaterial, position: new CANNON.Vec3(0, 0, 0) }); planeBody.quaternion.setFromAxisAngle(new CANNON.Vec3(1, 0, 0), Math.PI * -0.5);

world.addBody(planeBody); scene.add(plane);

/**

// Vehicle physics body const chassisShape = new CANNON.Box(new CANNON.Vec3(0.4, 0.25, 0.75)); const chassisBody = new CANNON.Body({ mass: 1500 }); chassisBody.addShape(chassisShape); chassisBody.position.set(1, 2, -3); chassisBody.angularVelocity.set(0, 0, 0); // Initial velocity

// Vehicle Three.js mesh const chassisGeometry = new THREE.BoxBufferGeometry(0.8, 0.5, 1.5); const chassisMaterial = new THREE.MeshStandardMaterial({ metalness: 0.8, roughness: 0.4, color: '#DF2800' }); const chassisMesh = new THREE.Mesh(chassisGeometry, chassisMaterial); scene.add(chassisMesh); chassisMesh.castShadow = true;

// Parent vehicle object const vehicle = new CANNON.RaycastVehicle({ chassisBody: chassisBody, indexRightAxis: 0, // x indexUpAxis: 1, // y indexForwardAxis: 2 // z });

// Wheels const wheelOptions = { radius: 0.2, directionLocal: new CANNON.Vec3(0, -1, 0), suspensionStiffness: 45, suspensionRestLength: 0.4, frictionSlip: 5, dampingRelaxation: 2.3, dampingCompression: 4.5, maxSuspensionForce: 200000, rollInfluence: 0.01, axleLocal: new CANNON.Vec3(-1, 0, 0), chassisConnectionPointLocal: new CANNON.Vec3(1, 1, 0), maxSuspensionTravel: 0.25, customSlidingRotationalSpeed: -30, useCustomSlidingRotationalSpeed: true };

const axlewidth = 0.4; wheelOptions.chassisConnectionPointLocal.set(axlewidth, 0.1, -0.7); vehicle.addWheel(wheelOptions); wheelOptions.chassisConnectionPointLocal.set(-axlewidth, 0.1, -0.7); vehicle.addWheel(wheelOptions); wheelOptions.chassisConnectionPointLocal.set(axlewidth, 0.1, 0.7); vehicle.addWheel(wheelOptions); wheelOptions.chassisConnectionPointLocal.set(-axlewidth, 0.1, 0.7); vehicle.addWheel(wheelOptions);

vehicle.addToWorld(world);

const wheelBodies = [], wheelMeshes = [];

vehicle.wheelInfos.forEach(wheel => { // Wheel physics body const shape = new CANNON.Cylinder( wheel.radius, wheel.radius, wheel.radius / 2, 20 ); const body = new CANNON.Body({ mass: 1, material: wheelMaterial }); var q = new CANNON.Quaternion(); q.setFromAxisAngle(new CANNON.Vec3(1, 0, 0), Math.PI / 2); body.addShape(shape, new CANNON.Vec3(), q); wheelBodies.push(body);

// Wheel Three.js mesh
const wheelGeometry = new THREE.CylinderGeometry(
    wheel.radius,
    wheel.radius,
    0.1,
    32
);
const wheelMeshMaterial = new THREE.MeshPhongMaterial({
    color: 0xff9852
});
const cylinder = new THREE.Mesh(wheelGeometry, wheelMeshMaterial);
cylinder.geometry.rotateZ(Math.PI / 2);
cylinder.castShadow = true;
wheelMeshes.push(cylinder);
scene.add(cylinder);

});

// Update the wheels to match the physics world.addEventListener('postStep', function () { chassisBody.wakeUp();

for (let i = 0; i < vehicle.wheelInfos.length; i++) {
    vehicle.updateWheelTransform(i);
    const t = vehicle.wheelInfos[i].worldTransform;

    console.log(t.position.y);

    // Update wheel physics bodies
    wheelBodies[i].position.copy(t.position);
    wheelBodies[i].quaternion.copy(t.quaternion);

    // Update wheel meshes
    wheelMeshes[i].position.copy(t.position);
    wheelMeshes[i].quaternion.copy(t.quaternion);
}

});

const moveCar = e => { if (e.type !== 'keydown' && e.type !== 'keyup') return;

const keyup = e.type === 'keyup';

vehicle.setBrake(0, 0);
vehicle.setBrake(0, 1);
vehicle.setBrake(0, 2);
vehicle.setBrake(0, 3);

const engineForce = 2000,
    maxSteerVal = 0.3;

switch (e.keyCode) {
    case 38: // Forward
        vehicle.applyEngineForce(keyup ? 0 : -engineForce, 2);
        vehicle.applyEngineForce(keyup ? 0 : -engineForce, 3);
        break;

    case 40: // Backward
        vehicle.applyEngineForce(keyup ? 0 : engineForce, 0);
        vehicle.applyEngineForce(keyup ? 0 : engineForce, 1);
        break;

    case 39: // Right
        vehicle.setSteeringValue(keyup ? 0 : -maxSteerVal, 2);
        vehicle.setSteeringValue(keyup ? 0 : -maxSteerVal, 3);
        break;

    case 37: // Left
        vehicle.setSteeringValue(keyup ? 0 : maxSteerVal, 2);
        vehicle.setSteeringValue(keyup ? 0 : maxSteerVal, 3);
        break;
}

}; window.onkeydown = moveCar; window.onkeyup = moveCar;

// Controls const controls = new OrbitControls(camera, canvas); controls.enableDamping = true;

const h = new THREE.AxesHelper(10); scene.add(h);

// Renderer const renderer = new THREE.WebGLRenderer({ canvas, antialias: true }); renderer.setSize(window.innerWidth, window.innerHeight); renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)); renderer.render(scene, camera);

renderer.shadowMap.enabled = true; renderer.shadowMap.type = THREE.PCFSoftShadowMap;

directionalLight.castShadow = true; directionalLight.shadow.mapSize.width = 1024; directionalLight.shadow.mapSize.height = 1024; directionalLight.shadow.camera.far = 20;

plane.receiveShadow = true;

// Animation const clock = new THREE.Clock(); let oldTime = 0;

const tick = () => { const elapsedTime = clock.getElapsedTime(); const frameTime = elapsedTime - oldTime; oldTime = elapsedTime;

// Update controls
controls.update();

// Update physics
world.step(1 / 60, frameTime, 3);
chassisMesh.position.copy(chassisBody.position);
chassisMesh.quaternion.copy(chassisBody.quaternion);

// Render
renderer.render(scene, camera);
// Run tick on next frame
window.requestAnimationFrame(tick);

};

tick();

// Resize scene on window resize window.onresize = () => { camera.aspect = window.innerWidth / window.innerHeight; camera.updateProjectionMatrix();

renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));

};

`

JackBiofryd commented 2 years ago

After trying things for so long, the bug was the rotation of the plane. My mistake. I replaced the planes with: ` const plane = new THREE.Mesh( new THREE.PlaneBufferGeometry(100, 100), new THREE.MeshStandardMaterial({ metalness: 0.3, roughness: 0.4, color: '#777777' }) ); plane.rotation.x = Math.PI * -0.5;

const q = plane.quaternion; const planeBody = new CANNON.Body({ shape: new CANNON.Plane(), mass: 0, material: groundMaterial, position: new CANNON.Vec3(0, 0, 0), quaternion: new CANNON.Quaternion(q.x, q.y, q.z, q.w) }); planeBody.quaternion.setFromAxisAngle(new CANNON.Vec3(1, 0, 0), Math.PI * -0.5);

world.addBody(planeBody); scene.add(plane);

`