找回密码
 立即注册
查看: 567|回复: 0

【UE4 & UE5 卡通渲染】一、基础描边部分

[复制链接]
发表于 2023-1-18 13:24 | 显示全部楼层 |阅读模式
前言

由于学习原因,所以目前转移到UE引擎进行学习哩,Unity制作的内容可能就会慢慢减少了,但是并不是会说完全不更新这块捏;
1、自定义模板-后处理自定义蒙版描边(外描边)

延迟渲染着色;不要使用前向渲染;
后处理的原理其实就是将当前画面当成贴图,输出到一个我们看不见的面片上;
1.1 后期材质处理



    • 后期处理体积拖入场景中;并在细节设置中勾选无限范围,使其后处理能影响整个场景;







    • 创建后期处理材质;添加在RenderFeature栏目中的后期处理材质中;实现出各种后处理渲染的堆叠;(权重1为开启后处理材质,反之为关闭);





1.2 深度信息获取



    • 项目设置-渲染-postprocessing-custom depth-启用自定义模具值(enabled with stencil);需要使用存入深度信息模具的buffer,不启用的话该buffer里是纯黑的,也就是没有存入深度信息,后续计算会出现错误效果;



1.3 后期材质混合顺序



    • 后处理材质中:材质域:后期处理;设置后期材质混合的位置:Post Process Material-混合位置-色调映射前(ToneMapping)
    • 混合位置在色调映射后会导致画面着色错误以及抖动,改成色调映射前才是正常效果;



1.4 使用自定义模板抠图

1.4.1 基础准备



    • 在后处理中设置后处理材质;在材质中通过使用SceneTexture场景纹理节点中调用PostProcessinput0(也就是后期处理材质的输入)可以输出当前的画面





    • 选中场景场景中的某个模型,选中后在属性面板-Rendering中找到Render Custom Depth Pass自定义深度模板,将其勾选上;勾选了之后蒙版就开启了;即便是0它也是有输出的,也可以改成其他的(0——255),主要功能是用于抠图或者实现一些遮挡关系





    • 然后再观察模式中进入BufferVisualization-CustomStencil(自定义模板)





    • 可以观察到使用了自定义深度处理的物体会显示出来;





    • 在材质中输出自定义深度信息,检查遮罩是否会产生抖动;如果产生抖动了注意检查后处理材质插入渲染排序的位置;需要在ToneMapping前进行插入才会避免TAA抗锯齿产生的抖动影响



1.4.2 自定义模板抠图



    • 主要目的是通过自定义模板去制作遮挡关系(Mask),然后通过Mask来裁掉没用的区域;如果自定义深度值小于1都输出0;反之输出1;意为抠出素材



1.5 后处理自定义蒙版偏移描边

1.5.1 实现原理



    • 比如最开始的物体为一个圆;我们通过使用后处理来将这个圆往四周方向进行相同长度的偏移,然后再进行平均计算得到均匀的偏移;然后这四个叠加在一起的圆减去最开始初始位置的圆得到了描边的部分;



1.5.2 前期准备



    • 调整好后处理材质;以及后处理材质插入的渲染顺序位置;另外检查项目设置中的后期材质自定义深度模板是否开启;调整好之后可以开始后续的后期材质制作;





