Questions about onPointerObservable

Dear experts, recently i am analyzing the performance bottleneck of the 3D viewer.

One of the issue i met is related to the mouse event onPointerObservable.

In the project, we used ArcRotateCamera and zoomToMouseLocation=true.

Based on my understanding, zoomtomouse will not actually calculate what the camera direction hit but with fixed radius. In some cases it is fine, however, when zooming in closer to the terrain, it is very difficult to move the view further.

So we introduced the onPointerObservable event and update the target and radius according to what is hit by the camera ray in POINTERWHEEL event. The overall logic works well. Then we hit the issue of performance when there is large mesh present in the scenario (e.g. terrain mesh).

The FPS will drop from 50 to 20-30fps whenever I zoom in/out or even pan the scene. It seems by default, the pickByRay will always be fired.

I will try the new GPUPick in onPointerObservable, my question is if it will improve the performance in my scenario? I am a bit confused with the workflow behind the onPointerObservable. When using GPUPick, will it still firstly calculate pickinfo under POINTERWHEEL event?

Or is there any better way to meet the original requirement?

Many thanks for your help. --Hui

This morning I am trying to create a PG for that.

And the issue that i find is a bit different now.

Mouse Event Test | Babylon.js Playground

I have try to load the terrain mesh in different coordinates method (one with node transform and uniformed vertices and the other with its absolute coordinates which are all very large). Other than that, they have exactly the same number of vertices and faces.


They all trigger ray hit test, but the performance is significantly different.

Is there any root cause behind these results? Does it mean that I need to always uniform the mesh coordinates?

Many Thanks.

Sorry need to update what i find again.

I have now convert the original glb to same un-uniformed form using “glTFPack” tool.

I have compared the two glb files, i cannot tell any difference between the two now.

But their mouse event (rotate by left click or pan by right click) performance is still with big difference.

Mouse Event Test | Babylon.js Playground

Can anyone help to explain the root cause?

Many thanks.

cc @ryantrem

Also adding @amoebachant for the input management

Just to be clear, “the 3D viewer” in this context is something you have created yourself, not the Babylon Viewer, correct?

I think in your case this will be somewhat slow, because this causes a ray cast every time the mouse wheel changes, and your model has a lot of indices/faces.

I believe they are independent, so if you wanted to use gpu picking instead of regular picking, you would need to disable regular picking. That said, as far as I know the gpu picker only tells you the hit mesh, not the triangle that was hit, so if I’m understanding your scenario correctly, I don’t think it would give you enough info.

In general, you may need to skip some ray casting on pointer events if you haven’t already. For example, setting scene.skipPointerMovePicking, scene.skipPointerDownPicking, etc. For your scenario, you may also be able to set scene.pointer*FastCheck. This will basically make ray casting return the first triangle it hits rather than the closest, but since your model is mostly flat, this might work just fine.

Depending on your needs, you might be able to use the actual Babylon Viewer as well. Here is an example:

As far as performance being different between the two models, I don’t have an answer yet. I did some profiling and saw that the same number of faces are being tested in the ray cast, but it’s slower on one model than the other (specifically it seems to be a Vector.subtractToRef, which so far doesn’t make any sense). I’ll see if I can find any more answers on this one.

2 Likes

To give you some updates, we have isolated the issue and it seems to look like a bug in the compiler. Somehow in one case the vector3 class is deoptimized for a reason we are not aware of yet.

We will keep this thread updated as soon as we know more

3 Likes

Sorry was travelling in the past days.

That is in fact the most confusing part. It seems that both mesh have the same level of complexity but the performance is different. One the factor is cleared with forum’s help, I may be able the prepare the mesh data in better form.

Thank you @Deltakosh and @ryantrem for your updates.

We finally have the explanation!!

The slow version is slow because with more than 1 million faces the memory cache is not as efficient as the other version.
Why? Because the slow version has faces dispatched in a random order where the fast version has faces gathered if they share common vertices.

To get rid of that we have introduce a new feature on mesh:

const terrain = scene.getMeshByName("Terrain");
await terrain.optimizeIndicesAsync();

That function will reorganize the indices to maximize cache hit.

PR: Add a new optimizeIndices features to improve cache hit on large models by deltakosh · Pull Request #16009 · BabylonJS/Babylon.js

1 Like

Thanks @Deltakosh as always. It explains the root cause behind, I will check if we can prepare the data with ordered face indices when generating the terrain.

Thanks @ryantrem, the PointerPickingConfiguration also helps to avoid some unnecessary ray hit test.

With the combination of two, the performance of terrain navigation is greatly improved. Truly saved my day. :slight_smile:

2 Likes