Prevent excessive `onViewMatrixChangedObservable`

My project occasionally runs some heavy pickWithRay in onViewMatrixChangedObservable.

I had to profile to improve my project’s performance.

I’ve found some logic scene.render() with camera.getViewMatrix somehow calls Observable.notifyObservers multiple times in a single frame.
I’ve already changed every camera.getViewMatrix() in my domain to camera._worldMatrix to prevent infinite onViewMatrixChangedObservable.notiftyObservers.

  1. Why does the engine call onViewMatrixChangedObservable.notiftyObservers inside getViewMatrix?
  2. Why does the engine update the camera before this.onBeforeRenderObservable.notifyObservers(this); and run _processSubCameras after.
  3. What is the best refactoring for me to fix this problem?

Any suggestions or inputs are appreciated :bowing_man:

1 Like

onViewMatrixChangedObservable should be notified only when the view matrix changes, or when true is passed to getViewMatrix (force parameter). The first three lines of this function are:

        if (!force && this._isSynchronizedViewMatrix()) {
            return this._computedViewMatrix;
        }
        <onViewMatrixChangedObservable is notified in later code>

If you can setup a repro, we can have a look at why you get too many notifications.

Regarding 2/, scene.render first update all cameras of the scene, then loop over the cameras and call _processSubCameras

1 Like

I think changing camera matrix in beforeRender causes another onViewMatrixChangedObservable notification.

The naming or method getWorldMatrix is misleading and has sideffects.

I’ve refactored my code to

  1. flag whenever onViewMatrixChangedObservable is notified
  2. move original observers to beforeRender and run only if the flag is true
  3. and release the flag after each frame

How about we do the similar in the engine?
Do notification in scene render or some places that insures frame cycle.
It might be a breaking change, but I plead it clears things out.

1 Like

As explained, with the existing code, the view matrix should only be recalculated when necessary. It would be great if you could setup a repro of your bug so that we can fix it on our side!

3 Likes

My current project is complex to replicate the whole reproduction in playground.

let me give you worst case scenario:

onViewMatrixChangedObservable causing Maximum call stack size exceeded | Babylon.js Playground (babylonjs.com)

some mild one:

How am I supposed to know Camera.getDirection might cause viewMatrixChanged?

excessive onViewMatrixChangedObservable | Babylon.js Playground (babylonjs.com)

current workaround:

workaround excessive onViewMatrixChangedObservable | Babylon.js Playground (babylonjs.com)

I know some logic like changing matrix inside notification is better to be avoided.
It should be at least documented.

More minimal https://playground.babylonjs.com/#26JHWG#3

I would say on the one hand this is expected behaviour. You are calling the function that triggers the callback from within the callback. But on the other hand, would be nice if Babylon caught the recursion.

1 Like

You can check reetrance more easily:

I also update the doc for the observable:

2 Likes