Search Unity

Overlay Shader is Overlaying with each others

Discussion in 'Shaders' started by Alde-Baran, Dec 26, 2020.

  1. Alde-Baran

    Alde-Baran

    Joined:
    Nov 15, 2019
    Posts:
    39
    I am trying the make shader for blood decals.
    But overlay blend shader is overlaying with object with same material.
    Code:
    Code (CSharp):
    1. // Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
    2.  
    3. Shader "Custom/OverlayBlend"
    4. {
    5.     Properties
    6.     {
    7.         _MainTex("Base (RGB) Trans (A)", 2D) = "white" {}
    8.         _Color("Color", Color) = (1,1,1,1)
    9.     }
    10.  
    11.         SubShader
    12.     {
    13.         Tags {"Queue" = "Transparent" "IgnoreProjector" = "True" "RenderType" = "Transparent"}
    14.         //Tags { "Queue" = "Transparent" }
    15.         ZWrite Off
    16.         Lighting Off
    17.         Cull Off
    18.         Fog { Mode Off }
    19.         Blend DstColor SrcColor
    20.        
    21.         LOD 110
    22.        
    23.         Pass
    24.         {
    25.            
    26.             CGPROGRAM
    27.             #pragma vertex vert_vct
    28.             #pragma fragment frag_mult
    29.             #pragma fragmentoption ARB_precision_hint_fastest
    30.             #include "UnityCG.cginc"
    31.  
    32.             sampler2D _MainTex;
    33.             float4 _MainTex_ST;
    34.             float4 _Color;
    35.  
    36.             struct vin_vct
    37.             {
    38.                 float4 vertex : POSITION;
    39.                 float4 color : COLOR;
    40.                 float2 texcoord : TEXCOORD0;
    41.             };
    42.  
    43.             struct v2f_vct
    44.             {
    45.                 float4 vertex : POSITION;
    46.                 fixed4 color : COLOR;
    47.                 half2 texcoord : TEXCOORD0;
    48.             };
    49.  
    50.             v2f_vct vert_vct(vin_vct v)
    51.             {
    52.                 v2f_vct o;
    53.                 o.vertex = UnityObjectToClipPos(v.vertex);
    54.                 o.color = v.color;
    55.                 o.texcoord = v.texcoord;
    56.                 return o;
    57.             }
    58.  
    59.             float4 frag_mult(v2f_vct i) : COLOR
    60.             {
    61.                 float4 tex = tex2D(_MainTex, i.texcoord);
    62.                 tex *= _Color;
    63.                 float4 final = tex;
    64.                 final.a = i.color.a * tex.a;
    65.  
    66.                 if (tex.r == i.color.r && tex.g == i.color.g && tex.b == i.color.b) {
    67.                     final.rgb = i.color.rgb * tex.rgb * 0;
    68.                 }
    69.                 else {
    70.                     final.rgb = i.color.rgb * tex.rgb * 2;
    71.                 }
    72.                 float4 last = lerp(float4(0.5f, 0.5f, 0.5f, 0.5f), final, final.a);
    73.  
    74.                
    75.  
    76.                 return last;
    77.  
    78.             }
    79.  
    80.             ENDCG
    81.  
    82.         }
    83.  
    84.  
    85.     }
    86.  
    87. }
    Picture: (should i censor this because of blood?)
    upload_2020-12-26_2-53-52.png
    How can i fix this? I want to ignore the object with same shader while blending.
     
  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,352
    There are kind of three options:

    Stencils
    You can have the shader write to the stencil buffer, and only render where the stencil has not already been written to.
    https://docs.unity3d.com/Manual/SL-Stencil.html
    Code (csharp):
    1. Stencil {
    2.   Ref 1
    3.   Comp NotEqual
    4.   Pass Replace
    5. }
    The caveat is you’d need to use alpha testing for the edge rather than doing a soft edge. This also means you can’t really fade them in / out, especially if you have them overlapping and want the most opaque one to show through. You can work around that by having the alpha be a wide gradient so they shrink instead of fade.

    Render Texture Mask
    The idea here is you render the alpha shapes to a single channel b&w full screen render texture, then use that as a full screen Blit to actually color the scene. You can actually do this as a multi render target setup so it’s treated a bit more like the stencil above. However this is a fairly advanced technique so I’m not going to talk too much more about it unless it’s something you’re interested in pursuing. However it does have the advantage that you can fade them individually and the most opaque blood splat will show though.

    Named Grab Pass
    https://docs.unity3d.com/Manual/SL-GrabPass.html
    This is the most straightforward way of handling this. The idea is you use a named grab pass, do the coloring in the fragment shader, and then blend into the scene using alpha blending. You want to use a named grab pass instead of the generic one because it’ll make a copy of the scene just before the first blood decal. This means each blood splat gets an unbloodied version of the scene to color preventing the overlapping.
    Code (csharp):
    1. Blend SrcAlpha OneMinusSrcAlpha
    2.  
    3. GrabPass { “_BloodGrabTexture” }
    4.  
    5. // in the fragment shader
    6. float4 tex = tex2D(_MainTex, i.texcoord);
    7. half4 grab = tex2Dproj(_BloodGrabTexture, i.grabPos);
    8. half4 outColor = tex * grab * 2.0; // equivalent to Blend DstColor SrcColor
    9. outColor.a = tex.a;
    10. return outColor;
     
    Alde-Baran likes this.
  3. Alde-Baran

    Alde-Baran

    Joined:
    Nov 15, 2019
    Posts:
    39
    I fix it with in another way.

    With these lines:
    Code (CSharp):
    1. Blend DstAlpha SrcAlpha
    2. BlendOp Min
    3. Blend DstColor SrcColor
    4.            
    5. AlphaToMask On
    Result:
    upload_2021-1-3_17-39-9.png
    Only problem is, decal edge's is broken when it's top of pure white object with bloom enabled.