- 基本概念
- 实现
- 列举需要的参数
- 在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();
// 绘制景深视锥范围
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
{
// 正交 cube
var 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绘制:
如何获取深度,可以参考我之前写的一篇: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 = focusNear) && (depth = focusNear) && (depth
关注
打赏
最近更新
- 深拷贝和浅拷贝的区别(重点)
- 【Vue】走进Vue框架世界
- 【云服务器】项目部署—搭建网站—vue电商后台管理系统
- 【React介绍】 一文带你深入React
- 【React】React组件实例的三大属性之state,props,refs(你学废了吗)
- 【脚手架VueCLI】从零开始,创建一个VUE项目
- 【React】深入理解React组件生命周期----图文详解(含代码)
- 【React】DOM的Diffing算法是什么?以及DOM中key的作用----经典面试题
- 【React】1_使用React脚手架创建项目步骤--------详解(含项目结构说明)
- 【React】2_如何使用react脚手架写一个简单的页面?