How to set mesh opacity without directly changing it's material's property

I have several cloned entities with the same model. I want to set opacity of each entity independently of each other. Is this possible?

Yes, you can use the setParameter method to change any material/shader uniform directly on a meshInstance, instead of a material, without affecting other entities using the same material. That would have to be done in code.

Here is a helpful thread: ☑ I have some problem when I change the material

Just note if you are using batching, those entities can’t be batched since a requirement for batching is having the same shader uniforms.

2 Likes

Also note that the material opacity has to either begin at a value lower than 1 (0.99999 will do) or be reset to such a value in code before the setParameter method will work.

2 Likes

I should have been more clear. Apparently PlayCanvas treats materials that have a 1.0 opacity as a special case and initializes them without defining a material_opacity attribute . So you must either start non-opaque (0.99999 opacity) or change it in code. But once you’ve changed it in code, you can change it back to 1.0 now that you’ve established the material_opacity attribute.

I don’t like having to set all my opaque materials to 0.99999, so I have my model dissolve code check to see if the first material in the entity model has a material_opacity attribute or not. And if not, then do it for me.

    if(this.entity.model.meshInstances[0].parameters.material_opacity === undefined){
		for (this.miStep = 0; this.miStep < this.entity.model.meshInstances.length; ++this.miStep){
            this.opacityFactor =this.entity.model.meshInstances[this.miStep].material.opacity;
			this.entity.model.meshInstances[this.miStep].material.opacity = (this.opacityFactor * 0.999999);
			this.entity.model.meshInstances[this.miStep].material.blendType = pc.BLEND_NORMAL;
			this.entity.model.meshInstances[this.miStep].material.update();	
            this.entity.model.meshInstances[this.miStep].setParameter('material_opacity', (this.opacityFactor);
		}

I’m pretty sure that the last line is valid and that you can reset your initial opacity back to 1.0 and that setParameter will work later on. But either way, the above code or something similar can make sure that your entity will dissolve using setParameter. You just have to make sure that you don’t build objects that have transparency in the first model.meshinstance. Otherwise, the material won’t get reset.

1 Like

Thanks for sharing it that @wturber, and for the explanation!

The 0.999 trick is basically the way to tell Playcanvas to include the blending/opacity shader chunk when it generates the shader for this material. Which by default isn’t included to save performance.

The setParameter(‘material_opacity’) updates the value of a shader uniform (read variable) which makes sense only if blending has been included to the shader rendering this material.

And setParameter is faster and more efficient than using material.update()

Changing our object dissolving to use setParameter improved the performance of our slow dissolving up/down of multiple objects with many materials by a substantial amount. It may have been you who explained that doing lots of material.update() calls makes it very likely that some kind of garbage cleanup will be invoked which will cause the app to stutter/pause.

From where I sit, setParameter should be the generally preferred method for dissolving objects. Though the benefit may not be noticeable if the number of materials is low.

2 Likes