ChunkMaterial experiment

I like writing shaders but i don’t like writing or reading too much code. I like using three’s built in materials as abstractions of real world materials like gold or plastic or rubber, in which case i don’t write any shader code.

Some times though i need to implement an effect that is not part of the lighting system, for which i need shaders. For example, if i want depth peeling, i need a depth peel stage in addition to clip planes, transformation, lighting etc. In this case, i want to keep the built-in material abstraction and flexibility (ie. use Phong, Lambert, PBR etc) but add my own logic on top of that.

If you ever found yourself looking at the src/renderers/shaders/ShaderLib folder of three.js and copying code from there into your own files, you might know what i’m talking about.

The idea behind this project is to decouple the various material abstractions from the THREE.WebGLRenderer. You can make your own SomeMaterial with the same interface as PhongMaterial like this:

class MyPhongMaterial extends ChunkMaterial{ //abstraction
   
  constructor(parameters){ // your parameters like color:myColor, shininess:myShininess 
  
    const defaultParameters = {
      map: null,
      normalMap: null,
      color, new THREE.Color(1,1,1)
      shininess: 1,
      awesomeness: 999,
    } 

    const uniforms = THREE.UniformsUtils.merge([
      THREE.UniformsLib.foo,
      THREE.UniformsLib.bar
    ])

    super({
      uniforms,          //give uniforms to ShaderMaterial
      vertexShader,      //give templates to ShaderMaterial
      fragmentShader,    //give templates to ShaderMaterial
      defaultParameters, //define the materials interface 
      parameters,        //if any optional parameters are provided use these
    })

  }
  
}

ChunkMaterial then servers as a framework for assembling valid GLSL out of chunks and templates, and wiring the appropriate object properties to uniforms.

In an ideal world this can solve these problems:

  • making new materials, or modifying existing ones, “globally” (ie. PhongMaterial needs a refactor) all should happen in the sub classes. ChunkMaterial super class has no idea how many materials you are using and what properties they have. If you want to extend from Material right now, you have to modify Material too, in order to include the properties of your new material.
  • modifying existing materials on the fly should be easier. These chunks are no longer black boxed, and their creation doesn’t have to be deferred. Ie. with Material the only way you can access this is through onBeforeCompile
  • reduce the size of your bundle, by making some abstractions. The gain is currently rather minimal, (2x-3x less code per Material___.js file) but stuff could be taken out of WebGLRenderer

Pitfalls:

  • getters and setters may have performance issues
  • not super easy to ensure that tree shaking is happening
  • Can lead to bloat when GLSL is present both in THREE.ShaderChunk and this framework’s chunks. This could be mitigated by using THREE.ShaderChunk and only providing overrides or additional chunks.

Would appreciate feedback.

5 Likes

Here’s a crude demo:
http://dusanbosnjak.com/test/webGL/three-chunk-material/

I didn’t check the reflection stuff but most of the maps and colors work. Reflectivity actually doesnt work on Physical but does with the Chunk version.

All these properties still trigger stuff inside the core. ShaderMaterial thus may have some reserved words/props. I want to namespace chunks properties to see what it takes to manage the defines.