How can I use DataTexture for BatchedMesh to access per-instance data in shader?

I was using InstancedMesh with custom InstancedBufferAttributes. Then I got to have many of such InstancedMeshs that use the same material, so I tried to use BatchedMesh to draw them at once. But I was getting some internal errors so I checked the ThreeJS code and then I found a big difference between InstancedMesh and BatchedMesh which was that InstancedMesh use InstancedBufferAttribute while BatchedMesh use DataTexture to manage per-instance data (this part). Does it mean BatchedMesh doesn’t use drawArraysInstanced internally therefore I can’t use InstancedBufferAttribute? If so, do I need to use DataTexture as well to achieve the same thing?

BatchedMesh uses multidraw.

Yes, you should use DataTexture.

Do you need help? (I’m using DataTexture also for my InstancedMesh2 library).

3 Likes

Yes I do! How do I access per-instance data using DataTexture? Meanwhile I’ll try to figure out myself by looking at the yours and THreeJS’s code

1 Like

Create DataTexture:

You can find utility methods for creating DataTexture here:

Like with BatchedMesh, create textures with equal width and height, because creating a texture width = N and height = 1, might fail.

Get Instance index in the shader

I recommend this site to check the shaders of three.js:
https://ycw.github.io/three-shaderlib-skim/dist

You should check these two parts

#include <batching_pars_vertex>
...
#include <batching_vertex>

You can get the instance ID in this way:

getIndirectIndex( gl_DrawID )

Get instance data

You can find utility methods for get data from texture here:

Obviously pay attention to the types and declare the texture uniform in your shader.

I hope I haven’t forgotten anything :slight_smile:

1 Like

I managed to use BatchedMesh instead of InstancedMesh, but the result performance was, even with dramatic decrease in the number of draw calls, not as good as expected. So I did some researching and It seems like, to benefit from both multi-drawing and instancing, you should use multiDrawElementsInstancedWEBGL or multiDrawArraysInstancedWEBGL. But my debugger said it was using multiDrawElementsWEBGL. So I checked the ThreeJS code and there was indeed a code that use the multiDrawElementsInstancedWEBGL but the code seemed unreachable. Because _multiDrawInstances has to be not null but there’s no code in ThreeJS that sets it with any value.

Is ThreeJS is still under development on using both MultiDraw and Instancing? cc @donmccurdy @agargaro

It’s possible to use those commands but it’s not recommended because they don’t work on firefox.

I created an example (not cleaned) that use multidrawInstanced to handle InstancedMesh LODs with a single drawCall, but I don’t think I’ll ever use it:

If individual frustum culling by instance might be useful to you, you might take a look at the library I linked to earlier.

2 Likes