技术美术知识学习4500:景深

news/2024/12/29 10:32:58/

学习教程来自:【技术美术百人计划】图形 4.5 Dof景深基础

笔记

1. 什么是景深

相机对焦点前后相对清晰的成像范围

2. 景深的作用

突出表达

3. 移动端景深效果实现

3.1 制作思路

在后处理阶段,制作mask,分别渲染模糊场景和正常场景,再合并效果

3.2 原图模糊处理

在OnrenderImage对MainTex中的纹理模糊,传值给BlurTex,再进行混合

Pass{CGPROGRAM#pragma vertex vert#pragma fragment frag                                                       // 顶点着色器和片源着色器声明#include "UnityCG.cginc"struct appdata{                                                             // 顶点着色器输入结构体,位置和UVfloat4 vertex : POSITION;float2 uv : TEXCOORD0;};struct v2f{                                                                 // 顶点着色器输出结构体,位置和UVfloat4 vertex : SV_POSITION;float2 uv : TEXCOORD0;};sampler2D _MainTex;float4 _BlurOffset;                                                         // 模糊偏移v2f vert (appdata v){v2f o;o.vertex = UnityObjectToClipPos(v.vertex);                              // 对象空间转换到裁剪空间o.uv = v.uv;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(final_depth.xxx, 1);return half4(s.rgb, 1);                                                 // 高斯模糊的效果对比//return half4(1,1,1, 1);                                                 // 高斯模糊的效果对比}                      ENDCG
}

3.3 获得景深Mask

获取深度Texture,对比设置的焦点并计算景深范围,范围内的不做模糊处理,值为0,范围外的渐变的规整到0-1并乘以smooth使其更平滑

Pass{CGPROGRAM#pragma vertex vert#pragma fragment frag                                                       // 顶点着色器和片源着色器声明#include "UnityCG.cginc"struct appdata{                                                             // 顶点着色器输入结构体,位置和UVfloat4 vertex : POSITION;float2 uv : TEXCOORD0;};struct v2f{                                                                 // 顶点着色器输出结构体,位置和UVfloat2 uv : TEXCOORD0;float4 vertex : SV_POSITION;};sampler2D _MainTex;sampler2D _BlurTex;                                                         // 模糊后的纹理sampler2D _CameraDepthTexture;                                              // 相机深度纹理float4 _BlurOffset;                                                         // 模糊范围偏移float _FocusDistance, _DepthOfField, _DofSmoothRange;                       // 焦点距离,景深,光滑过度  float _Step;               v2f vert (appdata v){v2f o;o.vertex = UnityObjectToClipPos(v.vertex);                              // 对象空间转换到裁剪空间o.uv = v.uv;return o;}       half4 frag (v2f i) : SV_Target{half4 col = tex2D(_MainTex, i.uv);                                      // 原图颜色half4 blur_col = tex2D(_BlurTex, i.uv);                                 // 模糊后的颜色// half depth = Linear01Depth(tex2D(_CameraDepthTexture, i.uv));        // 避免远裁面的值对景深效果的影响half depth = Linear01Depth(tex2D(_CameraDepthTexture, i.uv)).r * _ProjectionParams.z * _Step;//避免远裁面的值对景深效果的影响float focusNear = _FocusDistance - _DepthOfField;                       // 近焦距点float focusFar = _FocusDistance + _DepthOfField;                        // 远焦距点half final_depth = 0;if((depth>=focusNear)&&(depth<=focusFar));                              // 在景深范围内的点不做模糊else {if(depth<focusNear){                                                // 在景深范围之外的点,全部归到0-1final_depth = saturate(abs(focusNear-depth) * _DofSmoothRange); // 加入smooth使过度更平滑}else{final_depth = saturate(abs(focusFar-depth) * _DofSmoothRange);}}half4 final_col = lerp(col, blur_col, final_depth*1.2);                 // 使用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 脚本部分

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;                                              // 迭代次数[Range(0, 15)]public float _BlurRadius = 5;                                           // 模糊半径[Range(0, 10)]public float _DownSample = 2;                                           // 下采样次数[Range(0, 10)]public float _DepthOfField = 1.0f;                                      // 景深范围public float _FocusDistance = 1;                                        // 焦距void Start(){if (mat == null || SystemInfo.supportsImageEffects == false || mat.shader == null || mat.shader.isSupported == false){enabled = false;                                                // 判断材质和shader是否为空,是否被支持,来决定是否启用return ;}}void OnRenderImage(RenderTexture src, RenderTexture dest){{mat.SetFloat("_DepthOfField", _DepthOfField);mat.SetFloat("_FocusDistance", _FocusDistance);int width = (int)(src.width / _DownSample);                     // 下采样减少计算量int height = (int)(src.height / _DownSample);                   
//----------------------------- 高斯模糊 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);  // 创建2张RT交替处理Graphics.Blit(src, RT1, mat, 0);//Graphics.Blit(src, dest, mat, 1);for (int i = 0; i < _Iteration; i++)                            // 每次迭代减少尺寸,降采样{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++)                            // 每次迭代放大尺寸,升采样{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);}//------------------------------- 混合 Pass 1 ------------------------------// mat.SetTexture("_BlurTex", RT1);Graphics.Blit(src, dest, mat, 1);                               // 使用shader的第二个Pass混合原图和模糊RenderTexture.ReleaseTemporary(RT1);RenderTexture.ReleaseTemporary(RT2);                            // 释放}}
}

