跳到主要内容

控制描边形状

什么是描边和笔触

描边是让角色看起来像手绘的重要因素:

img

笔触是指一段描边起点到终点之间的宽度或颜色变化, 形成笔触的物理原因是笔尖在纸上压力的变化:

image-20240806231616172image-20240806231625666
无笔触, 描边等宽有笔触, 笔画的起点和终点更细

宽度一致的描边比较容易实现, 带笔触的描边实现比较困难, 而是否有笔触则是让描边看起来更像手绘的关键因素, 因此能否自动生成笔触一直是描边技术的分水岭.

描边也有不同的类型:

image-20230415230853374

描边和笔触的实现方法

下文列举了一些描边和笔触的实现方法.

MooaToon实现了GUILTY GEAR的分享中提到的外描边内描边:

- 外描边

外描边指描边在模型的外部, 也就是上图中的"Outline"类型. 是在渲染完角色之后再渲染一次角色背面模型, 同时沿法线方向挤出. 这是最经典的也是使用最广泛的描边技术.
此技术的缺点是挤出用的法线必须是平滑的, 否则描边在硬边处会断开. 并且描边类型单一, 细节不是很多.

由于模型硬边处的法线是断开的, 直接沿着法线挤出会造成描边断开, 所以描边法线需要重新计算:

烘焙描边法线方向

- 在UE中烘焙

  1. 保存所有修改
  2. 在角色骨骼网格体上右键: Scripted Asset Actions > Mooa Toon > Bake Smoothed Normal and Curvature:

- 在Houdini中烘焙

  1. 使用mooa_bakeSmoothedNormalToUV34节点烘焙描边法线
  2. 使用mooa_outlinePreview节点预览描边
  3. 确保已启用Display Option > Optimize > Remove Backfaces

在UE中检查烘焙的数据

你可以在UE中检查所有已烘焙的数据:

  1. 确保已正确设置Outline Material
  2. 将你的角色Actor设置到BP_MooaLookDevTool > Character Actors
  3. 勾选Show XXX以显示对应的烘焙数据

颜色(RGB, 0 - 255)代表方向(XYZ, -1 - 1), 以Show Baked Smooth Normal WS为例, 如果烘焙的数据正确, 颜色应该显示为平滑的世界空间方向, 不应该出现硬边.

绘制顶点色控制描边宽度

GUILTY GEAR中使用顶点色作为描边宽度, 从而在局部模拟笔触:

image-20240807224549061image-20240807224730920
带笔触的外描边用于控制宽度的顶点色
image-20240807224815969image-20240807224824810
肩膀处无宽度调整肩膀处有宽度调整

示例中的Unity Chan是在Houdini中绘制的顶点色:

image-20230416014146252

左: 调整前; 右: 调整后

提示

你也可以在BlenderMaya等DCC软件中绘制顶点色.

- 在UE中绘制

你可以直接在UE中绘制顶点色, 并实时预览结果:

- 在Houdini中绘制

  1. 选择并启用attributePaint_face_vertexColor_alpha节点
  2. 点击Reset All Changes
  3. 选择需要绘制的Group
  4. 选择你觉得合适的光照模式

image-20240814001004788

  1. 按回车键进入绘制模式, 按左上角的说明在模型上绘制Alpha, 注意FG的值: image-20240814001600880

  2. 在右下角显示设置中, 确保已启用: Optimize > Remove Backfaces:

  3. Display mooa_outlinePreview节点, 并选中attributePaint_face_vertexColor_alpha节点, 然后启用材质显示即可实时绘制并预览描边:image-20240814003003573

  4. 绘制完成后使用OUTPUT_FBXOUTPUT_OBJ节点导出模型, 并导入UE.

然后描边材质中启用Use Vertex Color A as Outline Width, 你就能看到修改后的结果:

image-20230416043932387

常见问题

错误的描边形状

这种描边的原理是将网格向外挤出, 然后仅渲染其背面作为描边. 由于挤出方向是最后计算的, 在建模过程中可能难以发现问题.

