卡通渲染 (Toon Shading)

17 / 17
实现一种非真实感渲染技术,通过将光照强度量化为离散的色阶,并通常结合边缘检测来模拟卡通或漫画书的视觉风格。

用 if-else 把连续的光照强度切成几个固定色阶,核心是这段代码:

下面拆解它。


卡通分级是什么

普通光照是连续渐变的——从最亮到最暗无缝过渡。卡通渲染把这个连续渐变"量化"成几个固定的亮度档位,就像只有几种灰度的印刷品。这样光影边界变得清晰硬朗,产生手绘或漫画的视觉风格。

代码里按 intensity = dot(normal, lightDir) 把亮度分成 5 个档位:0.2 / 0.4 / 0.6 / 0.8 / 1.0。


轮廓线怎么实现

轮廓线同样是视角技巧:

球体边缘处法线和视线垂直,dot(normal, viewDir) 接近 0,edge 接近 1。smoothstep 把这个值转成 0 到 1 的遮罩,thickness 控制轮廓粗细。最后用 mix(color, vec3(0.0), edgeFactor * 0.8) 把轮廓区域混合成黑色。


动画

光源方向随时间旋转:

阴影边界在球面上移动,你可以直观感受到分级的阴影是如何"跳变"的。


试着改一改

改动效果
把 5 个档位改成 3 个阴影更粗糙,更像简单漫画
outlineThickness 改为 0.2轮廓线变细
edgeFactor * 0.8 改为 edgeFactor * 1.0轮廓线变全黑

练习

练习区的 toonShading 函数已有 4 个档位(阈值略不同),轮廓线 thickness 也已设好,当前代码可以正常运行。尝试把 4 个档位的亮度系数(1.0, 0.7, 0.45, 0.25)改为(1.0, 0.6, 0.3, 0.1),观察阴影对比度的变化。

答案解析

toonShading 函数把 intensity = dot(normal, lightDir) 按阈值分级:

四个档位:高于 0.75 的区域最亮,低于 0.2 的区域最暗。阈值之间没有平滑过渡——这就是卡通效果的关键,边界是"跳"过去的,不是渐变的。

轮廓线 thickness 越大,黑边越粗;sin(u_time) * 0.08 让轮廓粗细轻微呼吸。

试着把最低档位的系数从 0.25 改成 0.0,看阴影区域会不会变成完全的黑色。

GLSL 代码编辑器

正确代码预览

当前代码预览