跳转到内容

Blender 3D:菜鸟到专业/Cycles 中的萤火虫问题

来自 Wikibooks,开放世界,开放书籍

看到那些小白点了吗?(点击查看全尺寸图片,仔细观察。)
萤火虫消失了。

Cycles 是一款很棒的渲染器,能够实现一些精美的灯光效果。然而,迟早你会遇到萤火虫问题,它们是指散落在图像各个部分的孤立亮像素。与简单的噪点(可以通过增加渲染样本数量来减少,或者通过简单的滤镜来减少)不同,萤火虫是由渲染计算中的数值不稳定性造成的,因为毕竟计算机只能以有限的精度计算公式。它们似乎是试图使用真实的物理公式来创建渲染结果的不可避免的结果。

但它们真的那么不可避免吗?实际上,我们可以使用各种技巧和调整来防止它们出现在渲染结果中。每种技术都有其优缺点(在工作量和不必要的副作用方面),因此由你决定使用哪种技术以及何时使用。

萤火虫往往不会影响最简单的渲染结果。这意味着需要花费一些工作来创建一个足够复杂的教程示例来展示它们。如果你已经拥有一个被萤火虫困扰的渲染结果,并且你来到这里是为了寻找解决方法,那么太好了——你可以直接跳到解决方案部分。否则,请耐心等待我们构建示例。

制作示例

[编辑 | 编辑源代码]

这个示例源于我尝试构建的一个真实模型:一栋带有百叶窗的房子,百叶窗由磨砂玻璃制成。一些涉及光线穿过一面窗格,在房间的漫反射墙壁上反弹,然后从另一面窗格射出的交互作用,以及构成玻璃材质的着色器组合,导致了萤火虫的出现。这个示例将把情况缩减到我能够展示问题的最小程度,即两个相邻房间,带两个窗户。

环切来划分房间(从下面看)

新建一个 Blender 文档。将渲染器切换到 Cycles。选择默认立方体,然后 TAB 进入编辑模式。将立方体水平方向稍微缩放一点,使房间不要太窄和太高。切换到面选择模式。选择底面并 DEL 删除它。我发现房间需要天花板才能显示萤火虫,但不需要地板,所以为什么不把它去掉呢?

给你的立方体添加一个 Solidify 修饰符,使墙壁具有非零厚度。确切的厚度并不重要。

房间之间的墙壁填满了。

接下来,在形状的侧面做一个环切 CTRL + R ,以定义前室和后室之间的边界。然后按 F ,新环的顶点应该连接起来,形成一个新的面,即房间之间的墙壁。

窗户和门道切入墙壁。

现在我们需要为窗户和房间之间的门道打孔。仍在面选择模式下,选择前面(你在 NUM1 视图中看到的那个),然后 I 内插一点。如果你内插得太远,你可能会发现高度变得太小,所以经过初始内插后,只需选择中间面并水平缩放它 S + X ,以制作一个看起来合理的窗户。

对前室右侧的墙壁和房间之间的墙壁执行相同的操作。一个真正的门道会延伸到地板,但我们在这个练习中使用的墙壁上的简单孔就足够了。

添加窗户

[编辑 | 编辑源代码]
带百叶窗的前窗。

添加一个新的水平平面。沿着 Y 轴缩小到其沿着 X 轴长度的 20%。添加两个阵列修饰符:一个沿着 Z 轴,恒定偏移量大约为 0.2,数量约为六个;另一个沿着 X 轴,恒定偏移量约为 2.2,数量为 4。将你得到的百叶窗阵列放置在前窗的孔内。

萤火虫的秘诀

在继续之前,我们不能忘记将窗户做成磨砂玻璃。将新的材质分配给你的窗户对象。打开节点编辑器,并按照右边的设置创建一个窗户玻璃的材质。将光滑 BSDF 的粗糙度设置为零,但请注意折射 BSDF 上的粗糙度设置很小,但不为零:我故意调整它以最大限度地生成萤火虫。设置为零会导致萤火虫消失,但这会失去这个练习的目的,对吧?

