Mesh linkage with (physics-free) constraints

Hello !

  • As far as I know, BabylonJS mesh constraints are physics oriented. (Please tell me if I’m wrong).
  • In Blender, there is something that I use very often which is the Transformation Constraint which ables to map a transform from a mesh to another, without any physics :
  • With these, in many case you can get rid of working with rigging, just adding a constraint, like “This mesh rotates X when that mesh moves Y

I propose to discuss adding a mesh.link method, very similar to the above constraint.
The code would be something like this :

  • pTR = parent Transform (ex : "position")
  • pAX = parent Axis (ex : "x")
  • pmin = parent min (ex : -1)
  • pmax = parent max (ex : 1)
  • cTR, cAX, cmin, cmax etc with child
function link(parent, child, pTR, pAX, pmin, pmax, cTR, cAX, cmin, cmax){
    parent.getScene().onBeforeRenderObservable.add(()=>{
        const value = parent[pTR][pAX];
        const param = (value-pmin)/(pmax-pmin);
        child[cTR][cAX] = cmin+param*(cmax-cmin);
    })
}

Also, in case we don’t want a linear mapping, we could add a custom function :

function link(parent, child, pTR, pAX, pmin, pmax, cTR, cAX, cmin=undefined, cmax=undefined, custom=undefined){
    parent.getScene().onBeforeRenderObservable.add(()=>{
        const value = parent[pTR][pAX];
        if(custom){
            child[cTR][cAX] = custom(value);
        } else {
            const param = (value-pmin)/(pmax-pmin);
            child[cTR][cAX] = cmin+param*(cmax-cmin);
        }
    })
}

Of course I’m not detailing the final implementation here :

  • Would be a new method of TransformNode, I guess
  • Would return the observable, with ability to delete with another unlink function.
  • etc…

As a Proof of Concept, I have done an example using the Buggy GLTF asset :

Screencast from 27-03-2025 16:12:23

Screencast from 27-03-2025 16:13:04

As you can see there are a total of 8 linkage, merging rotation, translation, etc.
The full “no rig” code is here :

// Wheeling
const wheeling = new BABYLON.TransformNode("wheeling");

// Link Wheels
link(wheeling, Axle_2, "rotation", "y", -1, 1, "rotation", "y", -1+Math.PI/2, 1+Math.PI/2);
link(Axle_2, Axle_3, "rotation", "y", -1, 1, "rotation", "y", -1, 1);
link(Axle_2, Axle_4, "rotation", "y", -1, 1, "rotation", "y", 1, -1);
link(Axle_2, Axle_5, "rotation", "y", -1, 1, "rotation", "y", 1, -1);

// Link Slider_0 (front)
const pos0 = Slider_0.position.clone();
link(Axle_2, Slider_0, "rotation", "y", -1, 1, "position", "x", null, null, (value)=>{
    return pos0.x+0.5*Math.cos(value);
});
link(Axle_2, Slider_0, "rotation", "y", -1, 1, "position", "z", null, null, (value)=>{
    return pos0.z+0.5-0.5*Math.sin(value);
});

// Link Slider_1 (back)
const pos1 = Slider_1.position.clone();
link(Slider_0, Slider_1, "position", "x", -1, 1, "position", "x", -1, 1);
link(Slider_0, Slider_1, "position", "z", pos0.z-1, pos0.z+1, "position", "z", pos1.z+1, pos1.z-1);

// Link Axles
link(Slider_0, Axle_1, "position", "x", -1, 1, "rotation", "z", 0.15+7.8, 0.15-7.8);
link(Axle_1, Axle_0, "rotation", "z", -1, 1, "rotation", "y", 0.1-1, 0.1+1);

What I like about this, is that since observable will be triggered in the same order than added, there in actually a perfect constraint chaining :

  • I start from wheeling which is just a Transform Node I plan to rotate
  • Passed to wheel_0 with specific angle mapping
    • passed to all 3 wheels as a copy (modulo revert)
  • Passed toward translation with custom sinus function (slider)
  • Passed toward rotation (horizontal axle)
  • Passed toward rotation (vertical axle)

Here is the PG demo :

NB: Please note that this custom GLB is just a renaming and remapping of hierarchy from the original GLB. All meshes are at the same pos, same transforms, no RIG

NB2: Topic about reworking this Buggy ! :slight_smile:

4 Likes

I believe there should be possibility for some easing.

Absolutely ! As well as adding an “influence” param like in Blender, we could set several ease options :slight_smile:

I can’t decide if easing should be implemented as a velocity easing, but if so then this is starting to become more “physics-based” than “simple links”. I kind of look to physics 6dof axis constraints and add a distance point-to-point constraint. All with animation-style easing? Is that too much? What about other than point to point?