How to efficiently highlight a large number of 3D boxes using shaders? (Performance issue)

Hello everyone,

I have a project requirement to highlight a large number of 3D boxes in three.js.

Currently, I have implemented a demo using a custom vertex shader (highlight.vs) to achieve box highlighting.

However, the rendering performance is very poor, and the frame rate drops sharply as the number of boxes increases.

I suspect the shader or the data transfer method might not be optimized, but I am not sure exactly how to improve it. I would like to ask if anyone has any ideas or experience to share.

  • Here is the demo I wrote: [box_highlight]
  • The highlight.vs handles the highlighting logic.
  • Currently, the implementation is (drawing each box separately / or drawing all at once) — please adjust based on your actual approach.

I want to understand:

  1. How to write shaders more efficiently for highlighting a large number of boxes?
    2. What are recommended ways to pass data such as box positions, sizes, and highlight states? (uniform arrays? DataTextures? instancing?)
    3. What practical performance optimization tips exist?
    4. Are there existing solutions or libraries that I can refer to?

Thank you very much!

What practical performance optimization tips exist?

While it’s not technically true, assume a rule that you are not allowed to use for-loops (or any loops for that matter) in GLSL shaders. Entirely. That for (int i = 0; i < BOX_COUNT; i++) { should be happening on the CPU (or in a compute shader, but these aren’t available in WebGL.)

All else looks ok :ok_hand:

How to write shaders more efficiently for highlighting a large number of boxes?

Do it on CPU - you can use raycaster to detect intersections / pointer position, and just flip buffer value from 0 to 1 (no need to even do that on every frame, since CPU allows you to track when pointer is moving.)

What are recommended ways to pass data such as box positions, sizes, and highlight states? (uniform arrays? DataTextures? instancing?)

For all - using buffers makes the most sense (instancing is not a form of passing data.)

Are there existing solutions or libraries that I can refer to?

Three.js already implements instancing for you (see source code in the link above.)

4 Likes

I just want to add.. that there are many legit uses for for loops in shaders, but this case isn’t a good one, and until you understand the ramifications, it may be best to avoid them.

A more optimal approach would be to use the per instance color attribute, if you’re only changing the color.

Or you can re-purpose the per instance color attribute, and interpret the color data however you need to indicate/render the selection state.

Or if you need a lot more data.. even adding new per instance attributes.. or as alluded to, using a datatexture or similar to store some state.

1 Like