实时水彩渲染Shader原理拆解:湿染、晕色与纸纤维模拟
程序如何模拟一滴颜料在纸上自由扩散的不可控美感?——从流体扩散算法到多层纹理混合的工程实践
一个看似简单实则极难的技术命题
水彩之所以是「水彩」,核心在于它那种不可控的美感——颜料在水分作用下自然扩散形成的边缘晕染效果,纸张纤维对颜色的微妙吸附差异,以及传统水彩特有的「留白」技法所创造的透气感。这些特性组合在一起,构成了水彩绘色的独特审美辨识度。但当一个独立游戏开发者试图用实时渲染技术复刻这种效果时,他面临的不是一个简单的视觉问题,而是一个需要同时处理流体力学仿真、多层纹理混合、噪声扰动和性能约束的系统性工程挑战。
本文不站「实时渲染无法还原手绘水彩」或「所有水彩效果都能被Shader模拟」的任何一边——两种立场都过度简化了真实技术的复杂度。我们要做的是:把实时水彩 Shader 的核心原理逐层拆解清楚,呈现每种技术方案的实际代价和视觉质量,并给出一套让独立游戏开发者能评估可行性与成本的参数化决策框架。Xmohe 希望帮每位技术美术建立「知其所以然」的水彩渲染判断力。
实时水彩 Shader 的三层架构
第一层:湿染扩散(Wet Spread)
这是水彩效果最核心的特征——当颜料接触到湿润纸面时,会像水滴渗入纸巾一样向外自然扩散,形成柔和的边缘过渡而非清晰的硬边。技术上通常采用基于速度的流体扩散方程求解器近似实现:将颜色值沿法线方向做高斯模糊扩散,扩散距离由一张「湿度贴图」控制。湿度贴图的每个像素代表该位置的湿润程度,决定了颜料在此处能扩散多远。关键难点在于扩散参数的选择——太小的扩散系数会导致效果过于克制(看起来像普通半透明贴图叠加),过大的系数则会让画面变成一团模糊(失去水彩应有的层次感和细节)。业界实践中,扩散范围通常控制在 2–8 像素之间,具体数值根据分辨率和观察距离动态调整。
第二层:颜料分层与叠色(Color Layering)
传统水彩中,画家会在前一层完全干燥后叠加新的颜色层,每一层都会通过底层颜色透出不同的视觉效果。这种「叠色」机制让水彩具有独特的色彩深度——不是简单地将 RGB 值相加,而是更接近物理上的透明混色。在实时渲染中,这一效果通常通过 alpha blending 模拟,但这只是近似。更精确的做法是使用光学模型(如 Kubelka-Munk 理论)来计算多层颜料的光散射效果。然而 Kubelka-Munk 计算开销较高,大多数实时实现采用了经过简化的近似公式,虽然不完全精确但在视觉上已足够接近。争议点在于:对于追求「学术级准确」的美术师来说,这些简化可能不够;而对于实时性能敏感的开发者来说,完整 Kubelka-Munk 模型又过于昂贵。
第三层:纸张纤维纹理(Paper Fiber Texture)
水彩颜料在纸张上的表现高度依赖纸张的物理属性——粗纹纸产生明显的颗粒感,细纹纸则更平滑。实时渲染中,这一效果通过叠加一层或多层纸张纹理贴图来实现。早期方案直接使用扫描的实体纸张纹理照片叠加在最终输出上,但这种方式最大的问题是「千篇一律」——每张纸的纹理有限,反复使用会导致画面出现可识别的重复模式。现代方案更多采用程序化噪声(Perlin噪声、Value噪声或 Worley噪声)来生成纸张纤维纹理,好处是可以无限变化且不存在重复风险,但挑战在于调参复杂度高,不同噪声参数会产生完全不同的视觉效果。此外,纸张纹理还需要考虑两个维度:① 宏观的「布列顿噪声」(Bruton noise,控制纸张表面的波纹起伏);② 微观的「纤维随机排列」(控制颜料颗粒在纤维间的分布)。两个维度的组合才是高质量水彩纸效果的完整描述。
关键洞察:实时水彩 Shader 的核心矛盾是「可控 vs 不可控」——水彩的魅力恰恰来自它的不可控性,但实时渲染本质上是确定性的系统。好的水彩 Shader 不是在两者之间做取舍,而是在确定性框架内引入受控的不确定性(即通过噪声和随机性模拟不可控的美感),这正是该技术路线最难也最有价值的部分。
三种主流方案的 GPU 性能成本对比
不同层级的水彩 Shader 实现方案对应显著不同的 GPU 开销,这直接决定了你的项目能在多大范围内应用这些效果。
低配方案(单层叠加 + 简易模糊):在低端设备上可用,每帧额外开销约 0.5ms。缺点是没有真正的扩散效果,更像是静态半透明纹理覆盖,视觉质感较弱。适合移动端或浏览器端轻量级项目。
中等方案(含扩散 + 纸张纹理):主流 PC/主机平台可用,每帧额外开销约 1–2ms。有真实的扩散效果和纸张纤维纹理,但需要注意多 Pass 带来的 Draw Call 增长。适合大多数独立游戏项目。
高保真方案(含扩散 + 光学叠色模型 + 程序化噪声):仅高端 PC/次世代主机可用,每帧开销 3–5ms+。视觉效果最接近真实水彩,但性能预算极高,不适合需要大量实时渲染的场景。适合追求极致品质的单机叙事项目。
一个常见的行业争论是「高保真水彩 Shader 的性能消耗是否值得」——这个问题没有统一答案,取决于项目的整体目标平台和技术栈。但对于大多数独立游戏而言,中等方案在视觉效果和性能之间提供了最佳平衡点。
编辑观点:技术服务于美学,而非美学屈就于技术
(以下为 Xmohe 内容团队的明确立场。)水彩风格的魅力恰恰来自它的不完美——手工绘制时的偶然渗色、笔触之间的不均匀干燥、甚至是画笔在粗糙纸面上留下的不规则痕迹——这些都是数字精确性难以复制的。因此,我们在设计水彩 Shader 时的首要原则应当是:用技术手段去保留这些「不完美的有机感」,而不是试图把它们全部抹平为完美的数字化结果。实践中这意味着允许一定程度的噪点和随机性存在于最终输出中,而不是用过多的后处理去「修正」水彩本身该有的样子。这也是为什么很多追求最高视觉品质的小团队仍然选择大量手工绘制而非纯程序化生成——即使程序化工具已经极其先进,真正的手工触感仍然是技术难以完全替代的。
初级用户路径:3 步启动水彩 Shader 研究
如果你是刚开始了解水彩渲染的美术设计师,按这三步走能在 1 周内建立基本认知。
第一步:选一个现有开源水彩 Shader 作为起点研读。推荐关注 Unity Asset Store 上的开源实现和 GitHub 上的 shader Toy 案例。不要从零写——先理解别人的实现思路,再逐步深入每一个模块的原理。
第二步:理解三个核心概念——扩散(扩散是如何通过模糊和透明度实现的)、叠色(alpha blending 如何模拟多层颜料)、纸张纹理(纸张贴图在哪里叠加、以什么强度叠加)。这三个概念构成了所有水彩 Shader 的共同基础。
第三步:在你的项目中做一个最小可行实验——导入一个开源水彩 Shader,替换为你的素材资产,调整扩散半径和噪声强度两个参数,观察变化。这个动手实验的价值远大于阅读十篇论文。
中级用户路径:水彩 Shader 的四维参数化决策框架
对有实际开发经验的技术美术,以下四个可调维度构成「水彩 Shader 选型调音台」。
维度一:扩散精度(低 ↔ 高)
扩散算法的复杂程度。低精度用简单的高斯模糊,高精度用带速度场的各向异性扩散。精度越高视觉效果越接近真实水彩,但计算量呈线性增长。建议从低精度起步,验证视觉效果合适后再考虑升级。
维度二:叠色模型(加法 ↔ 光学)
颜色叠加的准确度。加法混合简单高效但不够真实;光学混合(Kubelka-Munk 近似)更真实但开销更高。建议叙事驱动型项目用光学模型,动作类项目用加法混合以节省性能预算。
维度三:纹理来源(扫描 ↔ 程序化)
纸张纹理的获取方式。扫描真实纸张纹理有最真实的效果但也面临版权和泛化性问题;程序化噪声免费灵活但调试成本高。务实方案是两者的混合——用少量扫描纹理作为基础模板,再用程序化噪声添加随机扰动打破重复感。
维度四:多 Pass 数量(1 ↔ N)
Shader 执行的渲染 Pass 数量。1 Pass 最快但功能受限,N Pass 功能完整但 Draw Call 和帧率成本成倍增加。独立游戏建议在 2–3 Pass 区间内取得平衡,超过 5 Pass 就需要仔细评估项目整体性能预算了。
组合心法:「精度 × Pass 数」是最关键的二维组合——高扩散精度 + 多 Pass 带来最好的视觉效果,但也最贵。建议将高保真方案留给核心场景(主角特写、重要 UI),外围场景用精简方案。这样既保证了视觉品质的一致性,又控制了总体性能开销。
常见问题
Unity、Unreal、Godot 哪个引擎做水彩 Shader 最合适?
从 Shader 编写灵活性看,Unreal Material Editor 原生支持较多节点,Godot 的 Shader 语言简洁直白,Unity 则需要通过 Render Feature 或 SRP 定制获得更好的控制力。但从社区生态和资源丰富度来看,Unity 拥有最多的水彩 Shader 开源项目和教程文档。如果团队已有某个引擎的经验积累,不必为了水彩效果特意更换引擎——任何主流引擎都能实现合格的水彩效果。真正决定最终效果的是算法选择和调优深度,而非引擎本身。
湿染扩散算法真的需要用流体仿真吗?
严格来说不需要。大多数游戏中的「湿染」效果只是扩散方向的伪实现——通过简单的径向模糊加噪声扰动就能达到相当好的视觉效果。真正的流体仿真是用于影视级别的离线渲染,其计算复杂度不适合实时应用。如果你看到某些宣传声称使用了「真实流体模拟」,大概率是在离线烘焙阶段做了预计算,实时运行时仍使用的是查表或插值方案。这一点需要在讨论时保持清醒。
如何让水彩效果在不同光照条件下保持一致?
这是一个长期困扰水彩 Shader 设计者的难题。水彩的本质是一种表面材质效果,但传统上它并不遵循标准 PBR 材质的光照反射规律。解决方案之一是:将水彩效果作为 Post Process 层的叠加处理(放在光照计算之后),这样可以确保无论场景光照如何变化,水彩本身的视觉效果始终保持一致。缺点是这种方法无法利用场景的动态阴影和 GI 来增强水彩的真实感,是一种折中选择。
结语:水彩 Shader 是一场永无止境的优化旅程
实时水彩渲染领域没有一个「终稿」。随着硬件能力持续进步、渲染管线不断演进、AI 辅助工具日益成熟,水彩效果的逼真度和效率都在持续迭代。对于独立开发者而言,最重要的是不要被「完美水彩」的执念拖累——一个能在目标平台上稳定运行的中等品质水彩 Shader,配合精心设计的手绘资产,往往比一个追求极致保真却因性能问题被迫降低分辨率的「高性能」方案更能打动玩家。技术与美学的平衡,永远是一个动态的过程。