Material plugin dynamic shader code

hello

i’m currently working on fashion project
and i want to users allow to add some stickers to there cloth

i create material plugin for this
and my project work with only hard coded shaders
like this


    if (shaderType === "fragment") {
      return {
        CUSTOM_FRAGMENT_DEFINITIONS: `
            uniform sampler2D sticker_0_txtr;
          `,
        CUSTOM_FRAGMENT_BEFORE_LIGHTS: `
          surfaceAlbedo = baseColor;

          float halfSize = sticker_0_size / 2.0;

          vec2 uv =  vAlbedoUV;

          uv.x *= 1.0 / sticker_0_size;
          uv.y *= 1.0 / sticker_0_size;

          // todo this is not dynamic yet
          uv.x += 0.5;
          uv.y += 0.0;



          if ((sticker_0_uvof.x - halfSize) < vAlbedoUV.x && vAlbedoUV.x < (sticker_0_uvof.x + halfSize)) {
            if ((sticker_0_uvof.y - halfSize) < vAlbedoUV.y && vAlbedoUV.y < (sticker_0_uvof.y + halfSize)) {
              vec4 sticker = texture2D(sticker_0_txtr,uv);
              surfaceAlbedo = mix(surfaceAlbedo, sticker.rgb, sticker.a);
           }
          }
        `,
      };
    }

and that’s work find but i want to be able to add or remove stickers
so i change my code to something like this


    if (shaderType === "fragment") {
      if (this.stickers === undefined) return;

      let CUSTOM_FRAGMENT_DEFINITIONS = "";
      this.stickers.forEach(
        (_sticker, i) =>
          (CUSTOM_FRAGMENT_DEFINITIONS += `uniform sampler2D sticker_${i}_txtr;`)
      );

      let CUSTOM_FRAGMENT_BEFORE_LIGHTS: string = "surfaceAlbedo = baseColor;";

      this.stickers.forEach(
        (_sticker, i) =>
          (CUSTOM_FRAGMENT_BEFORE_LIGHTS += `
      float halfSize = sticker_${i}_size / 2.0;

      vec2 uv_${i} =  vAlbedoUV;
      uv_${i}.x *= 1.0 / sticker_${i}_size;
      uv_${i}.y *= 1.0 / sticker_${i}_size;

      // todo this is not dynamic yet
      uv_${i}.x += 0.5;
      uv_${i}.y += 0.0;

      if ((sticker_${i}_uvof.x - halfSize) < vAlbedoUV.x && vAlbedoUV.x < (sticker_${i}_uvof.x + halfSize)) {
        if ((sticker_${i}_uvof.y - halfSize) < vAlbedoUV.y && vAlbedoUV.y < (sticker_${i}_uvof.y + halfSize)) {
          vec4 sticker = texture2D(sticker_${i}_txtr,uv);
          surfaceAlbedo = mix(surfaceAlbedo, sticker.rgb, sticker.a);
       }
      }
    `)
      );
      return {
        CUSTOM_FRAGMENT_DEFINITIONS,
        CUSTOM_FRAGMENT_BEFORE_LIGHTS,
      };
    }

    return null;
  }

and pass stickers to materialPlugin class
but i think “getCustomCode” method is calling in “super” functions and “this.stickers” is undefined

i disable plugin and enable it in setTimeout but still material plugin not working

“getCustomCode” is calling again and this.stickers are avaliable but shader code is not recompiled i guss

is there any way to force material plugin (or mareial ) to recompile??

thanks for your time

You can make your getCustomCode() called again by declaring a define for which you will change the value each time you want to recompile: this will make the system recreate a new effect and recompile your shader. To trigger the call to createEffect(), you will have to flag your material as dirty (the the forceCompilation method in the PG):

Now, do scene.getMaterialByName("cloned").pluginManager.getPlugin("Colorify").forceCompilation() in the console of the browser: you will see a “cloned getCustomCode called” log that indicates that getCustomCode() has been called.

Note that:

    BABYLON.RegisterMaterialPlugin("Colorify", (material) => {
        material.colorify = new ColorifyPluginMaterial(material);
        return material.colorify;
    });

gets in your way in this case, so you should just create a new plugin instance yourself (see line 34).

thanks that is working fine

but my mistake was something else

in “getCustomCode” function “if (this.stickers === undefined) return;” i was return "void "in case of stickers was undefined ( at first call of “getCustomCode” i don’t know why but it’s happen)
and change “void” to empty object of shader code fix my problem

      if (this.stickers === undefined)
        return {
          CUSTOM_FRAGMENT_DEFINITIONS: "",
          CUSTOM_FRAGMENT_BEFORE_LIGHTS: "",
        };

still i don’t know why this happening

this is i simple PG i try to show you what i mean
toggle comment between line 146 and 147

thakns for your help :folded_hands:

The first call to getCustomCode() is made by the constructor of the base class when you call super(...) from the constructor of your plugin. At that time, test is not set yet (it is set after the super call), hence the undefined value.