【Shader】实验02——后处理实现景深效果

景深(Depth Of Field),是指在摄影机镜头或其他成像器前沿能够取得清晰图像的成像所测定的被摄物体前后距离范围。

而景深效果是指在焦距之外的地方都是模糊的,只有焦距的地方清晰。

通过采样摄像机的深度纹理,得到当前屏幕纹理每个点的深度,使用深度值与焦距值得到每个点到焦距的距离,并使用距离来对原图像和高斯模糊处理过的图像进行插值并输出即可。

景深效果示例

Shader代码

Shader "MyShaderTest/2_DepthOfField"
{
	Properties 
	{
		_MainTex ("Base (RGB)", 2D) = "white" {}
		_BlurMainTex("Bloom (RGB)", 2D) = "black" {}
		_LuminanceThreshold ("Luminance Threshold", Float) = 0.5
		_BlurSize ("Blur Size", Float) = 1.0
		_FocusStart("FocusStart", Float) = 0.4
		_FocusEnd("FocusEnd", Float) = 0.6
	}

	SubShader
	{
		ZTest Always Cull Off ZWrite Off

		CGINCLUDE
		#include "UnityCG.cginc"

		sampler2D _MainTex;
		half4 _MainTex_TexelSize;
		sampler2D _CameraDepthTexture;
		sampler2D _BlurMainTex;
		float _BlurSize;
		float _FocusStart;
		float _FocusEnd;

		struct v2fBlur
		{
			float4 pos : SV_POSITION;
			half2 uv[5] : TEXCOORD0;
		};

		//垂直方向(Y轴方向)的高斯模糊
		v2fBlur vertBlurVertical(appdata_img v)
		{
			v2fBlur o;
			o.pos = UnityObjectToClipPos(v.vertex);
			half2 uv = v.texcoord;

			o.uv[0] = uv;
			o.uv[1] = uv + float2(0.0, _MainTex_TexelSize.y * 1.0) * _BlurSize;
			o.uv[2] = uv - float2(0.0, _MainTex_TexelSize.y * 1.0) * _BlurSize;
			o.uv[3] = uv + float2(0.0, _MainTex_TexelSize.y * 2.0) * _BlurSize;
			o.uv[4] = uv - float2(0.0, _MainTex_TexelSize.y * 2.0) * _BlurSize;
			return o;
		}

		//水平方向(X轴方向)的高斯模糊
		v2fBlur vertBlurHorizontal(appdata_img v)
		{
			v2fBlur o;
			o.pos = UnityObjectToClipPos(v.vertex);
			half2 uv = v.texcoord;

			o.uv[0] = uv;
			o.uv[1] = uv + float2(_MainTex_TexelSize.x * 1.0, 0.0) * _BlurSize;
			o.uv[2] = uv - float2(_MainTex_TexelSize.x * 1.0, 0.0) * _BlurSize;
			o.uv[3] = uv + float2(_MainTex_TexelSize.x * 2.0, 0.0) * _BlurSize;
			o.uv[4] = uv - float2(_MainTex_TexelSize.x * 2.0, 0.0) * _BlurSize;

			return o;
		}

		fixed4 fragBlur(v2fBlur i) : SV_Target
		{
			float weight[3] = { 0.4026,0.2442,0.0545 };
			fixed3 sum = tex2D(_MainTex, i.uv[0]).rgb * weight[0];

			for (int it = 1; it < 3; it++)
			{
				sum += tex2D(_MainTex, i.uv[it * 2 - 1]).rgb * weight[it];
				sum += tex2D(_MainTex, i.uv[2 * it]).rgb * weight[it];
			}

			return fixed4(sum, 1.0);
		}


		struct v2f
		{
			float4 vertex : SV_POSITION;
			half2 uv : TEXCOORD0;
		};


		v2f vertDepthOfField(appdata_img v)
		{
			v2f o;
			o.vertex = UnityObjectToClipPos(v.vertex);
			o.uv = v.texcoord;

			return o;
		}


		fixed4 fragDepthOfField(v2f i) : SV_Target
		{
			float linearDepth = Linear01Depth(SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture,i.uv));
			
			float distance = 0; 

			if (linearDepth < _FocusStart)
			{
				distance = abs(linearDepth - _FocusStart);
			}
			else if (linearDepth > _FocusEnd)
			{
				distance = abs(linearDepth - _FocusEnd);
			}			

			half4 color = tex2D(_MainTex,i.uv);
			half4 blurColor = tex2D(_BlurMainTex, i.uv);

			color = lerp(color, blurColor, distance);

			return fixed4(color.rgb,1);
		}

		ENDCG

		Pass
		{  
			CGPROGRAM  
			#pragma vertex vertBlurVertical 
			#pragma fragment fragBlur	
			ENDCG  
		}

		Pass
		{  
			CGPROGRAM  
			#pragma vertex vertBlurHorizontal 
			#pragma fragment fragBlur	
			ENDCG  
		}

		Pass
		{
			CGPROGRAM
			#pragma vertex vertDepthOfField
			#pragma fragment fragDepthOfField
			ENDCG
		}
		
	}
	FallBack Off
}

挂在Camera上的C#脚本

using UnityEngine;

[ExecuteInEditMode]
public class DepthOfField : PostEffectsBase
{
    public Shader shader;
    private Material _material = null;
    public Material Material
    {
        get
        {
            if(_material == null)
                _material = CheckShaderAndMaterial(shader,_material);
            return _material;
        }
    }

    private Camera _camera;
    public Camera Camera
    {
        get
        {
            if (_camera == null)
                _camera = GetComponent<Camera>();
            return _camera;
        }
    }

    private void OnEnable()
    {
        Camera.depthTextureMode |= DepthTextureMode.Depth;
    }

    [Range(1f, 4.0f)]
    public int blurSpread = 2;

    [Range(0.01f, 1.0f)]
    public float focusStart = 0.1f;

    [Range(0.01f, 1.0f)]
    public float focusEnd = 0.2f;

    [Range(1, 4)]
    public int iterations = 2;
   
    private void OnRenderImage(RenderTexture source, RenderTexture destination)
    {        
        if (Material != null)
        {
            int rtW = source.width;
            int rtH = source.height;

			Material.SetFloat("_FocusStart", focusStart);
        	Material.SetFloat("_FocusEnd", focusEnd);

            RenderTexture buffer0 = RenderTexture.GetTemporary(rtW, rtH, 0);
            buffer0.filterMode = FilterMode.Bilinear;

            Graphics.Blit(source, buffer0);

            for (int i = 0; i < iterations; i++)
            {
                Material.SetFloat("_BlurSize", 1.0f + i * blurSpread);

                RenderTexture buffer1 = RenderTexture.GetTemporary(rtW, rtH, 0);
                Graphics.Blit(buffer0, buffer1, Material, 0);
                                                           
                RenderTexture.ReleaseTemporary(buffer0);
                buffer0 = buffer1;


                buffer1 = RenderTexture.GetTemporary(rtW, rtH, 0);
                Graphics.Blit(buffer0, buffer1, Material, 1);
                                                             
                RenderTexture.ReleaseTemporary(buffer0);
                buffer0 = buffer1;
            }

            Material.SetTexture("_BlurMainTex", buffer0);

            Graphics.Blit(source, destination,Material,2);

            RenderTexture.ReleaseTemporary(buffer0);
        }
        else
        {
            Debug.Log("没有shader,没法干活儿");
            Graphics.Blit(source, destination);
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值