you can make this effect by following the steps below:
Particle

RenderTextuer
you can store result by using RenderTexture. this is example of multipass in shadertoy:
https://www.shadertoy.com/view/ltccRl
iñigo quilez: Shadertoy uses multiple passes, one per "Buffer". As the name indicates, this passes store the results in a buffer. A buffer is just a texture. Unity will let you render to textures too.
I created a camera to Rendering particles to RenderTexture:


GrabPassing
you can grab pass for applying Distortion
I explained it in this post:
How can I replicate Quantum Break's distortion particle effect?
Blur
by using alpha in color over Lifetime we have simple blur


to get better result it's better to use simple blur , but how we achive blur?
Convolution matrix
In image processing, a kernel, convolution matrix, or mask is a small matrix. It is used for blurring, sharpening, embossing, edge detection, and more. This is accomplished by doing a convolution between a kernel and an image.
for more details, please follow this link

Shader "Smkgames/Convolution" { Properties { _MainTex ("Texture", 2D) = "white" {} [Enum(kerEdgeDetectionA,1,kerEdgeDetectionB,2,kerEdgeDetectionC,3,kerSharpen,4,kerBoxBlur,5)] _Kernel("Kernel", Float) = 1 } SubShader { // No culling or depth Cull Off ZWrite Off ZTest Always Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" struct appdata { float4 vertex : POSITION; float2 uv : TEXCOORD0; }; struct v2f { float2 uv : TEXCOORD0; float4 vertex : SV_POSITION; }; v2f vert (appdata v) { v2f o; o.vertex = UnityObjectToClipPos(v.vertex); o.uv = v.uv; return o; } sampler2D _MainTex; float4 _MainTex_TexelSize; float3x3 GetData(int channel, sampler2D tex, float2 uv, float4 size) { float3x3 mat; for (int y=-1; y<2; y++) { for(int x=-1; x<2; x++) { mat[x+1][y+1]=tex2D(tex, uv + float2(x*size.x, y*size.y))[channel]; } } return mat; } float3x3 GetMean(float3x3 matr, float3x3 matg, float3x3 matb) { float3x3 mat; for (int y=0; y<3; y++) { for(int x=0; x<3; x++) { mat[x][y] = (matr[x][y] + matg[x][y] + matb[x][y]) / 3.0; } } return mat; } float Convolve(float3x3 kernel, float3x3 pixels, float denom, float offset) { float res = 0.0; for (int y=0; y<3; y++) { for(int x=0; x<3; x++) { res += kernel[2-x][2-y]*pixels[x][y]; } } return res; } float _Kernel; fixed4 frag (v2f i) : SV_Target { float3x3 kerEdgeDetectionA = float3x3 ( 0.0, 0, -1.0, 1.0, 0, -1.0, 0.0, 1.0, 0.0); float3x3 kerEdgeDetectionB = float3x3 (0.0, 1.0, 0.0, 1.0, -4.0, 1.0, 0.0, 1.0, 0.0); float3x3 kerEdgeDetectionC = float3x3 (-1.0, -1.0, -1.0, -1.0, 8.0, -1.0, -1.0, -1.0, -1.0); float3x3 kerSharpen = float3x3 (0.0, -1.0, 0.0, -1.0, 5.0, -1.0, 0.0, -1.0, 0.0); float3x3 kerBoxBlur = (1.0/9.0)*float3x3 ( 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0); float3x3 kernelSelection; if(_Kernel == 1){ kernelSelection = kerEdgeDetectionA; }else if(_Kernel == 2){ kernelSelection = kerEdgeDetectionB; }else if(_Kernel == 3){ kernelSelection = kerEdgeDetectionC; }else if(_Kernel == 4){ kernelSelection = kerSharpen; }else if(_Kernel == 5){ kernelSelection = kerBoxBlur; } float3x3 matr = GetData(0, _MainTex, i.uv, _MainTex_TexelSize); float3x3 matg = GetData(1, _MainTex, i.uv, _MainTex_TexelSize); float3x3 matb = GetData(2, _MainTex, i.uv, _MainTex_TexelSize); float3x3 mata = GetMean(matr, matg, matb); // kernel float4 gl_FragColor = float4(Convolve(kernelSelection,matr,1.0,0.0), Convolve(kernelSelection,matg,1.0,0.0), Convolve(kernelSelection,matb,1.0,0.0), 1.0); return gl_FragColor; } ENDCG } } }
Boxblur
A box blur (also known as a box linear filter) is a spatial domain linear filter in which each pixel in the resulting image has a value equal to the average value of its neighboring pixels in the input image. It is a form of low-pass ("blurring") filter. A 3 by 3 box blur can be written as matrix
https://en.wikipedia.org/wiki/Box_blur

Shader "Smkgames/Simple Box Blur" { Properties { _MainTex ("Texture", 2D) = "white" {} } SubShader { Blend SrcAlpha OneMinusSrcAlpha Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" struct appdata { float4 vertex : POSITION; float2 uv : TEXCOORD0; }; struct v2f { float2 uv : TEXCOORD0; float4 vertex : SV_POSITION; }; v2f vert (appdata v) { v2f o; o.vertex = UnityObjectToClipPos(v.vertex); o.uv = v.uv; return o; } sampler2D _MainTex; float4 _MainTex_TexelSize; float4 box(sampler2D tex, float2 uv, float4 size) { float4 c = tex2D(tex, uv + float2(-size.x, size.y)) + tex2D(tex, uv + float2(0, size.y)) + tex2D(tex, uv + float2(size.x, size.y)) + tex2D(tex, uv + float2(-size.x, 0)) + tex2D(tex, uv + float2(0, 0)) + tex2D(tex, uv + float2(size.x, 0)) + tex2D(tex, uv + float2(-size.x, -size.y)) + tex2D(tex, uv + float2(0, -size.y)) + tex2D(tex, uv + float2(size.x, -size.y)); return c / 9; } float4 frag (v2f i) : SV_Target { float4 col = box(_MainTex, i.uv, _MainTex_TexelSize); return col; } ENDCG } } }

Repetition
you can use Rendertexture to store previous frame.so you can grab previous frame then blur. by repeating this you achieve blur.

Normal
float4 distortion = tex2D(_MainTex,i.uv); float3 distortionNormal = UnpackNormal(distortion);

Conclusion
Final shader:
Shader "Smkgames/BrokenGlass3D" { Properties{ _MainTex("MainTex",2D) = "white"{} _NormalIntensity("NormalIntensity",Float) = 1 _Alpha("Alpha",Float) = 1 } SubShader { Tags {"Queue"="Transparent" "RenderType"="Transparent"} Blend SrcAlpha OneMinusSrcAlpha GrabPass { "_GrabTexture" } Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" struct appdata { float4 vertex : POSITION; float2 uv : TEXCOORD0; float2 grabPos : TEXCOORD1; float3 normal :NORMAL; }; struct v2f { float2 uv : TEXCOORD0; float4 grabPos : TEXCOORD1; half3 worldNormal :TEXCOORD2; float4 vertex : SV_POSITION; }; sampler2D _MainTex; float _Intensity,_Alpha; v2f vert (appdata v) { v2f o; o.uv = v.uv; o.vertex = UnityObjectToClipPos(v.vertex); o.grabPos = ComputeGrabScreenPos(o.vertex); o.worldNormal = UnityObjectToWorldNormal(v.normal); return o; } sampler2D _GrabTexture; float _NormalIntensity; fixed4 frag (v2f i) : SV_Target { float4 distortion = tex2D(_MainTex,i.uv); float3 distortionNormal = UnpackNormal(distortion); distortionNormal.xy *= _NormalIntensity; normalize(distortionNormal); fixed4 col = tex2Dproj(_GrabTexture, i.grabPos+float4(distortionNormal.rgb,0)); return col; } ENDCG } } }
without using alpha in color over Lifetime:

by using alpha in color over Lifetime:

Source is available:
https://github.com/smkplus/RainDrop
There's more!
also you can make Ripples

Useful Links
https://80.lv/articles/breakdown-animated-raindrop-material-in-ue4/
https://seblagarde.wordpress.com/2013/01/03/water-drop-2b-dynamic-rain-and-its-effects/