【TA-霜狼_may-《百人计划》】图形4.5 DoF景深基础

4.5.1 景深

在这里插入图片描述
照片中有清晰的部分,有模糊的部分。
景深:Depth of field, DOF,景深是指相机对焦点前后相对清晰的成像范围。景深是针对相机成像出现的概念。
在这里插入图片描述

离散圈

在这里插入图片描述

4.5.2 景深的作用

景深是拍摄图像中的一个重要特征,可以选择性的强调画面中的一个部分,景深也是用来强调所拍摄画面的深度,增加层次感,还能够营造各种氛围,表达镜头语言。

4.5.3 移动端景深效果实现

在这里插入图片描述
在这里插入图片描述

景深的实现时间点

在这里插入图片描述
所以景深效果在后处理阶段进行

景深的制作思路

模拟景深制作mask =》 模糊景深 =》 正常景深 =》 合并。
在这里插入图片描述

景深mask制作

  1. 在camera上打开深度图在这里插入图片描述
  2. shader中获得景深值在这里插入图片描述
    归一化之后乘以摄像机远平面距离得到的景深图:
    在这里插入图片描述
  3. 计算近郊距离和远焦距离 (焦距±景深值)
    在这里插入图片描述
  4. 将当前深度值与景深值作比较,使得景深范围外的深度值朝着远离景深范围的方向增大。 在这里插入图片描述
    在这里插入图片描述
  5. 效果优化,添加一个平滑度效果
    在这里插入图片描述
  6. 生成模糊图(利用高斯模糊)思路就是取单个像素周围横竖包括自己的10个像素点进行取值再加权平均。
    在这里插入图片描述
    效果:
    在这里插入图片描述
    初次模糊得到的模糊结果不太理想,需要利用降采样再上采样的方法完善效果(在csharp中)

4.5.4 高级景深效果思路拓展

  • 简单的模糊会导致色彩溢出,颜色泄露:
    在这里插入图片描述
    利用扩散滤波,在景深部分使用更小的滤波核得到防止颜色溢出。

  • 模糊不连续缺陷
    在这里插入图片描述
    做前景和背景的单独区分,分别模糊,最后进行融合。

  • 散景的模拟(在高光区域最为显著)
    在这里插入图片描述

作业

DOF效果:

请添加图片描述
图片大小限制,还可以调整景深范围在这里没有展示出来。

代码部分

关键部分已经给出注释,较好理解。
shader代码:

Shader "Custom/Dof" {
	Properties {
		_MainTex ("Texture", 2D) = "white" { }
		_BlurOffset ("Blur Offset", vector) = (0, 0, 0, 0)
		_FocusRange ("Range Of Focus", float) = 10
		_FocusDistance ("Fcous Distance", range(0, 30)) = 10
		_DofSmoothRange ("Smooth Range", range(0, 1)) = 0.5
		_Step ("Step", range(0, 1)) = 0.5
	}


	SubShader {
		// Pass 0 对画面进行模糊处理
		Pass {
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag

			#include "UnityCG.cginc"

			sampler2D _MainTex;
			float4 _BlurOffset;

			struct v2f {
				float4 vertex : SV_POSITION;
				float2 uv : TEXCOORD0;
			};

			v2f vert(appdata_img v) {
				v2f o;
				o.vertex = UnityObjectToClipPos(v.vertex);
				o.uv = v.texcoord;
				return o;
			}

			half4 frag(v2f i) : SV_Target {
				// 高斯模糊
				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(s.rgb, 1);
			}

			ENDCG
		}

		// Pass 1 根据焦距进行模糊融合
		Pass {
			Cull Off
			ZTest Always
			ZWrite Off

			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag

			#include "UnityCG.cginc"

			sampler2D _CameraDepthTexture;
			sampler2D _MainTex;
			float4 _MainTex_TS;
			sampler2D _DoFTex;

			float _FocusDistance;
			float _FocusRange;
			float _DofSmoothRange;

			float _Step;

			struct v2f {
				float4 vertex : SV_POSITION;
				float2 uv : TEXCOORD0;
			};

			v2f vert(appdata_img v) {
				v2f o;
				o.vertex = UnityObjectToClipPos(v.vertex);
				o.uv = v.texcoord;
				return o;
			}

			fixed4 frag(v2f i) : SV_TARGET {
				// 原图
				fixed4 mainTex = tex2D(_MainTex, i.uv);
				// 模糊图
				fixed4 doFTex = tex2D(_DoFTex, i.uv);
				
				// 避免远裁面的值对景深效果的影响
				fixed depth = Linear01Depth(tex2D(_CameraDepthTexture, i.uv)).r * _ProjectionParams.z * _Step;

				// 近焦距离 和 远焦距离
				float focusNear = _FocusDistance - _FocusRange;
				float focusFar = _FocusDistance + _FocusRange;

				// 根据焦距重新进行赋值
				fixed final_depth = 0;
				if (depth < focusNear) {
					final_depth = saturate(abs(focusNear - depth) * _DofSmoothRange);
				} else if (depth > focusFar) {
					final_depth = saturate(abs(depth - focusFar) * _DofSmoothRange);
				}

				fixed4 finalColor = lerp(mainTex, doFTex, final_depth * 1.2);

				//return doFTex;
				return fixed4(finalColor.rgb, 1);
			}
			ENDCG
		}
	}
}

