Monday, July 16, 2018

unity - How can I make natural rain drops on screen?


I'm trying to make rain effect drop with metaballs and trail on screen.I find a clue in shadertoy but I didn't understand how implemented:


https://www.shadertoy.com/view/ltffzl


unfortunately it have many math calculations and i can't use it in unity because it produces a lag.obviously I should use textures but how can I have trail effect?!


enter image description here


my idea is using a texture and trail renderer for droping but how can I have metaballs effect? enter image description here






I could Implement Metaballs by This Article


https://github.com/smkplus/RainFX/tree/master


but I haven't Idea about trail



Answer



you can make this effect by following the steps below:



Particle



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:


ax


RenderTexture



you can grab pass for applying Distortion


I explained it in this post:


How can I replicate Quantum Break's distortion particle effect?




by using alpha in color over Lifetime we have simple blur


alphaovertime


gradiant


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


Kernel


 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




1_oos3y1ztoewgsubpdnbvea


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
}

}
}

blurbox



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


0fe28c6167db2132d4bb8677fc1b2050--leandro-erlich-argentina



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


record_2019_03_03_21_35_45_417



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:


record_2019_03_03_21_48_36_273


by using alpha in color over Lifetime:


record_2019_03_03_21_48_19_786



Source is available:


https://github.com/smkplus/RainDrop



also you can make Ripples


record_2019_03_04_22_10_25_457


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/


No comments:

Post a Comment

Simple past, Present perfect Past perfect

Can you tell me which form of the following sentences is the correct one please? Imagine two friends discussing the gym... I was in a good s...