实现效果
景深效果
实现思路
由两张图组成,分别是远处的模糊状态和近处的清晰状态,根据物体的深度判断物体离摄像机的距离确定物体的状态。两个图进行插值,越近越靠近清晰的图像。
代码
脚本代码:
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 update
private void OnEnable()
{
camera.depthTextureMode |= DepthTextureMode.Depth;
}
void Start()
{
}
// Update is called once per frame
void 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_TOP
if(_MainTex_TexelSize.y<0.0){
o.uv.y=1.0-o.uv.y;
}
#endif
return 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);
}
ENDCG
Tags{"RenderType"="Opaque"}
ZTest Always Cull Off ZWrite Off
//模糊处理
UsePass "Custom/Chapter12-GaussianBlur/GAUSSIAN_BLUR_VERTICAL"
UsePass "Custom/Chapter12-GaussianBlur/GAUSSIAN_BLUR_HORIZONTAL"
//混合图像pass
Pass{
CGPROGRAM
#pragma vertex vertBlur
#pragma fragment fragBlur
ENDCG
}
}
FallBack "Diffuse"
}