Implement a screen ink fluid effect using a particle system - KNOW

Previously, when you were working on your own audio visualization project, you wanted to achieve this effect as follows:

That is to display an ink fluid effect on the screen and let it rhythm with the audio.Get excited when you think about it!

When it comes to fluid effects, you naturally think of real simulation of fluid effects.However, the actual computational complexity of the fluid effect is enormous, and it is difficult to achieve this effect.Then I came up with a clever way to achieve the desired result lightly using a particle system with post-processing Shader.

The core idea is to convert the color of particles into gray values in post-processing.As shown below, the gray values are then re-mapped to a range using smoothstep.For example, c=smoothstep(0.85,0.9,gray).

I personally feel that this method is simple, but this kind of thinking is still very enlightening.

Before postprocessing is used:

Figure 1, Immediate ordinary particles before they are mapped

After using smoothstep mapping:

Figure 2, after mapping, notice that the previously separated particles are "glued" together

The post-processing core code is as follows:

Line 2 is the key, and by adjusting the values of _StepMin,_StepMax, the separated particles in Fig. 1 can be "glued" together to form a fluid.

Here is the complete code:

Shader "Hidden/Shuimo"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _BackgroundTex("BackgourndTex",2D) = "white"{}
        _BackGroundColor("BackGroundColor",Color) = (1,1,1,1)
        _BaseNoiseTex("BaseNoiseTex",2D) = "white"{}
        _BaseNoiseSpeed("BaseNoiseSpeed",vector) = (1,1,0,0)
        _BaseNoiseStrengh("BaseNoiseStrengh",Range(0,1)) = 0.2
        _FluidColor("FluidColor",Color) = (0,0,0,1)
        _StepMin("StepMin",Range(0,1)) = 0
        _StepMax("StepMax",Range(0,1)) = 1
        _ForegroundStrengh("ForegroundStrengh",float) = 1
        _BackgroundStrengh("BackgroundStrengh",float) = 1
        [Enum(Add,0,Split,1,Mul,2)] _BlendType("BlendTypeForeBack",float) = 0
        [Toggle(FLIP_FOREBACK)] _Flip(" IS_FLIP_FOREBACK",float) = 0
        [Toggle(IS_FLUID_PURE_COLOR)] _UsePureColor(" IS_Fluid_UsePureColor",float) = 0
    }

    CGINCLUDE

    #include "UnityCG.cginc"
    #pragma shader_feature FLIP_FOREBACK
    #pragma shader_feature IS_FLUID_PURE_COLOR

    fixed4 _FluidColor,_BackGroundColor;
    float _StepMin,_StepMax,_ForegroundStrengh,_BackgroundStrengh,_BaseNoiseStrengh;
    float _BlendType;
    float4 _BaseNoiseSpeed,_BaseNoiseTex_ST;
    sampler2D _MainTex,_BackgroundTex,_BaseNoiseTex;

    struct appdata
    {
        float4 vertex : POSITION;
        float4 uv : TEXCOORD0;
    };

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

    v2f vert (appdata v)
    {
        v2f o;
        o.vertex = UnityObjectToClipPos(v.vertex);
        o.uv.xy = v.uv;
        o.uv.zw = v.uv.xy * _BaseNoiseTex_ST.xy + _BaseNoiseTex_ST.zw;
        return o;
    }

    fixed4 frag (v2f i) : SV_Target
    {
        fixed4 col = tex2D(_MainTex, i.uv);
        fixed4 backTexCol = tex2D(_BackgroundTex, i.uv) * _BackGroundColor;
        fixed4 baseNoise = tex2D(_BaseNoiseTex,i.uv.zw + float2(_BaseNoiseSpeed.xy * 0.01 * _Time.y));

        //Background Add Details
        backTexCol.rgb += baseNoise.rgb * _BaseNoiseStrengh;

        #if FLIP_FOREBACK
            col = 1 - col;
        #endif

        //gray
        half3 gray = Luminance(col.rgb);
        //Adjust thickness of fluid edge
        gray = smoothstep(_StepMin,_StepMax,gray);

        half3 foregroundColor = half3(0,0,0);
        #if IS_FLUID_PURE_COLOR
            foregroundColor = lerp(col.rgb,_FluidColor.rgb,gray.r);
        #else
            foregroundColor = lerp(col.rgb,backTexCol.rgb,gray.r);
        #endif

        //Overlay Background
        if(_BlendType == 0){
            col.rgb = foregroundColor.rgb * _ForegroundStrengh + backTexCol * _BackgroundStrengh;
        }
        else if(_BlendType == 1){
            col.rgb = foregroundColor + (1 - gray.r) * backTexCol.rgb;
        }
        else{
            col.rgb = foregroundColor.rgb * _ForegroundStrengh * backTexCol * _BackgroundStrengh;
        }
        
        return col;
    }

    ENDCG

    SubShader
    {
        Cull Off ZWrite Off ZTest Always

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            ENDCG
        }
    }
}

In addition to the above effects, you can also modify the relevant parameters to achieve many unexpected beautiful effects, with rhythm, effect bars.For example:

Fluid effect with audio rhythm https://www.zhihu.com/video/1238460095379202048

Of course, it is customary to attach the project address:

https://gitee.com/jiuyueqiji123/NextGENProject/tree/master/NextGENProject/Assets/Samples/%E5%9F%BA%E4%BA%8E%E4%BE%8B%E5%AD%90%E7%B3%BB%E7%BB%9F%E6%B0%B4%E5%A2%A8%E9%A3%8E%E6%A0%BC%E5%8C%96%E6%95%88%E6%9E%9C​ gitee.com

Tags: Fragment

Posted on Sun, 03 May 2020 12:20:08 -0400 by burningkamikaze