How to set the value of a common uniform to several ShaderMaterials in one step?

Hello,

Coming from here: Proper way to animate a texture attached to a mesh?

I’m treating to do the whole “play animation” logic of a pseudo-sprite within the shader code (switching texture coordinates of a plane), to relieve JS of doing it.

To do so, I’m using a ShaderMaterial on the mesh, which is going to update the UV of the texture.

I need the timer tick to do the whole logic of the animation, and at the moment I didn’t found a way to get the timet tick (Date.now()) within the shader code.

I’ve found this topic in stackoverflow: How to set a time uniform in webgl - Stack Overflow

So I would need something like the WebGL getUniformLocation and gl.uniform1f to set the u_time uniform value in one step for several ShaderMaterials (one per sprite animation), but I haven’t found something similar in Babylon.

Is it possible to set the value of a global uniform used in several ShaderMatereials?

My idea is this:

In each ShaderMaterial:

   BABYLON.Effect.ShadersStore[`spriteMesh${this.idShader}FragmentShader`] = `
    precision highp float;
    varying vec2 vUv;
    uniform sampler2D textureSampler;
    uniform int initialTime; // This is local, I use shaderMaterial.setFloat
    uniform int frameStart; // This is local, I use shaderMaterial.setInt
    uniform int frameEnd; // This is local, I use shaderMaterial.setInt
    uniform int timerTick; // This is global and common to all sprites ShaderMaterials

    void main() {
        // Do the play animation logic
    }
`

In the main render loop:

// This should be done in Babylon instead WebGL
var timeLocation = context.getUniformLocation(program, "u_time"); 

function renderLoop(timeStamp) {
  // This should be done in Babylon instead WebGL
  gl.uniform1f(timeLocation, timeStamp/1000.0);
}

Ok I found it, it is in the Babylon Engine object, setFloat method :slight_smile:

But now I don’t know how to use the BABYLON.Engine.createPipelineContext method to get the uniform context, and if it is even possible to create a pipeline context common to all the pseudo-sprites ShaderMaterials :-/

1 Like

If you are using a shader material, you should use the methods provided by the ShaderMaterial class to set uniform values. This page should get you started:

https://doc.babylonjs.com/features/featuresDeepDive/materials/shaders/shaderMaterial/

Users don’t need to do that, you should have everything you need from the shader material class.

Yes, that’s how I do it at the moment, but since the timer tick is the same value in all ShaderMaterials, I was wondering if I could use a common uniform and update it in one step for all the ShaderMaterials.

If you confirm me this is not possible, then I will update it sprite by sprite.

If you must set different values for one or several uniforms, you should create different materials and set the right value(s) for each one. I don’t really see another way to do it.

1 Like

So to recapitulate, please correct me if I’m wrong.

There’s no way to have a common uniform to different ShaderMaterials and set their value in one step.

Each ShaderMaterial has to be treated as an individual piece, regardless we want to set the same value to an uniform of the same name in all of them

Correct, if you have several shader instances, you will have to set the values of their uniforms for all of them. Your use case is particular in that you set the same value for several instances, but the general case is that we may want to set a different value for each instance.

1 Like