两个脚本,一个开启深度图,一个用于处理
深度图c#

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

public class DepthTexture : MonoBehaviour
{

    private Camera currentCamera = null;

    private void Awake()
    {
        currentCamera = GetComponent<Camera>();
    }

    private void OnEnable()
    {
        currentCamera.depthTextureMode |= DepthTextureMode.Depth;
    }

    private void OnDisable()
    {
        currentCamera.depthTextureMode &= ~DepthTextureMode.Depth;
    }
}

渲染脚本

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

public class DoFScript : MonoBehaviour
{

    public Material mat;

    // 迭代次数
    [Range(1, 4)]
    public int _Iteration = 2;

    // 模糊半径
    [Range(0, 15)]
    public float _BlurRadius = 5;

    // 下采样次数
    [Range(0, 10)]
    public float _DownSample = 2;

    // 景深范围
    [Range(0, 10)]
    public float _FocusRange = 1.0f;

    // 焦距
    [Range(0, 30)]
    public float _FocusDistance = 10.0f;



    // Start is called before the first frame update
    void Start()
    {
        // 判断材质和shader是否为空,是否被支持,来决定是否启用
        if (mat == null || SystemInfo.supportsImageEffects == false || mat.shader == null || mat.shader.isSupported == false)
        {
            enabled = false;
            return;
        }
    }

    private void OnRenderImage(RenderTexture source, RenderTexture destination)
    {
        mat.SetFloat("_FocusRange", _FocusRange);
        mat.SetFloat("_FocusDistance", _FocusDistance);

        int width = (int)(source.width / _DownSample);
        int height = (int)(source.height / _DownSample);

        mat.SetVector("_BlurOffset", new Vector4(_BlurRadius / width, _BlurRadius / height, 0, 0));

        RenderTexture RT1 = RenderTexture.GetTemporary(width, height);
        RenderTexture RT2 = RenderTexture.GetTemporary(width, height);

        Graphics.Blit(source, RT1, mat, 0);

        // 下采样
        for (int i = 0; i < _Iteration; i++)
        {
            RenderTexture.ReleaseTemporary(RT2);

            width /= 2;
            height /= 2;

            RT2 = RenderTexture.GetTemporary(width, height);
            Graphics.Blit(RT1, RT2, mat, 0);

            width /= 2;
            height /= 2;
            RenderTexture.ReleaseTemporary(RT1);
            RT1 = RenderTexture.GetTemporary(width, height);
            Graphics.Blit(RT2, RT1, mat, 0);
        }

        // 上采样
        for (int i = 0; i < _Iteration; i++)
        {
            RenderTexture.ReleaseTemporary(RT2);

            width *= 2;
            height *= 2;

            RT2 = RenderTexture.GetTemporary(width, height);
            Graphics.Blit(RT1, RT2, mat, 0);

            width *= 2;
            height *= 2;
            RenderTexture.ReleaseTemporary(RT1);
            RT1 = RenderTexture.GetTemporary(width, height);
            Graphics.Blit(RT2, RT1, mat, 0);
        }

        // 调用第二个pass进行混合
        mat.SetTexture("_DoFTex", RT1);
        Graphics.Blit(source, destination, mat, 1);

        // 释放缓存
        RenderTexture.ReleaseTemporary(RT1);
        RenderTexture.ReleaseTemporary(RT2);
    }
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zczplus

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值