Search Unity

Multi-layered transparency optimization

Discussion in 'Shaders' started by hottabych, Oct 16, 2019.

  1. hottabych

    hottabych

    Joined:
    Apr 18, 2015
    Posts:
    103
    There is a bunch of semi-transparent gameobjects (e.g. car engine, with mechanisms inside with even smaller details inside), visible through each other. This multi-layered transparency is bad for a performance. How to optimize rendering?
    I have an idea to create a shader which will render 2 or 3 transparency passes and blur or cull layers that are deeper. But I don't know how to write such a shader. Is it possible via Shader Graph? Somebody dealt with same problem before?
     
  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    7,683
    Is it actually a problem, or are you just expecting it to be? Like if you make all these objects opaque are you getting good performance?

    Yes overdraw can be expensive, but you kind of have to live with it if you're doing transparency like this, and if it's not actually a performance problem (which it might not be if they don't cover a lot of the screen) then it's probably not worth spending time to fix.

    If you're blurring layers, you're still rendering them. Worse now you're rendering them to a separate render pass or doing a grab pass which is way, way more expensive than rendering them normally to begin with. Culling after N layers rendered is plausible, but not necessarily going to save you any performance. Transparent objects by their nature require they be rendered "back to front" to be properly sorted, that is to say render the objects further away first so that further away objects appear behind transparent objects that are closer. Basically there's no easy way to cull those objects that are 3 layers deep because you have to have already rendered them in the first place for sorting to work.

    So, options:

    Limit the number of objects visible and make objects opaque.
    If you're controlling how "deep" into the object you're rendering, show the layer you're on as opaque and only render one layer "above" as transparent. Doesn't really work great for something like an engine which doesn't have nice neat layers though.

    Use dithered transparency rather than alpha blending.
    You'd have to randomize the dither pattern either per object or by depth, but it'll get you a decent approximation of transparency while also eventually culling stuff that's too "deep". This has the nice advantage of being totally possible with Shader Graph. See this paper on hashed alpha testing:
    https://casual-effects.com/research/Wyman2017Hashed/index.html

    Use additive blending.
    If you really are having performance problems with the transparent layers, and this is for mobile, using additive blending instead of alpha blending may be faster to render. This won't be true on desktop, iOS, or some newer Android devices, though you also shouldn't be having performance problems from having a few layers of transparency like this on those. You could switch to opaque or alpha blended for the object you're selecting to make sure the object can be easily seen.
     
    hottabych likes this.