Replace the shader fragment of a PBR material using MaterialPlugin

I implemented fast SSS according to the article GDC 2011 – Approximating Translucency for a Fast, Cheap and Convincing Subsurface Scattering Look. In order to be compatible with multiple light sources, I had to modify the calculation of direct lighting in the PBR material. However, the regularization of the plugin is not convenient to use (and I don’t know much about regularization), and the code does not look beautiful. Is there any solution similar to the replace in Threejs?

This is the shader snippet I want to replace:

vec3 computeDiffuseLighting(preLightingInfo info, vec3 lightColor) {
    float diffuseTerm = diffuseBRDF_Burley(info.NdotL, info.NdotV, info.VdotH, info.roughness);
    return diffuseTerm * info.attenuation * info.NdotL * lightColor;
}

Now it works fine, but if I need to go deeper, I may need to modify more places. If I replace it in this way, I feel that the readability of the entire code is reduced.Is there any better solution?

1 Like

Did you try omitting the regex part in the lookup string? If String.replace is used under the hood (I haven’t had time to check), it should still work. Obviously, it will only replace the first occurrence of the lookup string — but I suppose that’s what you’re after anyway.

I believe @Evgeni_Popov will answer this question — I’m confident he’s the right person to provide an accurate response.

1 Like

Another possibility is to directly patch the pbrDirectLightingFunctions shader:

BABYLON.ShaderStore.IncludesShadersStore["pbrDirectLightingFunctions"] =
    BABYLON.ShaderStore.IncludesShadersStore["pbrDirectLightingFunctions"].replace(/vec3 computeDiffuseLighting.*?\}/gs, `
        vec3 computeDiffuseLighting(preLightingInfo info, vec3 lightColor) {
            vec3 diffuseTerm = vec3(1.0 / PI);
            #if BASE_DIFFUSE_MODEL == BRDF_DIFFUSE_MODEL_LEGACY
                diffuseTerm = vec3(diffuseBRDF_Burley(info.NdotL, info.NdotV, info.VdotH, info.roughness));
            #elif BASE_DIFFUSE_MODEL == BRDF_DIFFUSE_MODEL_BURLEY
                diffuseTerm = vec3(diffuseBRDF_Burley(info.NdotL, info.NdotV, info.VdotH, info.diffuseRoughness));
            #elif BASE_DIFFUSE_MODEL == BRDF_DIFFUSE_MODEL_EON
                vec3 clampedAlbedo = clamp(info.surfaceAlbedo, vec3(0.1), vec3(1.0));
                diffuseTerm = diffuseBRDF_EON(clampedAlbedo, info.diffuseRoughness, info.NdotL, info.NdotV, info.LdotV);
                diffuseTerm /= clampedAlbedo;
            #endif
            #ifdef FAST_SUBSURFACE
                ...
            #endif
            return diffuseTerm * info.attenuation * info.NdotL * lightColor;
        }
    `);
1 Like

If I use the Material plugin to implement this, do I need to call this replacement function in the constructor and give up using getCustomCode?

In addition, is there any solution similar to onBeforeComplie in threejs?

The third question is if i use Material Plguin’s getCustomCode to replace some code snippets, when a function needs to be replaced, how to write this regular expression? I tried but failed. I still use regular expressions too little. :joy:

You can do this replacement once at the start of your program. If you do so, you don’t need the regex part in your getCustomCode function, but you still need it because you inject some code in CUSTOM_FRAGMENT_BEGIN.

You can do it like this:

The best way is to use the code from the PG above and do a console.log(code) inside the options.processFinalCode function. That way, you will see the real code that is processed by the plugin manager, which could/will be different from the initial source code of the shader, because we apply some pre-processing on it (like removing extra spaces to shrink the size).

2 Likes

Thank you for your patience. Now I can go deeper with confidence. :grinning_face:

1 Like