Skip to content

Material.onBeforeCompile() enhancements #13446

@pailhead

Description

@pailhead

I would like a more robust Material.onBeforeCompile system to work with the current state of the default materials.

  1. It's not actually documented, but from the example it's not obvious that there is a very specific way in which the callback needs to be written. Any conditional logic inside the callback may or may not be executed depending on the order in which the materials have been added to the scene or encountered by the first render call.
    See:
    [BUG]: onBeforeCompile hashing #13192
    https://codepen.io/anon/pen/KQPBjd
    The workaround for this seems extremely hacky, and one has to think of functions/callbacks in a specific way, if that makes sense. Literally the raw code you write in the callback matters. I would like to not think of this function as data, but the stuff inside it as data. If you are writing some kind of a utility that somehow configures onBeforeCompile in different ways, rather than writing:
function myOnBeforeCompile(shader){
  if(someUniform){
    //replace some chunk
  }

  if(someArbitraryProperty){
    //replace some chunk
  }
 
  if(someCondition){
     //replace multiple chunks
  }

}
someMaterial.onBeforeCompile = someUniform ? onBeforeCompileForCombinationFOO : someOtherOnBeforeCompile
//or maybe something like this, but it feels weird, 
//whatever this Manager would do would probably look gnarly
someOtherMaterial.onBeforeCompile = OnBeforeCompileManager.getOnBeforeCompile( someUniform, someProperty)
  1. It's kinda verbose, and really wants me to understand that shader is a string. I would like it to be more like data. Instead of these chained "do stuff to string" calls, i would like to have a configurable object where i can say { chunkName: chunkString}. If replace() is the only thing i will ever want to call in this callback, on fragmentShader or vertexShader it would be nice if it's hidden away:
someMaterial.onBeforeCompile = shader = >{
   shader.fragmentShader = shader.fragmentShader.replace('#include <foo>', myFoo)
   shader.fragmentShader = shader.fragmentShader.replace('#include <bar>', myFoo)
   shader.fragmentShader = shader.fragmentShader.replace('#include <baz>', myFoo)
   // don't like calling shader.fragmentShader = shader.fragmentShader 
   // don't like looking for #include <> if I know that it's a chunk and it's name is foo,bar,baz
   // don't like calling string.replace()
//chunks as data
someMaterial.replacableChunksOrWhatever.foo = fooGLSL  
someMaterial.replacableChunksOrWhatever.bar = barGLSL  
someMaterial.replacableChunksOrWhatever.baz = bazGLSL  
  1. It's not obvious where uniforms, functions, attributes and varyings should be injected. Prepending the shader in the callback should work, but causes a warning for example with #extension directives (there's more stuff that happens above the pre-compile shader). Again i'd like to see it more as data.
someMaterial.onBeforeCompile = shader =>{
  shader.fragmentShader = myPrependedAndFormattedUniformsVaryings +  shader.fragmentShader 
  //...
}
//i'd rather see it as data and not concern myself over the semantics of how it gets injected
someMaterial.customGLSL.vertexUniforms.foo = {type: 'v4', value: new THREE.Vector4()} 

I've tried to implement these changes in:
#13198

Thoughts @Mugen87 ?

Per discussion with @mrdoob all of this would go away in favor of all the materials being rewritten with the node material. Until that happens, i would like to see a way to interact with the default materials thats more robust.

I think this is called configuration over convention. I would configure these materials with custom stuff upon construction, and then not care about the string manipulation, and particular moments in time like compile time.

Three.js version
  • Dev
  • r90
  • ...

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions