ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Unity卡通渲染全解析:从色阶光照到描边技术的完整实战指南

Unity卡通渲染全解析:从色阶光照到描边技术的完整实战指南 Unity 卡通材质这块我前前后后折腾了小半年从最初的瞎调参数到后来把光照模型、描边方案、渲染管线的适配全部理清楚中间踩了不少坑。这篇文章就把我这段时间积累的东西全部倒出来从思路到落地从选型到排错尽量说得直白一点希望能帮你少走点弯路。不管你是刚开始接触卡通渲染还是已经在做但总感觉效果不对这篇都应该对你有用。1. 卡通材质从思路到落地先把需求聊清楚很多朋友一上来就搜“Unity卡通材质Shader”然后找一段代码丢进工程结果发现效果很怪——要不就是颜色死板得像塑料要不就是描边粗得吓人要不就是光照一转动阴影就乱闪。归根结底是没搞明白一件事你想做的“卡通”到底是哪种卡通1.1 卡通的“卡通”到底卡在哪卡通渲染在图形学里叫Non-Photorealistic Rendering也就是非真实感渲染。它的核心不是还原现实而是“概括”——用更少的颜色层次、更明确的边缘、更夸张的明暗对比去模拟手绘动画的视觉感受。最常见的卡通风格可以拆成三个维度色阶化光照、边缘描边、高光形状控制。色阶化光照是卡通材质的灵魂。真实感渲染里光照从亮到暗是连续过渡的而卡通风格通常把过渡压缩成两三个台阶像是赛璐璐风格只有亮面和暗面暗面再叠一层二次阴影最多再加一点环境光补色。这种效果的原理是用NdotL法线方向点乘光源方向的结果做一个阈值判断然后映射到不同的颜色块上。说白了就是——不让你看到渐变只让你看到分界。边缘描边则是为了还原手绘线的感觉。很多卡通资产在建模阶段并没有单独画线稿所以需要通过渲染手段在物体边缘生成一圈线条。描边做得好不好直接影响整个画面的“手绘感”。做得过了脏做得不够糊。高光形状控制也是很多新手忽略的点。真实材质的高光是物理计算出来的位置和形状都很“老实”。但卡通风格的高光往往是美术手动摆上去的形状规则、边界清晰像漫画里那种圆形的、星星形状的光斑。所以你看卡通材质不是简单地把PBR贴图换成一张漫反射贴图就完事它是一个“概括光照”的系统工程。你要先想清楚自己的项目是二次元赛璐璐、美式卡通、还是风格化手绘三种风格对色阶数量、描边粗细、高光形状的要求完全不一样。1.2 三条路线怎么选Shader Graph、ASE、手写Shader定好风格之后接下来就是工具选型。Unity里做卡通材质主流有三条路线Shader Graph、Amplify Shader EditorASE、手写ShaderLab/CG代码。我三条都用过说下实际感受。Shader Graph是Unity官方在URP/HDRP管线下主推的可视化方案。它的优势是节点化操作变量改起来方便团队协作时美术同学也能上手调整。做卡通材质的大部分节点逻辑——比如用Lerp做色阶过渡、用Step做硬阈值、用GrabPass做透射——都能在Shader Graph里直接连出来。缺点也明显复杂逻辑写起来很绕比如做多Pass描边、自定义顶点动画、复杂的曲面细分可视化节点会让你晕头转向。而且Shader Graph在不同Unity版本里节点命名和功能差异很大2021 LTS和2022 LTS至少有两三处节点变化只换版本就要修半天。ASE是老牌的可视化插件。它的强项是可以直接嵌进旧版ShaderLab而且生成代码的可读性比Shader Graph好不少修改起来更灵活。很多独立游戏团队的卡通渲染都是ASE做的网上能找到大量插件版的卡通材质模板。不过ASE对URP的适配要看版本有些老版本生成的Shader在URP下会有兼容问题而且它不是官方工具升级Unity后失效的风险一直存在。手写Shader是进阶之路。看起来门槛高但实际上手写Shader反而能让你对渲染管线有更深的理解遇到问题时能精准定位。比如描边Pass要开Cull Front、反向法线扩展顶点这种逻辑用代码写非常直观一个Pass、两句顶点偏移、一行剔除设置就搞定了。而用Shader Graph做相同的功能要考虑视图方向、顶点位置变换矩阵节点连线得多出一大片。我的建议是项目周期紧、以美术驱动为主的团队选Shader Graph或ASE个人想深入研究卡通渲染原理的务必手写一遍。2. 核心基调渐变光照与色阶化的实现细节无论你选了哪条路光照处理都是卡通材质的大头。如果你只记住了这篇文章里的一件事那一定要是Ramp贴图——卡通光照的终极武器。2.1 Ramp纹理的拆分逻辑Ramp贴图也叫渐变纹理是一条从暗到亮的渐变色带。传统的做法是把它当成一个一维纹理用NdotL作为UV坐标去采样这样光照在明暗过渡时就会沿着Ramp的颜色走。但实际项目里Ramp往往不会单独做一张一维贴图而是把暗部色和亮部色分开控制。暗部色通常偏冷、偏灰、饱和度略高亮部色更接近固有色。因为暗部在视觉比重上低加一点蓝紫调能模拟环境冷光亮部则要保留角色固有色避免被光打“透”。色阶的数量是另一个关键决策。赛璐璐风格通常只做两档——亮面和暗面中间加一条非常窄的硬过渡。如果过渡太宽会像水彩晕染过渡太窄又会像闪屏一样闪烁。我常用的做法是NdotL计算完之后用smoothstep控制过渡带宽度。比如smoothstep(0.35, 0.4, NdotL)这样阴影分界线只有0.05的宽度干净利落。想要三档甚至四档色阶可以用多个Step节点叠加或者直接在Ramp贴图里做多段色带。但要注意色阶越多画面越接近真实卡通感反而会减弱。二次元日系风格里三档就到头了——阴影、半影、高光再往上一档就是美式漫画的硬线条风调性完全不同。2.2 前向渲染多光源的处理方案卡通材质在单主光下是最容易做好的。用GetMainLight拿到主光源方向算NdotL套Ramp完事。但实际游戏里很少只有一盏灯——比如角色站在路灯下侧面还有补光甚至还有实时点光源。这时候问题就来了多光源叠加如果用传统Blend方式叠加阴影色阶会被打乱明明暗面已经压暗了补光一照又亮回来画面一下子“灰”了。我的方案是“最优主光”策略。只让主光源参与卡通色阶计算其他辅助光源统一当作“附加亮度”附加到亮面色上但不参与暗面判断。这样角色转身时主光源决定明暗分界补光只是稍微提亮暗部不会破坏色阶的纯粹感。具体怎么实现在URP里可以通过LightLayer或者自定义LightMode标签决定哪些光源走全计算哪些只做附加。手写Shader里也可以手动指定只在某个Pass里执行主光计算其他光源Pass统一走一种简单的噪声叠加。这样实现出来的角色灯光效果比直接套用多光源混合自然得多。2.3 阴影与半影的过渡控制Unity的实时阴影默认是硬阴影对卡通风格来说其实是个优势——直接拿阴影贴图采样得到0或1刚好可以做色阶的暗面边界。但问题是实时阴影的边缘在物体表面上会有自阴影瑕疵尤其是模型的法线方向变化剧烈时阴影边缘会产生很脏的条纹。处理办法有两个方向。一是对阴影贴图采样结果做模糊——不是图片空间模糊而是采样时用偏移多次采样取平均得到一个半影过渡带。这个半影过渡带的宽度要控制得很窄大概2到4个纹素即可。另一个方向是混合“伪阴影”。也就是不依赖实时阴影而是用光照方向和投影矩阵计算一个简化版的投影比如在角色脚下加一个扁平的平面阴影卡通角色和地面接触处的接触阴影往往比真实的实时阴影更能突出手绘感。这个伪阴影不需要用到深度贴图用脚本或Shader计算出角色底部投影到地面的范围即可性能开销很低。我第一次做接触阴影时用的是Screen Space Shadow Mask叠加效果好但移动端开销偏高。后来改成用SDF符号距离场在脚底画椭圆阴影性能上去了视觉也干净。不过SDF要预计算地面形状不太适合地形复杂的场景取舍要看项目实际情况。3. 描边技术怎么做才不会让模型“糊成一团”描边是卡通材质的另一半灵魂。刚接触图形学的朋友往往会误以为描边就是“把模型沿着法线方向扩大一圈”实际做起来细节非常多稍微处理不好就会出现断线、锯齿、穿模、粗细不均匀等问题。3.1 背面放大描边的两大核心参数目前最主流的描边方案是“背面宽度描边”在渲染阶段单独画一个Pass开启Cull Front让相机只看到模型背面的多边形然后把这些多边形的顶点沿法线方向向外挤出一点点再用纯色填充。因为这个Pass绘制的是“内部”还是“外部”画的是背面扩张后的壳从正面看刚好露出一圈边线。这里有两个参数决定了描边质量挤出距离和法线来源。挤出距离一般用模型包围盒的百分比来控制。我做了一个可调属性默认值是模型大小的0.3%到0.8%。太细了高分辨率屏幕上等于没描边太粗了整个模型像被橡皮泥包了一圈。不同物体要分开调——小道具0.3%角色0.5%大型怪物0.6%到0.8%。法线来源尤其重要。有些早期写法用的是物体自身法线但实际上模型在建模软件里往往没展平法线法线不是平滑过渡的挤出后就会出现棱角分明的“爆边”。解决办法是把模型的导入设置里法线模式改为Calculated并把Smoothing Angle调到合适值一般是40到60度。如果模型是Low Poly风格甚至可以把角度设成180度强制所有法线平滑描边效果会更柔和。3.2 屏幕空间描边的适用场景背面描边虽然简单但有两个硬伤一是描边粗细会随着相机距离变化离远了线细到看不见离近了线粗到像灾难二是凹形部位——比如手指缝、衣服褶皱——背面扩张后容易遮挡正面细节。如果项目场景是固定摄像机视角比如2.5D视角或俯视角背面描边够用。但如果摄像机可以自由旋转和拉近拉远建议试试屏幕空间描边。屏幕空间描边的思路是把模型渲染一遍提取深度法线信息然后对像素周围做采样发现法线突变或深度差异大的地方就标记为边缘并填充描边色。这样做的好处是线条宽度始终保持在屏幕像素级别不受距离影响而且能精确勾出轮廓和细节褶皱。缺点是性能开销大——一张全屏的深度法线图和多次邻域采样在移动端是笔不小的开销我一般在PC端或高端移动设备上才用。还有一种折中的方案是“基于视角点乘的边缘光描边”——把视线方向和法线方向的夹角作为边缘检测依据夹角度数越大越接近边缘。这种方案虽然简单但只能描出模型轮廓描不了内部褶皱效果比屏幕空间差一些适合低配设备。3.3 描边断层与法线平滑的坑描边断层是我遇到的最常见问题——模型的某些部分线条突然中断尤其是手指、头发丝、布料褶皱等弯折剧烈的区域。排查了无数次后我发现主要还是模型法线问题。一是建模软件里的法线本身有硬边比如眉毛和头发之间的连接处法线本来就是断的二是Unity导入时自动平滑的角度设置不合理把不该平滑的面给平滑了导致描边Pass里顶点法线方向不一致挤出后互相打架。解决办法在建模软件里就给模型单独烘焙一套用于描边的平滑法线外加法线导出时放在UV3或UV4通道里Shader里用这套法线去挤出顶点。这样描边完全绕开原始法线的杂乱线条会稳定很多。或者直接在Unity里用脚本把顶点法线重新计算并覆盖到模型的法线槽里但这样会影响PBR光照表现不太推荐。还有一个细节是描边Pass里要把深度偏移关掉或调小。如果没有做偏移描边壳层和正面模型会发生Z-Fighting近景会看到线条在“抖动”。打开一个很小的Depth Bias就能解决推荐值在-1到-0.5之间。4. 实操演示URP里用Shader Graph搭一套全流程卡通材质前面讲了一堆理论现在来点实际的。我以URP Shader Graph为例带大家从头搭一套可用的赛璐璐风格卡通材质。这套方案兼顾了开发效率和可调性挺适合中小团队直接拿来做项目。4.1 工程环境与初始设置先交代环境Unity 2021.3 LTSURP 12.1版本Shader Graph版本对应。这个组合比较稳定节点命名和功能都有较好的兼容性。打开工程后确保Project Settings里Graphics设置的是URP管线资源。在URP Asset的Renderer配置里记得勾选Depth Texture和Opaque Texture。Depth Texture做描边和边缘检测时要用Opaque Texture做半透明互相遮挡效果时要用。这两项不开启后面很多功能会直接没反应。4.2 基础色、渐变光照、描边的组合实现在Project窗口右键创建Shader Graph选择URP Lit Shader Graph。打开后首先把Surface Type设为OpaqueWorkflow设成Metallic因为我们要用Metallic和Smoothness控制高光形状。Metallic全设0Smoothness看情况控制高光锐度建议0.6以上才好出高光感。创建三个关键子图光照、阴影、描边。光照子图取Main Light方向法线向量NdotL dot(法线方向, 主光方向)然后连接smoothstep设置两个值控制过渡带。smoothstep的Edge值可以暴露给材质参数最终通过Lerp把高光色和阴影色混合。阴影子图如果采样实时阴影贴图用Main Light Shadowmap节点输出一个0到1的值。配合NdotL的色阶结果一起用——NdotL是光照方向逻辑阴影是物体间遮挡逻辑两者组合起来才能表现物体之间的遮挡。描边子图具体实现要借助自定义函数节点因为Shader Graph节点面板里没有一个直接的“背面顶点挤出”节点。你可以把下面这段代码写成一个HLSL文件然后在Shader Graph里用Custom Function节点引用它。void OutlinePass_float( float3 positionOS, float3 normalOS, float outlineWidth, out float3 positionOS_Out ) { positionOS_Out positionOS normalOS * outlineWidth; }再把材质主节点的Surface Type改成不透明Render Face改成Back这样这个材质看起来是正面模型实际上额外画一层壳颜色设成描边色就完成了。但要注意Shader Graph里一个材质默认同时输出正面和背面如果只想要背面壳需要借助两个Pass的手写Shader扩展。这里我提供另一个思路直接在材质上做一个独立的“描边Shader变体”用第二套渲染队列来画壳。初学者最容易在这里卡住——Shader Graph默认没法方便地单独画背面。我的做法是单独的描边材质用最简的手写Shader实现同时给主材质挂一个脚本渲染完主材质后自动渲染描边材质。这种方式灵活而且描边可单独控制粗细和颜色。4.3 把材质接进游戏阴影、自发光、双面处理的联动材质建好之后导入一个带贴图的角色模型把主材质和描边材质都挂到不同的材质球上。此时角色应该已经有卡通色阶光照也有一圈清晰的黑色描边了。阴影部分需要检查角色是否正确接收环境阴影。URP默认的阴影接收会把阴影直接叠在颜色上出来的效果很平。你可以设置Main Light的Shadow Strength到0.7左右再配合我们前面说到的暗面色调节让阴影色的色相偏向冷色调会比默认的暗灰色耐看很多。自发光是很多卡通角色要用的比如眼睛、武器发光带。在Shader Graph里加一个Emission输入直接连一个自发光贴图即可。但要注意Emission的值如果大于1URP的Bloom会把它当成高亮区域这在卡通风格里是好事但小心别让整张脸都发光——我见过有的项目把所有亮部贴图都塞进Emission结果角色看起来像节能灯管全场光照全部失效。双面问题也是常见需求——头发片、布片、披风往往开了双面显示。在URP Lit Shader Graph里Surface Options里设置Render Face为Both即可。但使用双面显示时背后那一面因为法线方向是反的光照计算会出错导致背面的颜色完全不对。解决办法是再加一个法线翻转逻辑在片元着色阶段判断两面如果视角方向和法线方向点积为负就把法线翻转过来重新计算光照。这个操作在Shader Graph里的实现是把几何数据节点里的Normal Vector取一遍再用视向量和它做点积结果为负就取反。连好之后无论正面背面光照表现就一致了。5. 常见问题与排查技巧实录最后这部分是故障排查和性能调优。我把这几年做卡通材质过程中遇到的问题整理成一个列表多数都有对应解决方案希望能在你遇到类似问题时快速帮上忙。5.1 描边在远处断裂或近处穿模描边断裂多出现在法线硬边和低精度模型上。解决办法是开启描边法线的自动平滑或者把模型的Smoothing Angle提高到60度以上。如果还是断那就只能烘焙外卖法线到UV通道了。穿模出现在描边壳与模型自身交叉的地方比如两个手指靠很近。可以尝试降低描边宽度或者对描边材质开启Infinite Projection模式让描边归一化到屏幕空间后再偏移。URP里需要在Shader里手动处理这个投影矩阵比较麻烦但效果提升明显。5.2 阴影色阶出现条纹或者闪烁条纹一般是阴影贴图精度不够或者ShadowBias没调好。推荐把ShadowBias调到0.1以下NormalBias根据模型大小微调。闪烁则多发生在强转折边缘比如头发和脸的夹角属于深度贴图精度极限问题。解决方案是拉高阴影贴图分辨率或者给卡通材质用更高精度的深度偏移值。5.3 双面材质背面光照发黑这种情况几乎都是法线没有翻转导致的光照异常。确认一下你是否按照4.3里的方法做了法线双面翻转不是只有Cull Off就能解决的。双面的法线翻转可以用渲染的VFace语义来判断——正面是1背面是-1拿到这个值后法线乘以它就好了。5.4 移动端卡通材质的性能调优移动端做卡通材质最优先要控制的是Shader的复杂度。我的建议是不要用屏幕空间描边改用背面描边不采样过多的实时阴影用平面伪阴影代替Ramp贴图尺寸控制在128x128以内能完整体现色阶即可不开启HDR和Bloom或者用低档Bloom阈值让高光区域更强。多光源场景严格控制光源数量卡通材质每多一盏参与计算的光源性能就断崖式下降。所以尽量只保留一盏实时主光灯其他光源用烘焙或LightProbe补光这也符合2.2里讲的主光策略。5.5 Unity版本升级或管线切换后的材质失效Shader Graph节点在不同版本间有迁移问题ASE插件也需要跟着版本更新。我的经验是主力项目升级前先复制工程到分支测试一遍跑通后再合入主线。如果管线从内置渲染管线切换到URP旧Shader基本全军覆没需要重新编写。所以新建项目时务必先确定渲染管线再动手做材质省得后面推倒重来。我个人在实际操作中的体会是卡通材质最忌讳“一步到位”。刚开始的时候我的Ramp贴图做得太丰富色阶过渡太柔结果角色的脸始终像打了柔光滤镜一样离“二次元”差得很远。后来狠心把所有渐变全部砍掉只剩两个硬边色块角色的脸立刻“立”了起来那种手绘感才慢慢出来。建议你拿到任何卡通材质第一步先做减法——把色阶数压到最低把描边宽度先调到体感偏细再一点点加回去。每一次加法都要问自己这个参数是让画面更“手绘感”了还是只是让画面更“高级”了卡通渲染的好看往往不是往真实感方向调而是往“概括”的方向调。这篇文章基本覆盖了Unity卡通材质的全流程光照逻辑、描边方案、URP里的实操步骤、常见问题排查。如果你正卡在某一步可以对照着检查自己的材质设置。做完一版之后试着把它放到不同光照环境里跑一跑你会有新的理解。
返回列表