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
    #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
}

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)]
    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

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