UE 卡通着色 卡通描边

前言

卡通着色

描绘色带

  • 与写实风格不同,卡通渲染的色带(阴影,中间调,高光)呈现多段式分布
    unreal engine 4 cel shading

描绘色带的方法

  • 最常用的方法是比较表面normal朝向光照方向
    unreal engine 4 cel shading

  • 根据点成结果即可实现多段色带,若大于-0.8取深色,否则取浅色
    unreal engine 4 cel shading

  • 缺点

    该方法有一定的局限性,因为它只是简单的考虑某光线和表面相交的情况,所以无法反映其他的光照影响以及无法接受其他物体的投影

后处理材质

  • 定义

    后处理材质提供一个方法——可以在渲染完成后继续修改场景的整体外观,包括景深、运动模糊和辉光等等

  • 启用

    把"Material Domain"改为"Post Process"
    image-20230525143631012

计算光照缓冲

  • 思路

    我们知道最终渲染生成的画面是通过\(DiffuseColor \times Light\)得到的,这一计算结果便是Post-process Input。现在已知Post-process Input 和 DiffuseColor,Light的计算也就不难了。剩下的事就是获得两个缓冲区的数据——Post-process Input缓冲区(无任何后处理的最终渲染画面)和DiffuseColor缓冲区

  • 获取Post-process Input缓冲区

    这里需要用到"SceneTexture"节点,并将"Scene Texture id"换位"PostProcessInput"
    image-20230525151252043

  • 获取DiffuseColor缓冲区
    image-20230525151502822

  • 效果

    照亮的区域接近白色,没照亮的接近黑色
    image-20230525153344854

创建阈值

  • 为了渲染色带,在这里我们设定当光照缓冲值>0.5使用正常的Diffuse Color,光照缓冲值<0.5使用\(\frac{1}{2}\)的Diffuse Color
    image-20230525154532690

应用后处理材质

  • 欲将后处理材质应用到场景中需要创建"Post Process Volume"
  • 步骤
    • 拖取"Post Process Volume"
      image-20230525155542831
    • 添加"Post Process Materials"
      image-20230525155954198
    • 默认情况下,Post Process Volume只作用它范围内的对象,为了作用整个场景,需要勾选"Infinite Extent"
      image-20230525160222818
  • 效果
    image-20230525160324902

Tonemapping

  • 目标

    上图看起来有些不对劲,因为我们是在Tonemapping后应用的Cel shader,而Post-process Input缓冲区是最终的渲染图形,也就是说这是Tonemapping后的,所以我们需要将该数据转至Before Tonemapping

  • 实现

    在shader根节点处,将"Blendable Location"改为"Before Tonemapping"
    image-20230525222809385

  • 效果

    很不错符合预期
    image-20230525223026009

分离卡通渲染

  • 目标

    目前我们的后处理材质运用在整个场景,但我们大部分时候只想卡通渲染只作用于角色,而背景等不受影响

  • 解决方法

    解决方法便是自定义深度(Custom Depth)

    • 什么是自定义深度

      场景深度存储每个像素到相机平面的距离,而自定义深度更加特殊,它针对于指定的几何体。若场景深度小于自定义深度,保持不变;若大于,采用卡通渲染

    • 启用自定义深度

      点击指定几何体,启用"Render Custom Depth Pass"
      image-20230525230531753

  • 实现
    启用后进行深度比较即可
    image-20230525231559715

  • 效果
    image-20230525231631322

丰富色带

  • 目标

    从上图可以看出,目前实现效果仅仅表现了明暗两部分,但我们想要更加丰富得色带,如增加色带数量、色带和色带间的过渡等

  • 解决方法

    我们将使用查找表(Lookup Table)来丰富色带

    • 什么是查找表

      和乘法表类似,通过查找乘数和被乘数来迅速定位结果。而对于卡通渲染来说,查找表是一张包含明暗梯度关系的纹理图,这就如同normal map一般它的效果更加好

    • 如何使用查找表

      目前,我们计算阴影是通过将DiffuseColor * 0.5,而现在我们将使用查找表的值,而不是0.5

  • 实现

    • 更改查找表设置

      • 禁用sRGB

        在UE中,会将使用sRGB的纹理转换为线性颜色(方便计算),而sRGB适用于描述物体外观的纹理,对于normal这类计算数学计算的纹理不应转换到线性颜色空间
        image-20230525233206957

      • 禁用平铺(tiling)

        平铺将在从边缘采样时引发问题,如从左边缘取样一个像素,它将尝试混合到右边缘
        想禁用平铺,需要将 X 轴平铺方法更改为"Clamp",y轴同理
        image-20230525233844594

    • shader实现
      image-20230525234813412

  • 效果
    五种不同值的查找表的效果
    image-20230525234850209
    image-20230525234913762
    image-20230525234935011
    image-20230525234955480
    image-20230525235022521

卡通描边

  • 卡通描边有两种方法可以实现,一种是二次渲染,一种是通过后处理边缘检测

