卡通渲染(Toon Shading)光照方案:从技术实现到审美一致性的完整路径
Half Lambert 技术原理 · Ramp Texture 驱动光照分层 · 轮廓线各路方案横评 · 日系/欧美/中国风卡渲美学差异
卡通渲染(Toon Shading / Cel Shading)是独立游戏视觉差异化最重要的技术手段之一。与写实 PBR 追求物理正确性不同,卡渲追求的是「视觉表达的清晰度」——用阶梯化的光照分布、明确的明暗分界线和风格化的轮廓线,在玩家视觉系统中建立一种清晰、干净、易于识别的画面语言。
本文从光照计算的最底层的 Half Lambert 改造出发,逐步深入到轮廓线各路方案的横向对比与审美一致性控制,为独立游戏开发者提供从技术实现到审美决策的完整路径。
Half Lambert 光照模型的原理与卡渲改造
标准 Lambert 光照模型的计算公式为:diffuse = max(0, dot(N, L))。这意味着当光线与表面法线的夹角超过 90° 时,光照值为 0——即「纯黑阴影区」。这个从亮到暗的过渡是连续的、线性的,这就是 PBR 写实光照中的正确行为,但对卡通渲染来说不够「干净」。
Half Lambert 改造引入了一个简单的非线性变换:将 dot(N, L) 的值域从 [-1, 1] 映射到 [0, 1] 并加入指数控制。在 Unity Shader 中:halfLambert = pow(dot(N, L) * 0.5 + 0.5, _Steps)。其中 _Steps 参数控制光照阶梯的数量——值为 1 时产生两阶(亮/暗完全二分),值为 2 时产生三阶(高光/中间调/阴影)。
这种改造的数学本质是:用指数函数将连续的光照值压缩为可数阶梯单元。视觉上的效果是画面中不再有模糊的灰度渐变,取而代之的是明确的色块分区。这就是卡渲「干净感」的技术来源。
Ramp Texture 驱动光照分层的 Shader 实现
Ramp Texture(渐变贴图)是卡渲光照分层的核心工具,它将 Half Lambert 的指数控制进一步升级为可美术自定义的光照查找表(LUT)。
实现思路:在 Shader 中,将计算出的 halfLambert 值作为 UV 坐标的 U 分量,采样一张 1D 或 2D Ramp 贴图,用采样结果替代光照计算。美术人员只需要编辑这张贴图,就能完全控制光照分布——从硬朗的二值化到柔和的渐变过渡,从冷色阴影到暖色高光。
Ramp 贴图的制作规范:
- 尺寸通常为 256×1(1D)或 256×4(2D,支持 4 种不同光照条件)
- 横向坐标从左到右对应环境光→主光方向→高光区域
- 纵向行可分别控制晴天、阴天、黄昏、夜晚的不同光照调色板
- 推荐使用 16-bit 精度 PNG(避免 8-bit 的色带感)
在 URP 的 Shader Graph 中,实现路径是:将计算出的 NdotL 值经过 Remap 节点映射到 0-1 范围后,连接到 Sample Texture 2D 节点的 UV 输入,Sample 的 R 通道输出作为最终光照系数。
轮廓线渲染技术四路横评
轮廓线是卡渲「灵魂」的一部分——错误的轮廓线方案会让精心搭建的卡渲光照效果大打折扣。
| 方案 | 实现复杂度 | 效果质量 | 性能开销 | 分辨率敏感度 |
|---|---|---|---|---|
| Rim Light 方案 | 低(Fresnel 节点) | 中(内发光式) | 可忽略 | 低 |
| Back-Face 描边方案 | 中(双 Pass 渲染) | 高(几何轮廓精确) | 中(额外 Draw Call) | 低 |
| Edge Detection(后处理) | 高(全屏 Pass) | 中高(非几何精确) | 高(全屏渲染) | 中 |
| SDF 描边方案 | 高(预计算 SDF) | 极高(亚像素精度) | 低(仅纹理采样) | 极低 |
独立游戏首选方案:Back-Face 描边方案。它在实现复杂度和效果质量之间提供了最佳的平衡。具体实现:在第一 Pass 正常渲染角色,在第二 Pass 将模型沿法线方向外扩一定距离(由材质参数控制描边宽度),以纯色渲染外扩后的背面。
关键参数:描边宽度在像素空间保持恒定(屏幕空间宽度),而非世界空间宽度。通过将宽度参数乘以屏幕高度来实现:outlineWidth = _OutlineWidth / ScreenHeight。这样无论摄像机距离物体多远,轮廓线的屏幕像素宽度保持不变。
日系、欧美、中国风卡渲的光照美学差异
卡渲不是单一的技术标准——不同审美传统对光照有不同的视觉偏好:
日系卡渲(原神、崩坏等):光影分层细腻,通常使用 3-4 阶的 Ramp 光照。阴影区域保留一定的冷暖对比——阴影色偏向蓝紫,高光区域保留暖色调。轮廓线较细(1-2 像素),且部分区域(服装褶皱、发丝)不画轮廓以保持通透感。
欧美卡渲(Arc System Works 游戏如《罪恶装备》):光照层次更硬朗,倾向于 2 阶(完全二值化)的光照分层。阴影区域几乎不保留中间过渡,追求贴近漫画原作的平面感。轮廓线较粗(2-4 像素),且在运动时保持一致的视觉权重。
中国风卡渲(近年国产二游的趋势):整体更接近日系基底,但在色调上更倾向于高饱和度的环境色,阴影区域保留更多的原始色相(不向蓝紫方向偏移太多),轮廓线宽度在 1-3 像素之间动态调整。在面部光照上更倾向于保留正面的柔和光照,避免角色面部出现大面积的硬阴影。
对于独立游戏开发者:在选择卡渲审美路线时,不需要严格遵循某一条路线。更务实的做法是:搭建一套支持多 Ramp 贴图切换的 Shader(通过 Material Property Block 控制),在开发过程中通过 A/B 测试决定最终的视觉方向。
Shader Graph vs HLSL 混合方案的权衡
Unity URP 中的卡渲 Shader 面临实现路径的选择:
纯 Shader Graph 方案:利用 URP 的 Shader Graph 节点系统搭建卡渲效果。优点是可视化、迭代快、美术人员可以直接参与调整。缺点是复杂逻辑(多 Pass 描边、顶点外扩)在 Graph 中难以实现,且节点图膨胀后的维护成本高于代码。
HLSL 混合方案:在 Shader Graph 中嵌入 Custom Function 节点,写入 HLSL 代码实现核心逻辑(Ramp 采样、Half Lambert 计算、轮廓线 Pass)。外部光照管理和材质属性暴露仍使用 Graph 节点。
推荐路径:对于初次尝试卡渲的独立开发者,从纯 Shader Graph 开始(URP 的 Lit Shader 模板已经包含基本的卡渲节点支持),当需要轮廓线或复杂的多 Ramp 切换时,再引入 HLSL Custom Function。不要在一开始就追求「完全手写 Shader」——保持迭代速度和试错空间比追求底层控制权更重要。