1.5.3 实现蒙版偏移描边



    • 首先通过屏幕空间坐标中的屏幕空间UV来采样场景颜色;将当前画面当做贴图输出到看不见的面片上;





    • 确定四个方向的偏移;加在屏幕UV上进行偏移





    • 接着与自定义深度内容结合在一起;也就像是最开始提到的圆进行偏移;此处是将画面进行偏移;然后都叠加在一起在进行平均处理





    • 由于需要使用一个描边参数来控制;让美术使用起来方便;所以得设置一个参数来控制描边的效果





    • 最后叠加好的效果来减去本身的自定义深度;得到偏移的深度描边;然后再通过Lerp线性插值来插入描边颜色;(SceneTexture默认采样是四维向量,也就是RGBA;Color是三维的所以需要将Input0拆分成RGB,还有CustomStencil也是;所以Alpha只读取一个以为灰度值即可





    • 对于针对屏幕距离产生粗细度不变的描边则通过在描边宽度那边乘入屏幕空间尺寸即可;





    • 当前只有四个方向的重叠描边处理;如果对于圆形的物体在一些拐角处会产生描边不均匀的问题;所以除了上下左右的方向以外;还可以对左上、左下、右上、右下方向也进行处理;(这样描边就较为均匀,但是描边不能开得过于太大



<hr/>1.5.4 效果展示



    • 但是这样的描边对于多角度的几何体还是会存在不妥的描边效果;
    • 另外当模型产生重叠的时候,其重叠部分产生不了描边;
    • 但是当有物体产生遮挡的时候,描边会透过物体;



2. 深度信息-后处理边缘检测描边(外描边)

2.1 边缘检测介绍



    • 边缘检测是检测图像中不连续区域的技术;如下所示,这种不连续反映在法线、颜色、深度以及明度等属性上;





    • 采用这种方式来实现卡通描边的优点在于:

      • 简单快速地应用到整个场景
      • 由于shader总是遍历每一个像素,故能节省开销;在不同的距离下,描边粗细能保持相同(尽管有时可能是个缺点);
      • 后处理效果不会因模型的几何关系而被裁减。

    • 缺点则包括了:

      • 往往需要多种边缘检测算子来涵盖所有边缘情况,从这点而言,性能会下降;
      • 易产生噪点。因为边缘总生成在变化非常大的区域上。


2.2 卷积基础概念


  • 对每个像素执行卷积(Convolution)操作是边缘检测的一般方法。

    • 卷积是一种通过两组数据求取单个数字的线性运算;需要用一组既定矩阵(卷积核)的中心去遍历图像中的每个像素;卷积核会与当前所覆盖的像素进行每个位置上相对应的数量乘法运算,输出结果之和即为新的中心像素值;







    • 卷积计算;卷积核实质即为加权平均计算的权值定义



2.3 Sobel算子卷积计算



    • Sobel算子的两个卷积核Sx和Sy,分别包含水平和垂直的近似导数;计算如下;

A为源图像,Gx和Gy是两个图像);





    • 源图像A与(Sx,Sy)卷积,即为根号下(Sx * A)^2 + (Sy * A)^2;然后对其进行简化运算也就是Y = |Sx * A| + |Sy * A|





    • 调整源图像的八个方向结合起来的卷积核;也就是从a1到a9组成的卷积核,其a5为检测中心(0,0)
    • SceneDepth场景深度给到an,使其变化,Y不等于0时即可检测出边界



2.4 实现边缘检测


  • 实现思路;




    • 获取屏幕空间中每个像素的坐标;使用屏幕像素大小乘以偏移程度(参数)来确定屏幕中的像素会偏移多大程度;然后接入二维坐标构成源图像的卷积核
    • 后续将UV坐标也加上;该UV坐标指的是当前场景中所有物体的UV坐标,使其UV产生偏移从而得到卷积核的其他坐标数据;







    • 得到了每个像素部分的UV则对SceneTexture场景纹理中的深度信息进行采样;得到每一个偏移的深度信息;





    • 接着使用Clamp节点来限制描边产生的最大深度;以及通过Divide除法来调整范围较远的物体描边的显示效果;然后也再使用Clamp节点来限制其描边最大宽度





    • 根据Sobel算子的计算公式结合出Gx和Gy的内容;然后再一同计算得到最终的Y结果;(此时效果为已经进行了外扩的遮罩);





    • 当前为外扩深度效果减去自定义模板的遮罩即可得到描边部分的遮罩;





2.5 效果展示



    • 但是依旧效果并不是很好,因为不能根据模型的不同部位显示出不同的描边效果 OR 控制不同的粗细效果
    • 另外当模型产生重叠的时候,其重叠部分也依旧产生不了描边;
    • 但是当有物体产生遮挡的时候,描边会透过物体;



<hr/>3. 法线信息-后处理边缘检测描边(内外描边)


  • 注意项目设置-render设置为关闭前向渲染;因为需要使用延迟渲染管线才能使用到Gbuffer中的信息:有深度、模板、颜色、法线、世界位置、金属、粗糙、高光等等


3.1 简化Sobel算子卷积计算



    • 对Sobel卷积计算描边进行优化,只进行四个方向的偏移化简Sobel算子;与自定义蒙版描边类似;



3.2 实现边缘检测



    • 利用世界空间法线来进行偏移;实际上世界空间法线信息置灰的情况下就是一种遮罩;通过利用他来进行不同位置的偏移再与原本位置的世界空间法线相减可以得到偏移的描边部分





    • 获取屏幕空间中每个像素的坐标;使用屏幕像素大小乘以偏移程度(参数)来确定屏幕中的像素会偏移多大程度;然后接入二维坐标构成源图像的卷积核
    • 后续将UV坐标也加上;该UV坐标指的是当前场景中所有物体的UV坐标,使其UV产生偏移从而得到卷积核的其他坐标数据;





    • 当前的坐标信息来采样场景深度;得到偏移的深度信息;然后用原本的场景深度来减去每个偏移的部分内容得到偏移部分(也就是描边);





    • 根据公式计算,将偏移的描边部分都加起来;并进行abs绝对值处理;然后通过节点AddComponents将法线RGB通道组合一起;接着再通过后续参数控制描边的强度以及Power控制过渡等等;







    • 计算完毕后我们可以得到以下的效果;



<hr/>3.3 效果展示



    • 看着效果确实是不错的,但是随着相机距离不断得拉远,场景法线就会产生精度缺少问题;这样就导致了描边效果会变得细碎;







    • 而且此方案使用的是场景法线,这就导致了不能重新利用自定义深度以及自定义蒙版来控制单独的物体描边
    • 但是当有物体产生遮挡的时候,描边不会透过物体;



4.  深度信息-后处理深度描边(内外描边)

4.1 实现深度偏移描边



    • SceneTexelSize表达式通过屏幕像素大小来进行偏移,以此避免较低分辨率下的结果不一致;我们需要对UV分别进行偏移,因此分别Mask分出RG通道用于计算;





    • 通过乘以-1来翻转两个通道的方向,进行另外一个方向的偏移;然后接入屏幕空间UV;偏移当前这个UV;





    • 接着将相加的内容对场景深度进行采样;使其得到各个方向的深度偏移信息;以及通过Clamp节点限制深度描边在多少程度以外被剔除





    • 初始的场景深度信息减去这些偏移的信息得到偏移部分的深度信息;也就是描边部分;将这些部分都加在一起;以及使用Power节点来调整过渡





    • 注意后续加上Saturate节点进行钳制;防止深度效果溢出





    • 效果展示;虽然描边效果实现完毕;但是会发现其描边效果会导致所有物体都会被描上;且移动起来的时候;会在奇怪的角度产生奇特的UV偏移(因为是基于屏幕UV来计算的深度信息)但是描边效果是正确的;
    • 但是当有物体产生遮挡的时候,描边不会透过物体;



4.2 处理单独描边



    • 从文章前面的效果我们可以知道;

      • 自定义蒙版可以实现描边且单独对物体进行描边处理(因为结合了自定义蒙版);利用了屏幕空间偏移蒙版计算(遮罩计算较为模糊)
      • 自定义深度可以实现描边且单独对物体进行描边处理(因为结合了自定义深度);利用Sobel卷积核计算(遮罩计算较为清晰)


4.2.1 自定义蒙版计算遮罩



    • 由于卷积计算感觉消耗较大所以就使用自定义蒙版的方式来进行单独处理描边的遮罩计算;引入之前实现的自定义蒙版实现的遮罩;





    • 只是通过偏移实现出的遮罩确实是比较模糊



4.2.2 自定义深度计算遮罩



    • 引入之前实现的自定义深度实现的遮罩;





    • 通过卷积核计算实现出的遮罩确实是比较清晰



4.3 结合遮罩分离描边



    • 通过使用Lerp线性插值来分离描边;在遮罩范围内的输入计算的描边;而遮罩外的内容全部用黑色盖去;描边扩大范围控制在遮罩范围之内即可;



4.4 效果展示



    • 看着效果不错且精度并没有影响太大;虽然还是有一定的丢失;







    • 而且此方案使用的是场景法线,这就导致了不能重新利用自定义深度以及自定义蒙版来控制单独的物体描边
    • 但是当有物体产生遮挡的时候,描边不会透过物体;





4.5 总结



    • 虽然后处理可以实现描边较为方便;但是效果相较于多pass或者工匠绘制确实是还是比较欠缺的

<hr/>5. 模型重叠 - 固定模型外扩描边

5.1 原理说明



    • 这种描边通过复制一次模型并将复制的模型进行法线反转并开启背面剔除(UE4默认开启背面剔除);
    • 然后将反转后的模型放大一点并与原模型重合得到轮廓形成描边效果;

5.2 实现外扩描边



    • 创建材质,调整模式为Mask模式,且ShadingModel更改为无光照模式;接着勾选TwoSigned使材质不会被背面剔除





    • 设置描边颜色;以及使用TwoSigned双面符号节点将法线进行背面翻转(+1表示材质正面,-1表示材质背面);将其输入到不透明蒙版中;意为翻转的法线进行正面剔除





    • 使用世界空间顶点法线信息;乘以一个控制描边粗细的参数;接入到世界场景位置偏移WPO;也就是对当前物体材质朝着顶点法线的方向进行偏移(意为朝法线方向进行外扩);



5.3 依据分辨率保持描边比例



    • 想要依据屏幕分辨率的大小保持描边宽度的比例不变。就需要Viewsize节点,该节点输出的是当前屏幕的大小(一个二维向量);而SceneTexelSize节点,该节点输出的是当前场景的像素大小;注意不要混乱了;





    • 计算相机位置与绝对世界位置的距离然后除以Viewsize(观察尺寸)再与常量OutlineWidth相乘,这样我们的描边宽度就会依据分辨率的大小而保证比例不变



5.4 根据距离去除描边



    • 首先我们先构思如何让描边进行缓缓得剔除,而不是一下子剔除;这就让我们想到了动态系数这个概念,指的就是随着某条件在逐渐的变化,而这个变化也会带动着某个系数一起变化
    • PixelDepth表达式输出当前被渲染的像素深度;也就是像素到摄像机的距离





    • 首先将描边宽度常量与自定义深度信息进行相除,然后再用实际的深度信息来对当前的计算进行相除(将实际深度信息进行关联);然后再用原本的描边宽度减去当前这个会变化的描边达到动态变化描边数据

  • 补充:

    • CustomPixelDepth除以描边指的是深度值都是3000以内的时候,描边值为正常
    • 引入PixelDepth来作为实际深度的判断;如果他超出了3000深度值,就用原本描边减去深度计算中的描边,开始剔除其描边





    • 注意后续再加上Clamp节点限制描边的变化程度为0——10之间





    • 然后将当前计算的法线外扩方向与计算的描边信息相乘,使其可以沿着法线方向进行外扩;



5.4 效果展示



    • 效果也是正常不错的,可以离远了进行剔除,也不会出现太过粗的线条
    • 但是主要是在引擎中复制了两份模型,一份为正面剔除背面外扩,一份为正常材质,这样的情况下如果模型的运动的非静态的,这种方式就会失效;不可取;





<hr/>6. 邪道流重叠-资产重叠外扩描边

6.1 邪道流原理



    • 其实都跟模型复制的操作流程十分相似,只不过是在DCC软件中对模型进行复制,而不是在引擎中进行复制
    • 我们可以在DCC中对需要进行描边的模型进行复制重叠,接着再将沿着法线方向进行稍微外扩以及创建描边材质,以及顺带将法线翻转的工作也做了;
    • 这样复制的话,倘若模型是拥有骨骼需要进行移动的,也可以实现描边;

6.2 对模型资产进行处理



    • 将模型导入到blender中,然后进入到编辑模式中,对需要进行描边的网格体部分进行复制





    • 创建出描边的材质,并将外扩复制的模型进行材质指定





    • 对描边模型朝着法线方向进行缩放;调整缩放数值;





    • 然后将模型进行法线翻转;





    • 然后就可以检查到模型产生了一丝外扩的边缘;



6.3 实现描边材质



    • 将模型导入回引擎,然后直接对其描边材质插槽加入纯色材质即可实现描边;
    • 如果需要修改描边粗细,则需要重新进入DCC中进行调整;



6.4 效果展示



    • 效果比目前使用到的描边都好很多;不会有精度丢失,也不会随着视线描边变粗等情况出现;模型进行移动也可以实现描边跟随
    • 但是缺点是:

      • 模型面数还是增加了,无疑是会带来性能消耗;
      • 而且调整描边粗细需要重新到DCC软件中进行法线外扩,影响了整体项目流程;
      • 所以这个方案也还是不能选择;




<hr/>7. 后文

    此文章算是我最近对Unreal 引擎学习的一小部分吧;关于描边在Unreal引擎中还有很多奇怪的操作还没有讲清楚:改造引擎、奇怪的UE5等等,估计得放到下一次文章分享再讲解了嘞;之后得忙一阵子在进行更新,最后就是谢谢各位支持~~~~~

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-4-30 12:46 , Processed in 0.908037 second(s), 26 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表