Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

Can I disable a material or have it's draw pass completely skipped?

Discussion in 'General Graphics' started by Pinkuboxu, May 31, 2018.

  1. Pinkuboxu

    Pinkuboxu

    Joined:
    Mar 20, 2014
    Posts:
    54
    My scenario is that I have a character made up of multiple parts, but that I have either joined together or baked into one mesh at runtime to help keep the draw calls down. Many of the parts have different materials to help texture/color them for custom means, but also alpha channels for texture transparency and detail. I cannot bake the materials together into one because the way the overlapping meshes are they fight for Z Order and everything wonks up all inside out. So I have to have multiple materials to maintain proper transparency. This is fine but I would like to turn certain parts like accessories and clothing off and on. Since they belong to the same mesh I would think if there was a way to turn the material off or tell the renderer to not render that material at all, then that would be a good solution to the problem. I just can't find that functionality and fear it's not possible due to the nature of how the renderer works.

    Pretty sure I've been over the API enough to know there isn't a way to directly disable a particular Material but I'm lost as to if there is another way to have it not showing other than setting it to transparent and setting the alpha to zero or changing the texture to a 1x1 pixel transparent one, which isn't really ideal and seems kind of like a hack.

    Perhaps I can write a very simple shader that just sets the material to transparent and zeros the alpha and switch to that shader and back for the effect? I just thought of that but I'll have to try it. Any ideas would be welcome save for the ones that require me to change how my model is set up and I would rather not have to call a bake every time for a change... but I suppose that might also be an idea.

    PS: Also know about sub meshes but I'm still looking for a way to eliminate the draw calls of that submeshes material for speed, and great justice.
     
    Last edited: May 31, 2018
  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,256
    This comment:
    Runs counter to this comment:
    Each material is another draw call (or multiple draw additional calls depending on the shader, shadows, lights, etc.).
    Each sub mesh for skinned meshes is another draw call (or, again, potentially multiple draw calls) even if they are using the same material as skinned meshes aren't batched or instanced.

    Combining separate meshes with multiple materials into a single mesh object doesn't change this. You remove some overhead from having multiple game objects, but unless this are otherwise adding hundreds of additional game objects it's not likely to be significant. You're better off not merging them and just turning on and off the game objects as needed.

    That will indeed hide the mesh visually, but you're still rendering it as far as the GPU is concerned. It'll calculate all of the vertices and run the full fragment shader, and blend with the background, just with a blend value of zero. You're paying the full cost of it being there. Using a custom invisible shader would be cheaper, though the best solution is to have it output the position from the vertex shader as a constant value for all vertices (ie: o.pos = -1.0;) which will make it skip running the fragment shader entirely, but it'll be faster to just turn off the mesh.


    If you want to reduce the draw calls you have to merge the materials, which means merging the textures into an atlas or doing something like Brink where you give each "category" of part a section of a UV and merge into one or two texture sets.
    http://www.gdcvault.com/play/1014359/Punching-Above-Your-Weight-Small
    https://www.splashdamage.com/downloads/pubs/Punching_Above_Your_Weight.ppsx

    If you want to unique color parts you'll want to use vertex colors instead of material parameters.

    To make this clear, if you want to reduce draw calls for a skinned mesh you can't have multiple submesh / material indices. Ideally after you merge your mesh you will have only one or two material indices. Multiply sub meshes and material indices with the same material still means multiple draw calls.

    To deal with z order sorting, you may want to consider using an alpha tested material instead of alpha blended.
     
    Last edited: May 31, 2018
  3. Pinkuboxu

    Pinkuboxu

    Joined:
    Mar 20, 2014
    Posts:
    54
    Most of what you are saying I already understand. Sorry if I didn't explain what I do know well enough. I haven't attempted vertex coloring so I will try that and see if it works for my situation. Where you say my comments run counter, I probably typed a line, got inspired to try something suddenly, then came back and typed something else, trying to get back to my train of thought, and that ended up worded terribly. I should have edited that better but also burning the midnight oil, had insomnia the night before... sorry... personal problems, I digress.

    I'm working off a post I made the other day concerning the problem with the Alpha Blended rendering and the Z Order problem. I thought I had solved this long ago but I don't remember what material I used to solve it or even if I'm remembering correctly as I lost all of my projects late last year due to a RAID dying. The answer given was to use multiple materials, which I knew, but how to bake a texture and have one material and have the transparency look good. Alpha Test, like Cutout, on it's own will solve the Z Order issue, but looks bad when you have soft or gradient alpha in a texture. So I'd have to learn how to combine the two I guess since it's beyond my current shader coding knowledge. I don't know of any built in shaders like that, besides, I'm using the LWP and trying to get into programmable pipeline stuff.

    I did make a simple shader that just made things transparent. This did help to lower the draw calls but of course it's still drawing the material, which feels like a waste. I may just stop there, fix it up later, so I can get on with coding logic for a change, but I'm also inspired with the idea of checking into how much power programing the new render pipeline will give in this case. If there is a way to disable materials/submesh drawing, I would assume it would be there. Honestly, at this point I'm probably nitpicking and can get away with what I have but I get addicted to optimization concepts and "polishing aluminum foil balls" if that analogy makes sense. Thank you so much for the great ideas and help!
     
  4. Pinkuboxu

    Pinkuboxu

    Joined:
    Mar 20, 2014
    Posts:
    54
    Vertex coloring doesn't really work well for me. I had to add that to my own shader to get it to work and it ended up being more draw calls while on top of that I still haven't really figured out how to combine Alpha Test and Blended together correctly, which is also adding more overhead and making me waste time. I think I'll just do, as suggested and as I have done in other systems, keep parts separate and turn the objects or skinned mesh renderers on and off as needed. The whole ordeal ended up being less about the project I was working on and more about the concept of getting a single mesh and a single material work with alpha and that wasted time.
     
  5. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,256
    Yep, that is absolutely the case. Apart from particle, UI, and sprite shaders, the default Unity shaders ignore the vertex color.

    It shouldn't be. It should be either exactly the same number of draw calls, or less, again assuming you're using a single material across everything so the submeshes are merged. However if you're replacing materials that were transparent with ones that are opaque (or alpha tested), that can add more draw calls since those objects now cast and receive shadows and each shadow casting light can add between 2 and 7 (yes, really) passes. It's possible this is what you were seeing?

    You can't. Shaders can be alpha tested or alpha blended. There is no middle ground. You could optionally use dithered alpha testing, but it won't look as nice as real alpha blending.
    I guess technically there's alpha to coverage, but that's really dithered MSAA coverage sample alpha testing than alpha blending, and if you're not using MSAA isn't any different than alpha testing.
     
  6. Pinkuboxu

    Pinkuboxu

    Joined:
    Mar 20, 2014
    Posts:
    54
    Ah, then maybe I worded it wrong or it's not supported? I'm following this page from the manual, https://docs.unity3d.com/Manual/SL-AlphaTest.html. Anyway, I think I have it figured out for the most part, at least so far that I have enough to work with so I can get back to logic. Thanks for the help and information.
     
  7. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,256
    I should be more explicit in what I mean.

    You can use alpha testing by means of clip() and alpha blending together in the same pass, but the main benefits of alpha testing is being able to use alpha testing with ZWrite for proper sorting. If you use alpha blending with a shader that also uses ZWrite in the same pass you’ll get strange artifacts where “holes” will appear in places that the alpha is low, but ZWrite still occurred thus preventing objects behind it from rendering.

    In the last example on that page they have a two pass solution that does an initial ZWrite enabled alpha test pass to fill the z buffer, then a second to do the alpha blended pass. This can work well to get a mostly properly sorted but still alpha blended shader, but it doubles the draw calls as one is added for each pass.

    The example shader is also written in the deprecated fixed function format, and can be done a bit better using a surface shader or vertex fragment shader, like my example here:
    https://forum.unity.com/threads/sta...y-shiny-on-the-underside.393068/#post-2574717

    Note: there are some problems with shadowing mentioned in the tread on that shader. This can be solved to a degree with a custom vertex fragment shader, or just modifying the generated shader code from the surface shader. However since you’re using transparent shaders already, this is unlikely a concern for you. It does still use at least two drawcalls.