Unity 屏幕模糊效果

前几天,美术要我做一个屏幕模糊的效果,百度了半天,最后总算解决了。
趁着有时间,现在来总结一下。

首先我这边是为了出效果,所以原理先放一边,来谈谈如何实现。什么高斯模糊,均值模糊先忽略,看起来太懵,要花大时间去钻。总的来说,实现主要是两种类型,一种是基于摄像机,一种是基于UI遮罩实现。

摄像机实现

Shader部分
// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'Shader "CameraFilterPack/Blur_Movie" {Properties {_MainTex ("Base (RGB)", 2D) = "white" {}_TimeX ("Time", Range(0.0, 1.0)) = 1.0_Distortion ("_Distortion", Range(0.0, 1.0)) = 0.3_ScreenResolution ("_ScreenResolution", Vector) = (0.,0.,0.,0.)_Radius ("_Radius", Range(0.0, 1000.0)) = 700.0_Factor ("_Factor", Range(0.0, 1000.0)) = 200.0}SubShader {Pass{ZTest AlwaysCGPROGRAM#pragma vertex vert#pragma fragment frag#pragma fragmentoption ARB_precision_hint_fastest#pragma target 3.0#pragma glsl#include "UnityCG.cginc"uniform sampler2D _MainTex;uniform float _TimeX;uniform float _Distortion;uniform float4 _ScreenResolution;uniform float _Radius;uniform float _Factor;struct appdata_t {float4 vertex   : POSITION;float4 color    : COLOR;float2 texcoord : TEXCOORD0;};struct v2f{half2 texcoord  : TEXCOORD0;float4 vertex   : SV_POSITION;fixed4 color    : COLOR;};   v2f vert(appdata_t IN){v2f OUT;OUT.vertex = UnityObjectToClipPos(IN.vertex);OUT.texcoord = IN.texcoord;OUT.color = IN.color;return OUT;}#define tex2D(sampler,uvs)  tex2Dlod( sampler , float4( ( uvs ) , 0.0f , 0.0f) )float4 frag (v2f i) : COLOR{float factor = _Factor/_ScreenResolution.y * 64.0;float radius = _Radius/_ScreenResolution.x * 2.0;float4 col = 0.0; float4 accumColx = 0.0;float4 accumW = 0.0;for (float j = -5.0; j < 5.0; j += 1.0){for (float u = -5.0; u < 5.0; u += 1.0){ float2 offsetx = (1.0/_ScreenResolution.xy) * float2(u + j, j - u);col = tex2D(_MainTex, i.texcoord.xy + offsetx * radius);float4 movie = 1.0 + col * col * col * factor;accumColx = accumColx + col * movie;accumW += movie;}}  accumColx = accumColx/accumW;return accumColx;}ENDCG}}
}

c#部分

