Applying shaders to 2D images with transparency


In my project I’m going to have a certain number of 2D images with transparency that I want to be able to display in either full colour (so, no effects or shaders etc applied) or in black and white (greyscale or desaturated). I want to avoid having to import colour and greyscale versions of every image into the project, so I’m trying to find a way of removing the colour from the assets at runtime whenever required, using shaders or whatever method works best.

There will also be 3D objects in the scene, and currently I have a nice greyscale shader running on all the entities that have the render component, applying a new material with the shader in it to their meshInstances, as explained here: Custom Shaders | Learn PlayCanvas

The shader is just a port of this simple PIXI JS one: filters/grayscale.frag at main · pixijs/filters · GitHub

This works great for 3D primitives whose textures don’t have any transparency, but not my 2D images - I don’t know if I can even apply a shader to a sprite at all, but instead I’ve tried flat planes with the 2D image set as both diffuseMap and opacityMap, but they immediately lose their transparency when the shader is applied. I can’t seem to get the new shader material to honour the opacityMap of the original material by using: material.setParameter(‘opacityMap’ …

When you’re applying a shader to an object, why do you need to create a new material? Is there a way of applying it to the existing one, and thus retaining all of the configurations already set for it?

Is there a better way of applying the opacityMap to the new material?

Or is there something in the shader that I should change?

Ideally I’d like to apply the shader to sprites instead of planes with 3D materials on them, but I can’t seem to find any evidence to suggest that this is possible. Please correct me if I’m wrong.

Or in general, if anyone knows the best way of applying a greyscale effect to a 2D image and retain its transparency, I’d love to know. It’s early on in the project so I’m flexible on the solution, but I admit I don’t know a lot about shaders. If there’s a way it can be done without shaders at all, I’d certainly be interested in that as well.