【笔记】【百人计划】图形4.5 Dof景深基础

图形4.5 Dof景深基础

一、景深

image-20221004232304423

  • 景深
    • 相机对焦点前后相对清晰的成像范围。
    • 虽然透镜只能将光聚到一个固定的距离(焦距),远离此点则会逐渐模糊,但在一段特定的距离内,模糊的程度是无法察觉的,这段距离称之为景深。
    • 当焦点设在超焦距处时,景深会从超焦距的一半延伸到无限远,对于一个固定的光圈来说,这是最大的景深。

image-20221004232630406

脱焦的点扩大到超过像素大小以后,就会出现模糊

二、作用

  • 选择性突出或强调画面中的一部分,吸引观察者的注意力到画面中清晰对焦的部分,忽略其他模糊部分的细节
  • 强调所拍摄场景的深度,增加画面的层次立体感
  • 艺术意境的表达
  • 表达主观的视线。在电影学中,通过调节浅景深的镜头,使之对焦在不同位置上,来表示某个人的主观视线的转移
  • 交代人物之间的关系。在电影学中,通过景深聚焦位置的变化来表达前景和背景人物之间的关系

三、移动端景深实现

  • 制作思路
    • 模拟景深制作mask
    • 模糊场景
    • 正常场景
    • 合并

image-20221004233203292

计算时对于从深度图中获取深度的处理,需要乘以远裁面的大小,获得绝对的相机深度。

1
half depth = Linear01Depth(tex2Dd(_CameraDepthTexture,i.uv))*_ProjectionParams.z;

(这一部分感觉可以替换成恢复线性深度的处理)

因为我们不希望远裁面的位置影响到我们的景深效果(吗?我觉得这一点可以再斟酌一下)

然后通过焦距设置以及该深度计算景深Mask

1
2
3
4
5
6
7
8
9
10
11
float focusNear = _FocusDistance - _DepthOfField;
float focusFar = _FocusDistance + _DepthOfField;

half finnal_depth = 0;
if ((depth >= focusNear) && (depth <= focusFar));
else {
if(depth < focusNear)
finnal_depth = saturate(abs(focusNear - depth));
if(depth > focusFar)
finnal_depth = saturate(abs(depth - focusFar));
}

搞了一个如下的Mask效果,靠近焦距就不模糊(0),远离焦距就模糊(1)

image-20221004234304634

接下来的计算就很自然了,卷积,然后根据mask和原图进行插值。

image-20221004234515207

通过降采样多次迭代处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
void OnRenderImage(RenderTexture src, RenderTexture dest) {
{
material.SetFloat("_DepthOfField", _DepthOfField);
material.SetFloat("_FocusDistance", _FocusDistance);

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

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

material.SetVector("_BlurOffset", new Vector4(_BlurRadius / wdith, _BlurRadius / height, 0, 0));
Graphics.Blit(src,RT1,material,0);
for (int i=0; i <_Iteration;i++){
RenderTexture.ReleaseTemporary(RT2);
width /= 2;
height /= 2;
RT2 = RenderTexture.GetTemporary(width, height);
Graphics.Blit(RT1,RT2,material,0);

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

for (int i=0; i <_Iteration;i++){
RenderTexture.ReleaseTemporary(RT2);
width *= 2;
height *= 2;
RT2 = RenderTexture.GetTemporary(width, height);
Graphics.Blit(RT1,RT2,material,0);

RenderTexture.ReleaseTemporary(RT1);
width *= 2;
height *= 2;
RT1 = RenderTexture.GetTemporary(width, height);
Graphics.Blit(RT2,RT1,material,0);
}
material.SetTexture("_BlurTex",RT1);
Graphics.Blit(src,dest,material,1);
RenderTexture.ReleaseTemporary(RT1);
RenderTexture.ReleaseTemporary(RT2);
}
}

可见在实际操作中,为了获得好的模糊效果,是在第一个pass中完成多次的降采样与卷积,然后在第二个pass中进行mask的提取与插值

image-20221004235732752

四、高级景深效果思路拓展

image-20221005000034529

颜色泄露

image-20221005000123337

模糊不连续缺陷

焦点在背景时,前景会被截断——前后景分离

image-20221005000357241

散景的模拟

image-20221005000627815

作业

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

参考资料

[1] https://www.bilibili.com/video/BV1dv411u7KA

【技术美术百人计划】图形 4.5 Dof景深基础