Zelda Wind Waker blending style

I feel it would be a neat trick to get particles to render together like a single layer
what we can do is on the left, what I like is on the right - has anyone asked this before?

once assembled in a sort order (youngest first) the shader (animated per emitter) alpha’s the entire system out.

it’s outside my scope, I goofed with shaders but just trial and error…I guess if they were alpha cutout but rendered front to back in 1 pass like geo, then alpha in a second for blending? does that seem right?

Doesn’t need two passes. If you render with one pass using discard or clip() and outputting an alpha you can get this kind of effect. The main issue will be draw order. For Unity if you use sort by distance and set the material to use an alpha test queue (like 2499) it’ll sort front to back. You could also use a stencil.

1 Like

so I was at a huge loss to implementing but stealing from Preventing additive blending of transparent Unity sprites

I was able to write up with vertex color

yes depth/sorting is still tough to work out, alphaTest causes motion blur effect. weird2me

Shader "Test/Particle Union" {
 Properties {
     _MainTex ("Base (RGB)", 2D) = "white" {}
 }
 
 SubShader {
    Tags { "Queue"="Transparent" }

    Pass {
        Stencil {
            Ref 1
            Comp NotEqual
            Pass Replace

        }

         Blend One OneMinusSrcAlpha     
 
         CGPROGRAM
         #pragma vertex vert
         #pragma fragment frag
         #include "UnityCG.cginc"
         
         uniform sampler2D _MainTex;
         
         struct v2f {
             half4 pos : POSITION;
             fixed4 color : COLOR;
             half2 uv : TEXCOORD0;

         };
         
         v2f vert(appdata_full v) {
             v2f o;
             o.pos = UnityObjectToClipPos (v.vertex);
             o.color = v.color;
             half2 uv = MultiplyUV( UNITY_MATRIX_TEXTURE0, v.texcoord );
             o.uv = uv;

             return o;
         }

         half4 frag (v2f i) : COLOR {
        
         half4 color = tex2D(_MainTex, i.uv);
         if (color.a < 0.1)
                 discard;                    
         return color * i.color;
         ;

         }
         ENDCG
    }

} 
Fallback off

}

It looks like Unity always sorts particles as if they’re transparent, which means the single pass stencil or depth method will always be a little weird. Stencil will ensure a single “layer”, but not the correct sorting. Single pass depth won’t work at all.

However you can always do the old pre pass z write method.

Shader "Particles/Z Write Pre-Pass Alpha Blend"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _Cutoff ("Cutoff", Range(0,1)) = 0.5
    }
    SubShader
    {
        Tags { "Queue"="Transparent" "RenderType"="Transparent" }
        LOD 100

        Pass {
            ColorMask 0

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;

            fixed _Cutoff;
            
            v2f vert (appdata_full v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
                return o;
            }
            
            void frag (v2f i)
            {
                fixed4 col = tex2D(_MainTex, i.uv);
                clip(col.a - _Cutoff);
            }
            ENDCG
        }

        Pass
        {
            Blend SrcAlpha OneMinusSrcAlpha
            ZWrite Off

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma multi_compile_fog
            
            #include "UnityCG.cginc"

            struct v2f
            {
                float2 uv : TEXCOORD0;
                fixed4 color : TEXCOORD1;
                UNITY_FOG_COORDS(2)
                float4 vertex : SV_POSITION;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;

            fixed _Cutoff;
            
            v2f vert (appdata_full v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
                UNITY_TRANSFER_FOG(o,o.vertex);
                o.color = v.color;
                return o;
            }
            
            fixed4 frag (v2f i) : SV_Target
            {
                fixed4 col = tex2D(_MainTex, i.uv);
                clip(col.a - _Cutoff);
                UNITY_APPLY_FOG(i.fogCoord, col);
                col.rgb *= i.color.rgb;
                col.a = i.color.a;
                return col;
            }
            ENDCG
        }
    }
}

5 Likes

The big thing Nintendo has going for it with their effects is absolute control over how things are rendered. I’m pretty sure they’re using stencils to do this effect on the GCN, but for it to work properly it requires front to back opaque sorting order. Since Unity doesn’t appear to do this with particles even when using an opaque shader the order will always be off and you’re left with the two pass depth method. If you could sort front to back you could use the single pass stencil method that I suspect they used and get proper depth sorting and the single layer look.

2 Likes

well it’s pretty damn great what you posted, helped me out a ton and I learned something, lot of fun throwing this together.

still having fun with this :0

2 Likes

How would one make this work with SpriteRenderers?