(房间墙壁可以保持 Blender 分配的默认漫反射材质。)

设置好窗户材质后,复制你的百叶窗对象,旋转并定位副本,使其位于侧窗的孔内。将房间之间的孔留空(毕竟它一个门道)。

完成步骤

[编辑 | 编辑源代码]

作为我们生成萤火虫步骤的最后一步,将灯光对象的类型更改为太阳,并将角度更改为接近水平,使其照射到侧窗。将其强度设置为 3。将相机的位置调整为直接看向前窗。此外,将渲染样本数量增加到 100;这应该足以减少噪点。

因此,总而言之,我们有从前室侧窗的百叶窗中以低角度照射进来的阳光,在前后房间之间反弹,然后从前窗的百叶窗中射出,所有百叶窗都是由略微磨砂的玻璃制成的。

萤火虫!(点击仔细观察。)

如果一切顺利,按下 F12 进行渲染应该会生成右边的图像。

解决问题 1:渲染调整

[编辑 | 编辑源代码]
相关的渲染器设置

好的,现在我们已经可以制造问题了,我们如何解决它呢?

可能首先要尝试的是一两个渲染器设置。在渲染 上下文中查找采样和光线路径面板,如右边所示。在采样面板中,查找“Clamp”字段。如果非零,则对每个像素的光强计算施加一个最大值。通常 1.0 对应于全白,但某些点可能比这更亮。尝试将默认值 0 更改为例如 3,然后重新渲染。

在我们这个简单的示例中,这应该足以解决萤火虫问题。然而,我遇到过一两个情况,其中这会降低某些明亮的间接照明的强度,导致整体渲染结果显得更柔和。

所以让我们尝试下一个方法。将 Clamp 设置回 0,这次在光线路径面板中,查找“No Caustics”复选框。焦散可能是逼真的灯光效果的重要组成部分,但如果你的场景不需要它们,禁用它们可以帮助消除萤火虫,并且可能加快渲染速度。但是,此复选框的工具提示警告说,结果可能会是更暗的图像。

在我们这个简单的示例中,选中此复选框确实有效。

尝试的第三个渲染器设置是“无焦散”(No Caustics) 勾选框下方的字段,名为“过滤光滑”(Filter Glossy)。它对某些类型的灯光反弹进行故意模糊处理,牺牲了一点照明精度以避免出现萤火虫。再次,在我们这种情况下,此选项有效:将其设置为例如 1 的值,确实可以修复萤火虫。

但是,在某些时候,您可能会发现这三种技术都无法解决您的问题:它们可能对渲染没有影响,或者可能在某些地方导致无法接受的质量损失。毕竟,由于这些设置适用于整个渲染,因此它们可能是一种比较粗糙的工具。

因此,为了进行下一步修复,我们需要求助于合成器。

解决问题 2:去斑点滤镜

[编辑 | 编辑源代码]

解决萤火虫问题的方法是对渲染后的图像进行某种处理。如果您熟悉 Gimp 或 Photoshop 等图像编辑程序,您肯定见过去斑点滤镜,它的作用就是专门平滑掉与图像其他部分不匹配的随机点。原则上,您可以使用图像编辑程序来修补您的渲染(有些制作专业级渲染的人确实这样做),但如果您要渲染动画会发生什么?想象一下,要手动修复数百甚至数千帧!

Blender 也有很多图像处理操作,可以在合成器中使用,包括去斑点滤镜。而且,很棒的一点是,这些操作可以在渲染每一帧后自动应用。