以下原因都可能导致描边挤出方向错误:

  • 网格数据问题:
    1. 错误或者缺失的法线
    2. 错误或者缺失的UV
    3. 一个面的UV面积为0
  • 网格拓扑问题:
    1. 一条边的长度为0
    2. 一个面的面积为0
    3. 多于4个边的多边形
    4. 位置重合的顶点
    5. 多于2个多边形共用同一条边
    6. 距离很近的多层网格, 如果描边宽度大于网格间隙就会导致穿模
    7. 单面网格, 描边一定会在正反面交界处断开

一些建议:

  1. 在导出模型之前仔细确认数据是否正确, 是否有非法拓扑
    1. 你可以在Houdini的Geometry Spreadsheet面板中检查所有几何属性
    2. 确保在Houdini中使用了mooa_dataInit节点
    3. Houdini的Clean/PolyDoctor节点可以快速检查并修复非法拓扑
  2. 在UE中使用BP_MooaLookDevTool检查烘焙的数据
  3. 仔细检查描边出错的顶点附近的网格
  4. 避免给单面网格添加外描边
    1. 使用内描边替代外描边
    2. 如果一定要使用外描边, 务必确保正反面交界处的宽度为0
  5. 避免给距离很近的复杂多层网格添加外描边
    1. 使用内描边替代外描边
    2. 降低宽度

Alembic

虽然Houdini在导出Alembic时可以通过Additional UV Attributes导出多个UV通道, 但是UE导入Alembic为Geometry Cache时不支持多个UV通道.

由于Alembic通常只用于离线生产或过场动画, 所以你可以连同mooa_outlinePreview节点生成的描边网格一起导出到UE. 并且要确保导入设置中的Compressed Position Precision足够小.

- 内描边

与外描边相对, 内描边通常直接画在贴图上. 内描边和外描边相互配合可以实现很漂亮的描边效果.

该方法的有点是简单且可控, 但由于贴图有分辨率限制, 加上描边通常很细, 导致在近距离观察时描边会出现模糊和锯齿.

这些方法可以在不增加贴图分辨率的同时减少模糊和锯齿:

- 本村线抗锯齿

在GUILTY GEAR中, 本村・C・純也提出了一种叫"本村线"的方法, 通过特殊的UV布局和贴图, 可以不受分辨率限制在任何距离获得完美的内描边:

image-20240807230344217image-20240807230353543
用常规方法画在贴图上的内描边使用本村线获得的内描边
image-20240807230554102image-20240807230608290image-20240807230627758
本村线的UV和贴图远处观察本村线内描边近处观察本村线内描边
image-20240807230724190image-20240807230736775image-20240807230745817
常规方法的UV和贴图远处观察常规内描边近处观察常规内描边

该方法无需依赖渲染算法即可获得高精度的内描边, 且在不同引擎和渲染器间通用, 但是美术师的工作量非常大.

- SDF抗锯齿

还有一种方法通过将常规方法的内描边贴图转换为SDF贴图以提高精度并且宽度可控, 类似于基于SDF的高精度文字渲染.

MooaToon暂不支持此方法.

- 后处理描边

后处理描边是在屏幕空间内对深度/法线/颜色缓冲区做卷积计算得出的描边.

优点是全屏生效, 性能开销与场景复杂度无关, 且可以实现几乎全部类型描边.

缺点是难以精确控制局部描边.

如果需要精确控制描边可见性与宽度, 需要对渲染管线做一些额外开发, 例如二之国 (CG world 2018-06):

image-20240807231912200image-20240807231753490image-20240807231810858image-20240807231850311
固有色顶点色Mesh ID顶点色突变的地方会检测为描边

目前你可以直接通过插件获得后处理描边, 比如:

- Pencil+

Pencil+是电影行业常用的描边插件, 其代表着行业最高的品质, 可控性和易用性.

但只能用于离线用途, 且目前并无UE版本.

- 其他前沿技术

近几年学术界出现了一些新技术, 比如实时的带笔触的描边, 基于神经网络的描边等.

但离落地到工业界还需要一段时间.