Three needs a system for registering materials with a renderer

Right now, if you want to extend an existing material class, it is very difficult. It requires using onBeforeCompile for the new material (although built-in materials do not need to use onBeforeCompile).

Furthermore, built-in materials have their shaders registered in a private state that is not modifiable for new materials here:

There is no way for the author of a new material to add to that private map.

So then, if the material author does this:

class AwesomeMaterial extends MeshPhysicalMaterial {
  type = 'AwesomeMaterial' // THIS
  // ...

as is customary with writing new classes for Three.js, the result of this new type value will cause the material’s internal vertexShader to be undefined and causes a runtime error.

And this happens:

class AwesomeMaterial extends MeshPhysicalMaterial {
  type = 'AwesomeMaterial'

  onBeforeCompile = (shader) => {
    console.log(shader.vertexShader) // logs undefined, but we expected at least the shader from `MeshPhysicalMaterial` which we extended from.

To avoid the problem with the new type value, we can simply not set a new value, and leave it as "MeshPhysicalMaterial" for example. Then we can extend the material by patching in new features. However, this means that now tools like three-devtools will show the material as “MeshPhysicalMaterial” instead of as “AwesomeMaterial”, making debug more difficult.

TLDR, writing new material classes is tricky and doesn’t afford the same conveniences as with built-in material classes.

What WebGLRenderer needs is a way for people to register materials in such a way that both built-in materials, and new materials, enjoy the exact same benefits and behavior, for developer consistency. Both built-in and custom materials would be registered the same way (perhaps built-in materials are pre-registered by default). This way, there’s one consistent way to do things.