mesh.registerAfterWorldMatrixUpdate - Bug or Feature?

Hi, I am not sure this if this is a bug or a feature…

I am tracking 3D movements of sphere meshes by projecting them down onto a “ground plane” where correspondingly colored tubes move in the ground plane tracking the Y component of the sphere meshes.

Kind of a “drop vertical shadow onto the ground” for each sphere except that the ‘shadow’ is a colored rod that ‘rolls’ back and forth ( in the Y direction only ) dependent on where the parent sphere is positioned above.

I registered a routine as callback on each sphere mesh which simply calls

sphere.registerBeforeRender(function(mesh){
var absPos = mesh.getAbsolutePosition();
mesh.metadata.spotLine.translate( newBABYLON.Vector3(0, absPos.y, -100), 1 );
}

The metadata field is used to link the sphere with its colored rod or ‘spotLine’, I am not using the usual parent-child relationship because I want the rod to only respond to changes in the Y direction.

This was working great and as expected until I noticed that if I zoomed in so that a sphere was not visible then the corresponding colored rod was not updating position anymore.

“Duhhhhh” - my callback was triggered by a Render event so of course Babylon is well written and does not waste time rendering things that will not be seen anyway - my callback stops being called as soon as a sphere moves out of view.

Ok so thenI then changed the event type to ‘registerAfterWorldMatrixUpdate’ - so that my code would be called whenever the sphere mesh was moved.

Then I had a problem, infinite recursion because my callback function uses var absPos = mesh.getAbsolutePosition();

At first glance ‘getAbsolutePosition()’ would appear to be a “read only” operation but I guess if concurrent code is a factor then it might be necessary to somehow ‘lock’ the mesh, apply any pending transformations - then read the result and ‘unlock’ the mesh in which case ‘getAbsolutePosition()’ might be considered more of a ‘read and write’ operation.

==============================

Traceback

My routine is called ‘addSpot’ - I would add that this “infinite” recursion is actually happening at the stage when I first create the sphere with my routine addSpot() and then attempt to register my callback function with “registerAfterWorldMatrixUpdate”.

10:54:15.270 too much recursion babylon.js:16:1
_update http://localhost/Babylon.js-master/dist/babylon.js:16
update http://localhost/Babylon.js-master/dist/babylon.js:16
_updateBoundingInfo http://localhost/Babylon.js-master/dist/babylon.js:16
_afterComputeWorldMatrix http://localhost/Babylon.js-master/dist/babylon.js:16
computeWorldMatrix http://localhost/Babylon.js-master/dist/babylon.js:16
getAbsolutePosition http://localhost/Babylon.js-master/dist/babylon.js:16
addSpot http://localhost/Babylon.js-master/sandbox/skeletonBone1.12.js:281
notifyObservers http://localhost/Babylon.js-master/dist/babylon.js:16
computeWorldMatrix http://localhost/Babylon.js-master/dist/babylon.js:16
getAbsolutePosition http://localhost/Babylon.js-master/dist/babylon.js:16
addSpot http://localhost/Babylon.js-master/sandbox/skeletonBone1.12.js:281
notifyObservers http://localhost/Babylon.js-master/dist/babylon.js:16
computeWorldMatrix http://localhost/Babylon.js-master/dist/babylon.js:16
getAbsolutePosition http://localhost/Babylon.js-master/dist/babylon.js:16
addSpot http://localhost/Babylon.js-master/sandbox/skeletonBone1.12.js:281
notifyObservers http://localhost/Babylon.js-master/dist/babylon.js:16
computeWorldMatrix http://localhost/Babylon.js-master/dist/babylon.js:16
getAbsolutePosition http://localhost/Babylon.js-master/dist/babylon.js:16
addSpot http://localhost/Babylon.js-master/sandbox/skeletonBone1.12.js:281

I am having a little difficultly expressing the question behind all of this but I will have a go…

I guess it boils down to asking something about the nature of concurrent operations, it is possible for getAbsolutePosition to trigger meaningful (by meaningful I mean real positional change has been written) to the matrix for the mesh in question in the sense that the mesh has been transformed during the call - OR - is the mesh position unchanging for the duration of the getAbsolutePosition call and hence it is not strictly necessary for BabylonJS to issue an event that will fire up registerAfterWorldMatrixUpdate and so lead to infinite recursion?

I don’t have an infinite recursion when calling getAbsolutePosition inside the registerAfterWorldMatrixUpdate callback:

https://playground.babylonjs.com/#KYLSMM

I think you will need to provide a PG so that we can have a look.

Evgeni_Popov

Thanks for the fast reply, I noted your suggestion “I think you will need to provide a PG so that we can have a look.”

My project is v.large as it is a rigged human skeleton.

In a sense trying to cut down to a workable example for PG is very similar to the task of taking your PG code and integrating it into mine and seeing if my problem goes away.

I can see your code works - it is expressed differently to mine.

I will work away at your PG and my code in parallel and see if I can isolate which could equally result in a PG or alternatively an understanding which I will post here.

Thanks - Jon

1 Like

Update - one essential difference in my code compared with Evgeni_Popov’s PG is that my sphere is owned by another mesh ( actually a skeletal bone ) - the sphere is a ‘marker’ that moves with the skeleton bone and projects a colored line vertically on the floor for analysis of postural movements.

I commented out the line of code that parented the sphere with the owning bone and the infinite recursion disappeared.

I then locally edited Evgeni_Popov’s code and added an arbitary second sphere to be parent on the first sphere but I could not reproduce the infinite recursion.

This at least gives me a handle on the problem and an avenue to explore but I suspect it will take quite a few debug sessions to get the root of the problem.

As promised I will post here when I have anything of value to be shared.

1 Like

Are you sure your addSpot method does not update the mesh position/rotation/scale (maybe indirectly through some other calls)?

This method is called in the onAfterWorldMatrixUpdateObservable event, so if it modifies the mesh in any way, the call to getGlobalPosition will retrigger a world matrix computation, which will retrigger the onAfterWorldMatrixUpdateObservable event, and so on.

Hi Evgeni Popov,

I have been checking for any hidden relationships that I might have coded but so far nothing has turned up, I am going to carry on looking at this to see if I can break the problem open.

Thanks Jon