Dynamic Batching using webGPU

Hi, I’m currently learning it’s basic api.
I think we can merging meshes through webGPU compute shader and return back it’s value. so that make it faster calculation when we want to merging meshes.

I’m researching is any other way to use webGPU make my project faster, which is blender like 3D web Editor. Above idea was driven from how to apply dynamic batching faster without CPU’s heavy calculation.

Give me any advice. Thanks for reading :slight_smile:

1 Like

That seems to have something to do with what I’m also dealing with. I am also learning the 3js node system in order to be able to use the potential of wgsl. I’m already merging meshes of different resolutions seamlessly with webgl very efficiently via the gpu. This is easy to do with vertex shaders

I wrote something about this recently, here:

These are many individual meshes that appear as one. Is this what you mean?

But with wgsl and compute shaders there are possibilities that were previously only possible under the #450 shader standard which never existed for webgl.

You mean that “ShaderNode” class in three.js? I’m currently digging on how it looks like, and I guess it is only way to use WebGPURenderer with customized shader is using ShaderNode Class to make computeShader or Vertex shader or others.

But I think vertex shader you mentioned can be done by Legacy API(webGL). Is it right? Then I think it would cause lots of CPU calculation or draw calls.

I use the vertexShader in WebGL2 to change vertex positions. Since the vertexShader is specifically designed for vertex calculations, as its name suggests, it is ideal for this.

Shaders are all executed by the gpu (vertexShader, fragmentShader, computeShader).

The vertexShader has direct access to the geometry attributes (position, normal, uv, custom geometry attributes)

Caring about vertices is the very nature of the vertex shader and there is nothing more appropriate than manipulating vertex positions directly.

The fragment shader is only executed after the vertex shader has been run through for all vertices, because only then are the necessary positions, normals, uvs of each vertex available to the fragment shader in order to be able to linearly interpolate the positions, normals, uvs between the vertices in order to be able to calculate the pixel color.

Since the VertexShader and the FragmentShader are very specialized shaders in order to be able to achieve the best possible performance in their area of ​​responsibility, they are not optimal for general calculation purposes.

I understand the node system in such a way:

shader functions assigned to
"material.positionNode = " are interpreted as vertex shaders
shader functions assigned to
"material.colorNode = " are interpreted as fragment shaders.

Using compute shaders for manipulating vertex positions does not seem appropriate to me, because in the end you would have to transfer your values ​​to the vertex shader anyway.

The compute shader is an unspecialized shader. So it can be used for all sorts of calculations in the gpu. The computeShader can’t do what vertexShader and fragmentShader do any better! It is simply better suited for all other purposes.

E.g. calculate textures or calculate a swarm of particles as in the compute examples.

For me it is very valuable for displacementTexture calculations. I can then use these textures in vertex shaders for vertex shifts.

Great! In my case, I’ve tried to reduce the drawCalls. But, merging meshes to reduce DrawCall should calculated on CPU side. Is it right? OtherWise, lots of meshes(vertices) would calculated on vertexShader, which make lots of drawCalls with mesh counts. (1000 mesh => 1000 drawCall)

I let the vertexShaders do the merging of all the meshes in each frame, because that would be way too much for the CPU. The vertex shaders don’t have any trouble with it at all. If my surface would not move then I could also do the merging in the CPU but then only in side threads.

Depending on the distance, my ocean consists of just a few meshes or over 100 meshes. And all vertices change their position in every frame due to the waves. So everything is very dynamic, without any stuttering.
The vertex shaders calculate this entire dynamic. The CPU would be completely overwhelmed.

I leave the creation of new meshes to other CPU cores (new threads) so that the core running my main application (mainthread) is undisturbed. A CPU also has multiple cores (mine has 8 cores). I let the VertexShaders do the dynamic vertex manipulation and vertice adjustment. If you’ve seen the short videos in the page link I shared at the beginning, you’ll see that the vertex shaders have absolutely no problem moving all the many thousands of vertices on my ocean surface and aligning the edge vertices precisely with each other.

My ocean is currently still running with WebGL2.
What advantage does WebGPU have for me if I already have all the dynamics in WebGL2 in the GPU?

The waves also have to be recalculated in each frame and I have to calculate a new displacement texture for each frame. This displacement texture is then passed to the vertex shaders so they can use it to perform the vertex shifts.
Calculating textures is cumbersome in WebGL2. For this you need so-called renderTargets and I need 5 in a row.

And that’s where the compute shaders comes into play for me.

Thanks. That’s what I looking for it…

Currently researching will the overhead of compute Shader would be better than heavily use it on CPU or not. I saw your work(https://codepen.io/Spiri0/pen/qBQzJNr) wave simulation on code pen. I’ll start from here to test if compute Shader will make it better or not.

I made the CodePen example for the three.js developers to show an error with DataTextures in connection with the positionNode. This is not due to the positionNode itself, but there is a float format incompatibility between the float type in DataTextures and wgsl, i.e. WebGPU. It will be fixed but probably not yet with r156.

What you’re doing sounds good. Doing the mesh creation in a compute shader would have the advantage that the DataTexture would become obsolete, because compute shaders can use the wgsl textureStore command to store textures directly.

This could possibly circumvent the current compatibility problem between wgsl and DataTextures.

However, I don’t yet know how to use the textureStore command in conjunction with the storage node. I asked the developers on github to create an example. It may be that this is not possible yet with r155, because I can’t find anything with workgroup_size in nodes.js in the three directory (three/examples/jsm/nodes/nodes.js). This is a compute shader specific command to set the number of gpu cores to use for the calculation.

Here is the url on the subject here in the forum. But since all this is still so new, nobody knows something about it. That’s why I suggested to the developers in github to create an example with the node system. The ability to store textures is one of the most valuable things compute shaders can do.

P.S. In the codePen example, I’m not concerned with wave simulation. I save all vertex coordinates in a DataTexture and then pass them on to the vertex shader. The reason I’m doing this is because, on the one hand, textures are a great data store for xyz coordinates when using FloatType32. That is precisely the accuracy of the GPU. On the other hand, because shaders only ever see the attributes that are currently being processed. Only the vertex shader has direct access to the attributes (position, normal, uv, …) of the geometry object and only to the vertex currently being processed. However, if you have wireframes with different resolutions, you want to be able to calculate connection conditions, and for this you need the position of neighboring vertices.

The example is a small part of my ocean. But it is very well suited to understand a lot. I create the geometry with its attributes from scratch because I need an index attribute for the vertices