Yo @Deltakosh @sebavan @nasimiasl if your still around.
I have a question about the PBRCustomMaterial binding function with support for both WebGL and WebGPU.
I think the norm in PBRCustomMaterial what to use pbr.onBindObservable.add
to assign a callback for you to run things like effect.setFloat("time", this._time)
for example.
I saw another post about that not working for someone also using WebGPU and the solution had a different approach of using:
pbr.onEffectCreatedObservable.add(e => {
e.effect.onBind = (effect) =>{
effect.setFlow("time", this_.time)
}
})
Which is the correct way for a universal pbr custom material that must for work for both WebGL and WebGPU ?
It currently only work with WebGL and it will convert at creation time to wglsl cause everything in those mat is pretty specific to glsl.
The best way to approach those kind of materials would be through material plugins.
Yo @sebavan .. Your right, material plugin seems to be a nice approach. I have implemented material plugin as the underlying material for custom material in the Babylon Toolkit / Unity Exporter.
namespace PROJECT {
/**
* Custom Shader Material
* @class MyTestMaterial
*/
export class MyTestMaterial extends TOOLKIT.CustomShaderMaterial {
public constructor(name: string, scene: BABYLON.Scene) {
super(name, scene);
this.plugin = new PROJECT.MyTestMaterialPlugin(this);
}
}
/**
* Custom Shader Material Plugin
* @class MyTestMaterialPlugin
*/
export class MyTestMaterialPlugin extends TOOLKIT.CustomShaderMaterialPlugin {
public constructor(material:BABYLON.Material) {
// the second parameter is the name of this plugin.
// the third one is a priority, which lets you define the order multiple plugins are run. Lower numbers run first.
// the fourth one is a list of defines used in the shader code.
super(material, "MyTestMaterial", 100, { MYTESTMATERIAL: false });
// let's enable it by default
this._enable(true);
}
// Also, you should always associate a define with your plugin because the list of defines (and their values)
// is what triggers a recompilation of the shader: a shader is recompiled only if a value of a define changes.
prepareDefines(defines, scene, mesh) {
defines["MYTESTMATERIAL"] = true;
}
// This is used to inform the system which language is supported
isCompatible(shaderLanguage) {
switch (shaderLanguage) {
case BABYLON.ShaderLanguage.GLSL:
case BABYLON.ShaderLanguage.WGSL:
return true;
default:
return false;
}
}
// Get custom shader code
getCustomCode(shaderType, shaderLanguage) {
if (shaderType === "fragment") {
// we're adding this specific code at the end of the main() function
if (shaderLanguage === BABYLON.ShaderLanguage.WGSL) {
return {
CUSTOM_FRAGMENT_MAIN_END: `
var luma = fragmentOutputs.color.r*0.299 + fragmentOutputs.color.g*0.587 + fragmentOutputs.color.b*0.114;
fragmentOutputs.color = vec4f(luma, luma, luma, 1.0);
`,
};
}
return {
CUSTOM_FRAGMENT_MAIN_END: `
float luma = gl_FragColor.r*0.299 + gl_FragColor.g*0.587 + gl_FragColor.b*0.114;
gl_FragColor = vec4(luma, luma, luma, 1.0);
`,
};
}
// for other shader types we're not doing anything, return null
return null;
}
// Get the classname
getClassName() {
return "MyTestMaterialPlugin";
}
}
}