Alternative to .onBeforeCompile for material extension

Current approach of letting the user do whatever they want with the shader code from within .onBeforeCompile is very powerful, and yet, at the same time, quite messy and fragile.

One of the biggest issues is dynamic nature of the material code, if you allow making arbitrary modification to the code – you can not assume that material code will remained the same between builds, and you have to construct that code string every time to check, this creates waste both in terms of CPU cycles and in terms of GC overhead, as that string will likely end up as garbage.

My proposal is quite simple. I propose having more restrictive transformers which can be registered onto a material. Transformers can be entirely static for most usecases, and where that’s not enough, we could offer dynamic transformers – with the main difference that the library can detect that and optimize usecases where only static transformers are being used. One fairly substantial benefit also – is the added semantic information which library can use for various optimizations and error checking.

My observation boils down to the fact that most .onBeforeCompile functions do just 1 thing:

  • find a RegEx pattern in shader code string
  • replace that occurrence with a fixed string

Here is an example to illustrate current usage:

material.onBeforeCompile = function(shader){
        shader.vertex = shader.vertex.replace('a','b');
}

What i propose would be:

const transform = new ShaderTransformReplace(VertexShader, 'a','b');
material.addShaderTransform(transform);

Since there is no arbitrary code being executed anymore, we know that material shader does not change as long as list of transforms hasn’t changed (in addition to other things, like defines and lighting which we already have had).

A couple of ideas on top of this proposal:

  • if user adds transorms (‘a’,’b’) and (‘a’,’c’) – we can detect that and remove latter transform or warn the user, as we know that pattern will no longer be matched.
  • If shader code is ‘aaa’ and user adds transform (‘b’,’c’) – we can detect that such transform would be pointless and remove it or warn the user

Author: Fantashit

3 thoughts on “Alternative to .onBeforeCompile for material extension

  1. @Usnul from your comments in #7522 (comment) (thank you for writing those by the way!) I assumed your worry was mainly about the internal structure and code clarity of NodeMaterial, and that you weren’t concerned about — or haven’t had time to consider — its functionality or readiness for use. Is that accurate?

    I would like to think we can have NodeMaterial in good shape within months, not years. On that timescale, a general shader transform system would be unnecessary.

  2. @donmccurdy
    My takeaway from this is that there is no plan to touch onBeforeCompile currently with the expectation that Node-based shaders will be ready soon (within a 2+ months)

    wrt Node-based shader in general, yes, I find the solution to be a desirable one, my issue is with how it’s done, and that’s separate from the current thread – you’re absolutely right.

    @mrdoob
    I apologize if I come off as hard. I make no demands, merely express my wishes to clarify my position. I am thankful for the work of yourself and other capable and diverse individuals who have in the past, currently are, and will in the future be contributing to making three.js great, again – I’m sorry if that was not clear.

    @pailhead
    Thanks for the pointer. Documentation for that code will be a substantial undertaking.

Comments are closed.