playcanvas / engine

JavaScript game engine built on WebGL, WebGPU, WebXR and glTF
https://playcanvas.com
MIT License
9.69k stars 1.36k forks source link

Implement material level uniform buffer (WebGPU initially) #6157

Open mvaligursky opened 8 months ago

mvaligursky commented 8 months ago

Current status

On WebGPU, the plan is to have 3 levels of uniform buffers:

Material Uniform buffer(s)

There are two ways to implement this:

  1. Material has a single uniform buffer (unlikely option)
    • We create a single Uniform Buffer, which would contain all material properties used by all variations. The list can be obtained from material, but it lacks the parameter types. Types would need to be known / added for this to work. Currently those are collected when the shader finishes compilation.
    • This is complicated / impractical to do, as we do not know all shader variants that we end up generating for a material.
  2. Material has multiple uniform buffers (most likely implementation)
    • Material.variants will store an instance of UniformBuffer (a new uniform buffer for each compiled version of the shader).
    • When the material properties are updated, the Material’s version will be incremented. When a shader variant with a uniform buffer is used for rendering, it will be updated with material properties if the version is non-matching.
    • If meshInstance has some override material properties, it needs its unique Material level UniformBuffer for this mesh. MeshInstance._shader array stores shader variants used by the mesh instance, and this will be extended to store matching array of UniformBuffer instances. When its version does not match material’s UB’s version, it will memcopy it, and apply meshInstance properties on top.
Maksims commented 8 months ago

There are sometimes even global uniform, e.g. time or windDirection that would be re-used by multiple shaders.

mvaligursky commented 8 months ago

There are sometimes even global uniform, e.g. time or windDirection that would be re-used by multiple shaders.

Yep that already works fine. Whatever is not in the view / material uniform blocks is automatically added to the mesh uniform block .. so that would be the case with those global uniforms.

At some point we might enable users to add global uniforms to the view UB, but for now they'd be per mesh.

willeastcott commented 8 months ago

In terms of architecture, I would very much like a Material (or derived class) be just the material properties (and state) plus the update function to mark the material as dirty. But all details relating to uniforms/rendering should ideally be owned/managed by the renderer. This would help simplify our material classes massively.