您可以按照以下步骤进行操作:
粒子
RenderTextuer
您可以使用RenderTexture存储结果。这是sharttoy中的多次通过的示例:
https://www.shadertoy.com/view/ltccRl
奎尼兹(Iñigoquilez):Shadertoy使用了多次通过,每个“缓冲区”使用一次。顾名思义,此过程将结果存储在缓冲区中。缓冲区只是一个纹理。Unity也可以让您渲染到纹理。
我创建了一个将粒子渲染到RenderTexture的相机:
抢通
您可以抓住通行证申请扭曲
我在这篇文章中对此进行了解释:
如何复制Quantum Break的失真粒子效果?
模糊
通过在生命周期中使用Alpha颜色,我们可以进行简单的模糊
为了获得更好的结果,最好使用简单的模糊,但是我们如何实现模糊呢?
卷积矩阵
在图像处理中,核,卷积矩阵或掩码是小矩阵。它用于模糊,锐化,压纹,边缘检测等。这是通过在内核和映像之间进行卷积来实现的。
有关更多详细信息,请点击此链接
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
框模糊(也称为框线性滤波器)是一种空间域线性滤波器,其中,所得图像中的每个像素的值等于输入图像中其相邻像素的平均值。它是低通(“模糊”)滤波器的一种形式。可以将3 x 3框模糊表示为矩阵
https://zh.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
}
}
}
重复
您可以使用Rendertexture来存储前一帧。因此,您可以抓取前一帧然后进行模糊处理。通过重复此操作,您可以实现模糊效果。
正常
float4 distortion = tex2D(_MainTex,i.uv);
float3 distortionNormal = UnpackNormal(distortion);
结论
最终着色器:
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
}
}
}
在整个生命周期中不使用彩色Alpha:
通过在整个生命周期中使用Alpha颜色:
资料来源:
https://github.com/smkplus/RainDrop
还有更多!
你也可以做涟漪
有用的链接
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/