using UnityEngine;[ExecuteInEditMode]
[AddComponentMenu ("Camera Filter Pack/Blur/Movie")]
public class CameraFilterPack_Blur_Movie : MonoBehaviour {#region Variablespublic Shader SCShader;private float TimeX = 1.0f;private Vector4 ScreenResolution;private Material SCMaterial;[Range(0,1000)]public float Radius = 150.0f;[Range(0,1000)]public float Factor = 200.0f;[Range(1,8)]public int FastFilter = 2;public static float ChangeRadius;public static float ChangeFactor;public static int ChangeFastFilter;#endregion#region PropertiesMaterial material{get{if(SCMaterial == null){SCMaterial = new Material(SCShader);SCMaterial.hideFlags = HideFlags.HideAndDontSave;        }return SCMaterial;}}#endregionvoid Start () {ChangeRadius = Radius;ChangeFactor = Factor;ChangeFastFilter = FastFilter;SCShader = Shader.Find("CameraFilterPack/Blur_Movie");if(!SystemInfo.supportsImageEffects){enabled = false;return;}}void OnRenderImage (RenderTexture sourceTexture, RenderTexture destTexture){if(SCShader != null){int DownScale=FastFilter;TimeX+=Time.deltaTime;if (TimeX>100)  TimeX=0;material.SetFloat("_TimeX", TimeX);material.SetFloat("_Radius", Radius/DownScale);material.SetFloat("_Factor", Factor);material.SetVector("_ScreenResolution",new Vector2(Screen.width/DownScale,Screen.height/DownScale));int rtW = sourceTexture.width/DownScale;int rtH = sourceTexture.height/DownScale;if (FastFilter>1){RenderTexture buffer = RenderTexture.GetTemporary(rtW, rtH, 0);Graphics.Blit(sourceTexture, buffer, material);Graphics.Blit(buffer, destTexture);RenderTexture.ReleaseTemporary(buffer);}else{Graphics.Blit(sourceTexture, destTexture, material);}}else{Graphics.Blit(sourceTexture, destTexture);        }}
void OnValidate()
{ChangeRadius=Radius;ChangeFactor=Factor;ChangeFastFilter=FastFilter;
}// Update is called once per framevoid Update () {if (Application.isPlaying){Radius = ChangeRadius;Factor = ChangeFactor;FastFilter = ChangeFastFilter;}#if UNITY_EDITORif (Application.isPlaying!=true){SCShader = Shader.Find("CameraFilterPack/Blur_Movie");}#endif}void OnDisable (){if(SCMaterial){DestroyImmediate(SCMaterial);        }}}

将CameraFilterPack_Blur_Movie 挂在你想实现模糊得摄像机上,就可以实现屏幕模糊效果了。

调整Radius,Factor,FastFilter三个值去得到你想要得模糊度。

但这个效果,并不是我要的效果。我做的是2D休闲小游戏的开发,要求背景模糊,但是UI不能模糊。有人说,你看上面效果,UI不是没有模糊吗?不是完全符合你的开发需求?其实,在上面的场景里,我用了两个摄像机,一个主相机照场景,一个UI相机照UI。我只是让主相机模糊了,但UI相机还是正常的。而我开发的2D游戏,是只有一个摄像机的,所以这个方法不能符合我的开发需求。

基于UGI遮罩实现

Shader部分

Shader "MyShader/BackBlur" {Properties{[PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {}_Color ("Main Color", Color) = (1,1,1,1)_Size ("Size", Range(0, 20)) = 1}Category {  // We must be transparent, so other objects are drawn before this one.  Tags {"Queue"="Transparent""IgnoreProjector"="True""RenderType"="Transparent""PreviewType" = "Plane""CanUseSpriteAtlas" = "True"}  SubShader {  // Horizontal blur  GrabPass {                      Tags { "LightMode" = "Always" }  }  Pass {Tags { "LightMode" = "Always" }  Name "BackBlurHor"CGPROGRAM  #pragma vertex vert  #pragma fragment frag  #pragma fragmentoption ARB_precision_hint_fastest  #include "UnityCG.cginc"  struct appdata_t {  float4 vertex : POSITION;  float2 texcoord : TEXCOORD0;float4 color    : COLOR;};  struct v2f {  float4 vertex : POSITION;  float4 uvgrab : TEXCOORD0;float4 color    : COLOR;};v2f vert (appdata_t v) {  v2f o;o.vertex = UnityObjectToClipPos(v.vertex);  #if UNITY_UV_STARTS_AT_TOP  float scale = -1.0;  #else  float scale = 1.0;  #endif  o.uvgrab.xy = (float2(o.vertex.x, o.vertex.y*scale) + o.vertex.w) *  0.5;  o.uvgrab.zw = o.vertex.zw;  o.color = v.color;return o;  }  sampler2D _GrabTexture;  float4 _GrabTexture_TexelSize;float4 _MainTex_TexelSize;float _Size;uniform float4 _Color;// static float GaussianKernel[9] = {//     0.05, 0.09, 0.12,//     0.15, 0.18, 0.15,//     0.12, 0.09, 0.05// };// static float GaussianKernel[19] = {//     0.01, 0.02, 0.03, 0.04, 0.05, 0.06, 0.07, 0.08, 0.09,//     0.1,//     0.09, 0.08, 0.07, 0.06, 0.05, 0.04, 0.03, 0.02, 0.01,// };// static float GaussianKernelD[19] = {//     -9.0, -8.0, -7.0, -6.0, -5.0, -4.0, -3.0, -2.0, -1.0,//     0.0,//     +1.0, +2.0, +3.0, +4.0, +5.0, +6.0, +7.0, +8.0, +9.0,// };half4 GrabPixel(v2f i, float weight, float kernelx){if (i.uvgrab.x == 0 && i.uvgrab.y == 0){kernelx = 0;}return tex2Dproj(_GrabTexture, UNITY_PROJ_COORD(float4(i.uvgrab.x +  _GrabTexture_TexelSize.x*kernelx*_Size, i.uvgrab.y, i.uvgrab.z, i.uvgrab.w))) * weight;}half4 frag( v2f i ) : COLOR {  half4 sum = half4(0,0,0,0);// #define GRABPIXEL(weight, kernelx) tex2Dproj(_GrabTexture,  UNITY_PROJ_COORD(float4(i.uvgrab.x + _GrabTexture_TexelSize.x * kernelx*_Size, i.uvgrab.y,  i.uvgrab.z, i.uvgrab.w))) * weightsum += 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);// sum += GrabPixel(i, 0.01, -9.0);// sum += GrabPixel(i, 0.02, -8.0);// sum += GrabPixel(i, 0.03, -7.0);// sum += GrabPixel(i, 0.04, -6.0);// sum += GrabPixel(i, 0.05, -5.0);// sum += GrabPixel(i, 0.06, -4.0);// sum += GrabPixel(i, 0.07, -3.0);// sum += GrabPixel(i, 0.08, -2.0);// sum += GrabPixel(i, 0.09, -1.0);// sum += GrabPixel(i, 0.10,  0.0);// sum += GrabPixel(i, 0.09, +1.0);// sum += GrabPixel(i, 0.08, +2.0);// sum += GrabPixel(i, 0.07, +3.0);// sum += GrabPixel(i, 0.06, +4.0);// sum += GrabPixel(i, 0.05, +5.0);// sum += GrabPixel(i, 0.04, +6.0);// sum += GrabPixel(i, 0.03, +7.0);// sum += GrabPixel(i, 0.02, +8.0);// sum += GrabPixel(i, 0.01, +9.0);float4 col5 = tex2Dproj(_GrabTexture, UNITY_PROJ_COORD(i.uvgrab));float decayFactor = 1.0f;if (i.uvgrab.x == 0 && i.uvgrab.y == 0){decayFactor = 0;}sum = lerp(col5, sum, decayFactor) * i.color *  _Color;return sum;  }  ENDCG  }  // Vertical blur  GrabPass {                          Tags { "LightMode" = "Always" }  }  Pass {  Tags { "LightMode" = "Always" }Name "BackBlurVer"CGPROGRAM  #pragma vertex vert  #pragma fragment frag  #pragma fragmentoption ARB_precision_hint_fastest  #include "UnityCG.cginc"  struct appdata_t {  float4 vertex : POSITION;  float2 texcoord: TEXCOORD0;  float4 color    : COLOR;};  struct v2f {  float4 vertex : POSITION;  float4 uvgrab : TEXCOORD0;  float4 color    : COLOR;};  v2f vert (appdata_t v) {  v2f o;  o.vertex = UnityObjectToClipPos(v.vertex);  #if UNITY_UV_STARTS_AT_TOP  float scale = -1.0;  #else  float scale = 1.0;  #endif  o.uvgrab.xy = (float2(o.vertex.x, o.vertex.y*scale) + o.vertex.w) *  0.5;  o.uvgrab.zw = o.vertex.zw;  o.color = v.color;return o;  }  sampler2D _GrabTexture;  float4 _GrabTexture_TexelSize;  float _Size;uniform float4 _Color;half4 GrabPixel(v2f i, float weight, float kernely){if (i.uvgrab.x == 0 && i.uvgrab.y == 0){kernely = 0;}return tex2Dproj( _GrabTexture, UNITY_PROJ_COORD(float4(i.uvgrab.x,  i.uvgrab.y + _GrabTexture_TexelSize.y*kernely*_Size, i.uvgrab.z, i.uvgrab.w))) * weight;}half4 frag( v2f i ) : COLOR {half4 sum = half4(0,0,0,0);  // #define GRABPIXEL(weight,kernely) tex2Dproj( _GrabTexture,  UNITY_PROJ_COORD(float4(i.uvgrab.x, i.uvgrab.y + _GrabTexture_TexelSize.y * kernely*_Size,  i.uvgrab.z, i.uvgrab.w))) * weight  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);// sum += GrabPixel(i, 0.01, -9.0);// sum += GrabPixel(i, 0.02, -8.0);// sum += GrabPixel(i, 0.03, -7.0);// sum += GrabPixel(i, 0.04, -6.0);// sum += GrabPixel(i, 0.05, -5.0);// sum += GrabPixel(i, 0.06, -4.0);// sum += GrabPixel(i, 0.07, -3.0);// sum += GrabPixel(i, 0.08, -2.0);// sum += GrabPixel(i, 0.09, -1.0);// sum += GrabPixel(i, 0.10,  0.0);// sum += GrabPixel(i, 0.09, +1.0);// sum += GrabPixel(i, 0.08, +2.0);// sum += GrabPixel(i, 0.07, +3.0);// sum += GrabPixel(i, 0.06, +4.0);// sum += GrabPixel(i, 0.05, +5.0);// sum += GrabPixel(i, 0.04, +6.0);// sum += GrabPixel(i, 0.03, +7.0);// sum += GrabPixel(i, 0.02, +8.0);// sum += GrabPixel(i, 0.01, +9.0);float4 col5 = tex2Dproj(_GrabTexture,  UNITY_PROJ_COORD(i.uvgrab));float decayFactor = 1.0f;if (i.uvgrab.x == 0 && i.uvgrab.y == 0){decayFactor = 0;}sum = lerp(col5, sum, decayFactor) * i.color *  _Color;return sum;  }  ENDCG  }}  }
}

C#部分

using System.Collections;
using UnityEngine;namespace Hyperbyte
{public static class UIExtentions{// Clear all child gameobjects of the given gameobject.public static void ClearAllChild(this GameObject obj){if (obj.transform.childCount > 0){foreach (Transform child in obj.transform){GameObject.Destroy(child.gameObject);}}}// Clear all child gameobjects of the given transform.public static void ClearAllChild(this Transform obj){if (obj.childCount > 0){foreach (Transform child in obj){GameObject.Destroy(child.gameObject);}}}// Clear all child gameobjects of the given rect transform.public static void ClearAllChild(this RectTransform obj){if (obj.childCount > 0){foreach (Transform child in obj){GameObject.Destroy(child.gameObject);}}}// Activates the given gameobject with animation. used for only popups of the game.public static void Activate(this GameObject target, bool addToStack = true){// target.gameObject.SetActive(true);// target.transform.SetAsLastSibling();// if(addToStack) {//     UIController.Instance.Push(target.name);// }}// Deactivates the game object with animation.public static void Deactivate(this GameObject target){// Animator animator = target.GetComponent<Animator>();// if (animator != null)// {//     animator.Play("Close");//     UIController.Instance.StartCoroutine(DisableWindow(target));// }// else// {//     target.SetActive(false);//     UIController.Instance.Pop(target.name);// }}/// <summary>/// Disable given gameobject and removes it from stack added to any./// </summary>static IEnumerator DisableWindow(GameObject target){yield return new WaitForSeconds(0.3F);// target.SetActive(false);// UIController.Instance.Pop(target.name);}}
}

用MyShader/BackBlur新建一个材质,再新建一个Image。把这个Image的材质设置为它。它挡住的地方(层级比他低的)都会变得模糊。
这就完美符合我的需求了。只要把IMAGE遮住底部,就可以完美实现背景模糊的效果。调整它的层级就能决定谁模糊,谁不模糊。

Unity 屏幕模糊效果相关推荐

  1. Unity屏幕永远保持为固定分辨率

    Unity屏幕永远保持为固定分辨率 Unity屏幕永远保持为固定分辨率 前言 开题废话 Unity版本 正题: 打开一场景 创建脚本并且编写 挂在脚本到场景摄像机上边 以不同比的分辨率运行程序,并且观 ...

  2. Unity 屏幕特效 之 简单地调整颜色的 色散效果 的实现

    Unity 屏幕特效 之 简单地调整颜色的 色散效果 的实现 目录 Unity 屏幕特效 之 简单地调整颜色的 色散效果 的实现 一.简介

  3. Unity 屏幕特效 之 简单地使用 Shader 获取深度,实现景深效果

    Unity 屏幕特效 之 简单地使用 Shader 获取深度,实现景深效果 目录

  4. Unity 屏幕特效 之 热浪扭曲效果的实现

    Unity 屏幕特效 之 热浪扭曲效果的实现 目录 Unity 屏幕特效 之 热浪扭曲效果的实现 一.简介 二.关键技术

  5. Unity 屏幕特效 之 简单地调整颜色的亮度、饱和度、对比度

    Unity 屏幕特效 之 简单地调整颜色的亮度.饱和度.对比度 目录 Unity 屏幕特效 之 简单地调整颜色的亮度.饱和度.对比度 一.简介

  6. unity 手机 模糊效果_GUI背景模糊效果优化

    欢迎关注"数天技术"!" 作者介绍:数字天空项目组客户端工程师 – 文立" 导语 在游戏界面显示时,通常会对背景进行模糊,使显示界面更加清楚.此外,在处理景深( ...

  7. unity屏幕后处理全家桶之color grading

    color grading color grading指的是对最终的游戏界面进行颜色和亮度的改变或矫正.你可以理解为增加滤镜. 屏幕后处理全家桶里的color grading是完全实时hdr工具,内部 ...

  8. Unity屏幕适配解决方案

    文章目录 UI尺寸选择 市面设备比例 内存占用 分辨率适配 高分辨率 分屏模式 宽高比适配 常规尺寸适配 刘海屏适配 全面屏适配 UI尺寸选择 市面设备比例 截至2017年9月,iOS与Android ...

  9. Unity屏幕射线碰撞

    Layers层: 从Layers设置看来,最多支持32层.  图层的值开始依次 0^2,1^2, 2^2, 3^3 依次增加. 当摄像机Culling Mask属性 Nothing= –1 Eveni ...

最新文章

  1. Shell中自定义函数
  2. 在循环递增一次的数组中插入元素
  3. 解决:Java HotSpot(TM) 64-Bit Server VM warning: INFO: os::commit_memory(0x00000000c5330000, 986513408,
  4. 手机uc浏览器夜间模式怎么设置调成全黑
  5. python如何获取请求的url_听说你在学习:如何通过代码请求URL地址
  6. idea mac 替换_史上最全的IntelliJ IDEA For Mac快捷键!快来收藏吧!
  7. rvest | 网络爬虫初步——使用CSS选择器
  8. ubuntu常用命令(未整理)
  9. html中的背景颜色渐变效果,如何CSS实现网页背景三种颜色渐变效果?
  10. 数据同步,数据库实时迁移同步方案,数据库同步软件
  11. mysql vsize_Oracle 中的Userenv()
  12. 【猛料】腾讯前总监受贿侵占数百万获刑9年
  13. 解决新安装的 Arch Linux 在 GNOME 中搜狗输入法不显示候选词和输入延迟的问题
  14. Java入门——while循环:求珠穆朗玛峰高度
  15. mysql数据库 mdf 文件_如何连接到MDF数据库文件?
  16. 常用字符集编码的概要特性(一)
  17. Taro小程序,底部输入框获取键盘高度动态设置bottom有延迟解决
  18. 小红书服装行业数据可视化
  19. 什么是单页应用?它的优缺点?其缺点的解决方案是什么?
  20. python爬虫爬取pdf_Python 爬虫:爬取教程生成 PDF

热门文章

  1. CBS基于冲突的搜索算法流程和核心
  2. 计算机网络安全凭据,账户为用户或计算机提供安全凭证,以便用户和计算机能够登录到网络,并拥有响应访 - 百科题库网...
  3. 靠着群友的接济,一毛不拔的学会了Python!(学习路线+资料分享)
  4. Ta-Lib用法介绍 !
  5. 文档排版软件CTex,Winedt10使用(一)---安装
  6. Codeforces 513F1 513F2 Scaygerboss 网络流
  7. SQL SERVER数据库误删除误格式化误重装软件覆盖数据恢复修复
  8. 【Redis】回顾下Redis的过期策略
  9. STL库:stack和queue
  10. Android PowerManagerService简单分析