实现效果
景深效果
实现思路
由两张图组成,分别是远处的模糊状态和近处的清晰状态,根据物体的深度判断物体离摄像机的距离确定物体的状态。两个图进行插值,越近越靠近清晰的图像。
代码
脚本代码:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class DepthOfField : PostEffectsBase
{public Shader bloomShader;private Material bloomMaterial = null;public Material material{get{bloomMaterial = CheckShaderAndCreateMaterial(bloomShader, bloomMaterial);return bloomMaterial;}}//迭代次数[Range(0, 4)]public int iterations = 3;//模糊范围[Range(0.2f, 3.0f)]public float blurSpread = 0.6f;//缩放系数[Range(1, 8)]public int downSample = 2;[Range(0.0f, 50f)]//近处与远处的分割线的距离public float Threshold = 10f;[Range(0.0f, 1.0f)]//近处的模糊系数public float NearBlurSize = 0.0f;//远处的模糊系数[Range(0.0f, 1.0f)]public float FarBlurSize = 1.0f;private Camera myCamera;public Camera camera{get{if (myCamera == null){myCamera = GetComponent<Camera>();}return myCamera;}}private Transform myCameraTransform;public Transform cameraTransform{get{if (myCameraTransform == null){myCameraTransform = camera.transform;}return myCameraTransform;}}// Start is called before the first frame updateprivate void OnEnable(){camera.depthTextureMode |= DepthTextureMode.Depth;}void Start(){}// Update is called once per framevoid Update(){}public void OnRenderImage(RenderTexture source, RenderTexture destination){if (material != null){//传参material.SetFloat("_Threshold", Threshold);material.SetFloat("_NearBlurSize", NearBlurSize);material.SetFloat("_FarBlurSize", FarBlurSize);int rtW = source.width / downSample;int rtH = source.height / downSample;RenderTexture buffer0 = RenderTexture.GetTemporary(rtW, rtH, 0);buffer0.filterMode = FilterMode.Bilinear;//传递清晰的图像buffer0 = source;for (int i = 0; i < 3; 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, 1);Graphics.Blit(buffer0, buffer1, material, 1);RenderTexture.ReleaseTemporary(buffer0);buffer0 = buffer1;}//将提取出来的图像模糊处理后存储到纹理中material.SetTexture("_Blur", buffer0);//利用第四个pass将模糊的图像和原图合并起来Graphics.Blit(source, destination, material,2);RenderTexture.ReleaseTemporary(buffer0);}else{Graphics.Blit(source, destination);}}
}
shader
// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'Shader "Custom/depthoffield"
{Properties{_MainTex ("Base (RGB)", 2D) = "white" {}}SubShader{CGINCLUDE#include "unityCG.cginc"sampler2D _MainTex;half4 _MainTex_TexelSize;sampler2D _Blur;float _Threshold;sampler2D _CameraDepthTexture;float _NearBlurSize;float _FarBlurSize;//混合图像的片段着色器的结构图struct v2fblur{float4 pos:SV_POSITION;//清晰和模糊的纹理坐标一致half2 uv:TEXCOORD0;//深度纹理坐标half2 uv_depth:TEXCOORD1;};//顶点着色器v2fblur vertBlur(appdata_img v){v2fblur o;o.pos =UnityObjectToClipPos(v.vertex);o.uv =v.texcoord;o.uv_depth =v.texcoord;//平台差异化处理#if UNITY_UV_STARTS_AT_TOPif(_MainTex_TexelSize.y<0.0){o.uv.y=1.0-o.uv.y;}#endifreturn o;}//片段着色器fixed4 fragBlur(v2fblur i):SV_Target{//清晰图像fixed4 maincolor = tex2D(_MainTex,i.uv);//模糊图像fixed4 blurcolor =tex2D(_Blur,i.uv);//深度值float linearDepth =LinearEyeDepth(SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture,i.uv_depth));//与临界值的插值float dis = (linearDepth-_Threshold);if(dis<=0){dis*=_NearBlurSize;}else{dis*=_FarBlurSize;}//限定在[0,1]dis = clamp(abs(dis),0,1);//插值颜色,近处的模糊系数小,远处大return lerp(maincolor,blurcolor,dis);}ENDCGTags{"RenderType"="Opaque"}ZTest Always Cull Off ZWrite Off//模糊处理UsePass "Custom/Chapter12-GaussianBlur/GAUSSIAN_BLUR_VERTICAL"UsePass "Custom/Chapter12-GaussianBlur/GAUSSIAN_BLUR_HORIZONTAL"//混合图像passPass{CGPROGRAM#pragma vertex vertBlur#pragma fragment fragBlurENDCG}}FallBack "Diffuse"
}