How’s this operation from a performance standpoint? Is it particularily slow (for example, if I’d add 10 decals to the material, each with its own individual matrix)?
The cost of SetMatrix() itself is inconsequential. Unity is doing multiple of these for every single dynamic object on screen.
The cost of a single mul in a shader isn’t too bad. A lit shader does a handful of these for lighting already. Adding 10 of these can be a not insignificant cost, but sampling of 10 extra textures is probably a more expensive aspect.
Good point. I can make them all use single texture or some form of atlas. For cases like limited number of blood splatters where the oldest is reused for the next one (similar to object pooling).
Speaking of that, what would be the most efficient way to store decals then? Generating decal meshes? Because storing info for decal UVs in vertices or texture will be resolution limited, and using matrices can be costly with large number of them, as you said
I should rephrase: “the cost of sample any texture 10 extra times”. An atlas or texture array both remove the issue of running out of samplers, but what’s expensive doing decals in the shader like this is doing the tex2D() 10 times, even if it’s the same texture all 10 times.
That’s not to say this isn’t a viable way to do decals, especially if you only want decals on a few specific objects or characters, it’s totally fine.
And yes, using a ring buffer so you only have some max number of decals is a good way to limit the number of them you have.
Often the best way to do decals is by having them be their own object. In the past that might mean just a transparent quad placed just above the surface. Today that might mean a quad or cube, but using a special material that samples the depth texture to only draw over close surfaces, or even draws to the GBuffers if you’re using deferred rendering. Some more advanced setups might draw decals to a render texture in UV space (think Portal or Splatoon, or blood splatters on zombies in some games) so they only need to be drawn once and then can stick around forever after that for no extra cost. Others use Forward+ rendering techniques where the screen is sliced up into sections and what decals are visible in each screen “tile” is calculated before hand. Or mesh decals are used where the decal is actual geometry just above the surface of the object, but clipped to the bounds of the decal, which is what Doom Eternal does. Etc.
About other workflows, I wont pretend to understand how Forward+ method works, mesh is more understandable, but how “render to texture” way works in Unity? Does texture baking still require a hack where you need to flatten an object (UV to 3d), place it next to orthographic camera, and render? Or there is some more automated way?