using UnityEngine; //设置在编辑模式下也执行该脚本 //[ExecuteInEditMode] //添加选项到菜单中 [AddComponentMenu("RapidBlurEffect")] public class RapidBlurEffectUtlis : MonoBehaviour { static class Uniforms { internal static readonly int _DownSampleValue = Shader.PropertyToID("_DownSampleValue"); } //-------------------变量声明部分------------------- #region Variables //指定Shader名称 private string ShaderName = "Learning Unity Shader/Lecture 15/RapidBlurEffect"; public Shader CurShader; //着色器和材质实例 private Material CurMaterial; //降采样次数 [Range(0, 6), Tooltip("[降采样次数]向下采样的次数。此值越大,则采样间隔越大,需要处理的像素点越少,运行速度越快。")] public int DownSampleNum = 2; //模糊扩散度 [Range(0.0f, 20.0f), Tooltip("[模糊扩散度]进行高斯模糊时,相邻像素点的间隔。此值越大相邻像素间隔越远,图像越模糊。但过大的值会导致失真。")] public float BlurSpreadSize = 2.0f; //迭代次数 [Range(0, 8), Tooltip("[迭代次数]此值越大,则模糊操作的迭代次数越多,模糊效果越好,但消耗越大。")] public int BlurIterations = 2; #endregion public void SetShader(Shader s) { CurShader = s; } Material material { get { if (CurMaterial == null && CurShader != null) { CurMaterial = new Material(CurShader); CurMaterial.hideFlags = HideFlags.HideAndDontSave; } return CurMaterial; } } #region Functions //-----------------------------------------【Start()函数】--------------------------------------------- // 说明:此函数仅在Update函数第一次被调用前被调用 //-------------------------------------------------------------------------------------------------------- void Start() { //判断当前设备是否支持屏幕特效 if (!SystemInfo.supportsImageEffects) { enabled = false; return; } } //-------------------------------------【OnRenderImage()函数】------------------------------------ // 说明:此函数在当完成所有渲染图片后被调用,用来渲染图片后期效果 //-------------------------------------------------------------------------------------------------------- void OnRenderImage(RenderTexture sourceTexture, RenderTexture destTexture) { //着色器实例不为空,就进行参数设置 if (material != null) { //【0】参数准备 //根据向下采样的次数确定宽度系数。用于控制降采样后相邻像素的间隔 float widthMod = 1.0f / (1.0f * (1 << DownSampleNum)); //Shader的降采样参数赋值 //material.SetFloat("_DownSampleValue", BlurSpreadSize * widthMod); material.SetFloat(Uniforms._DownSampleValue, BlurSpreadSize * widthMod); //设置渲染模式:双线性 sourceTexture.filterMode = FilterMode.Bilinear; //通过右移,准备长、宽参数值 int renderWidth = sourceTexture.width >> DownSampleNum; int renderHeight = sourceTexture.height >> DownSampleNum; // 【1】处理Shader的通道0,用于降采样 ||Pass 0,for down sample //准备一个缓存renderBuffer,用于准备存放最终数据 RenderTexture renderBuffer = RenderTexture.GetTemporary(renderWidth, renderHeight, 0, sourceTexture.format); //设置渲染模式:双线性 renderBuffer.filterMode = FilterMode.Bilinear; //拷贝sourceTexture中的渲染数据到renderBuffer,并仅绘制指定的pass0的纹理数据 Graphics.Blit(sourceTexture, renderBuffer, material, 0); //【2】根据BlurIterations(迭代次数),来进行指定次数的迭代操作 for (int i = 0; i < BlurIterations; i++) { //【2.1】Shader参数赋值 //迭代偏移量参数 float iterationOffs = (i * 1.0f); //Shader的降采样参数赋值 //material.SetFloat("_DownSampleValue", BlurSpreadSize * widthMod + iterationOffs); material.SetFloat(Uniforms._DownSampleValue, BlurSpreadSize * widthMod + iterationOffs); // 【2.2】处理Shader的通道1,垂直方向模糊处理 || Pass1,for vertical blur // 定义一个临时渲染的缓存tempBuffer RenderTexture tempBuffer = RenderTexture.GetTemporary(renderWidth, renderHeight, 0, sourceTexture.format); // 拷贝renderBuffer中的渲染数据到tempBuffer,并仅绘制指定的pass1的纹理数据 Graphics.Blit(renderBuffer, tempBuffer, material, 1); // 清空renderBuffer RenderTexture.ReleaseTemporary(renderBuffer); // 将tempBuffer赋给renderBuffer,此时renderBuffer里面pass0和pass1的数据已经准备好 renderBuffer = tempBuffer; // 【2.3】处理Shader的通道2,竖直方向模糊处理 || Pass2,for horizontal blur // 获取临时渲染纹理 tempBuffer = RenderTexture.GetTemporary(renderWidth, renderHeight, 0, sourceTexture.format); // 拷贝renderBuffer中的渲染数据到tempBuffer,并仅绘制指定的pass2的纹理数据 Graphics.Blit(renderBuffer, tempBuffer, material, 2); //【2.4】得到pass0、pass1和pass2的数据都已经准备好的renderBuffer // 再次清空renderBuffer RenderTexture.ReleaseTemporary(renderBuffer); // 再次将tempBuffer赋给renderBuffer,此时renderBuffer里面pass0、pass1和pass2的数据都已经准备好 renderBuffer = tempBuffer; } //拷贝最终的renderBuffer到目标纹理,并绘制所有通道的纹理到屏幕 Graphics.Blit(renderBuffer, destTexture); //清空renderBuffer RenderTexture.ReleaseTemporary(renderBuffer); } //着色器实例为空,直接拷贝屏幕上的效果。此情况下是没有实现屏幕特效的 else { //直接拷贝源纹理到目标渲染纹理 Graphics.Blit(sourceTexture, destTexture); } } #endregion }