Cannot get mesh to update texture u v values

I cannot understand why the following is not altering the texture on the entity, nothing is happening at all to the texture

    var meshes = this.entity.model.model.meshInstances;

    
    this.transform.set(1, 0.5, 0, 0.5);
    console.log('updating material');
    meshes[0].setParameter("texture_diffuseMapTransform", this.transform.data);
    meshes[0].setParameter("texture_emissiveMapTransform", this.transform.data);
    meshes[0].setParameter("texture_opacityMapTransform", this.transform.data);

i know the code runs but the texture doesn’t change

So frustrating!
Sometimes it feels like Playcanvas makes difficult stuff easy and easy stuff difficult

I have created a simple project to illustrate the problem

https://playcanvas.com/project/407405/overview/animated-texture-test

I thought I had followed the tutorial faithfully and the tutorial project appears to work fine but my own attempts are failing. what on earth is wrong?

Is there any reason you’re not using these:

https://api.playcanvas.com/classes/Engine.StandardMaterial.html#diffuseMapOffset
https://api.playcanvas.com/classes/Engine.StandardMaterial.html#emissiveMapOffset
https://api.playcanvas.com/classes/Engine.StandardMaterial.html#opacityMapOffset

e.g.:

material.diffuseMapOffset.set(u, v);
material.emissiveMapOffset.set(u, v);
material.opacityMapOffset.set(u, v);
material.update();

You would obtain the material in a number of ways. Either with a script attribute:

pc.script.attribute('material', 'asset', [], {
    type: 'material',
    max: 1
});

Or you get it from a particular pc.MeshInstance:

var material = this.entity.model.meshInstances[0].material;`

i only want to change the offset on one instance, and those are not mentioned in the tutorial on animated textures.

Just create a duplicate material for that instance.

put that code into my test project but no errors and no change :frowning:

var meshes = this.entity.model.model.meshInstances;
            var material = this.entity.model.meshInstances[0].material;
            // create the transform vector (tilingx, tilingy, offsetx, offsety)
            // and override the material properties for this mesh
            // This allows us to use different settings for different Entities, but share the same material
            //this.transform.set(dx, dy, x * dx, (1 - dy) - (y * dy));
            if (frame==1) {
            this.transform.set(1, 0.5, 0, 0.5);
                material.diffuseMapOffset.set(0, 0.5);
            } else {
            this.transform.set(1, 0.5, 0, 0);  
                material.diffuseMapOffset.set(0, 0);
            }
            console.log('updating material');
            console.log(this.transform.data);
            
            
            meshes[0].setParameter("texture_diffuseMapTransform", this.transform.data);
            meshes[0].setParameter("texture_emissiveMapTransform", this.transform.data);
            meshes[0].setParameter("texture_opacityMapTransform", this.transform.data);

You missed:

material.update();

ah! yes, thank you.
but how do I clone a material so that I can set it on one instance and create a unique u v?

I would still like to understand why following the tutorial example it didn\t work, I am new to playcanvas and it would really help to understand why my first attempts using the setParameter are not working when they appear to work fine on the tutorial project.

Option 1:

var materialClone = someMaterial.clone();
this.entity.model.meshInstances[0].material = materialClone;

Option 2:
Duplicate the material in the Asset Panel and assign in script from a script attribute using the second line above.

I don’t know why the other way didn’t work - @dave might know.

thank you for filling in the blanks, much appreciated.

It may be that if you use default transform of 0,0,1,1 initially - then shader will not have uniforms for transforms, and sending other params - will be ignored then. Setting initial offset/tiling values to different from 0,0,1,1 might solve a problem for you.
@Mr_F would need to confirm that.

I’m running into a similar problem where I’m trying to save draw calls by having one material and a dynamically generated texture from multiple images and changing the offset/tiling on each mesh instance.

When set the offset/tiling directly on the material it works fine but not when I apply it to the mesh instance.

this works:

    var meshes = this.plane.model.meshInstances;
    var material = this.plane.model.material;

      material.diffuseMap = texture;
      material.diffuseMapOffset= new pc.Vec2(0,0.5);
      material.diffuseMapTiling= new pc.Vec2(0.333,0.5);
     material.update();

this does not:

this.transform = new pc.Vec4();
this.transform.set(.333,0.5, .333, 0.5);
meshes[0].setParameter("texture_diffuseMapTransform", this.transform.data);
material.update();

Would cloning the material have any impact on draw calls?

Would you recommend another way of displaying 20k plus icons?

Thank you.

Hi @noah_mizrahi,

If you aren’t using batching then each mesh instance will require a separate draw call to get rendered, even if they are all using the same material.

If you are using batching, then the batcher will group all mesh instance that share the same material and material properties to get rendered using the same draw call.

That means if you are using the same material but you are changing the diffuseMap transforms that will still count as a different combo that requires a separate draw call.

I think for icons/graphics your best bet are sprites using texture atlases. That way you can load a single texture atlas that contains multiple icons and then use sprites to render them in place.

1 Like

Thanks @Leonidas, always there with the answer!

If I needed to display 10k icons as performant as possible would you recommend using a ui elements instead?

A texture atlas seems like a good way to go if I needed to animate the icons.

If the icons are for UI then yes. If not, sprites would be a pretty I would have thought.

The major issue is the sprite editor not being able mass create a sprite asset per ‘frame’ but Leonidas might have some editor side script for that

I don’t have something handy, but indeed that would be useful to have. I have being using texture atlases a lot recently and it gets tedious to after a while.

@noah_mizrahi, I imagine you aren’t trying to display 10k different icons at the same time/view, just scattered in your scene. Right?

If that’s the case, some things I would keep in mind to get the best performance:

  • Definitely have frustum culling enabled in your camera.
  • Definitely leverage batching where you are able.
  • You will have to use several texture atlases for your 10k icons, a single one won’t have sufficient resolution of course. That means that you should take care of your VRAM allocation, that is the total video memory your textures occupy. If you are able to load/unload texture assets from memory, if you know for a fact that those textures/sprites aren’t rendered in the current frame that would help you reduce your VRAM usage.

It’s a feature request I made in the Editor repo. I’m trying to find the time to setup the editor environment on my laptop to help out the Editor team with the smaller requests.

1 Like