Search Unity

Metaball Shader / Blend One Channel Independently..? Help !

Discussion in 'Shaders' started by coidevoid, Mar 19, 2019.

  1. coidevoid

    coidevoid

    Joined:
    Oct 26, 2017
    Posts:
    55
    Hello there!

    I'm working on a Metaball Shader with the ShaderGraph
    I've got a render texture that capture that:
    Capture.PNG
    I use the channels that way :
    Red : Shadow Level
    Blue : Emission Level
    Alpha : Alpha Cutout under 0.5

    And I'd like to use the Green Channel to select a color in the albedo depending of the level of green.
    So for exemple in pseudo code:

    If (G > 0.3) Select Blue
    else if (G>0.4) Select Purple
    etc..

    BUT everything is blended together so it is impossible to really have a particle that has one flat green value so impossible to select the right color to replace with.

    I was wondering, is it possible to do something in my particle shader like :

    [Blend One OneMinusSrcAlpha] for the Red, Blue and Alpha channel
    and
    [Blend One Zero] for the Green channel ?

    That problem is really important for my project, I would be really thankfull if you find a way to achieve to help me with it.
     
  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,339
    It is not possible to define different blend modes for different RGB channels for a single pass.

    Options:

    "Blend One OneMinusSrcAlpha, One Zero"
    You can use different blend modes for RGB vs Alpha, so it'd be plausible to shuffle the output data around and do it that way, but if you're using the alpha for blending, then this is a dead end.

    "ColorMask RBA"
    Render using two passes. The first one uses a ColorMask RBA and Blend One OneMinusSrcAlpha, the second is identical to the first pass, but uses ColorMask G and Blend One Zero. As you can probably guess, the first pass only renders to the red, blue, and alpha, and the second pass renders to the green.
     
  3. coidevoid

    coidevoid

    Joined:
    Oct 26, 2017
    Posts:
    55
    Interesting, I'm not use to shader writing so what I did is I took the Sprite-Default Shader and modify it, so to have multiple pass should I just copy / past the "pass" block and add the different param over ?

    That's my code :
    Code (CSharp):
    1.  
    2. Shader "Sprites/CustomDefault"
    3. {
    4.     Properties
    5.     {
    6.         [PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {}
    7.         _Color ("Tint", Color) = (1,1,1,1)
    8.         [MaterialToggle] PixelSnap ("Pixel snap", Float) = 0
    9.     }
    10.  
    11.     SubShader
    12.     {
    13.         Tags
    14.         {
    15.             "Queue"="Transparent"
    16.             "IgnoreProjector"="True"
    17.             "RenderType"="Transparent"
    18.             "PreviewType"="Plane"
    19.             "CanUseSpriteAtlas"="True"
    20.         }
    21.  
    22.         Cull Off
    23.         Lighting Off
    24.         ZWrite Off
    25.    
    26.  
    27.         Pass
    28.         {
    29.         ColorMask R
    30.         Blend One OneMinusSrcAlpha
    31.         CGPROGRAM
    32.             #pragma vertex vert
    33.             #pragma fragment frag
    34.             #pragma multi_compile _ PIXELSNAP_ON
    35.             #include "UnityCG.cginc"
    36.            
    37.             struct appdata_t
    38.             {
    39.                 float4 vertex   : POSITION;
    40.                 float4 color    : COLOR;
    41.                 float2 texcoord : TEXCOORD0;
    42.             };
    43.  
    44.             struct v2f
    45.             {
    46.                 float4 vertex   : SV_POSITION;
    47.                 fixed4 color    : COLOR;
    48.                 float2 texcoord  : TEXCOORD0;
    49.             };
    50.            
    51.             fixed4 _Color;
    52.  
    53.             v2f vert(appdata_t IN)
    54.             {
    55.                 v2f OUT;
    56.                 OUT.vertex = UnityObjectToClipPos(IN.vertex);
    57.                 OUT.texcoord = IN.texcoord;
    58.                 OUT.color = IN.color * _Color;
    59.                 #ifdef PIXELSNAP_ON
    60.                 OUT.vertex = UnityPixelSnap (OUT.vertex);
    61.                 #endif
    62.  
    63.                 return OUT;
    64.             }
    65.  
    66.             sampler2D _MainTex;
    67.             sampler2D _AlphaTex;
    68.             float _AlphaSplitEnabled;
    69.  
    70.             fixed4 SampleSpriteTexture (float2 uv)
    71.             {
    72.                 fixed4 color = tex2D (_MainTex, uv);
    73.  
    74.         #if UNITY_TEXTURE_ALPHASPLIT_ALLOWED
    75.                         if (_AlphaSplitEnabled)
    76.                             color.a = tex2D (_AlphaTex, uv).r;
    77.         #endif //UNITY_TEXTURE_ALPHASPLIT_ALLOWED
    78.                 return color;
    79.             }
    80.  
    81.             fixed4 frag(v2f IN) : SV_Target
    82.             {
    83.                 fixed4 c = SampleSpriteTexture (IN.texcoord) * IN.color;
    84.                 // if(c.a<=0) discard;
    85.                 c.rgb *= c.a;
    86.                 return c;
    87.             }
    88.         ENDCG
    89.         }
    90.        
    91.    
    92.  
    93.         Pass
    94.         {
    95.         ColorMask GBA
    96.         Blend One OneMinusSrcAlpha
    97.  
    98.         CGPROGRAM
    99.             #pragma vertex vert
    100.             #pragma fragment frag
    101.             #pragma multi_compile _ PIXELSNAP_ON
    102.             #include "UnityCG.cginc"
    103.            
    104.             struct appdata_t
    105.             {
    106.                 float4 vertex   : POSITION;
    107.                 float4 color    : COLOR;
    108.                 float2 texcoord : TEXCOORD0;
    109.             };
    110.  
    111.             struct v2f
    112.             {
    113.                 float4 vertex   : SV_POSITION;
    114.                 fixed4 color    : COLOR;
    115.                 float2 texcoord  : TEXCOORD0;
    116.             };
    117.            
    118.             fixed4 _Color;
    119.  
    120.             v2f vert(appdata_t IN)
    121.             {
    122.                 v2f OUT;
    123.                 OUT.vertex = UnityObjectToClipPos(IN.vertex);
    124.                 OUT.texcoord = IN.texcoord;
    125.                 OUT.color = IN.color * _Color;
    126.                 #ifdef PIXELSNAP_ON
    127.                 OUT.vertex = UnityPixelSnap (OUT.vertex);
    128.                 #endif
    129.  
    130.                 return OUT;
    131.             }
    132.  
    133.             sampler2D _MainTex;
    134.             sampler2D _AlphaTex;
    135.             float _AlphaSplitEnabled;
    136.  
    137.             fixed4 SampleSpriteTexture (float2 uv)
    138.             {
    139.                 fixed4 color = tex2D (_MainTex, uv);
    140.  
    141.             #if UNITY_TEXTURE_ALPHASPLIT_ALLOWED
    142.                             if (_AlphaSplitEnabled)
    143.                                 color.a = tex2D (_AlphaTex, uv).r;
    144.             #endif //UNITY_TEXTURE_ALPHASPLIT_ALLOWED
    145.                     return color;
    146.             }
    147.  
    148.             fixed4 frag(v2f IN) : SV_Target
    149.             {
    150.                 fixed4 c = SampleSpriteTexture (IN.texcoord) * IN.color;
    151.                 // if(c.a<=0) discard;
    152.                 c.rgb *= c.a;
    153.                 return c;
    154.             }
    155.         ENDCG
    156.         }
    157.     }
    158. }
     
    Last edited: Mar 19, 2019
  4. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,339
    Yep, that looks about right. However I missed one part of your first post. Shader Graph. That means you're using an SRP, either the LWRP or HDRP, and neither of those support shaders with multiple passes, even with hand written vertex fragment shaders. You'll have to write this as two separate shaders and assign two materials to your particle system... and hope the SRPs handle that properly.
     
  5. coidevoid

    coidevoid

    Joined:
    Oct 26, 2017
    Posts:
    55
    I'm not even using a Particle System but a Sprite Renderer to show my "particles".
    So I guess I'm gonna try with a Quad instead, I hope the performance are similar.
    I'll let you know if that works, thanks a lot for your help
     
  6. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,339
    Are you using an SRP? If you're using sprites, you probably shouldn't be using the LWRP or HDRP as neither are designed for 2D stuff. Stick with the built in forward renderer.

    I mean, sprites will work, it's just not (yet) what they're designed to handle. The LWRP specifically has a number of advantages for sprites when it comes to dealing with lighting, but the HDRP is mostly designed around deferred rendering which isn't terribly sprite friendly.
     
  7. coidevoid

    coidevoid

    Joined:
    Oct 26, 2017
    Posts:
    55
    Yeah I'm using the LWRP, I'd love to do without it but I'm not able to write my own shader and my game does really need some.
     
  8. coidevoid

    coidevoid

    Joined:
    Oct 26, 2017
    Posts:
    55
    I have tried with a quad and 2 materials instead and the performance are even worse than when i'm using 2 different cameras / render texture with 2 times more sprite..
     
  9. coidevoid

    coidevoid

    Joined:
    Oct 26, 2017
    Posts:
    55
    Little update, I have updated my Project to be using the built in default renderer.
    I did the shader for my metaball that I guess can be far more optimized.
    But the real lost of performance is because of the 2nd pass in my "Particle" Shader.

    Can I do something to improve the performance ?
    Here's the code of the particle shader:

    Code (CSharp):
    1.  
    2. Shader "Sprites/CustomDefault"
    3. {
    4.     Properties
    5.     {
    6.          _MainTex ("Sprite Texture", 2D) = "white" {}
    7.          _AlphaMask("Alpha Cutout Mask", 2D) = "white"{}
    8.         [MaterialToggle] PixelSnap ("Pixel snap", Float) = 0
    9.     }
    10.  
    11.     SubShader
    12.     {
    13.         Tags
    14.         {
    15.             "Queue"="Transparent"
    16.             "IgnoreProjector"="True"
    17.             "RenderType"="Transparent"
    18.             "PreviewType"="Plane"
    19.             "CanUseSpriteAtlas"="True"
    20.         }
    21.  
    22.        
    23.         Pass
    24.         {
    25.         Cull Off
    26.         Lighting Off
    27.         ZWrite Off
    28.         ColorMask RBA
    29.         Blend One OneMinusSrcAlpha
    30.  
    31.         CGPROGRAM
    32.             #pragma vertex vert
    33.             #pragma fragment frag
    34.             #pragma multi_compile _ PIXELSNAP_ON
    35.             #include "UnityCG.cginc"
    36.            
    37.             struct appdata_t
    38.             {
    39.                 float4 vertex   : POSITION;
    40.                 float4 color    : COLOR;
    41.                 float2 texcoord : TEXCOORD0;
    42.             };
    43.  
    44.             struct v2f
    45.             {
    46.                 float4 vertex   : SV_POSITION;
    47.                 fixed4 color    : COLOR;
    48.                 float2 texcoord  : TEXCOORD0;
    49.             };
    50.            
    51.  
    52.             v2f vert(appdata_t IN)
    53.             {
    54.                 v2f OUT;
    55.                 OUT.vertex = UnityObjectToClipPos(IN.vertex);
    56.                 OUT.texcoord = IN.texcoord;
    57.                 OUT.color = IN.color ;
    58.                 return OUT;
    59.             }
    60.  
    61.             sampler2D _MainTex;
    62.  
    63.             fixed4 SampleSpriteTexture (float2 uv)
    64.             {
    65.                 fixed4 color = tex2D (_MainTex, uv);
    66.                 return color;
    67.             }
    68.  
    69.             fixed4 frag(v2f IN) : SV_Target
    70.             {
    71.                 fixed4 c = SampleSpriteTexture (IN.texcoord) * IN.color;
    72.                 c.rgb *= c.a;
    73.                 return c;
    74.             }
    75.         ENDCG
    76.         }
    77.        
    78.         Pass
    79.         {
    80.         Cull Off
    81.         Lighting Off
    82.         ZWrite Off
    83.         ColorMask G
    84.         Blend One Zero
    85.  
    86.         CGPROGRAM
    87.             #pragma vertex vert
    88.             #pragma fragment frag
    89.             #pragma multi_compile _ PIXELSNAP_ON
    90.             #include "UnityCG.cginc"
    91.            
    92.             struct appdata_t
    93.             {
    94.                 float4 vertex   : POSITION;
    95.                 float4 color    : COLOR;
    96.                 float2 texcoord : TEXCOORD0;
    97.             };
    98.  
    99.             struct v2f
    100.             {
    101.                 float4 vertex   : SV_POSITION;
    102.                 fixed4 color    : COLOR;
    103.                 float2 texcoord  : TEXCOORD0;
    104.             };
    105.            
    106.  
    107.             v2f vert(appdata_t IN)
    108.             {
    109.                 v2f OUT;
    110.                 OUT.vertex = UnityObjectToClipPos(IN.vertex);
    111.                 OUT.texcoord = IN.texcoord;
    112.                 OUT.color = IN.color ;
    113.                 return OUT;
    114.             }
    115.  
    116.             sampler2D _MainTex;
    117.             sampler2D _AlphaMask;
    118.  
    119.  
    120.             fixed4 SampleSpriteTexture (float2 uv)
    121.             {
    122.                 fixed4 color = tex2D (_MainTex, uv);
    123.                 return color;
    124.             }
    125.  
    126.             fixed4 frag(v2f IN) : SV_Target
    127.             {
    128.                 fixed4 d = tex2D(_AlphaMask, IN.texcoord);
    129.                 if(d.a<1)discard;
    130.                 return IN.color;
    131.             }
    132.         ENDCG
    133.         }
    134.  
    135.        
    136.     }
    137. }

    Thanks
     
  10. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,339
    If you need the different behaviour, you need to render each "particle" twice. Two pass shaders are generally a much faster option than the alternatives, but you're still doubling the fillrate requirements.
     
  11. coidevoid

    coidevoid

    Joined:
    Oct 26, 2017
    Posts:
    55
    Well the thing I figured out was that the batching ignore the multi-pass materials so my FPS drop by 100..
     
  12. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,339
  13. coidevoid

    coidevoid

    Joined:
    Oct 26, 2017
    Posts:
    55
    Oh that's an interesting way of doing that, you're a magician man that's crazy how I see you on every threads finding creative way to help people.
    I'm gonna try I will let you know if that's better ! Thanks
     
  14. coidevoid

    coidevoid

    Joined:
    Oct 26, 2017
    Posts:
    55
    The particle system was an awesome idea, that has fixed all my issues of performance, thanks!