# Technical art knowledge learning 4500: depth of field

Learning tutorials from: [technical art hundred talents plan] graphics 4.5 Dof depth of field Foundation

# note

## 1. What is depth of field

The relatively clear imaging range before and after the focus of the camera

## 2. Function of depth of field

Prominent expression

## 3. Realization of depth of field effect at mobile terminal

### 3.1 production ideas

In the post-processing stage, make a mask, render the fuzzy scene and the normal scene respectively, and then merge the effects

### 3.2 fuzzy processing of original drawing

Blur the texture in MainTex in OnrenderImage, pass the value to BlurTex, and then mix

```Pass{
CGPROGRAM

#pragma vertex vert

#include "UnityCG.cginc"

struct appdata{                                                             // Vertex shader input structure, position and UV
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};

struct v2f{                                                                 // Vertex shaders output structures, positions, and UV s
float4 vertex : SV_POSITION;
float2 uv : TEXCOORD0;
};

sampler2D _MainTex;
float4 _BlurOffset;                                                         // Fuzzy offset

v2f vert (appdata v){
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);                              // Object space to crop space
o.uv = v.uv;
return o;
}

half4 frag (v2f i) : SV_Target{

//-----------------------------------Gaussian blur processing-------------------------------------//
half2 uv1 = i.uv + _BlurOffset.xy * half2(1,0) * -2;
half2 uv2 = i.uv + _BlurOffset.xy * half2(1,0) * -1;
half2 uv3 = i.uv;
half2 uv4 = i.uv + _BlurOffset.xy * half2(1,0) * 1;
half2 uv5 = i.uv + _BlurOffset.xy * half2(1,0) * 2;

half2 uv6 = i.uv + _BlurOffset.xy * half2(0,1) * -2;
half2 uv7 = i.uv + _BlurOffset.xy * half2(0,1) * -1;
half2 uv8 = i.uv;
half2 uv9 = i.uv + _BlurOffset.xy * half2(0,1) * 1;
half2 uv10 = i.uv + _BlurOffset.xy * half2(0,1) * 2;

half4 s = 0;
s += tex2D(_MainTex, uv1) * 0.05;
s += tex2D(_MainTex, uv2) * 0.25;
s += tex2D(_MainTex, uv3) * 0.40;
s += tex2D(_MainTex, uv4) * 0.25;
s += tex2D(_MainTex, uv5) * 0.05;

s += tex2D(_MainTex, uv6) * 0.05;
s += tex2D(_MainTex, uv7) * 0.25;
s += tex2D(_MainTex, uv8) * 0.40;
s += tex2D(_MainTex, uv9) * 0.25;
s += tex2D(_MainTex, uv10) * 0.05;

s /= 2;

//return half4(final_depth.xxx, 1);
return half4(s.rgb, 1);                                                 // Effect comparison of Gaussian blur
//return half4(1,1,1, 1);                                                 //  Effect comparison of Gaussian blur
}

ENDCG
}
```

### 3.3 obtaining depth of field Mask

Obtain the depth Texture, compare the set focus and calculate the depth of field range. Those within the range are not blurred, and the value is 0. The gradient outside the range is normalized to 0-1 and multiplied by smooth to make it smoother

```Pass{
CGPROGRAM
#pragma vertex vert

#include "UnityCG.cginc"

struct appdata{                                                             // Vertex shader input structure, position and UV
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};

struct v2f{                                                                 // Vertex shaders output structures, positions, and UV s
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};

sampler2D _MainTex;
sampler2D _BlurTex;                                                         // Blurred texture
sampler2D _CameraDepthTexture;                                              // Camera depth texture
float4 _BlurOffset;                                                         // Fuzzy range offset
float _FocusDistance, _DepthOfField, _DofSmoothRange;                       // Focus distance, depth of field, smooth transition
float _Step;

v2f vert (appdata v){
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);                              // Object space to crop space
o.uv = v.uv;
return o;
}

half4 frag (v2f i) : SV_Target{
half4 col = tex2D(_MainTex, i.uv);                                      // Original color
half4 blur_col = tex2D(_BlurTex, i.uv);                                 // Blurred color

// half depth = Linear01Depth(tex2D(_CameraDepthTexture, i.uv));        //  Avoid the influence of the value of the far cut surface on the depth of field effect
half depth = Linear01Depth(tex2D(_CameraDepthTexture, i.uv)).r * _ProjectionParams.z * _Step;//Avoid the influence of the value of the far cut surface on the depth of field effect
float focusNear = _FocusDistance - _DepthOfField;                       // Near focal point
float focusFar = _FocusDistance + _DepthOfField;                        // Far focal point

half final_depth = 0;
if((depth>=focusNear)&&(depth<=focusFar));                              // Points within the depth of field are not blurred
else {
if(depth<focusNear){                                                // Points outside the depth of field are all assigned to 0-1
final_depth = saturate(abs(focusNear-depth) * _DofSmoothRange); // Add smooth to make the transition smoother
}else{
final_depth = saturate(abs(focusFar-depth) * _DofSmoothRange);

}
}

half4 final_col = lerp(col, blur_col, final_depth*1.2);                 // Mix with Mask
//return half4(final_depth,final_depth,final_depth, 1);
return half4(final_col.rgb, 1);
//return half4(depth.xxx, 1);
// return half4(col.rgb, 1);

}

ENDCG
}
```

