Search Unity

  1. Calling all beginners! Join the FPS Beginners Mods Challenge until December 13.
    Dismiss Notice
  2. It's Cyber Week at the Asset Store!
    Dismiss Notice

How to keep consistent colour transparency?

Discussion in 'Shaders' started by Lethn, Oct 9, 2019.

  1. Lethn


    May 18, 2015

    I've been posting a lot on this topic and I think it's because I'm trying to find a method that best suits my needs for getting some kind of influence map setup for my game. The problem I have is there are solution that do sort of work but they don't achieve the effect I want exactly or if they do work it is incredibly complex and expensive for the effect I'm trying to make.

    So I thought, well if it works on Opaque, wouldn't the simplest answer be to either make an Opaque shader transparent or have a transparent shader behave like an Opaque so I can achieve the stencil effect I want without having to do anything ridiculous? The example I'm looking at is the green and white spheres down below at the end of the page except of course I plan on having the same colours blend in with each other.

    The reason I want to have these spheres transparent is so that the player can see everything inside and interact with things within the spheres so I need to find out whether it's possible to do this. I guess now I think about it more rather than doing anything complicated the best way may actually be to make the Opaque see through somehow and sort of trick it into behaving like a transparent shader but not if that makes sense.
  2. Lethn


    May 18, 2015
    I hate it when I write a lengthy post and potentially find an answer but there's one problem now that I'm dealing with.

    The answer is here, Zwrite but it seems that for me at least there's a problem line causing issues where it creates the same effect of the colours blending when they shouldn't be, to be specific, I want to keep the transparency but I don't want any alpha blending now I have a better understanding of shader behaviour.
  3. Lethn


    May 18, 2015
    Okay I'm going to take forever trying to explain what I'm going for so I decided to take a screenshot and highlight the problems I'm having, it's interesting because Z Write and backface culling changes things around a bit but what I want is to be able to have all those colours the same. I don't want this weird additive blending effect happening as that is what is preventing me from having transparent influence borders that don't overlap.

    I reckon once I can get rid of this problem I'll actually be able to take away the sphere material with some sort of Y offset to the point I'll have nicely overlapping borders by themselves and it will all work really cheaply too.

    Code (CSharp):
    3. Shader "Custom/TransparentInfluenceShader"
    4. {
    5.     Properties
    6.     {
    7.         _MainTex("Base (RGB)", 2D) = "white" {}
    8.         _Color("Color (RGBA)", Color) = (1, 1, 1, 1)
    9.     }
    11.         SubShader
    12.         {
    13.             Tags {"Queue" = "Transparent" "IgnoreProjector" = "True" "RenderType" = "Transparent"}
    16.             Blend OneMinusDstColor One
    17.             ZWrite on
    18.             Cull Back
    19.             LOD 100
    21.             Pass
    22.             {
    23.                 CGPROGRAM
    25.                 #pragma vertex vert alpha
    26.                 #pragma fragment frag alpha
    28.                 #include "UnityCG.cginc"
    30.                 struct appdata_t
    31.                 {
    32.                     float4 vertex   : POSITION;
    33.                     float2 texcoord : TEXCOORD0;
    34.                 };
    36.                 struct v2f
    37.                 {
    38.                     float4 vertex  : SV_POSITION;
    39.                     half2 texcoord : TEXCOORD0;
    40.                 };
    42.                 sampler2D _MainTex;
    43.                 float4 _MainTex_ST;
    44.                 float4 _Color;
    46.                 v2f vert(appdata_t v)
    47.                 {
    48.                     v2f o;
    50.                     o.vertex = UnityObjectToClipPos(v.vertex);
    51.                     v.texcoord.x = 1 - v.texcoord.x;
    52.                     o.texcoord = TRANSFORM_TEX(v.texcoord, _MainTex);
    54.                     return o;
    55.                 }
    57.                 fixed4 frag(v2f i) : SV_Target
    58.                 {
    59.                     fixed4 col = tex2D(_MainTex, i.texcoord) * _Color;
    60.                     return col;
    61.                 }
    63.                 ENDCG
    64.             }
    65.         }
    66. }
    Here's the shader code I have so far, it's pretty basic but I'm convinced this is a culling and alpha source issue but let me know if I'm way off with my assumptions.
  4. Lethn


    May 18, 2015
    Yep I can at least identify the problem now and it's definitely a culling issue, what's happening is as I rotate the camera because the spheres are inside each other the edges of the spheres that are overlapping each other are doing almost a form of z-fighting and popping back and forth.

    Does anyone have any ideas of how to fix this? I want to prevent that from happening altogether and just have them render the same.
  5. bgolus


    Dec 7, 2012
    The ZWrite technique you saw recommended kind of works, but with some caveats. For the single pass version, it's highly dependent on the sorting order being perfect, which is rarely true. Really you need to render using two passes, once drawing depth only, and then a second time drawing the color. This works really well for single objects, but with multiple objects you'd need to render the depth for all of the objects before the color passes render, and the way Unity handles shaders with multiple passes this isn't always perfect. So then you could have two separate materials with different queues and either have duplicate renderers for every transparent object, or if it only has one material slot you can assign multiple materials to the one object and it'll render it multiple times.

    However for this particular case, since you're just looking to render a solid color, using the stencil buffer is likely going to be the better option.

    Code (csharp):
    1. ZWrite Off
    2. Stencil {
    3.     Ref 1
    4.     Comp NotEqual
    5.     Pass Replace
    6. }
    How this works is when an object renders it first tests if the stencil buffer value for that pixel is not equal (Comp) to 1 (Ref). If the value is 1, it does not render to that pixel. If it is not 1, it renders the object, and sets the stencil buffer to 1 (Pass) for that pixel. The default value in the stencil buffer should be 0 when each frame starts to render, as long as nothing else you're doing is using the stencil.
    Lethn likes this.
  6. Lethn


    May 18, 2015
    @bgolus I just wanted to post I've been experimenting with the shader you gave me and the explanation was fantastic, thanks for telling me what was going on I may have a look at doing something more complicated with what you've talked about in your post but this method works absolutely fine for my purposes right now.

    What would be really nice is if I could implement a stencil buffer in the shader graph itself so I can do fancier effects but I'll just have to experiment to find out about that. Here's to hoping this helps anyone else getting very frustrated with the way shaders work.
    Last edited: Oct 16, 2019
  7. bgolus


    Dec 7, 2012
    Yep. I think people ask for this or similar stuff in the Shader Graph subforum every other week. It's something Unity has commented that they'd like to do and is on their list of things to look into, but it's a long list.