二次渲染

  • 思想

    复制指定mesh并赋予它指定颜色(一般为黑色),再稍稍放大复制的mesh,最后用复制的mesh覆盖原mesh,多出的部分即为物体轮廓

  • 存在的问题

    • 只是这样简单的实现会发现复制对象的颜色会覆盖原本的mesh,如何解决呢?

      可行的方案是对复制的mesh先翻转法线方向,再启用背面剔除(因为法线定义了mesh的正面和背面),这一方案可行的关键在于这样实施后我们会得到mesh的内部而剔除mesh的外部

  • 优点

    • 生成的轮廓总能呈现清晰干净的线条
    • 能够通过简单地手动调整顶点来修改轮廓样式
    • 边缘线会随着模型距离的变化而变化
  • 缺点

    • Mesh数量翻倍,性能不友好
    • 不会过渡勾勒内部轮廓
    • 轮廓有因模型遮挡而被裁剪的风险
    • 能很好地处理凸表面,但在凹表面和硬表面边缘会产生离断空洞
  • 实现

    • shader根节点的"Blend Mode"改为"Masked"
      image-20230526105442052

    • "Shading Model"改为"Unlit"
      image-20230526105510731

    • 启用"Two Sided"

      "Two Sided"会禁用背面剔除
      image-20230526105609507

    • 翻转mesh
      image-20230527135333604

    • 复制mesh

      • 在"Content Drawer"中创建一个"BLue Printer class"组件,添加一个mesh组件(类型根据你的模型来定)
        image-20230527140107275
      • 在"Mesh"中使用模型的原材质函数,在"Outline"中使用Outline material
        image-20230527140044323
        image-20230527140141982
    • 效果
      image-20230527150840035

    • 优化

      有时候我们并不希望边缘线会随着模型距离的变化而变化,那又如何实现呢?

      • 利用"ViewSize"求得当前分辨率大小,再使用相机到物体的距离除以"ViewSize",最后乘上控制物体轮廓大小的因子
        image-20230527153805077

边缘检测

  • 边缘检测是一种用于检测图像中不连续区域的技术,这种不连续性体现在法线、颜色、深度、亮度等

  • 优点

    • 快速应用到整个场景
    • 节省开销
    • 在不同的距离下,描边粗细能保持相同
    • 后处理效果不会因模型的几何关系而被裁减
  • 缺点

    • 需要多种边缘检测算子来涵盖所有边缘情况
    • 易产生噪点。因为边缘总生成在变化非常大的区域上
  • 执行边缘检测的方法:拉普拉斯边缘检测算法(Laplacian edge detection)

    • 实质:计算一定范围内的斜度变化量

    • 计算过程

      • 卷积核
        unreal engine toon outline

      • 卷积运算

        这里计算的斜率为1,变化量很大,这意味着该区域可能是是一个边缘
        unreal engine toon outline

      • 整体运算
        unreal engine toon outline

  • 实现

    • 避免纹理分辨率对纹理的采样影响
      假设目前采样的目标纹理分辨率为100x100,在uv空间一个像素点大小就是0.01,如果要采样下一个像素点就需要+0.01,这正是问题所在。当纹理分辨率变为200x200,一个像素点大小为0.05,若依旧是+0.01,则会采样到第二个像素点

      image-20230527172341594

    • 使用的卷积核
      unreal engine toon outline

    • 边缘检测
      image-20230527175240455

    • 效果
      image-20230527180157262

    • 优化

      目前还有些问题:有些边缘只有细小的深度差异;背景也参加了边缘检测

      • 深度变化值大于4才显示边缘
        image-20230527185830168
      • 深度大于9000的像素不参与边缘检测
        image-20230527190508413
      • 效果
        image-20230527190523084
      • 最终实现图
        image-20230527190548278
    • 控制描边粗细
      为了控制描边粗细需要更大的卷积核,但这意味着更消耗性能(采样点增多),我们需要一种方法既能增大卷积核,性能也不差,该方法就是扩张卷积(3D视觉开发者社区 (orbbec.com.cn)这篇讲的不错)

      • 为什么使用扩张卷积?

        • 因为扩张卷积可以增大感受野,在检测中能对较大物体表现出较好的效果

        • 既能不增加采样个数,也能扩大卷积核

          扩张率定义卷积核因子的间距
          unreal engine toon outline

      • 实现
        image-20230527212026321

      • 效果
        扩张率为1、2、3对应的效果
        image-20230527212125369
        image-20230527212208736
        image-20230527212316087

      • 将线框和背景lerp
        image-20230527213423497
        image-20230527213452937

reference

UE4卡通渲染基础教程 Part1:Cel Shading - 知乎 (zhihu.com)

虚幻引擎中的后期处理效果 | 虚幻引擎5.0文档 (unrealengine.com)

Unreal Engine 4 Cel Shading Tutorial | Kodeco

UE4卡通渲染基础教程 Part2:Toon Outline - 知乎 (zhihu.com)

Constant Material Expressions in Unreal Engine | Unreal Engine 5.1 Documentation

3D视觉开发者社区 (orbbec.com.cn)

posted @ 2023-05-27 23:03  爱莉希雅  阅读(482)  评论(0编辑  收藏  举报