StandardMaterial in WebGL2 recognizes the pointSize property.
WebGPU does not. All points are the default size.
Not supported according to
https://doc.babylonjs.com/setup/support/webGPU/webGPUStatus#features-with-incomplete-support
Opening Feature Request instead.
Yup, we need to wait on WebGPU here
They won’t add support in the specification, because it’s not supported by DX12 and/or Vulkan and/or Metal.
So, if we want to support it transparently, we’ll have to emulate it, which is probably not straightforward, as we’ll have to change the mesh geometry at render time, to use quads instead of points - the vertex and fragment shaders will also have to be dynamically updated.
That’s what I was thinking on how to implement. Generate the quads on the GPU. Only send points from CPU.
Here’s a very early prototype of potential pointSizeSupport in WebGPU.
It does not have enough features to realy be called a PointsCloudSystem yet.
Modified from the boid flow demonstration playground.
Essentially using an instanced matrix without needing CPU buffers to contain instance parameters.
There is an essentially unused compute shader (well, used once to initialize the GPU buffer).
A lot of unused parameters passed as a uniform.
I think it has potential. It tops out (for me on Android) at around 700000 particles and starts to slow down during user camera moves after that.
Internally (i.e. on the GPU) I think it’s could be reduced to using 4 floats per particle. Z is initialized to 0, and there’s an extra, I think unused, float.
Modified from boid with
- added worldViewProjection in vertex shader, which enables changing the camera view.
- called update() only once, which I hope means the compute shader is called only once.
- made the mesh a square instead of triangles, this doubles the number of vertices processed.
- set initializing CPU buffer to null, which I hope allows it to be garbage collected.
Seeking comments on whether this is a path worth pursuing. Will this have CPU space improvements without performance degredation? How does the max number of particles compare to other methods on WebGL2 or WebGPU?
Implementing point size support in the core would probably be too complicated, for little return on investment. Updating the PCS class using quad instantiation might be easier, however, and it could also be quite fast in WebGL2, meaning we wouldn’t have to maintain two implementations…
I think you’re right. I’m using this as an opportunity to learn the basics of WGSL. Of course, I’m learning from code in Babylon that you wrote. As far as I can tell, one mechanism in WebGPU comes down to a draw(6, …) command
on the positions buffer. This is demonstrated in this WebGPU example.
I think what you’re referring to boils down to a drawArray or drawElement with a Quad primitive. However, I don’t see quad as a GPUPrimitiveTopology in the WebGPU spec.
enum GPUPrimitiveTopology {
“point-list”,
“line-list”,
“line-strip”,
“triangle-list”,
“triangle-strip”,
};
I think the closest is a 4-element triangle strip. But it may require a positions buffer that contains the vertex position data, whereas the draw(6…) approach above does not.
I’m also unsure where in the render pipeline that these draw commands exist.
You know much much more than I do. I apologize if I’m just wasting your time here.
Yes, a quad is drawn as two triangles. You can use non-indexed triangles in Babylon by calling Mesh.convertToUnIndexedMesh
. This way, you will get the vertex index thanks to gl_VertexID
in glsl (equivalent to vertex_index
in WebGPU) and use it to retrieve the extent of the particle for this vertex.
You can implement it like this:
You have to create a position vertex buffer to replace the existing vertex buffer of the ground, because this buffer must be flagged as “instanced”, meaning each entry of the buffer is used for one instance of the quad (this position buffer gives the position of each particle).
You also have to set ground.subMeshes[0].verticesCount = 6
to indicate that the quad geometry is made of 6 vertices (2 triangles), because by default SubMesh.verticesCount
is set to the number of entries in the position buffer (1000 in the PG).
Lastly, you have to indicate that the ground mesh must be drawn as an instanced geometry, by setting a value to forcedInstanceCount
, which is the number of instances you want to draw (here, the number of particles).
Not at all, it’s an interesting subject to discuss!
This is awesome! I was hoping for an easy way to turn an existing mesh (and VertexBuffer) into sized points at each vertex, but I’m not sure that’s possible. It’s great that instanced is done with points and not matrices!
I think the major remnant (maybe) is to add a parameter to updateDirectly for source offset (and it’s call to engine.updateDynamicVertexBuffer).
Yes, it could be nice to have another “srcOffset” parameter for updateDirectly
(there’s a workaround, though, which is to create an array buffer view which takes this offset into account).