Many objects causing low fps, optimization possible without losing individual objects?

Hi,

I have coded my first threejs project (AmbientLight, DirectionalLight, PerspectiveCamera, OrbitControls, WebGLRenderer) for the following use case:

  • I have a scene where I created 1800 BufferGeometry objects based on a list of vertices.
  • On top of that I created 1800 TextGeometries each being positioned in the center of its related BufferGeometry each with a text based on the related BufferGeometry’s “userData”.
  • Furthermore I have some user interactivity in a way that you can hover with the mouse over the objects using Raycaster to have them change their color as a feedback and display their individual “userData” in an HTML table.

As you might guess I now face some nasty performance issues with an fps<15.

I tried to research for performance optimization techniques like merging the meshes and re-using materials etc. But as far as I understand I would lose the ability of interacting with the individual objects, wouldn’t I?

What can I do to improve the performance without losing the ability to interact with the individual objects?

Thanks and regards,
carlo

Look into instancing. It’s a must!

1 Like

Hi Mark and thanks for your reply!

I suppose you mean InstancedMesh? I have looked into that shortly during my research but then I was put off, because it says that “if you have to render a large number of objects with the same geometry”. In my case the BufferGeometries are built based on a list of vertices, so that each geometry might be a little different in terms of shape.

Or do I misunderstand the statement? Is it still possible to use InstancedMesh in my case?

I guess not then. I missed that part in reading the description of your problem.

Makes me wonder if there’s a solution where the rendering is done on the backend and a merged object is the result… just not sure. Very speculative.

1 Like

I’ve seen Gatsby mentioned in this forum several times.


https://threejs.org/examples/?q=insta#webgl_instancing_raycast


Makes me wonder if there’s a solution where the rendering is done on the backend and a merged object is the result… just not sure. Very speculative.

4 Likes

Thanks Garrett for your example!

I will need to take some time to look at the code to understand if it’s working out for me…

I found out that in my case the 1800 BufferGeometries are not really a problem, they still allow an fps=56 which is fine I guess. But rather the 1800 TextGeometries seem to be eating the performance! So I tried to implement instancing for the meshes of the TextGeometries only.

It basically works, but unfortunately I have not yet found a way to change the individual text to be displayed. I know how to set the individual position (matrix.setPosition) and orientation (matrix.lookAt) of the instanced meshes, but how can I change the text?

Text as geometry?

I’m sorry Mark, i don’t understand your comment. Do you ask what i mean with TextGeometry?

I think Mark is wondering why you need 1800 text geometries. There must be some other way to achieve this.

Well, my use case is as follows:

  1. I have a structure of many quad and tria meshes (created from vertices via json)
  2. I want to load text data (via json) that contains a dict of data for each quad/tria
  3. I want to map the different sets of text data to the quad/tria meshes from the loaded dict based on a selection from a pull down menu
  4. I want some mouse hover interactivity like displaying the complete list of text data per quad/tria mesh in a html table together with a color change “feedback” when the mouse hovers over the quads/trias.

I managed to achieve all requirements, but only with TextGeometries, which is not really fun due to the low fps.

I tried different approaches:

  1. Text Textures: not possible, because I cannot have text images for all possible text.
  2. CanvasGeometry: flexible with text, but the quality is not great due to the blurriness if scaled
  3. TextGeometry: flexible with text, good quality if scaled, but resource intensive due to triangulation

Does anyone know a better approach to my use case that I overlooked?

Have you considered all these possibilities?

1 Like

And these
https://threejs.org/docs/index.html#manual/en/introduction/Creating-text

I’m not entirely sure, but I’ve been looking at this example to implement text via CSS rather than geometry:

https://threejs.org/examples/?q=css#css2d_label

Honestly, most available ways of rendering text are going to handle this poorly out of the box… SDF fonts would be my recommendation, since it should be possible to merge their geometries or use instancing. I’d try Troika 3D Text - Troika JS, and ask on their github page if the performance is still bad. It supports GPU instancing but that part is currently undocumented (GPU Instancing - Troika JS).

three-bmfont-text might also be an option if you merge the geometries after generating.

I wouldn’t try to raycast against the text directly, it’d be much better to just raycast against simple planes.

Thanks hofk, that’s a lot, I guess I’ll need some time to go through everything and get my head around.
Very good resource! :+1:

Yes, except the last one “Troika Text”.
I will definitely check out that one now.
Thanks!

Thanks Mark,
I guess these are sprites if I’m not wrong. In my very case I would like to have the text really “mapped” to the planes, so sprites are not exactly for that, since they keep their position and are always in front.

I hope I don’t mix up, at least that’s what I understood about sprites…

So I guess I’ll to check out Troika Text then! Thanks don!