The white area is the blurred area (out of focus area)

## 3.4 script part

```using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class DOF : MonoBehaviour
{
public Material mat;
// Start is called before the first frame update
[Range(1, 4)]
public int _Iteration = 2;                                              // Number of iterations
[Range(0, 15)]
[Range(0, 10)]
public float _DownSample = 2;                                           // Down sampling times
[Range(0, 10)]
public float _DepthOfField = 1.0f;                                      // Depth of field range
public float _FocusDistance = 1;                                        // focal length

void Start()
{
if (mat == null || SystemInfo.supportsImageEffects == false || mat.shader == null || mat.shader.isSupported == false){
enabled = false;                                                // Judge whether the material and shader are empty and supported to determine whether they are enabled
return ;
}
}

void OnRenderImage(RenderTexture src, RenderTexture dest)
{
{
mat.SetFloat("_DepthOfField", _DepthOfField);
mat.SetFloat("_FocusDistance", _FocusDistance);
int width = (int)(src.width / _DownSample);                     // Down sampling reduces the amount of calculation
int height = (int)(src.height / _DownSample);
//-----------------------------Gaussian blur Pass 0----------------------------//

RenderTexture RT1 = RenderTexture.GetTemporary(width, height);
RenderTexture RT2 = RenderTexture.GetTemporary(width, height);  // Create 2 RT alternates
Graphics.Blit(src, RT1, mat, 0);
//Graphics.Blit(src, dest, mat, 1);
for (int i = 0; i < _Iteration; i++)                            // Each iteration reduces size and downsampling
{
RenderTexture.ReleaseTemporary(RT2);
width = width / 2;
height = height / 2;
RT2 = RenderTexture.GetTemporary(width, height);
Graphics.Blit(RT1, RT2, mat, 0);
width = width / 2;
height = height / 2;
RenderTexture.ReleaseTemporary(RT1);
RT1 = RenderTexture.GetTemporary(width, height);
Graphics.Blit(RT2, RT1, mat, 0);

}
for (int i = 0; i < _Iteration; i++)                            // Each iteration enlarges the size and samples in liters
{
RenderTexture.ReleaseTemporary(RT2);
width = width * 2;
height = height * 2;
RT2 = RenderTexture.GetTemporary(width, height);
Graphics.Blit(RT1, RT2, mat, 0);
width = width * 2;
height = height * 2;
RenderTexture.ReleaseTemporary(RT1);
RT1 = RenderTexture.GetTemporary(width, height);
Graphics.Blit(RT2, RT1, mat, 0);
}

//-------------------------------Mixed Pass 1------------------------------//
mat.SetTexture("_BlurTex", RT1);

Graphics.Blit(src, dest, mat, 1);                               // Use the shader's second Pass to mix the original and blur

RenderTexture.ReleaseTemporary(RT1);
RenderTexture.ReleaseTemporary(RT2);                            // release
}
}
}

```

## 4. Thinking expansion of advanced depth of field effect

### 4.1 color leakage

The color of the focus area is blurred into the background
Solution: diffusion filtering, specify the fuzzy range

### 4.2 fuzzy discontinuity

Fuzzy discontinuity in foreground area
Solution: calculate the foreground separately and make a Mask to fuse the background

### 4.3 scatter simulation (Bokeh)

In order to simulate the effect of different light sources in depth of field
Solution: modify the filtering formula

## 1. Achieve depth of field effect

Gaussian blur

The effect of the above code

After bilateral filtering based on normal, the color leakage is improved, and the blurred color feels normal

A potential bug is that the code in the tutorial video does not release RT1 in time, resulting in the video memory running full. Release it before application

## 2. Analyze the implementation of depth of field effect in official post-processing plug-in PPS

After a brief look at the code, it is relatively shallow. It may not be understood correctly. There is probably the following process

```enum Pass
{
CoCCalculation,             // By depth, focus distance_ LensCoeff calculates the value of CoC, feeling and final for upper edge interpolation_ Depth similar
CoCTemporalFilter,          // If TAA is enabled, filter the CoC value in the Texture
DownsampleAndPrefilter,     // Down sampling
BokehSmallKernel,           // 5 blur methods to calculate dof texture (color of out of focus blur)
BokehMediumKernel,
BokehLargeKernel,
BokehVeryLargeKernel,
PostFilter,
Combine,                    // Combine the color of the original image with the blurred color
DebugOverlay
}
```

Keywords: Unity

Added by klaibert26 on Fri, 12 Nov 2021 12:55:15 +0200