Scripting for Material Instance Animations

I’m just getting started with PlayCanvas and have been reading and learning. I made a project to explore texture animations. I’d like to understand if it is possible to assign one material to two objects and animate that material differently on each object. In the project, I setup a script that accepts an array of material asset references, an array of entity references, an array of configuration data for texture map UV animations, and an array of configuration data for tint animations. My goal was to apply all sets of animation data (scrolling, spinning, and tint) to all the provided references with this added functionality: If you pass a material asset reference, all objects with that material are animated but if you pass an entity reference, only that entity will be animated even if the material is shared with other entities.

So far the script is doing everything except material instance animation, and I have to say I’m really pleased with the level of documentation provided for this engine. However, I am unsure if material instancing is supported and was hoping someone could point me in the right direction.

When animating material assets I am accessing [materialAsset].resource.[animationParameter] and this successfully updates all entities that have that material asset applied. When animating by entity reference I tried accessing [entity].render.material.[animationParameter] and [entity].render.meshInstances[0].material.[animationParameter] and these attempts also update all objects that have the material applied.

Hi @bdb and welcome,

Nice example! Yes, material instances as you define them are supported in PlayCanvas by accessing and setting the material properties directly on a mesh instance.

You will have to use the setParameter method, which works the same both on the material and on the mesh instance level. Although the parameters are undocumented for the moment and are subject to change.

For example to set the diffuse channel transform (offset/tiling) you can do this directly on a mesh instance, and it will affect only that mesh instance:

   this.uniform0[0] = tileWidth;
    this.uniform0[1] = 0;
    this.uniform0[2] = tileOffsetX;
    this.uniform1[0] = 0; 
    this.uniform1[1] = tileHeight;
    this.uniform1[2] = tileOffsetY;
    meshInstance.setParameter("texture_diffuseMapTransform0", this.uniform0);

Source: Material parameter uniform names have changed since 1.46.0


Using setParameter has the additional benefit of better performance, when compared to material.update. Since it updates a single uniform value it’s much better when required to make calls per frame, as in an animation.