# 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
[Toggle(FLIP_FOREBACK)] _Flip(" IS_FLIP_FOREBACK",float) = 0
[Toggle(IS_FLUID_PURE_COLOR)] _UsePureColor(" IS_Fluid_UsePureColor",float) = 0
}

CGINCLUDE

#include "UnityCG.cginc"

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));

backTexCol.rgb += baseNoise.rgb * _BaseNoiseStrengh;

#if FLIP_FOREBACK
col = 1 - col;
#endif

//gray
half3 gray = Luminance(col.rgb);
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

{
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: