brianzinn / react-babylonjs

React for Babylon 3D engine
https://brianzinn.github.io/react-babylonjs/
809 stars 102 forks source link

Unwanted Shivering and slowing down while rendering multiple tubes with warning. #276

Closed harit-m-kumar closed 1 month ago

harit-m-kumar commented 1 year ago

I was trying to render tubes to mark paths in a grid. It works fine with small number of tubes, but when the number grows to 2500+, the screen shivers automatically, slows down and I get this warning -

[Violation] Handling of 'wheel' input event was delayed for 881 ms due to main thread being busy. Consider marking event handler as 'passive' to make the page more responsive.

My code is

props.lanes.forEach((lane, i) => {
  items.push(
    // <lines points={lane} updatable={true} key={i}></lines>

    <tube
      key={'tube' + props.changeIndex + 'element' + i}
      name="tube"
      path={lane}
      radius={2}
      updatable={true}
      arc={0}
    >
      <standardMaterial
        diffuseColor={Color3.FromHexString("#FFCD11")}
        name="tube"
      />
    </tube>

    )});
Xample commented 1 year ago

My guess is that this is a side effect, changing to passive event won't change anything. When you scroll, both your JS code and chrome can get this event. But chrome will wait for your code to be first ran before scrolling the page. It does so because you could dismiss the event calling preventDefault on it (in which case chrome will not scroll anything). You can however tell chrome "don't wait on me, I will not prevent default in anycase" flagging the event listener with a passive: true property. In that case, chrome will scroll in any way without waiting for your JS event loop to complete, which will result in a smoother scroll.

I therefore suspect your code to listen for the wheel somewhere (typically the camera will listen for the scroll event to zoom in) and chrome detecting this event will apply its optimization rule complaining it took too long between the event to be fired and the return of this event's callback.

How to fix this ? I've no idea… I discovered babylonjs and react last week to say so. In any way flagging the wheel input as passive won't solve anything, it will even be worse as chrome will try to scroll the page (which is likely not what you want).

I'm having the same kind of question regarding building a lot of items into the scene https://github.com/brianzinn/react-babylonjs/issues/275 The problem is that we are doing a real-time processing within a single threaded engine, we have less than 1000/FPS milliseconds per frame, beyond this delay, the scene will lag.

I'm absolutely not an expert, but a possible theoretical way could be to delegate the building of your tubes to another threaded process. This would involve sending a message to a worker itself building the scene using babylonjs and returning the backed mesh once it's done. You might not have the result within the same frame, (perhaps it will appear 881ms) later, but at least building the meshed will not block the rendering.

Now, a react-babylonjs expert will probably explain how to use a GPU instancing properly (but I don't know yet how to do so)

brianzinn commented 1 year ago

Everytime changeIndex prop is updated - it will dispose your entire list and rebuild it (assuming you render that list). I don't see the calling code outside of that snippet, but suspect that is the cause. The key prop is a unique identifier in the list to let the reconciler associate it within it's algorithm. In terms of slowness with that then you can work out the performance depending on the size of your list and the frequency that changeIndex is being updated. Otherwise you can look at what you would do instead imperatively and translate that to the declarative syntax.

harit-m-kumar commented 1 year ago

Tried avoiding changeIndex, but the issue persists. Does translating to declarative syntax mean using Babylon JS?

harit-m-kumar commented 1 year ago

[Violation] 'message' handler took ms - this is the issue being said in console repeatedly

brianzinn commented 1 year ago

Creating thousands of meshes takes time, so you would need to look at the impact of creating them and disposing them repeatedly. The reconciler will use the key identifier you provide to track the instances - or otherwise dispose and create new instances.

dennemark commented 1 year ago

Isnt the other issue the amount of draw calls created by so many meshes? I would consider merging all those meshes, which would require not using the declarative approach. Or using instances maybe?

brianzinn commented 1 year ago

Good point @dennemark - if it's not just a contrived example - I have one way here: https://brianzinn.github.io/react-babylonjs/examples/basic/instanced-mesh-hex

brianzinn commented 1 month ago

closing from inactivity. it looks resolved.