Unity Shader PostProcessing - 7 - DepthOfField(DOF)景深
文章目录
- 基本概念
- 实现
- 列举需要的参数
- 在Scene视图下显示Gizmos
- 在Shader中标出有效景深深度
- 添加高斯模糊处理
- 将提取的景深与高斯模糊图混合
- 再次将平滑过的景深与模糊的图片进行融合
- 总结
- Project
基本概念
在百度百科里有解析:景深。
引用其简短描述的一段话:
景深(DOF),是指在摄影机镜头或其他成像器前沿能够取得清晰图像的成像所测定的被摄物体前后距离范围。光圈、镜头、及焦平面到拍摄物的距离是影响景深的重要因素。
在聚焦完成后,焦点前后的范围内所呈现的清晰图像的距离,这一前一后的范围,便叫做景深。
在镜头前方(焦点的前、后)有一段一定长度的空间,当被摄物体位于这段空间内时,其在底片上的成像恰位于同一个弥散圆之间。被摄体所在的这段空间的长度,就叫景深。换言之,在这段空间内的被摄体,其呈现在底片面的影象模糊度,都在容许弥散圆的限定范围内,这段空间的长度就是景深。
可以看看里面介绍的视频,说得挺简洁的,我总结为下图:
影响景深的参数,我来说明一下:(上图DOV是我在作画时写错的,应该是DOF)
- F:是对焦点。
- C1和C2:是对焦点与瞳孔(或镜头)连接直线上,在焦点前后两个深蓝色的圆圈,叫:弥散圆。如果弥散圆大小超出了瞳孔(或镜头)能识别的范围,图像就会模糊,就像对焦的内容与相机底片不能一一对准。
- 瞳孔(光圈):从上面的C1和C2的后半部分的描述,我们可以知道光圈的大小也会影响景深。大光圈(大瞳孔)可以营造出突出前景以及模糊背景的效果(生活中就是拍那些室内光线弱一些的场景),小光圈(小瞳孔)一般需要对图像焦距内容与背景能清晰融合,一般现实生活中拍摄户外用。瞳孔(镜头)也可以说是摄影中的:光圈,光圈就如同瞳孔,遇到弱光瞳孔会放大,接受更多的光子信息,遇到强光就瞳孔会缩小,减少接受光子,起到保护眼睛的作用,而保护眼睛的同时,这样就会对人眼影像内容的质量会有一个自动控制调节的功能:将过低,或是过高的光亮(颜色)信息自动提升或是降低亮度,看到这里,我终于知道HDR的由来了,光圈的自动放大与缩小,理解上就是HDR的处理,就是模拟类似人眼的瞳孔自动放大或是缩小的功能来提高在弱光与强光下的图像质量(提高弱光与强光的细节度,这样就相对不会太暗,或是太亮导致图像都看不清);
- DOF:就是景深(Depth Of Field)的意思,景深的意思就是,对焦点前后两个弥散圆之间的距离,叫景深。(你可以理解就是瞳孔(或镜头)能清晰呈像的距离)
OK,了解了基本概念后,我们就在Unity中,使用后处理来模拟。
实现
但是我们的镜头,并没有说明光圈(瞳孔)此类东西,所以我也不打算真的就实打实的去按上面的方式来实现。我也不需要什么弥散圆,我就用几个参数来模拟就好了,达到差不多的效果就好了。
列举需要的参数
我总结了一下,需要下面几个参数会比较好调整景深的效果:
- 景深对焦距离:类似概念途中的F
- 景深值:类似概念图中的DOF
代码中就是:
[Header("Pickup DOV")]
[Range(0.01f, 100f)]
public float focusDistance = 10; // 景深对焦距离
[Range(0.1f, 50f)]
public float depthOfField = 10f; // 景深值
在Scene视图下显示Gizmos
OK,就这么简单,两个参数。
然后在OnDrawGizmos()函数中,将景深参数绘制出来,方便调试用,不然调起来,会相当蛋疼。
代码如下:
private void OnDrawGizmos(){if (cam == null) cam = GetComponent<Camera>();// 绘制景深视锥范围Gizmos.color = Color.green;Matrix4x4 temp = Gizmos.matrix;Gizmos.matrix = Matrix4x4.TRS(transform.position, transform.rotation, Vector3.one);var n = focusDistance - depthOfField * 0.5f;var f = focusDistance + depthOfField * 0.5f;Gizmos.DrawFrustum(Vector3.zero, cam.fieldOfView, f, n, cam.aspect);Gizmos.matrix = temp;// 绘制对焦点的圆Gizmos.color = Color.red;Gizmos.DrawWireSphere(transform.position + transform.forward * focusDistance, focuseSphereSize);// 绘制对焦点与镜头距离:焦距Gizmos.color = Color.cyan;Gizmos.DrawLine(transform.position, transform.position + transform.forward * focusDistance);}
另附送绘制:相机的 正交 cube
private void DrawCameraWireframe(){Gizmos.color = cam_frustum_color;Matrix4x4 temp = Gizmos.matrix;Gizmos.matrix = Matrix4x4.TRS(cam.transform.position, cam.transform.rotation, Vector3.one);if (!cam.orthographic){// 透视视锥Gizmos.DrawFrustum(Vector3.zero, cam.fieldOfView, cam.farClipPlane, cam.nearClipPlane, cam.aspect);}else{// 正交 cubevar far = cam.farClipPlane;var near = cam.nearClipPlane;var delta_fn = far - near;var half_height = cam.orthographicSize;var half_with = cam.aspect * half_height;var pos = Vector3.forward * (delta_fn * 0.5f + near);var size = new Vector3(half_with * 2, half_height * 2, delta_fn);Gizmos.DrawWireCube(pos, size);}Gizmos.matrix = temp;}
看看Scene视图下的Gizmos绘制:
在Shader中标出有效景深深度
如何获取深度,可以参考我之前写的一篇:Unity Shader - 获取BuiltIn深度纹理和自定义深度纹理的数据。
OK,下一步,我们在Shader中,将深度值,在景深范围内的都标红色输出,否则输出绿色,如下Shader:
fixed4frag_pickupDOV (v2f_pickupDOV i) : SV_Target {float depth = LinearEyeDepth(SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, i.uv));float halfOfDOV = _DepthOfField * 0.5;// 在景深内if ( (depth > (_FocusDistance - halfOfDOV)) && (depth < (_FocusDistance + halfOfDOV)) ) return fixed4(1, 0, 0, 1);// 不在景深距离else return fixed4(0, 1, 0, 1);
}
OK,再下一步就是,运行看看效果:
OK,提取景深深度值完成后,我们将将代码改回:
- 在景深内输出0,就是不模糊的地方
- 在景深外输出1,就是需要模糊的地方
fixed4 frag_pickupDOV (v2f_pickupDOV i) : SV_Target {float depth = Linear01Depth(SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, i.uv)) * _ProjectionParams.z;float halfOfDOV = _DepthOfField * 0.5;float focusNear = _FocusDistance - halfOfDOV;float focusFar = _FocusDistance + halfOfDOV;if ( (depth >= focusNear) && (depth <= focusFar) ) return 0; // 在景深内输出0,就是不模糊的地方else {return 1; // 在景深外输出1,就是需要模糊的地方}
}
运行看看效果
添加高斯模糊处理
有了景深深度提取后,我们添加高斯模糊来模拟景深的模糊效果。
相关文章:Unity Shader PostProcessing - 6 - GaussianBlur 高斯模糊+CommandBuffer使用做一些其他的特效。
将提取的景深与高斯模糊图混合
景深可以提取了,高斯模糊也有了,那么就可以开始混合处理了。
如下图:
但是混合效果不是很好,就是因为提取的景深太多硬的边界了。
我们再添加一个平滑范围值:
[Range(0f, 10f)]public float dofSmoothRange = 0.5f; // 景深平滑过渡范围
然后传入到Shader来平滑
fixed4 frag_pickupDOV (v2f_pickupDOV i) : SV_Target {float depth = Linear01Depth(SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, i.uv)) * _ProjectionParams.z;float halfOfDOV = _DepthOfField * 0.5;float focusNear = _FocusDistance - halfOfDOV;float focusFar = _FocusDistance + halfOfDOV;if ( (depth >= focusNear) && (depth <= focusFar) ) return 0; // 在景深内输出0,就是不模糊的地方else {if (depth < focusNear) // 在景深前return _DofSmoothRange == 0 ? 1 : saturate(abs(focusNear - depth) * _DofSmoothRange);if (depth > focusFar) // 在景深后return _DofSmoothRange == 0 ? 1 : saturate(abs(depth - focusFar) * _DofSmoothRange);return 1; // 在景深外输出1,就是需要模糊的地方}}
在输出一下提取的景深数值:
再次将平滑过的景深与模糊的图片进行融合
这次看起来好了。
再添加一个Timeline来控制景深参数:
- 对焦点
- 景深范围
- 平滑范围值
先看看提取的景深值的情况:
再看看正确效果:
最后给人物加上动画:
总结
总体来说,这个我自己总结的景深效果不太好,因为参数太难控制,以后等积累到一定程度,再回头看看unity内置的景深,然后再次重写。
还有,景深的效果真的非常耗性能,光模糊的采样就够多了,还有之前的提取景深呢,后面还有混合呢。。。手机端怕是要死翘翘。手机端如果要做景深,只能在特定视角下处理吧(就是DC,或是性能较高的情况下处理,或是用更加次的效果,只突出某部分就好,就是不模糊指定的部分,其他部分均值模糊一下就好了,我之前实现的一个,就可以Mask掉不需要模糊的:Unity Shader PostProcessing - 6 - GaussianBlur 高斯模糊+CommandBuffer使用做一些其他的特效,起始还有更简单的制作方式,那就是镜头剔除掉需要突出的内容,Camera.CullMask,然后渲染,再模糊,再另一个相机渲染原来不需要模糊的部分就可以了。)
Project
backup : UnityShader_DepthOfFieldTesting_2018.3.0f2
Unity Shader PostProcessing - 7 - DepthOfField(DOF)景深相关推荐
- Unity Shader PostProcessing - 8 - Bloom 泛光
文章目录 实现 提取亮度图 将提取的像素模糊 将模糊的像素与原图叠加 Project References 事情一大堆,要拿快递,又要寄快递,还要帮人板家具,还要去买菜,还要偶尔做饭,还要做包子,拖地 ...
- Unity Shader PostProcessing - 11 - Depth Fog/Height Fog - 雾效/深度雾效/高度雾/深度+高度雾
文章目录 观察生活中的雾 Scenario 1 - Pure Depth Fog - 纯深度雾 提取有用信息 Scenario 2 - Height Fog - 带高度的雾 提取有用信息 Scenar ...
- Unity Shader PostProcessing - 5 - PixelSyle 像素化风格
我的童年乐趣,基本上,都是花在:小霸王游戏机.红白机.街机里,很多那种像素化的游戏. 今天在研究别的东西时,看到一些像素化的游戏,有想起,之前想要试试这个后处理效果的.今天就试试吧. 先上个图,下图是 ...
- Unity Shader - Planar Shadow - 平面阴影
文章目录 整体运行效果 思路 Shader 问题 Z-Fighting,解决:按法线方向偏移一丢丢 绘制 Alpha 混合重叠,解决:使用 stencil buffer 来规避 为何出现这个问题 解决 ...
- Unity Shader - 模仿RenderImage制作全屏Quad,可以制作自定义后处理的流程
文章目录 先尝试GL类来制作 Shader CSharp 画个三角型 画个全屏的Quad 发现GL没有RenderTarget之类的 使用CommandBuffer来绘制全屏的Quad GL渲染到目标 ...
- Unity Shader - Post Processing 15 - Height Fog (Plus) - 后效 高度雾 改进版 (Parallax)、模拟闪电在云层中SSS
文章目录 环境 问题 Parallax 原理 GGB 效果 模拟闪电在云层中SSS 测试脚本 效果 GIF Project References 环境 Unity : 2018.2.11f1, 201 ...
- (一)unity shader在实际项目中出现的问题————unity的后处理插件景深效果在某些低档机(如三星)无效的解决方案
本专栏主要解决一些移动平台上unity shader效果异常的问题.很多情况下我们发现unity中的shader在PC平台效果正常,但是在移动平台上效果不对,或者部分机型效果不对的问题,尤其是低档老年 ...
- Unity 屏幕特效 之 简单地使用 Shader 获取深度,实现景深效果
Unity 屏幕特效 之 简单地使用 Shader 获取深度,实现景深效果 目录
- Unity Shader-Command Buffer的使用(景深与描边效果重置版)
Unity Shader-Command Buffer的使用(景深与描边效果重置版) https://blog.csdn.net/puppet_master/article/details/72669 ...
最新文章
- 卧槽!竟然可以直接白嫖 Github Action 的 2C7G 服务器!
- css中超级链接样式的设置顺序
- mysql查询表字段是否存在_Mysql判断表字段或索引是否存在
- 数据结构----二叉树叶子结点到根节点的高度计算
- NOIp2018滚粗记
- 如何通过输入域名直接访问项目地址
- JDK源码(11)-Long、Short
- 如何将java项目部署到Linux服务器上
- 一天搞懂深度学习(李宏毅)-学习笔记
- python 网络音乐播放器(二):tkinter 实现歌词同步滚动
- lua搭建ui_[专栏作家] Lua写UI的一些使用心得
- ax200 兼容性问题 老路由器_我的华硕AX89X 160频宽和MU-MIMO问题,小米10测速-路由器交流...
- linux统计单拷贝基因家族,为什么要进行基因家族分析?
- air dots 配对_Redmi AirDots可以作为iphone的合格伴侣吗?
- 漫谈 MQ:要消息队列(MQ)有什么用?
- via浏览器 html代码,网页黑色加强的css代码
- Web自动化测试-Protractor基础(二)
- php将阿拉伯数字转换成中文大写,PHP将阿拉伯数字转换成汉字大写支持小数点
- 脸书注册消失;网信办约谈脉脉;滴滴试运营监控|互联网行业公会
- 程序员间 日常商业互捧。。