Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Body behaving erratically when pivot point is away from centre of mass (?) #1240

Open
jes opened this issue Sep 3, 2023 · 5 comments
Open

Comments

@jes
Copy link

jes commented Sep 3, 2023

Hi, I'm trying to make a clock escapement simulator using Matter.js. It should be a very simple problem as there are only 2 degrees of freedom (rotation of the escape wheel, rotation of the anchor).

However I am having trouble modelling the anchor because I want it to pivot around a point that is quite far away from the centre of mass.

I have made this minimal test case to demonstrate the problem: https://incoherency.co.uk/matterjs-test-case/

Can anyone suggest what I should do about this?

The JavaScript source is:

"use strict";

let Engine = Matter.Engine,
    Render = Matter.Render,
    Runner = Matter.Runner,
    Bodies = Matter.Bodies,
    Body = Matter.Body,
    Composite = Matter.Composite,
    Constraint = Matter.Constraint,
    Mouse = Matter.Mouse,
    MouseConstraint = Matter.MouseConstraint;

let engine = Engine.create();
let render = Render.create({
    element: document.getElementById('matter'),
    engine: engine,
});
let runner = Runner.create();

let mouseConstraint = MouseConstraint.create(engine, {
    mouse: Mouse.create(render.canvas),
    constraint: { render: { visible: true, } }
});
Composite.add(engine.world, mouseConstraint);

addBody(200, 0); // 200 is the x location, 0 is the pivot offset (this body behaves sensibly but is not what I want
addBody(600, -113); // 600 is the x location, -113 is the pivot offset (this body is what I want but behaves erratically)

Render.run(render);
Runner.run(runner, engine);

function addBody(xLocation, yPivotOffset) {
    let p1 = makePart(-45, 160, 15);
    let p2 = makePart(45, 160, 15);

    let body = Body.create({parts: [p1, p2]});
    Body.translate(body, {x:xLocation, y:300});

    let constraint = Constraint.create({
        pointA: {x: xLocation, y: 300},
        bodyB: body,
        pointB: {x:0, y:yPivotOffset},
    });

    Composite.add(engine.world, [body, constraint]);
}

function makePart(angle, distance, radius) {
    let x = distance * Math.sin(angle * Math.PI/180);
    let y = distance * Math.cos(angle * Math.PI/180);
    return Bodies.circle(x, y, radius);
}
@jes
Copy link
Author

jes commented Sep 3, 2023

If I change yPivotOffset of the first body from 0 to -1, then it also exhibits erratic behaviour sometimes, but not quite as easily.

It certainly seems that there is something wrong whenever the pivot is anywhere other than the centre of mass.

@jes
Copy link
Author

jes commented Sep 3, 2023

I have found a solution: https://incoherency.co.uk/matterjs-test-case/fixed.html

I needed to leave the two balls as separate bodies and constrain their locations with constraints, instead of trying to turn them into oen body.

It seems like this is a bug in compound bodies, since to my mind the two methods should give the same outcome.

@oli414
Copy link

oli414 commented Nov 8, 2023

I seem to be running into this bug as well:

https://jsfiddle.net/Oli414/2gapbwoq/

@jes did you notice a performance difference with your solution compared to using a compound? I'd expect there to be some extra overhead. I'm a bit concerned about using your solution at a larger scale.

@oli414
Copy link

oli414 commented Nov 9, 2023

I've been trying to dig a bit deeper, I might have found the underlying issue. But for now the best I've got is a better temporary solution.

First of all some discoveries regarding this bug:

With that in mind I ended up cloning the repo to see if I could figure out what was going on, focusing on a single iteration of the constraint solver. I found that there was a discrepancy in the inertia value between single-part bodies and multi-part bodies.

A compound consisting of 3 squares (3 times 64x64, forming a 192x64 rectangle) has an inertia of 33554.432 as opposed to a single rectangle having an inertia of 167772.16 (1 time 192x64), 5 times that of the 3 separate squares.

You can manually set the compound's inertia to the correct value and the constraint starts to behave identically to a constraint with a non-compound body.
https://jsfiddle.net/Oli414/dw8zf3yn/

I'm don't know enough about the inner workings of this physics engine to make a bugfix, but something seems off about the way the inertia is calculated for compound bodies.

@jes
Copy link
Author

jes commented Dec 8, 2023

Thanks for looking at this. No I did not notice any performance difference, but I'm only using 2 balls, so I wouldn't.

Your finding that the inertia is calculated incorrectly for compound bodies sounds promising.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants