Body behaving erratically when pivot point is away from centre of mass (?)
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);
}
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.
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.
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.
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:
-
It works at certain scales, this smaller example doesn't seem to have any issues: https://jsfiddle.net/Oli414/q5p0hzfg/
-
It works if the compound only consists of 1 part: https://jsfiddle.net/Oli414/4a7ywgmf/
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.
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.