效果排序 高斯+降采样>高斯>均值
CommandBuff的实现效果好,效率可控,但缺点是无法用在UI上
UI上用模糊好像只能是GrabPass,其他方法暂时没想到
参考了一些文章,下面是连接,在他们基础上做了些修改,仅作为个人学习使用
高斯模糊:
https://blog.csdn.net/pz789as/article/details/79050631
https://blog.csdn.net/puppet_master/article/details/52783179
http://www.ruanyifeng.com/blog/2012/11/gaussian_blur.html
基于CommandBuff的高斯模糊:
https://www.gameres.com/844940.html
均值模糊:
https://blog.csdn.net/puppet_master/article/details/52547442
https://zhuanlan.zhihu.com/p/145463708
_MainTexture_TexelSize
{TextureName}_TexelSize - a float4 property contains texture size information:
- x contains 1.0/width
- y contains 1.0/height
- z contains width
- w contains height
均值模糊代码:
Shader "UI/BlurUI_SimpleBlur"
{
Properties
{
_Color("Color", COLOR) = (1,1,1,1)
_Radius("Blur Radius", Range(0, 4)) = 1
_Size("Blur Size", Range(0, 5)) = 1
}
SubShader
{
Tags{ "Queue" = "Transparent"}
//GrabPass {}
GrabPass{}
Pass
{
//Blend SrcAlpha OneMinusSrcAlpha
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float4 vertex : SV_POSITION;
float4 screenPos : TEXCOORD0;
float4 grabPos : TEXCOORD1;
};
sampler2D _GrabTexture;
float4 _GrabTexture_TexelSize;
float4 _Color;
int _Radius;
float _Size;
v2f vert(appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.screenPos = ComputeScreenPos(o.vertex);
o.grabPos = ComputeGrabScreenPos(o.vertex);
return o;
}
half4 frag(v2f i) : SV_TARGET
{
float4 result = tex2Dproj(_GrabTexture, i.screenPos);
i.grabPos.zw = i.screenPos.zw;
for (int range = 1; range <= _Radius; range++)
{
//对
float2 w1 = i.screenPos.xy + float2(_GrabTexture_TexelSize.x * 0, _GrabTexture_TexelSize.y * range * _Size);
i.grabPos.xy = w1;
result += tex2Dproj(_GrabTexture, i.screenPos + i.grabPos);//用屏幕坐标+偏移,这里没搞懂,但是实测效果确实好
float2 w2 = i.screenPos.xy + float2(_GrabTexture_TexelSize.x * 0, _GrabTexture_TexelSize.y * -range * _Size);
i.grabPos.xy = w2;
result += tex2Dproj(_GrabTexture, i.screenPos + i.grabPos);
}
result /= _Radius * 2 + 1; //除以_Radius*2取均值
return result;
}
ENDCG
}
GrabPass{}
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
};
struct v2f
{
float4 vertex : SV_POSITION;
float4 screenPos : TEXCOORD0;
float4 grabPos : TEXCOORD1;
};
sampler2D _GrabTexture;
float4 _GrabTexture_TexelSize;
float4 _Color;
int _Radius;
float _Size;
v2f vert(appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.screenPos = ComputeScreenPos(o.vertex);
o.grabPos = ComputeGrabScreenPos(o.vertex);
return o;
}
half4 frag(v2f i) : SV_TARGET
{
float4 result = tex2Dproj(_GrabTexture, i.screenPos);
i.grabPos.zw = i.screenPos.zw;
for (int range = 1; range <= _Radius; range++)
{
float2 w3 = i.screenPos.xy + float2(_GrabTexture_TexelSize.x * range * _Size, _GrabTexture_TexelSize.y * 0);
i.grabPos.xy = w3;
result += tex2Dproj(_GrabTexture, i.screenPos + i.grabPos);
float2 w4 = i.screenPos.xy + float2(_GrabTexture_TexelSize.x * -range * _Size, _GrabTexture_TexelSize.y * 0);
i.grabPos.xy = w4;
result += tex2Dproj(_GrabTexture, i.screenPos + i.grabPos);
}
result /= _Radius * 2 + 1;
float4 col = half4(_Color.a * _Color.rgb + (1 - _Color.a) * result.rgb, 1.0f);
return col;
}
ENDCG
}
}
}
高斯模糊代码:
Shader "UI/BlurUI_GaussianBlur"
{
Properties
{
_Color("Color", COLOR) = (1,1,1,1)
//_Radius("Blur Radius", Range(0, 4)) = 1
_Size("Blur Size", Range(0, 5)) = 1
}
SubShader
{
Tags{ "Queue" = "Transparent"}
//GrabPass {}
GrabPass{}
Pass
{
//Blend SrcAlpha OneMinusSrcAlpha
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float4 vertex : SV_POSITION;
float4 screenPos : TEXCOORD0;
float4 grabPos : TEXCOORD1;
};
sampler2D _GrabTexture;
float4 _GrabTexture_TexelSize;
float4 _Color;
int _Radius;
float _Size;
v2f vert(appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.screenPos = ComputeScreenPos(o.vertex);
o.grabPos = ComputeGrabScreenPos(o.vertex);
return o;
}
half4 GrabPixel(v2f i, float weight, float kernelx)
{
//float2 w1 = i.screenPos.xy + float2(_GrabTexture_TexelSize.x * 0, _GrabTexture_TexelSize.y * kernelx * _Size);
//i.grabPos.xy = w1;
// return tex2Dproj(_GrabTexture, i.screenPos + i.grabPos) * weight;
return tex2Dproj(_GrabTexture, i.screenPos + UNITY_PROJ_COORD(float4(i.grabPos.x + _GrabTexture_TexelSize.x*kernelx*_Size, i.grabPos.y, i.grabPos.z, i.grabPos.w))) * weight;
}
half4 frag(v2f i) : SV_TARGET
{
//float4 result = tex2Dproj(_GrabTexture, i.screenPos/*UNITY_PROJ_COORD(i.grabPos)*/);
//i.grabPos.zw = i.screenPos.zw;
half4 sum = half4(0,0,0,0);
sum += GrabPixel(i, 0.05, -4.0);
sum += GrabPixel(i, 0.09, -3.0);
sum += GrabPixel(i, 0.12, -2.0);
sum += GrabPixel(i, 0.15, -1.0);
sum += GrabPixel(i, 0.18, 0.0);
sum += GrabPixel(i, 0.15, +1.0);
sum += GrabPixel(i, 0.12, +2.0);
sum += GrabPixel(i, 0.09, +3.0);
sum += GrabPixel(i, 0.05, +4.0);
//for (int range = 1; range <= _Radius; range++)
//{
// //对
// float2 w1 = i.screenPos.xy + float2(_GrabTexture_TexelSize.x * 0, _GrabTexture_TexelSize.y * range * _Size);
// i.grabPos.xy = w1;
// result += tex2Dproj(_GrabTexture, i.screenPos + i.grabPos);
// float2 w2 = i.screenPos.xy + float2(_GrabTexture_TexelSize.x * 0, _GrabTexture_TexelSize.y * -range * _Size);
// i.grabPos.xy = w2;
// result += tex2Dproj(_GrabTexture, i.screenPos + i.grabPos);
//}
//result /= _Radius * 2 + 1; //除以_Radius*2取均值
return sum;
}
ENDCG
}
GrabPass{}
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
};
struct v2f
{
float4 vertex : SV_POSITION;
float4 screenPos : TEXCOORD0;
float4 grabPos : TEXCOORD1;
};
sampler2D _GrabTexture;
float4 _GrabTexture_TexelSize;
float4 _Color;
int _Radius;
float _Size;
v2f vert(appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.screenPos = ComputeScreenPos(o.vertex);
o.grabPos = ComputeGrabScreenPos(o.vertex);
return o;
}
half4 GrabPixel(v2f i, float weight, float kernely)
{
//return tex2Dproj(_GrabTexture,i.screenPos + UNITY_PROJ_COORD(float4(i.grabPos.x, i.grabPos.y + _GrabTexture_TexelSize.y*kernely*_Size, i.grabPos.z, i.grabPos.w))) * weight;
return tex2Dproj(_GrabTexture,i.screenPos + UNITY_PROJ_COORD(float4(i.grabPos.x, i.grabPos.y + _GrabTexture_TexelSize.y*kernely*_Size, i.grabPos.z, i.grabPos.w))) * weight;
}
half4 frag(v2f i) : SV_TARGET
{
//float4 result = tex2Dproj(_GrabTexture, i.screenPos/*UNITY_PROJ_COORD(i.grabPos)*/);
//i.grabPos.zw = i.screenPos.zw;
half4 sum = half4(0,0,0,0);
sum += GrabPixel(i, 0.05, -4.0);
sum += GrabPixel(i, 0.09, -3.0);
sum += GrabPixel(i, 0.12, -2.0);
sum += GrabPixel(i, 0.15, -1.0);
sum += GrabPixel(i, 0.18, 0.0);
sum += GrabPixel(i, 0.15, +1.0);
sum += GrabPixel(i, 0.12, +2.0);
sum += GrabPixel(i, 0.09, +3.0);
sum += GrabPixel(i, 0.05, +4.0);
//for (int range = 1; range <= _Radius; range++)
//{
// float2 w3 = i.screenPos.xy + float2(_GrabTexture_TexelSize.x * range * _Size, _GrabTexture_TexelSize.y * 0);
// i.grabPos.xy = w3;
// result += tex2Dproj(_GrabTexture, i.screenPos + i.grabPos);
// float2 w4 = i.screenPos.xy + float2(_GrabTexture_TexelSize.x * -range * _Size, _GrabTexture_TexelSize.y * 0);
// i.grabPos.xy = w4;
// result += tex2Dproj(_GrabTexture, i.screenPos + i.grabPos);
//}
//result /= _Radius * 2 + 1;
float4 col = half4(_Color.a * _Color.rgb + (1 - _Color.a) * sum.rgb, 1.0f);
return col;
}
ENDCG
}
}
}
CommandBuff高斯模糊代码:
Shader
抓图做模糊用
Shader "Hidden/SeparableGlassBlur" {
Properties {
_MainTex ("Base (RGB)", 2D) = "" {}
}
CGINCLUDE
#include "UnityCG.cginc"
struct v2f {
float4 pos : POSITION;
float2 uv : TEXCOORD0;
float4 uv01 : TEXCOORD1;
float4 uv23 : TEXCOORD2;
float4 uv45 : TEXCOORD3;
};
float4 offsets;
sampler2D _MainTex;
v2f vert (appdata_img v) {
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.uv.xy = v.texcoord.xy;//正常uv
//偏移值 沿左右上下进行偏移 六套UV,横竖12个偏移值
o.uv01 = v.texcoord.xyxy + offsets.xyxy * float4(1,1, -1,-1);
o.uv23 = v.texcoord.xyxy + offsets.xyxy * float4(1,1, -1,-1) * 2.0;
o.uv45 = v.texcoord.xyxy + offsets.xyxy * float4(1,1, -1,-1) * 3.0;
return o;
}
half4 frag (v2f i) : COLOR {
half4 color = float4 (0,0,0,0);
//根据权重叠加偏移后的颜色
color += 0.40 * tex2D (_MainTex, i.uv);
color += 0.15 * tex2D (_MainTex, i.uv01.xy);
color += 0.15 * tex2D (_MainTex, i.uv01.zw);
color += 0.10 * tex2D (_MainTex, i.uv23.xy);
color += 0.10 * tex2D (_MainTex, i.uv23.zw);
color += 0.05 * tex2D (_MainTex, i.uv45.xy);
color += 0.05 * tex2D (_MainTex, i.uv45.zw);
return color;
}
ENDCG
Subshader {
Pass {
ZTest Always Cull Off ZWrite Off
Fog { Mode off }
CGPROGRAM
#pragma fragmentoption ARB_precision_hint_fastest
#pragma vertex vert
#pragma fragment frag
ENDCG
}
}
Fallback off
} // shader
放在物体上
Shader "Effects/FrostedGlass"
{
Properties
{
_FrostTex ("Fross Texture", 2D) = "white" {}
_FrostIntensity ("Frost Intensity", Range(0.0, 1.0)) = 0.5
}
SubShader
{
Tags { "RenderType"="Transparent" "Queue" = "Transparent" }
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uvfrost : TEXCOORD0;
float4 uvgrab : TEXCOORD1;
float4 vertex : SV_POSITION;
};
sampler2D _FrostTex;
float4 _FrostTex_ST;
float _FrostIntensity;
sampler2D _GrabBlurTexture_0;
sampler2D _GrabBlurTexture_1;
sampler2D _GrabBlurTexture_2;
sampler2D _GrabBlurTexture_3;
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uvfrost = TRANSFORM_TEX(v.uv, _FrostTex);
o.uvgrab = ComputeGrabScreenPos(o.vertex);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
float surfSmooth = 1-tex2D(_FrostTex, i.uvfrost) * _FrostIntensity; //模糊强度贴图
surfSmooth = clamp(0, 1, surfSmooth);//限制到0-1的区间
half4 refraction;
half4 ref00 = tex2Dproj(_GrabBlurTexture_0, i.uvgrab); //通过屏幕坐标采样抓到并模糊处理后的贴图
half4 ref01 = tex2Dproj(_GrabBlurTexture_1, i.uvgrab);
half4 ref02 = tex2Dproj(_GrabBlurTexture_2, i.uvgrab);
half4 ref03 = tex2Dproj(_GrabBlurTexture_3, i.uvgrab);
float step00 = smoothstep(0.75, 1.00, surfSmooth);//进行平滑过渡
float step01 = smoothstep(0.5, 0.75, surfSmooth);
float step02 = smoothstep(0.05, 0.5, surfSmooth);
float step03 = smoothstep(0.00, 0.05, surfSmooth);
refraction = lerp(ref03, lerp( lerp( lerp(ref03, ref02, step02), ref01, step01), ref00, step00), step03);
return refraction;
}
ENDCG
}
}
}
C#
using UnityEngine;
using UnityEngine.Rendering;
[ExecuteInEditMode]
[ImageEffectAllowedInSceneView]
[RequireComponent(typeof(Camera))]
public class CommandBufferBlur : MonoBehaviour
{
Shader _Shader;
Material _Material = null;
Camera _Camera = null;
CommandBuffer _CommandBuffer = null;
Vector2 _ScreenResolution = Vector2.zero;
RenderTextureFormat _TextureFormat = RenderTextureFormat.ARGB32;
public void Cleanup()
{
if (!Initialized)
return;
_Camera.RemoveCommandBuffer(CameraEvent.BeforeForwardAlpha, _CommandBuffer);
_CommandBuffer = null;
Object.DestroyImmediate(_Material);
}
public void OnEnable()
{
Cleanup();//先清理
Initialize();//初始化
}
public void OnDisable()
{
Cleanup();
}
public bool Initialized
{
get { return _CommandBuffer != null; }
}
void Initialize()
{
if (Initialized)
return;
//根据shader创建材质球
if (!_Shader)
{
_Shader = Shader.Find("Hidden/SeparableGlassBlur");
if (!_Shader)
throw new MissingReferenceException("Unable to find required shader \"Hidden/SeparableGlassBlur\"");
}
if (!_Material)
{
_Material = new Material(_Shader);
_Material.hideFlags = HideFlags.HideAndDontSave;
}
//创建摄像机
_Camera = GetComponent<Camera>();
if (_Camera.allowHDR && SystemInfo.SupportsRenderTextureFormat(RenderTextureFormat.DefaultHDR))
_TextureFormat = RenderTextureFormat.DefaultHDR;
//创建commandbuffer
_CommandBuffer = new CommandBuffer();
_CommandBuffer.name = "Blur screen";
int numIterations = 4;
//屏幕尺寸
Vector2[] sizes = {
new Vector2(Screen.width, Screen.height),
new Vector2(Screen.width / 2, Screen.height / 2),
new Vector2(Screen.width / 4, Screen.height / 4),
new Vector2(Screen.width / 8, Screen.height / 8),
};
for (int i = 0; i < numIterations; ++i)
{
int screenCopyID = Shader.PropertyToID("_ScreenCopyTexture");
_CommandBuffer.GetTemporaryRT(screenCopyID, -1, -1, 0, FilterMode.Bilinear, _TextureFormat);
//当前场景渲染到RT上
_CommandBuffer.Blit(BuiltinRenderTextureType.CurrentActive, screenCopyID);
int blurredID = Shader.PropertyToID("_Grab" + i + "_Temp1");
int blurredID2 = Shader.PropertyToID("_Grab" + i + "_Temp2");
//申请两个临时缓存RT
_CommandBuffer.GetTemporaryRT(blurredID, (int)sizes[i].x, (int)sizes[i].y, 0, FilterMode.Bilinear, _TextureFormat);
_CommandBuffer.GetTemporaryRT(blurredID2, (int)sizes[i].x, (int)sizes[i].y, 0, FilterMode.Bilinear, _TextureFormat);
//降采样
_CommandBuffer.Blit(screenCopyID, blurredID);
_CommandBuffer.ReleaseTemporaryRT(screenCopyID);
//横向偏移
_CommandBuffer.SetGlobalVector("offsets", new Vector4(2.0f / sizes[i].x, 0, 0, 0));
_CommandBuffer.Blit(blurredID, blurredID2, _Material);
//纵向偏移
_CommandBuffer.SetGlobalVector("offsets", new Vector4(0, 2.0f / sizes[i].y, 0, 0));
_CommandBuffer.Blit(blurredID2, blurredID, _Material);
//按照index输出RT
_CommandBuffer.SetGlobalTexture("_GrabBlurTexture_" + i, blurredID);
}
//_Camera.AddCommandBuffer(CameraEvent.AfterForwardAlpha, _CommandBuffer);
_Camera.AddCommandBuffer(CameraEvent.BeforeForwardAlpha, _CommandBuffer);
_ScreenResolution = new Vector2(Screen.width, Screen.height);
}
void OnPreRender()
{
if (_ScreenResolution != new Vector2(Screen.width, Screen.height))
Cleanup();
Initialize();
}
}
网友评论