二次元卡通角色渲染实现

基本原理

文中蓝色字体为应用于本案例的技术

一、效果分析

这里的卡通效果针对日式卡通渲染 Cel Shading

  • 首先,角色有明显的轮廓线。
  • 其次,角色身上的色调呈色阶式呈现,有大片的纯色色块和明显的明暗交界线。
  • 突出的高光区和边缘光
  • 为了丰富效果,加上类似边缘光的高光。

二、描边

  • 作品集中的角色渲染使用的是基于几何生成方法的描边,还有其他很多描边方法不做过多的赘述。

1.基于几何生成方法的描边

描边是一个单独的几何体,在做完正常渲染的部分后,再在一个正面剔除的pass中,将顶点沿着顶点法线方向膨胀一段距离(在观察空间),然后用描边色输出。这个描边的pass放在正常渲染的pass之后可以用深度测试过滤掉不必要的像素,防止像素被重复绘制。

ps1:“描边粗细随摄像机拉近而变粗”问题:

描边宽度是相对于世界空间不变的,所以相机拉近会变粗,可以将法线外扩调整为NDC空间。

ps2:“非平滑物体法线断裂”问题:

将断裂处的法线重新平均计算,写入模型的切线空间里。(只有切线空间和法线空间才能随模型随骨骼动画而运动)。

2.基于视角方向的描边

用视角方向和法线方向的点乘来估计模型的边缘。缺点是边缘线的粗细变化不好控制。

3.基于后处理的描边

这种描边比较适合应用在场景中。在作品集的医院场景中我是用的就是基于后处理的描边技术。

获取图片中如果一个像素与相邻像素的深度或法线相差的很大,就将这个像素定义为边缘。法线信息和深度信息可以在Gbuffer中的法线图和深度图中查找,然后用边缘检测算法去寻找这些像素。但是这种方法的缺点是会忽略一些模型的边缘,比如桌子上的一张纸就无法描边。

4.内描边

另外本方案还使用了一张内描线贴图来增加描线的细节。内描边在尽量使用横平竖直的uv采样,可以有效避免锯齿的出现。

三、漫反射

1. 从多色阶降到低色阶。

本方案只考虑了一个方向光的光照效果。

漫反射效果是用了一张亮部贴图和一张暗部贴图来分别控制亮部和暗部的颜色。想要把平滑过渡的漫反射变成有明显边界的色阶,就要把漫反射从0到1的过渡变成突然的“跳跃式”过渡。

  1. 本方案用到的方法是用一个阈值控制跳跃过渡的位置。用smoothstep函数和半lambert求得一个范围很小的从0到1的过渡(防止边缘的锯齿),然后用这个值去lerp暗部和亮部的贴图。
  2. lambert采样ramp贴图,ramp图是一维色彩查找表。也可以用lambert和phong的二维数采样二维的颜色查找表。
  3. 为漫反射增加lightmap,g通道与lambert相加再smoothstep,使衣服的凹陷等位置的更难以作为亮部呈现。

2. 插值得到的色阶是连续的,但是亮暗面分别是冷色调和暖色调。

四、高光反射

  1. 本方案用一张贴图的rgb通道分别控制高光强度、高光偏移量(主要是头发阴影的偏移)、高光范围。高光用normal向量点乘view向量(这样点乘是为了表现金属、皮革所做的trick),色阶化方式与漫反射相同。
  2. 边缘光基于费涅尔产生的背面补光,为角色的非皮肤区添加边缘光。使用非皮肤区的mask贴图。

五、环境光

  1. 本方案中,ao信息存储在顶点色的r通道中,将顶点色信息在分别与漫反射和高光相乘。
  2. 加实时阴影(atten)效果并不好,面部阴影很奇怪。
  3. 卡通角色通常在某些特定角度光照下才能有比较好的效果,在开放世界中为每个角色附加一盏自己的灯光方向,和角色一起转动。

六、优化

1. 面部法线替换

面部由于法线方向变化比较复杂,在某些光照角度会有阴影很“脏”的现象。在模型中改变面部法线朝向,把一个球体的法线替换进去,使其平滑。

2. 控制外轮廓描边粗细不变

把法线外扩的距离转换到在NDC空间的距离再外扩。

3. 描边在有明显转角的地方断掉

对模型外扩使用的发现数据进行修改。把法线数据进行平均计算,再把新法线写进切线空间里。




升级URP管线下的二次元卡通渲染

一、模板准备

修改升级URP管线必备的设置

 Tags {"RenderPipeline" = "UniversalPipeline"}

#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"

HLSLPROGRAM
ENDHLSL
等等...

二、描边Pass

URP管线下不能直接添加pass,否则会覆盖前一个pass,需要定义不同的tags。

//第一个pass的tags
Tags{"LightMode" = "UniversalForward"}

//第二个pass的tags
Tags{"LightMode" = "SRPDefaultUnlit"}

第二个pass让顶点沿法线向外膨胀,并做正面剔除,效果对比如下:

描边优化:

1.

三、性能优化

 1.拆开两个pass(urp渲染管线定制)

每个身体部位要调用两个pass导致passcall过多,对性能造成影响

若有收获,就点个赞吧

猜你喜欢

转载自blog.csdn.net/weixin_64540465/article/details/123835791