实现思路:离中心点越远的像素 模糊效果越明显 UV偏移的量越大 shader
// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
Shader "3D/ScreenEdgeBlur" {
//------------------------------------【属性值】------------------------------------
Properties
{
_MainTex("主纹理 (RGB)", 2D) = "white" {}
_IterationNumber("迭代次数", Int)=16
}
//------------------------------------【唯一的子着色器】------------------------------------
SubShader
{
//--------------------------------唯一的通道-------------------------------
Pass
{
//设置深度测试模式:渲染所有像素.等同于关闭透明度测试(AlphaTest Off)
ZTest Always
//===========开启CG着色器语言编写模块===========
CGPROGRAM
//编译指令: 指定着色器编译目标为Shader Model 3.0
#pragma target 3.0
//编译指令:告知编译器顶点和片段着色函数的名称
//vert_img是在UnityCG.cginc中定义好的,当后处理vert阶段计算常规,可以直接使用自带的vert_img
#pragma vertex vert_img
#pragma fragment frag_blur
//包含辅助CG头文件
#include "UnityCG.cginc"
//外部变量的声明
uniform sampler2D _MainTex;
uniform float _Value;
uniform float _Value2;
uniform float _Value3;
uniform int _IterationNumber;
float4 frag_blur(v2f_img i) : SV_TARGET
{
//【2】获取纹理坐标的x,y坐标值
float2 uv = i.uv;
//【3】纹理坐标按照中心位置进行一个偏移
uv -= _center;
//【4】初始化一个颜色值
float4 color = float4(0.0, 0.0, 0.0, 0.0);
//【6】设置坐标缩放比例的值
float scale = 1;
//【7】进行纹理颜色的迭代
for (int j = 1; j < _IterationNumber; ++j)
{
//将主纹理在不同坐标采样下的颜色值进行迭代累加
color += tex2D(_MainTex, uv * scale + _center);
//坐标缩放比例依据循环参数的改变而变化
scale = 1 + (float(j * 0.02));
}
//【8】将最终的颜色值除以迭代次数,取平均值
color /= (float)_IterationNumber;
return color;
}
//===========结束CG着色器语言编写模块===========
ENDCG
}
}
}
C#
using UnityEngine;
using System.Collections;
using XLua;
namespace bgdust
{
[ExecuteInEditMode]
public class ScreenBlurEffect : MonoBehaviour
{
//-------------------变量声明部分-------------------
#region Variables
public Shader CurShader;//着色器实例
private Material CurMaterial;//当前的材质
[Range(2, 50)]
public float IterationNumber = 15;
public Vector2 center = new Vector2(0.5f, 0.5f);
public static Vector2 ChangeValue;
public static float ChangeValue2;
#endregion
//-------------------------材质的get&set----------------------------
#region MaterialGetAndSet
Material material
{
get
{
if (CurMaterial == null)
{
CurMaterial = new Material(CurShader);
CurMaterial.hideFlags = HideFlags.HideAndDontSave;
}
return CurMaterial;
}
}
#endregion
//-----------------------------------------【Start()函数】---------------------------------------------
// 说明:此函数仅在Update函数第一次被调用前被调用
//--------------------------------------------------------------------------------------------------------
void Start()
{
//依此赋值
ChangeValue = center;
ChangeValue2 = IterationNumber;
//找到当前的Shader文件
CurShader = Shader.Find("3D/ScreenEdgeBlur1");
//判断是否支持屏幕特效
if (!SystemInfo.supportsImageEffects)
{
enabled = false;
return;
}
}
//-------------------------------------【OnRenderImage()函数】------------------------------------
// 说明:此函数在当完成所有渲染图片后被调用,用来渲染图片后期效果
//--------------------------------------------------------------------------------------------------------
void OnRenderImage(RenderTexture sourceTexture, RenderTexture destTexture)
{
if (CurShader != null)
{
//申请两块降低分辨率的RT 优化像素的采样次数
//RenderTexture rt1 = RenderTexture.GetTemporary(sourceTexture.width / (int)IterationNumber, sourceTexture.height / (int)IterationNumber, 0, sourceTexture.format);
RenderTexture rt1 = RenderTexture.GetTemporary(sourceTexture.width, sourceTexture.height, 0, sourceTexture.format);
Graphics.Blit(sourceTexture, rt1);
//设置Shader中的外部变量
material.SetFloat("_IterationNumber", IterationNumber);
material.SetVector("_center", center);
//将进行过模糊操作的RT输出出来用rt2存起来
Graphics.Blit(rt1, destTexture, material, 0);
RenderTexture.ReleaseTemporary(rt1);
}
//着色器实例为空,直接拷贝屏幕上的效果。此情况下是没有实现屏幕特效的
else
{
//直接拷贝源纹理到目标渲染纹理
Graphics.Blit(sourceTexture, destTexture);
}
}
//-----------------------------------------【OnValidate()函数】--------------------------------------
// 说明:此函数在编辑器中该脚本的某个值发生了改变后被调用
//--------------------------------------------------------------------------------------------------------
void OnValidate()
{
//将编辑器中的值赋值回来,确保在编辑器中值的改变立刻让结果生效
ChangeValue2 = IterationNumber;
ChangeValue = center;
}
//-----------------------------------------【OnDisable()函数】---------------------------------------
// 说明:当对象变为不可用或非激活状态时此函数便被调用
//--------------------------------------------------------------------------------------------------------
void OnDisable()
{
if (CurMaterial)
{
DestroyImmediate(CurMaterial);
}
}
}
}
原图 正常效果
降低分辨率后的效果
|