1. 从“贴图感”到“绘画感”:一个困扰我很久的材质问题
如果你在Blender里做过一段时间的NPR渲染,大概率经历过这个阶段:模型建好了,灯光打好了,摄像机也架好了,渲染出来的东西却总觉得“差点意思”。差在哪?差在材质上。模型表面的纹理看起来太“干净”、太“均匀”、太“数字”了,像是从素材库里直接拖出来贴上去的,缺少那种手绘画面里笔触叠加、颜料堆积、边缘微微溢出的生动感。
这个问题困扰了我很久。我试过在纹理上叠加噪波,试过用色彩渐变做随机化,甚至试过手动在纹理上画脏迹,效果都不太理想。要么是随机感太强导致画面显得脏乱,要么是叠加方式太生硬,纹理和底色之间像隔了一层,完全没有“画上去”的感觉。直到我开始认真研究程序化滤镜在着色器编辑器里的组合方式,特别是桑原滤镜(Kuwahara Filter)在Blender里的实现思路,才真正找到了一个相对通用的解法。
这篇文章要聊的,就是怎么用一套材质节点组合,让任何纹理——不管是程序化生成的还是外部导入的——都自带一种“绘画感”。核心思路不是去修改纹理本身,而是在纹理和最终输出之间插入一层“风格化处理层”,通过着色器编辑器里的节点编排,模拟出手绘笔触的叠加效果。这套方案不依赖任何外部插件,纯节点实现,适合所有对NPR渲染感兴趣的Blender用户,无论你是刚接触着色器的新手,还是已经能写自定义节点组的老手,都能从中找到可以直接复用的思路。
2. 为什么“绘画感”的本质是边缘处理而不是纹理本身
2.1 手绘画面和数字纹理的根本差异
先想清楚一个问题:为什么手绘画面看起来有“绘画感”,而数字纹理看起来就是“贴图”?很多人第一反应是“因为手绘有笔触”。这个答案对,但不够精确。笔触的本质是什么?是局部区域内的颜色一致性加上区域边界的不规则性。
你拿一支画笔在纸上画一笔,这一笔覆盖的区域里,颜色是相对均匀的,但区域的边缘不是一条数学意义上的直线或曲线,而是带有毛糙感、有颜料堆积、有轻微溢出的不规则边界。数字纹理的问题在于,它的颜色变化要么太“硬”——边缘锐利得像刀切,要么太“软”——过渡均匀得像数学函数。手绘的妙处在于,它在“硬”和“软”之间找到了一个中间态:区域内部平滑,区域边界有结构化的不规则。
这就引出了桑原滤镜的核心思想。桑原滤镜最初是一种图像处理算法,它的做法是在每个像素周围取一个方形区域,然后把区域内的像素分成若干个象限,每个象限计算均值和方差,最后选择方差最小的那个象限的均值作为输出。这个操作的视觉效果是:平坦区域保持平滑,边缘区域产生类似油画笔触的块状结构。换句话说,它把“边缘”变成了“笔触”。
2.2 在着色器里复现桑原思路的可行性分析
在Blender的着色器编辑器里,你没法直接对屏幕空间做卷积运算,因为着色器是逐像素计算的,没有“邻域”的概念。但这不意味着桑原滤镜的思路没法用。关键在于转换视角:把屏幕空间的邻域操作,转换成纹理空间的采样操作。
具体来说,你可以用纹理坐标的偏移来模拟“邻域采样”。比如,对一个纹理进行多次采样,每次采样的UV坐标加上一个微小的偏移量,然后对这些采样结果做加权平均或选择操作。这个思路在程序化纹理上尤其好用,因为程序化纹理本身就是UV坐标的函数,你可以任意控制采样位置。
注意:这套方案对性能有一定要求。每次额外的纹理采样都会增加着色器的计算量,如果你的场景里有大量使用这套材质的物体,渲染时间会明显上升。建议在最终渲染前先在小分辨率下测试效果。
2.3 为什么选择在着色器层面做而不是后期处理
有人可能会问:为什么不在合成节点里做后期处理?合成节点确实可以做滤镜,但它的局限在于它是屏幕空间的。屏幕空间的滤镜会随着摄像机距离和角度的变化而产生不一致的效果——近处的物体笔触大,远处的物体笔触小,移动摄像机时笔触还会“滑动”。这种不稳定感在动画里尤其明显。
在着色器层面做的好处是,滤镜效果是绑定在物体表面的。无论摄像机怎么动,笔触都“贴”在模型上,不会产生滑动感。而且你可以针对不同的物体使用不同的参数,比如近景物体用强笔触,远景物体用弱笔触,这在合成节点里很难做到。
3. 搭建“绘画感”材质节点组的完整流程
3.1 基础纹理的准备与预处理
在开始搭建风格化层之前,你需要先有一个基础纹理。这个纹理可以是程序化生成的(比如噪波、沃罗诺伊、渐变),也可以是外部导入的图片纹理。不管来源是什么,建议先做一步预处理:把纹理的颜色空间统一到sRGB,并且确保纹理的对比度不要太高。原因很简单:风格化层会放大纹理的局部差异,如果原始纹理的对比度已经很高,叠加风格化层后画面会显得过于杂乱。
具体操作上,如果你用的是图片纹理,在图像纹理节点后面接一个色相/饱和度/明度节点,把饱和度稍微降低10%到20%,明度稍微提高5%左右。这一步不是必须的,但实测下来能让后续的风格化效果更自然。如果你用的是程序化纹理,建议在纹理生成节点后面接一个颜色渐变节点,把输出范围压缩到0.2到0.8之间,避免纯黑和纯白区域。
3.2 核心节点链:从纹理坐标到笔触化输出
整个风格化层的核心思路是:对同一纹理进行多次采样,每次采样使用略微不同的UV偏移,然后通过混合节点把这些采样结果组合起来。组合的方式决定了最终的笔触风格。
先看节点链的基本结构。从纹理坐标节点出发,接一个映射节点用来控制整体缩放和偏移。然后从映射节点的输出引出一条线,接一个矢量运算节点,模式设为“加”,第二个输入接一个噪波纹理节点,用来生成随机的偏移量。这个噪波纹理的缩放值决定了偏移的“粒度”——缩放值越大,偏移越细碎,笔触越细腻;缩放值越小,偏移越粗犷,笔触越明显。
接下来是关键步骤:把经过偏移的UV坐标分别接入多个图像纹理节点(或者同一个程序化纹理节点的多个实例),每个纹理节点使用不同的偏移强度。建议至少用3个采样,最多不超过5个。采样数量越多,笔触的层次感越丰富,但性能开销也越大。实测下来,3个采样在大多数场景下已经足够,5个采样适合特写镜头。
每个纹理节点的输出接入一个混合节点,混合模式选择“叠加”或“柔光”,系数控制在0.3到0.5之间。混合节点的顺序很重要:先混合两个采样,再把结果和第三个采样混合,以此类推。这样做的原因是,链式混合能让笔触的叠加更自然,避免所有采样同时混合导致的“糊成一团”。
3.3 用颜色渐变控制笔触的“硬边”与“软边”
混合完所有采样之后,你会得到一个带有笔触感的纹理输出。但这个输出可能还是太“软”,笔触的边缘不够清晰。这时候需要接一个颜色渐变节点,把混合结果的对比度拉高。颜色渐变的插值模式选择“恒定”或“线性”,具体取决于你想要的效果。
如果你想要油画式的硬边笔触,把颜色渐变的两个控制点拉近,让过渡区域变窄。如果你想要水彩式的软边笔触,把控制点拉开,让过渡区域变宽。这个参数没有标准值,需要根据你的纹理内容和想要的风格来调。我的经验是,对于人物皮肤这类需要柔和过渡的材质,渐变控制点之间的距离保持在0.3左右;对于岩石、布料这类需要明显笔触的材质,距离可以压缩到0.1以下。
提示:颜色渐变节点的输出可以再接一个凹凸节点,用笔触的明度变化来驱动法线扰动。这样笔触不仅体现在颜色上,还体现在表面的微观起伏上,立体感会强很多。
3.4 把风格化层接入原理化BSDF的正确姿势
风格化层的输出最终要接入原理化BSDF的“基础色”输入。但直接接进去可能会发现颜色偏暗或偏亮,这是因为风格化层的输出范围可能超出了0到1。建议在风格化层和BSDF之间接一个映射范围节点,把输出范围重新映射到0到1之间。
另外,如果你想让笔触效果更明显,可以把风格化层的输出同时接入粗糙度输入。笔触密集的区域粗糙度低一些,笔触稀疏的区域粗糙度高一些,这样在光照下笔触的立体感会更强。具体做法是用一个颜色渐变节点把风格化输出转换成灰度,然后接入粗糙度。渐变的方向决定了粗糙度和笔触密度的对应关系,你可以根据实际效果调整。
4. 不同纹理类型下的参数微调策略
4.1 程序化纹理:噪波、沃罗诺伊、马氏分形的差异化处理
程序化纹理是这套方案的最佳搭档,因为它们的UV坐标完全可控,采样偏移的效果最明显。但不同类型的程序化纹理需要不同的参数策略。
噪波纹理的特点是连续且平滑,适合用较小的采样偏移(0.01到0.03)和较多的采样数量(4到5个)。偏移太大会导致噪波结构被破坏,看起来像电视雪花。沃罗诺伊纹理本身就有明显的细胞结构,采样偏移可以稍大一些(0.03到0.05),采样数量3个就够了,因为沃罗诺伊的边缘本身就很清晰,不需要太多叠加。马氏分形介于两者之间,偏移量控制在0.02到0.04,采样数量4个左右。
下面这个表格是我在实际项目中总结的参数参考,你可以直接拿来用,然后根据具体效果微调:
| 纹理类型 | 采样偏移量 | 采样数量 | 混合系数 | 渐变压缩比 |
|---|---|---|---|---|
| 噪波纹理 | 0.01-0.03 | 4-5 | 0.3-0.4 | 0.2-0.3 |
| 沃罗诺伊 | 0.03-0.05 | 3 | 0.4-0.5 | 0.1-0.2 |
| 马氏分形 | 0.02-0.04 | 4 | 0.35-0.45 | 0.15-0.25 |
| 图片纹理 | 0.005-0.015 | 3-4 | 0.25-0.35 | 0.2-0.4 |
4.2 图片纹理:如何避免采样偏移导致的“重影”
图片纹理的情况比较特殊。因为图片纹理本身有明确的图案内容,采样偏移过大时会产生明显的“重影”效果——你能看到同一个图案被复制了多次,只是位置略有偏移。这在人物脸部、文字、标志等有明确语义的纹理上是灾难性的。
解决方法是把采样偏移量控制在极小的范围内(0.005到0.015),并且减少采样数量(3个足够)。同时,混合模式建议选择“柔光”而不是“叠加”,因为柔光对底层纹理的改动更温和。如果重影问题依然明显,可以尝试把偏移方向限制在单一轴向(比如只做水平偏移),这样重影会呈现为“拖影”而不是“多重曝光”,在某些风格下反而更有绘画感。
另一个技巧是用纹理的明度来调制偏移强度。具体做法是:把图片纹理的明度输出接入一个颜色渐变节点,然后用渐变结果去乘以偏移量。这样,纹理的暗部区域偏移小(保持清晰),亮部区域偏移大(产生笔触),整体效果会更自然。
4.3 混合纹理:当程序化和图片纹理同时存在时
实际项目中,经常需要把程序化纹理和图片纹理混合使用。比如用噪波纹理做底色,用图片纹理做细节。这种情况下,风格化层应该分别处理两种纹理,然后再混合,而不是先混合再风格化。
原因很简单:程序化纹理和图片纹理对采样偏移的敏感度不同。如果先混合再风格化,你只能用一套参数,要么牺牲程序化纹理的笔触感,要么让图片纹理产生重影。分别处理的话,你可以给程序化纹理用大偏移多采样,给图片纹理用小偏移少采样,最后用一个混合着色器节点把两个风格化结果按需混合。
混合的方式建议用正片叠底或线性减淡,具体取决于你想要的是“暗部笔触”还是“亮部笔触”。正片叠底会让笔触主要体现在暗部,适合表现阴影区域的绘画感;线性减淡会让笔触主要体现在亮部,适合表现高光区域的绘画感。
5. 实测中遇到的五个坑和对应的解法
5.1 笔触在UV接缝处断裂
这是最常见的问题。因为采样偏移是在UV空间做的,当UV坐标跨越接缝时(比如从0.99跳到0.01),偏移后的坐标会跑到纹理的另一侧,导致接缝处出现明显的断裂。
解法有两个。第一个是在UV接缝处降低偏移强度。具体做法是用一个几何数据节点获取物体的UV坐标,然后用矢量运算计算当前UV到最近接缝的距离,距离越近偏移越小。这个方案效果最好,但节点链会比较复杂。第二个方案更简单:把纹理的映射模式改为“扩展”而不是“重复”,这样UV超出0到1范围时不会跳回另一侧,而是延续边缘像素。这个方案不能完全消除断裂,但能把断裂的视觉影响降到最低。
5.2 渲染时间翻倍甚至更多
前面提到过性能问题,这里展开说。每次额外的纹理采样都会增加着色器的计算量,而着色器是在每个像素上执行的。一个1080p的画面有超过200万个像素,每个像素多做3次纹理采样,计算量的增加是相当可观的。
实测数据:在一个中等复杂度的场景里(约50万个面),使用基础原理化BSDF的渲染时间是每帧12秒。加入3次采样的风格化层后,渲染时间上升到每帧28秒。加入5次采样后,上升到每帧45秒。这个开销在静帧渲染里可以接受,但在动画渲染里就需要权衡了。
优化的思路有几个。一是降低风格化层的分辨率,用纹理坐标节点的“物体”模式而不是“UV”模式,这样采样偏移是在物体空间做的,不受纹理分辨率影响。二是只在摄像机可见的物体上使用风格化层,远景物体用普通材质。三是把风格化层烘焙成纹理,虽然失去了实时调整的灵活性,但渲染速度会回到正常水平。
5.3 笔触方向过于随机导致画面“脏”
采样偏移如果完全随机,笔触方向就没有规律,画面会显得很“脏”。手绘笔触虽然也有随机性,但通常有一个主导方向——比如顺着物体的结构走,或者顺着光照方向走。
解法是用物体的法线或纹理的梯度来调制偏移方向。具体做法是:把几何数据节点的法线输出接入一个矢量运算节点,提取法线的X和Y分量,然后用这两个分量去乘以偏移量。这样笔触就会顺着物体的表面曲率方向排列,看起来更有“画上去”的感觉。另一个方案是用纹理的梯度来调制方向,但节点链会更复杂,适合对效果有更高要求的情况。
5.4 颜色溢出导致画面过饱和
风格化层的混合操作(尤其是“叠加”模式)会放大颜色的饱和度。如果原始纹理的颜色已经比较鲜艳,叠加后可能会出现颜色溢出,画面看起来像打翻了颜料盘。
解法是在风格化层之后接一个色相/饱和度/明度节点,把饱和度降低15%到25%。同时,在混合节点里把系数控制在0.5以下。如果溢出依然严重,可以把混合模式从“叠加”改为“柔光”,柔光对颜色的放大效应要温和得多。
5.5 不同物体的笔触大小不一致
这个问题在场景里有多个物体时特别明显。因为采样偏移是在UV空间做的,而不同物体的UV缩放可能不同,导致同样的偏移量在不同物体上产生不同大小的笔触。
解法是用物体的尺寸来归一化偏移量。具体做法是用几何数据节点的“尺寸”输出,计算物体的包围盒尺寸,然后用这个尺寸去缩放偏移量。这样无论物体大小如何,笔触的物理尺寸都是一致的。这个方案需要一些矢量运算节点的配合,但效果非常显著,尤其是在建筑场景或产品展示场景里。
6. 把这套材质用在动画项目里的注意事项
6.1 帧间稳定性:为什么笔触会“闪烁”
如果你把这套材质用在动画里,可能会发现笔触在帧与帧之间会“闪烁”——同一位置的笔触形状在变化。这是因为采样偏移依赖的噪波纹理是三维的,时间轴变化时噪波的值也在变化。
解法是把噪波纹理的“W”输入固定,或者用一个值节点代替噪波纹理来生成偏移量。值节点输出的是常数,不随时间变化,这样笔触在帧间就是稳定的。如果你需要笔触有缓慢的变化(比如模拟颜料干燥的过程),可以用一个时间节点驱动值节点的输出,但变化速度要非常慢,否则会显得不自然。
6.2 运动模糊和景深对笔触效果的影响
运动模糊和景深是动画渲染里常用的效果,但它们会和风格化层产生交互。运动模糊会把笔触“拉长”,景深会把笔触“模糊化”。这两个效果叠加在风格化层上,可能会让笔触变得不可辨认。
建议在渲染设置里先关闭运动模糊和景深,确认笔触效果满意后再开启。如果开启后笔触效果损失太多,可以适当降低运动模糊的采样数或景深的模糊半径。另一个方案是把风格化层放在景深之后——但这在Blender的渲染管线里做不到,因为着色器是在景深之前执行的。所以只能通过参数调整来平衡。
6.3 多角度渲染时的一致性检查
这套材质的效果和摄像机角度有关,因为采样偏移是在UV空间做的,而UV空间和摄像机角度是独立的。但光照会影响笔触的可见度——在暗部,笔触可能完全看不见;在亮部,笔触可能过于明显。
建议在最终渲染前,从多个角度渲染测试帧,检查笔触在不同光照条件下的表现。如果发现某个角度下笔触效果不理想,可以调整风格化层的混合系数或颜色渐变的压缩比。我的经验是,把混合系数控制在0.3到0.4之间,能在大多数光照条件下保持稳定的笔触可见度。
7. 从这套方案延伸出去的几个玩法
7.1 用笔触层驱动置换做立体笔触
前面提到过用笔触驱动凹凸,其实还可以更进一步:用笔触层驱动置换。在材质设置里把置换模式改为“置换和凹凸”,然后把风格化层的输出接入置换节点的“高度”输入。这样笔触不仅体现在颜色和法线上,还体现在实际的几何位移上。渲染出来的效果就像是颜料真的堆在画布上,立体感非常强。
这个玩法的代价是需要更高的网格密度,因为置换是在顶点层面执行的。如果网格太稀疏,置换效果会显得很粗糙。建议在使用前先对物体做一次细分,细分级别根据物体尺寸和笔触大小来定。实测下来,笔触大小在0.05左右时,细分级别需要达到3到4级才能有平滑的置换效果。
7.2 结合Freestyle做轮廓线的风格统一
Blender的Freestyle功能可以渲染出轮廓线,但默认的轮廓线是纯色的,和风格化材质的笔触感不太搭。你可以用风格化层的输出颜色来驱动Freestyle的线条颜色,让轮廓线也有笔触的明暗变化。
具体做法是在Freestyle的线条样式里,把颜色改为“材质”模式,然后选择一个使用风格化材质的材质槽。这样轮廓线的颜色就会跟随风格化层的输出变化,整体风格会更统一。这个技巧在制作手绘风格的角色插画时特别有用。
7.3 把节点组打包成可复用的资产
这套节点链搭建一次之后,可以打包成节点组,方便在其他项目里复用。打包的方法很简单:选中所有风格化相关的节点,右键选择“创建节点组”,然后把需要暴露的参数(比如采样偏移量、混合系数、渐变压缩比)提升为节点组的输入。
打包成节点组的好处是,你可以在不同的材质里引用同一个节点组,修改节点组里的参数会同步影响所有引用它的材质。这在需要统一风格的项目里非常实用。另外,你还可以把节点组保存为资产,在Blender的资产浏览器里直接拖拽使用,省去每次重新搭建的时间。
提示:打包节点组之前,建议先把节点命名规范化。比如把“映射”节点改名为“UV缩放”,把“噪波纹理”改名为“偏移噪波”,这样在节点组内部查看时更容易理解每个节点的作用。
8. 我个人在实际操作中的几点体会
这套材质方案我从去年开始在自己的项目里反复使用和调整,踩了不少坑,也总结了一些文档里不会写的经验。
第一,不要追求一步到位。刚开始调参数的时候,很容易陷入“这个参数调一点,那个参数也调一点”的循环,结果越调越乱。我的做法是先把所有参数恢复到默认值,然后只调一个参数,观察效果变化,确认这个参数的作用后再调下一个。虽然慢,但能建立起对每个参数的直觉。
第二,保存多个版本。风格化材质的参数组合非常多,有时候你调出一个满意的效果,但过两天想微调时已经忘了当初是怎么调的。建议每调出一个满意的版本就保存一个副本,命名带上日期和关键参数值,比如“绘画感材质_偏移0.02_采样4_混合0.35”。这样以后需要类似效果时可以直接调用。
第三,多看手绘作品。这套材质的目标是模拟手绘感,所以最好的参考不是其他3D作品,而是真正的手绘作品。我经常在Pinterest上找油画、水彩、素描的局部放大图,观察笔触的形态、边缘的处理、颜色的过渡方式,然后回到Blender里尝试用节点复现。这个过程本身也是提升审美的好方法。
第四,性能和质量永远需要权衡。这套方案的效果和采样数量直接相关,但采样数量又直接影响渲染时间。我的建议是:在预览阶段用2个采样,在最终渲染时用4到5个采样。预览阶段看的是整体效果和构图,笔触细节可以暂时忽略;最终渲染时再追求质量。这样能把调整周期缩短至少一半。
第五,不是所有场景都适合这套方案。这套材质最适合的是风格化场景——比如卡通渲染、手绘插画、概念艺术。如果你做的是写实渲染,这套方案会让画面显得“不真实”。所以在使用前先想清楚项目的风格定位,不要为了用而用。