效果
原理:
开启摄像机的深度模式,将深度保存到一张名为_CameraDepthTexture(Unity5.0之后才有)内置的纹理中.
如果深度在焦点范围内就用原图,否则就用模糊图。
Shader:
Shader "DepthOfFiled"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_BlurSize ("Blur Size", Float) = 0.1
} CGINCLUDE #include "UnityCG.cginc" sampler2D _MainTex;
sampler2D _BlurTex;
sampler2D _CameraDepthTexture;
uniform half4 _MainTex_TexelSize;
uniform float _BlurSize;
uniform float _FocusDistance;
uniform float _FocusRange; static const half weight[] = {0.0205, 0.0855, 0.232, 0.324};
static const half4 coordOffset = half4(.0h,.0h,-.0h,-.0h); struct v2f_blurSGX
{
float4 pos:SV_POSITION;
half2 uv:TEXCOORD0;
half4 uvoff[]:TEXCOORD1;
}; struct v2f_dof
{
float4 pos:SV_POSITION;
half2 uv:TEXCOORD0;
}; v2f_blurSGX vert_BlurHorizontal(appdata_img v)
{
v2f_blurSGX o;
o.pos = mul(UNITY_MATRIX_MVP,v.vertex);
o.uv = v.texcoord.xy;
half2 offs = _MainTex_TexelSize.xy*half2(,)*_BlurSize;
o.uvoff[] = v.texcoord.xyxy+offs.xyxy*coordOffset*;
o.uvoff[] = v.texcoord.xyxy+offs.xyxy*coordOffset*;
o.uvoff[] = v.texcoord.xyxy+offs.xyxy*coordOffset; return o;
} v2f_blurSGX vert_BlurVertical(appdata_img v)
{
v2f_blurSGX o;
o.pos = mul(UNITY_MATRIX_MVP,v.vertex);
o.uv = v.texcoord.xy; half2 offs = _MainTex_TexelSize.xy*half2(,)*_BlurSize;
o.uvoff[] = v.texcoord.xyxy+offs.xyxy*coordOffset*;
o.uvoff[] = v.texcoord.xyxy+offs.xyxy*coordOffset*;
o.uvoff[] = v.texcoord.xyxy+offs.xyxy*coordOffset; return o;
} fixed4 frag_Blur(v2f_blurSGX i):SV_Target
{ fixed4 c = tex2D(_MainTex,i.uv)*weight[];
for(int idx=; idx<; idx++)
{
c+=tex2D(_MainTex,i.uvoff[idx].xy)*weight[idx];
c+=tex2D(_MainTex,i.uvoff[idx].zw)*weight[idx];
} return c;
} v2f_dof vert_Dof(appdata_img v)
{
v2f_dof o;
o.pos = mul(UNITY_MATRIX_MVP,v.vertex);
o.uv = v.texcoord.xy; return o;
} fixed4 frag_Dof(v2f_dof i):SV_Target
{
fixed4 c = tex2D(_MainTex,i.uv);
fixed4 b = tex2D(_BlurTex,i.uv); float depth = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, i.uv);
//将深度值转化到01线性空间
depth = Linear01Depth(depth); return lerp(c,b,saturate(sign(abs(depth-_FocusDistance)-_FocusRange))); }
ENDCG SubShader
{
// No culling or depth
//Cull Off ZWrite Off //Pass 0
Pass
{
ZTest Always
CGPROGRAM
#pragma vertex vert_BlurHorizontal
#pragma fragment frag_Blur ENDCG
} //Pass 1
Pass
{
ZTest Always
CGPROGRAM
#pragma vertex vert_BlurVertical
#pragma fragment frag_Blur ENDCG
} //Pass 2
Pass
{
ZTest Off
Cull Off
ZWrite Off
Fog{ Mode Off }
ColorMask RGBA CGPROGRAM
#pragma vertex vert_Dof
#pragma fragment frag_Dof ENDCG
} }
}
C#代码
using UnityEngine;
using System.Collections; [ExecuteInEditMode]
[RequireComponent(typeof(Camera))]
public class DepthOfFieldPostEffect : MonoBehaviour { public Material Mat;public float BlurSize =;
public int interator = ;
[Range(,)]
public float FocusDistance = 0.5f;
[Range(,0.5f)]
public float FocusRange=0.1f; void OnEnable()
{
GetComponent<Camera> ().depthTextureMode = DepthTextureMode.Depth;
}
void OnDisable()
{
GetComponent<Camera> ().depthTextureMode = ~DepthTextureMode.Depth;
}
// Use this for initialization
void Start () { } // Update is called once per frame
void Update () { } void OnRenderImage(RenderTexture src,RenderTexture dest)
{
var w = src.width / ;
var h = src.height / ;
var tmp1 = RenderTexture.GetTemporary (w, h);
var tmp2 = RenderTexture.GetTemporary (w, h);
Mat.SetFloat ("_BlurSize", BlurSize);
Mat.SetFloat ("_FocusDistance", FocusDistance);
Mat.SetFloat ("_FocusRange", FocusRange); Graphics.Blit (src, tmp1); for (int i = ; i < interator; i++) {
Graphics.Blit (tmp1, tmp2, Mat,);
Graphics.Blit (tmp2, tmp1, Mat,);
} Mat.SetTexture ("_BlurTex", tmp1); Graphics.Blit (src, dest,Mat,); RenderTexture.ReleaseTemporary (tmp1);
RenderTexture.ReleaseTemporary (tmp2); }
}