schteppe / cannon.js

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

Momentum not conserved #497

Open Jasbir23 opened 3 months ago

Jasbir23 commented 3 months ago

I am trying to implement ideal world physics. When an object collides with a static body, the momentum should be conserved, however the velocity after collision is more than the initial velocity of the object. here is a code snippet -

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Cannon.js Collision Example</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/cannon.js/0.6.2/cannon.min.js"></script>
  </head>
  <body>
    <h1>Cannon.js Collision Example</h1>
    <pre id="output"></pre>
    <script>
      // Setup world
      const world = new CANNON.World();
      world.gravity.set(0, 0, 0);

      // Define materials and contact material
      const dynamicMaterial = new CANNON.Material("dynamicMaterial");
      const staticMaterial = new CANNON.Material("staticMaterial");
      const contactMaterial = new CANNON.ContactMaterial(
        dynamicMaterial,
        staticMaterial,
        {
          friction: 0,
          restitution: 1,
        }
      );
      world.addContactMaterial(contactMaterial);

      // Create dynamic body
      const dynamicShape = new CANNON.Sphere(1);
      const dynamicBody = new CANNON.Body({
        mass: 5,
        material: dynamicMaterial,
      });
      dynamicBody.addShape(dynamicShape);
      dynamicBody.position.set(0, 10, 0);
      dynamicBody.velocity.set(0, -10, 0);
      world.addBody(dynamicBody);
      dynamicBody.linearDamping = 0;
      dynamicBody.angularDamping = 0;

      // Create static body
      const staticShape = new CANNON.Plane();
      const staticBody = new CANNON.Body({
        mass: 0, // static body
        material: staticMaterial,
      });
      staticBody.addShape(staticShape);
      staticBody.position.set(0, 0, 0);
      staticBody.quaternion.setFromEuler(-Math.PI / 2, 0, 0); // Ensure the plane is horizontal
      world.addBody(staticBody);

      // Output element
      const output = document.getElementById("output");

      // Simulate world
      const timeStep = 1 / 60;
      for (let i = 0; i < 400; i++) {
        world.step(timeStep);
        const time = (i * timeStep).toFixed(2);
        const position = dynamicBody.position.y.toFixed(2);
        const velocity = dynamicBody.velocity.y.toFixed(2);
        output.innerHTML += `Time: ${time}<br>`;
        output.innerHTML += `Dynamic body position: ${position}<br>`;
        output.innerHTML += `Dynamic body velocity: ${velocity}<br><br>`;
      }
    </script>
  </body>
</html>

Here initial velocity of the body is -10 and after collision the velocity becomes 11.53. Ideally, the velocity should have become 10 after collision since restitution is 1.

Jasbir23 commented 3 months ago

I am facing similar issues with non static bodies as well when trying to create perfectly elastic collisions.

Body 1 mass = 1 position = (-10,0,0) Velocity = 10 units (along x axis)

Body 2 mass = 1 position = (0,0,0) Velocity = 0

After collision - Body 1 velocity = -0.77 Body 2 velocity = 10.77

Where is this extra 0.77 coming from ? Restitution is 1