[SOLVED] Global shaderChunk uniform

Hello everyone!

I’d like to add some global post-effect (e.g. raising all the vertices by some Y value) implemented via vertex shader. I modify the transformVS by adding an uniform and performing simple Y-shift:

   pc.shaderChunks.transformVS = `       
        uniform float shiftY;    //uniform definition
        .......

       vec4 posW = dModelMatrix * vec4(localPos, 1.0);
       posW = posW + vec4(0.0, shiftY, 0.0, 0.0);    //uniform usage
   `

In order to pass a new shiftY value to the shader, I have to go through the scene hierarchy recursively and set the shiftY value to each material on the scene using setParameter, e.g.

const applyShaderValue = (entity) =>  {
       entity.model.meshInstances.forEach(mi => {
            mi.material.setParameter('shiftY', 2.5);    // pass the new uniform value
        });
       entity.children.forEach(applyShaderValue);  //recursive call
}

This is quite heavy task, especially when there are a lot of entities on the scene.

I wonder if there is a way to set the ‘global’ shiftY value somewhere (e.g. apply it once for the whole scene), instead of setting it for each entity’s material individually?

1 Like

Hi @Igor,

I don’t think there is an easy way of doing this, without modifying the PlayCanvas engine.

A lighter alternative of what you are doing is instead of looping through all mesh instances and applying the parameter, is to do it on all materials.

So basically grab a list of all the materials in your scene and do the same. To get that list you can use the asset registry.

var assets = this.app.assets.filter(function (asset) {
    return asset.type === 'material';
});

assets.forEach( asset => {
   const material = asset.resource;
   material.setParameter('shiftY', 2.5);
});
2 Likes

you can do this just once, when you initialize engine or your class:
this.myParam = this.device.scope.resolve("shiftY");

and then update it like this per frame:
this.myParam.setValue(5.0);

just make sure that whatever name you pick it’s unique, otherwise it can get overwritten.

4 Likes

Thank you @Leonidas, that solution sounds great!

But what happens if I have cloned (dynamically created) materials
const newMaterial = oldMaterial.clone(),

AFAIK they aren’t stored in the AssetsRegistry?

1 Like

Yes, if you are dynamically creating materials those you need to manually add to that list.

@mvaligursky’s solution is much cleaner I think!

1 Like

Thanks guys! @mvaligursky’s solution worked perfectly!

2 Likes