Untiy使用Shader实现镜头模糊效果
前言
最近公司接了一个光学实验的项目,因为开发需求较模糊,我只能做一些简单的开发功能。于是在网上查相关资料,使用shader实现了一个简单的镜头模糊效果,在这里记录下,便于以后开发使用。
步骤
1.创建一个shader,用以实现镜头的模糊效果,实现代码如下所示:
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 Always
CGPROGRAM
#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
}
}
}
2.创建CameraFilterPack_Blur_Movie.cs脚本,用以调用实现镜头模糊功能的调用,代码如下所示:
using UnityEngine;
[ExecuteInEditMode]
[AddComponentMenu("Camera Filter Pack/Blur/Movie")]
public class CameraFilterPack_Blur_Movie : MonoBehaviour
{
#region Variables
public 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 float ChangeRadius;
//public static float ChangeFactor;
public float ChangeFactor;
//public static int ChangeFastFilter;
public int ChangeFastFilter;
#endregion
#region Properties
Material material
{
get
{
if (SCMaterial == null)
{
SCMaterial = new Material(SCShader);
SCMaterial.hideFlags = HideFlags.HideAndDontSave;
}
return SCMaterial;
}
}
#endregion
void 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 frame
void Update()
{
if (Application.isPlaying)
{
Radius = ChangeRadius;
Factor = ChangeFactor;
FastFilter = ChangeFastFilter;
}
#if UNITY_EDITOR
if (Application.isPlaying != true)
{
SCShader = Shader.Find("CameraFilterPack/Blur_Movie");
}
#endif
}
void OnDisable()
{
if (SCMaterial)
{
DestroyImmediate(SCMaterial);
}
}
}
3.将上述脚本挂载到场景中的Camera中,并将shader文件拖拽到脚本上,如下图所示:
4.修改脚本中的Radius的值,即实现了镜头模糊效果,如下图所示: