Best Way to Reduce Draw Calls?

Hey!

So, I’m trying to reduce draw calls in my project. But here’s the catch: I’m using TransformControls in order to move objects. The approaches I can envision are as follows:

  1. Create an InstancedMesh for each type of object, and when I select and instance via raycaster do the following: Set the instance as invisible in the instanced mesh, or something similar, then create a mesh with the same geometry and material in its location to be moved by TransformControls. Then reverse it when selecting something else.

  2. Somehow learn how to use InstancedBufferGeometry (Problem with this is that I don’t understand why I need to write a shader for that, or what it would even do)

  3. Merge all items in the scene into one giant item, then somehow label what geometry belongs to what items. Use a similar approach from there as #1.

Any other suggestions? If you recommend one of these, do you have any recommendations for how to go about implementing it? (Especially option 2, I know nothing about manually writing shaders)

Thanks,
S41L0R

2 Likes

I would suggest (1), or something similar:

Create an InstancedMesh for each type of object. When you “select” an instance, put a dummy object at its location (e.g. an invisible box) and allow TransformControls to manipulate that. Each frame, you can update the position of the instance with the current position of the dummy object, until the user is done editing.

2 Likes

That’s a great solution! Thanks!

1 Like

Actually, one more question:

So, I’m turning my imported models into InstancedMeshes. Now, these objects are groups with several meshes inside. What I could do is keep all these groups, but replace the meshes inside of them with InstancedMesh indexes. Is this possible?

Otherwise, the problem I’d be facing is I need to merge the geometries and materials, which I don’t really know how to do, as not all the BufferGeometries have the same attributes, and I don’t even know where to start when merging materials.

Any ideas?

the problem I’d be facing is I need to merge the geometries and materials, which I don’t really know how to do…

If they can be merged (and sometimes they can’t, without help from a 3D artist) then gltfpack or Blender would probably be the easier tools to use for this.

To the first part of your question, are you…

  • a. loading the same model N times, and that model has M meshes?
  • b. loading N different models, and each model i has Mi meshes?

… the way of using InstancedMesh would probably be different in these cases.

So unfortunately I can’t merge these in blender because these meshes are extracted from the user’s existing game dump of Breath of the Wild, as these meshes belong to Nintendo and it would be illegal to distribute them. So I want something that can be run on the user’s computer in an automated process.

And to your other question, I am A, loading the same model N times and it has M meshes.

In that case I think you probably want to do something like:

  1. Load the model once.
  2. Traverse the model, gathering a list of its Mesh instances.
  3. Replace each Mesh with an InstancedMesh with count N.
  4. To set the position of the instance i, traverse the list and update each InstancedMesh at index i.

If the objects/groups within each model have different positions/scales/rotation you may need to account for that at step (4) on normalize it ahead of time, but I think I would start with steps 1-4.

1 Like

I had a long message here asking about a few things but after a while I now understand what you meant. Thanks!

I do have one just general question though: What is the difference between setPosition() and makeTranslation()?

As well as that, if the user adds a model of an existing type to the scene would you recommend having a new InstancedMesh just for all the user’s current session additions of that type, or should I rebuild the InstancedMesh completely, with a new count?

When you first create an InstancedMesh for a model, give it a higher count than you need. You can then decrease the count to what you actually need, and gradually increase it up to the original maximum. You cannot increase it beyond that initial maximum without allocating a new InstancedMesh. The memory cost of a higher-than-necessary count is low, something like 64 bytes per instance. Think of this as a “pool” of instances you can use later.

I do have one just general question though: What is the difference between setPosition() and makeTranslation() ?

setPosition leaves the existing scale and rotation intact and just modifies position. makeTranslation resets everything, leaving only the given position.

Thank you, that’s really helpful. I’ll keep your first post marked as the solution as the rest has been more specific to my project, but this just about covered everything.

Thanks again!

2 Likes