4. 高级景深效果思路扩展

4.1 颜色泄露

对焦区域的颜色被模糊到了背景中
解决:扩散滤波,规定模糊的范围

4.2 模糊不连续

前景区域的模糊不连续
解决:前景单独计算,制作一个Mask去融合背景

4.3 散景模拟(Bokeh)

为了模拟不同光源在景深下的效果
解决:修改滤波的公式

作业

1. 实现景深效果

高斯模糊下

上边代码实现的效果

换成基于法线的双边滤波后,颜色泄露的情况有所改善,模糊的颜色也感觉正常了



一个潜在的bug,教程视频中的代码没有及时释放RT1,导致显存跑满,改为申请前释放即可

2. 分析官方后处理插件PPS中景深效果的实现

简单看了下代码,看的比较浅,不一定理解的对,大概有以下过程

enum Pass
{CoCCalculation,             // 由深度、焦点距离、_LensCoeff计算CoC的值,感觉和上边插值用的final_depth类似CoCTemporalFilter,          // 开启TAA的话将Texture中CoC的值进行滤波DownsampleAndPrefilter,     // 下采样BokehSmallKernel,           // 5种模糊方式计算dof纹理(焦外模糊的颜色)BokehMediumKernel,BokehLargeKernel,BokehVeryLargeKernel,PostFilter,Combine,                    // 将原图的颜色和模糊后的颜色结合DebugOverlay 
}

http://www.ppmy.cn/news/945523.html

相关文章

景深决定照相机什么特性_相机的景深是什么

相机的景深是什么 所谓景深&#xff0c;就是当焦距对准某一点时&#xff0c;其前后都仍可清晰的范围。它能决定是把背景模糊化来突出拍摄对象&#xff0c;还是拍出清晰的背景。我们经常能够看到拍摄花、昆虫等的照片中&#xff0c;将背景拍得很模糊(称之为小景深)。但是在拍摄纪…

【Unity3D】资源文件 ② ( Unity 中场景文件简介 | 查看场景文件内容 | 场景文件相关操作 | 创建场景 | 打开场景 )

文章目录 一、Unity 中场景文件简介二、查看场景文件内容三、场景文件相关操作1、添加场景2、打开场景 一、Unity 中场景文件简介 Unity 编辑器中的 场景文件 是以 " .unity " 为后缀的文件 , 该文件中会记录所有 游戏物体 GameObject , 以及游戏物体的相关数据 , 如…

unity shader景深效果

实现效果 景深效果 实现思路 由两张图组成&#xff0c;分别是远处的模糊状态和近处的清晰状态&#xff0c;根据物体的深度判断物体离摄像机的距离确定物体的状态。两个图进行插值&#xff0c;越近越靠近清晰的图像。 代码 脚本代码&#xff1a; using System.Collections; …

RabbitMQ的应用场景

1.异步处理 消息队列的主要特点是异步处理&#xff0c;主要目的是减少请求响应时间&#xff0c;实现非核心流程异步化&#xff0c;提高系统响应性能。 所以典型的使用场景就是将比较耗时而且不需要即时&#xff08;同步&#xff09;返回结果的操作&#xff0c;作为消息放入消息…

Unity 景深Depth Of Field

目录 介绍 准备 设置 基于Unity Builtin 管线 基于Unity URP 基于Unity HDRP 介绍&#xff1a; 景深效果Depth Of Field是摄影界的老常客了&#xff0c;在游戏中也非常多见&#xff0c;它能够大幅提升游戏画面体验和真实度&#xff0c;使得物体看起来更有细节。 GTA5中的…

第一讲 构图和景别

文章目录 构图中心点构图水平线构图法对称线构图三分线构图法对角线构图引导线构图法前景构图填充构图留白构图重复构图对比构图 景别参考文献 构图 中心点构图 中心构图是将主体放置在画面中心进行构图。这种构图方式的最大优点就在于主体突出、明确&#xff0c;而且画面容易…

Unity景深效果

Unity景深效果 window packagemanager postprocessing installproject面板右键创建post-processing profile主相机设置layer 比如layerA主相机添加组件 post-process layer 里面设置layer为layerA 主相机添加 post-process volume2创建的文件拖到volume上的 profilevolume 勾选…

用Unity实现景深效果

用Unity实现景深效果 景深也是一种非常常见的后处理手段&#xff0c;它用来模拟相机拍摄画面的效果。今天我们讨论如何在Unity中实现它。 简单来说&#xff0c;景深效果可以拆分为两个部分&#xff0c;一个部分是聚焦&#xff0c;使画面中指定的区域清晰显示&#xff0c;另一个…