Unity Shader 景深效果

效果

原理:

开启摄像机的深度模式,将深度保存到一张名为_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[4] = {0.0205, 0.0855, 0.232, 0.324};
    static const half4 coordOffset = half4(1.0h,1.0h,-1.0h,-1.0h);

    struct v2f_blurSGX
    {
        float4 pos:SV_POSITION;
        half2 uv:TEXCOORD0;
        half4 uvoff[3]: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(1,0)*_BlurSize;
        o.uvoff[0] = v.texcoord.xyxy+offs.xyxy*coordOffset*3;
        o.uvoff[1] = v.texcoord.xyxy+offs.xyxy*coordOffset*2;
        o.uvoff[2] = 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(0,1)*_BlurSize;
        o.uvoff[0] = v.texcoord.xyxy+offs.xyxy*coordOffset*3;
        o.uvoff[1] = v.texcoord.xyxy+offs.xyxy*coordOffset*2;
        o.uvoff[2] = v.texcoord.xyxy+offs.xyxy*coordOffset;

        return o;
    }

    fixed4 frag_Blur(v2f_blurSGX i):SV_Target
    {
        
        fixed4 c = tex2D(_MainTex,i.uv)*weight[3];
        for(int idx=0; idx<3; 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 =10;
    public int interator = 2;
    [Range(0,1)]
    public float FocusDistance = 0.5f; 
    [Range(0,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 / 8;
        var h = src.height / 8;
        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 = 0; i < interator; i++) {
            Graphics.Blit (tmp1, tmp2, Mat,0);
            Graphics.Blit (tmp2, tmp1, Mat,1);
        }

        Mat.SetTexture ("_BlurTex", tmp1);

        Graphics.Blit (src, dest,Mat,2);

        RenderTexture.ReleaseTemporary (tmp1);
        RenderTexture.ReleaseTemporary (tmp2);

    }
}
原文地址:https://www.cnblogs.com/mrblue/p/7875755.html