Pass explicit vertex count to mesh

I’ve been working on a webGPU implementation of a flocking simulation using compute shaders. I’m currently rendering millions of triangles using instancing with forcedInstanceCount but this isn’t the most efficient way as I know there’s a bit of overhead with instancing.

Not sure if I’ve missed it in the API but I was wondering if there was a way to set an explicit vertex count, similar to forcedInstanceCount but for a non instanced shader, my idea was just to manually pass a vertex buffer into the vertex shader and reuse that along with the computeBuffer values to render all the boids as one mesh.

I don’t think you need anything special here:

Just do mesh.setVerticesData("position", buffer) and you should be good. When we pass data to the GPU, we don’t pass a vertex count, we just set vertex buffers.

It’s the index buffer which will give the number of triangles to draw in the end.

I was thinking something similar to directx’s draw method where you can pass in the number of vertices.

I’ve used it in directx in the past with a vertex shader something like the below.

v2f vert(uint vertexID : SV_VertexID) {
        uint boidIndex = vertexID / 3;
        Boid boid = boids[boidIndex];
        v2f o;
        float3 pos = _Positions[vertexID % 3];
        rotate2D(pos.xy, boid.vel);
        o.vertex =  worldViewProjection * (pos * _Scale) + float4(boid.pos.xy, 0, 0));
        return o;
      }

Where _Positions is just a uniform buffer of length 9 which contains the 3 points of the triangle that are reused. This seems to be almost twice as fast as using instances when there are millions of triangles involved.

I understand I could do an indexed draw too but would you be able to further clarify how I’d go about doing it without making an index buffer thats millions of items long? It really only needs to be of length 3 which I can then reuse with something like the above shader.

I’ll take a look at it as soon as I can, but probably not until next week, as we are about to release the new v6 version!

All good I managed to work it out! Did it by doing the following:

var boidMesh = new Mesh("custom", scene);
boidMesh.setVerticesData(VertexBuffer.PositionKind, [0]);
boidMesh._unIndexed = true;
boidMesh.subMeshes[0].verticesCount = numBoids * 3;

When rendering millions of triangles like this using instancing seems to have a bit of overhead as it almost halves the frame rate, so this lets me just render directly from the positions in the storageBuffer as one big mesh.

Works smoothly now even with 8 million boids! my new limitation is that it seems the storageBuffer size limit is 128mb, is there a way I can increase this somehow?

It’s good that you found a way!

You should avoid accessing private variables, though, as they might be renamed/deleted in future versions. Instead, you can do: mesh.isUndexed = true;

The default WebGPU limits are quite low (see WebGPU) but you can request higher limits by filling in the deviceDescriptor property of the options parameter you pass to the constructor.

To simplify things, we’ve added the setMaximumLimits property to the option object, which will set the maximum limits supported by your browser/GPU (there’s also the enableAllFeatures property which will enable all extensions supported by your browser/GPU). The playground is to set both properties to true.

Note that Chrome does not yet implement all limits correctly (for example, Chrome says 60 for maxInterStageShaderComponents but my GPU supports more).