Search Unity

Textmesh pro stencil shader

Discussion in 'Shaders' started by BinaryCats, Jun 21, 2019.

  1. BinaryCats

    BinaryCats

    Joined:
    Feb 8, 2016
    Posts:
    317
    Hello,

    I have some transparent text in my UI. This text sits across transparent Images.

    I want it so wherever the text overlaps the image, the image behind is not rendered. My first goto was creating a stencil shader, by minorly editing the TextMesh Pro's shader

    This is the result: (I have a black skybox) (text / green image / red image have 50% transparency)

    The intended result is for the text to render as white(with 50% transparency) ontop of the images (not tinted green/red by the images behind)

    However you can obviously see the whole glyph, the stencil creating a black box around each letter.


    Has anybody done anything like this before? How can I go about achieving my desired effect?

    Thanks in advance
     
  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,343
    If you're writing to the stencil buffer, any geometry that is rendered will write to the stencil. For text, each character is a texture on a quad, so the entire quad is what writes to the stencil. Alpha blending doesn't have any effect here since anywhere the shader has output an alpha of 0.0 ... the shader still output a value, and thus the GPU wrote to the stencil.

    The solution for this with stencils is to not use alpha blending, but to use alpha testing via clip() or discard commands, or using alpha to coverage via AlphaToMask On (which mostly works with MSAA, but is similar to clip() when MSAA is disabled), but that has its own problems.

    Unfortunately TMP's shaders don't make this super easy to implement cleanly, especially if you plan on using any of the extra features, like outlines. Basically you do not want the outside edge of the character to use alpha for transparency otherwise you'll get a dark edge around the characters. The best option is likely going to be adding something like this:

    Code (csharp):
    1. float    sd = (bias - c) * scale; // a line already in the TMP shaders
    2. if (sd < 1) discard; // discard if the alpha is less than fully opaque