在您的 Blender 文档中打开一个节点编辑器 窗口(您可以重新使用默认窗口布局底部的“时间线” 窗口,只需稍微提高高度)。查找图标 ,它表示要编辑的节点类型:点击显示小图层或薄片的图标,代表合成器(在 Blender 2.68 中位于中间,在早期版本的 Blender 中位于左侧)。您应该立即看到一个“使用节点”(Use Nodes) 勾选框出现在这些图标的右侧:选中它以启用基于节点的合成。您应该会获得一个默认的节点设置,如右图所示。

将两个现有节点稍微拉开,以便在它们之间腾出空间放置一个新的节点。按下  SHIFT + A  调出“添加”菜单,并在“滤镜”(Filter) 子菜单中查找“去斑点”(Despeckle) 条目。将新的去斑点节点移到您之前清理的间隙中,如果定位正确,它应该会自动连接到链中,如下图所示。

要查看更改的效果,将 3D 视图窗口切换到“图像编辑器”(Image Editor) 窗口。确保显示的图像为“渲染结果”(Render Result)。在用于选择图像槽位的菜单(应该显示“槽位 1”(Slot 1))旁边,有一个用于选择要显示的图像层的菜单:。“渲染层”(RenderLayer) 是渲染器提供的原始输出,而“合成”(Composite) 是经过合成器处理后的结果。在两者之间切换,您应该会发现默认的去斑点滤镜设置已经删除了一些萤火虫,但不是全部。我发现如果将“阈值”(Threshold) 滤镜参数从默认的 0.5 降低到类似 0.1 的值,那么所有的萤火虫确实都消失了。

去斑点滤镜的工作原理

[编辑 | 编辑源代码]

去斑点滤镜专门用于去除孤立的异常像素。这与模糊滤镜不同,模糊滤镜会将一堆像素平均在一起,可能会将萤火虫分散到更大的区域,而不是去除它。

但是,那些“阈值”(Threshold) 和“邻近”(Neighbor) 参数究竟是什么意思呢?以下解释是根据对 Blender 源代码的研究,主要是在source/blender/compositor/operations/COM_DespeckleOperation.cpp .

中进行的。正在处理的目标像素与其八个邻居进行比较。但是,这些邻居并不等同对待:每个邻居都获得一个权重,用于控制其在计算中的相对重要性。水平和垂直邻居的权重均为 1,而对角邻居的权重较低,为 (大约为 0.7)。这反映了这样一个事实,即它们沿对角线稍微远一些,因此它们对结果的影响相应地更小。

对于每个邻居像素,“阈值”(Threshold) 输入参数将与每个邻居的 R、G 和 B 分量(归一化为 0 为黑色,1 为最大亮度)与目标像素的对应分量之间的差值进行比较;如果任何对应对的分量的差值超过阈值,则邻居像素值将累加到一个平均值(按邻居权重加权)上,代码将其称为color_mid_ok——如果你愿意,可以认为它是目标像素的“正确”值。所有邻居像素,无论是在阈值内还是阈值外,都累加到另一个(也加权)平均值上,称为color_mid。值w是所有贡献给color_mid_ok.

的邻居的总权重。然后,值w除以所有邻居像素的总权重(4 × 1 + 4 × ),得到一个介于 [0.0 .. 1.0] 之间的分数,并将得到的分数与“邻近”(Neighbor) 输入参数进行比较。同样,将color_mid(所有邻居的平均值)的组件与原始目标像素的组件之间的差值与“阈值”(Threshold) 进行比较。如果两种比较都返回小于或等于,则认为像素不需要校正。但是,如果两种比较都大于,则目标像素将从其初始值调整为color_mid_ok平均值,根据“Fac”输入插座的值。如果“Fac”为 1.0(默认值),则像素将完全替换为color_mid_ok;否则它将成为此值与其原始值的相应混合。

“Fac”可用于微调去斑点滤镜的效果。例如,如果它来自一个反转的边缘检测(“Kirsch”)滤镜,那么它可以用于减少沿尖锐边缘的效果,因为这些边缘可能会混淆滤镜。

华夏公益教科书