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 #pragma fragment frag / / vertex shader and source shader declaration #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 #pragma fragment frag / / vertex shader and source shader declaration #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 }
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)] public float _BlurRadius = 5; // Fuzzy radius [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----------------------------// mat.SetVector("_BlurOffset", new Vector4(_BlurRadius / width, _BlurRadius / height, 0, 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
task
1. Achieve depth of field effect
Gaussian blur
After bilateral filtering based on normal, the color leakage is improved, and the blurred color feels normal
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 }