UE 后期处理

news2024/11/15 11:54:01

UE4后期处理材质的一些应用(上) - 哔哩哔哩 (bilibili.com)

UE4后期处理材质的一些应用(下) - 哔哩哔哩 (bilibili.com)

后期处理材质的作用

    后期处理材质使您能够设置与后期处理一起使用的材质,以创建破坏的视觉屏幕效果、区域类型效果或只能通过后置处理材质才能实现的游戏整体外观 

        对影响颜色、色调映射、光照的属性和功能进行组合选择,从而定义场景的整体外观。

        可以放置多个体积来定义特定区域的外观,也可以将其设置为影响整个场景。

流程

主要步骤

1.在场景中添加PostProcessVolume (后期处理体积)(同一个区域建议有一个即可,防止出现冲突)

2.在渲染功能中点开后期处理材质,添加数组元素,选择资产引用,为数组元素添加后期处理材质 (想要实现的效果,检查材质之间是否有冲突)

3.放大后期处理体积(使视角摄像头在其范围内)或在后期处理体积设置中勾选无限范围,即可看到添加后期处理材质后的场景变化 (只有进入范围才会生效,根据需求设置范围)

4.效果对比(根据材质)

使用前:

使用后

材质应用 

黑白蒙版遮罩 

设置

在材质参数中修改材质域为后期处理


可混合位置修改为色调映射前(可解决画面抖动、锯齿等问题) 

SceneTexture(场景纹理):这个节点输入UV值,你可以获取到这个UV对应的像素点的各个属性,比如SceneColor(场景颜色),SceneDepth(场景深度),CustomDepth(自定义深度)等等,如果不输入UV,则默认为对所有像素点都做一样的处理

修改此节点的场景纹理ID为自定义模具(用来获取场景中开启自定义模具的物体在画面中的纹理信息)

连接至自发光颜色并保存

选择需要处理的Actor ,细节面板打开渲染自定义深度通道,默认自定义深度模具值为0 

效果

使用后期处理材质前

使用后期处理材质后

原因

屏幕全是黑色,并没有高亮出我们选择的物体,这是因为我们给自定义深度模具值为0,所以SceneTexture自定义模具对我们选择的物体在屏幕中的位置输出的颜色数值为4维数组(0,0,0,0),分别对应RGBA,

对比

我们把自定义深度模具值改为1后再次观察前后变化 

  现在正确的把我们选择的物体显示出来了,SceneTexture自定义模具对我们选择的物体在屏幕中的位置输出的4维颜色数组为(1,1,1,1),那么举一反三,当我们把自定义深度模具值调的越大,自发光的亮度应该越亮。

我们把自定义深度模具值改为10后看看变化 

这个方法可以给我们指定的物体生成黑白蒙版遮罩,且不同的自定义模具值可以提供不同的4维颜色数组,所以可以用自定义深度模具值来处理复杂的情况,等于把开启了自定义深度的物体进行了分级  

遮挡物体描边显示 

效果展示

使用前

使用后

步骤 

        首先要找到物体的边缘边界,假设这是场景的自定义深度图,每一格是一个像素,里面存放着各个像素点的自定义深度值 

我们看到的物体内部是蓝色数值,红色的就是我们需要的边,正无穷就是没有开启自定义深度的物体外部 

判定物体的边有很多种方法,我们要先搞清楚以下几点:

       a.物体的内部:可以获取到自定义深度的数值,上下左右4个像素点都可以获取自定义深度

       b.物体的边缘:可以获取到自定义深度的数值,上下左右4个像素点不全都能获取到自定义深度

       c.物体的外部:自定义深度的数值为正无穷,上下左右4个像素点不全都能获取到自定义深度

       通过上述规律,我们可以用这种方法确定物体的边界:当一个像素点自身的自定义深度值不为正无穷,但上下左右四个像素点的和却为正无穷时,这个像素点就是物体的边(UE4中没有正无穷,所以用一个很大的数来近似判定是否为正无穷) 

SceneTextureCustomDepth(自定义深度)就是用来输出这张图的 

但是直接连接的话由于数值都大于1,所以都显示为白色,需要除以一个很大的数来把数值控制在0-1之间才能正确显示我们需要的结果

解决办法

       这里我们用Divide节点,把自定义深度除以很大的数,场景由于是无穷大,值大于1,物体则会小于1

   这样就得到了我们需要的自定义深度图

 实现

先创建一个ScreenPosition(屏幕位置)节点,ScreenPosition的原点在屏幕左上角 

ViewportUV输出的是每个像素点在屏幕上的UV值(2维数组),取值范围是0~1,等于是每个像素点的UV都获取一次,然后进行处理,连接到自发光可以看到,横坐标为R值纵坐标为G值,右上角为(1,0)显示红色,左下角为(0,1)显示绿色,右下角为(1,1)显示黄色(红+绿为黄色) 

  PixelPosition输出的是每个像素点在屏幕上的位置坐标,取值范围是0~屏幕尺寸,直接连接到自发光可以看到画面偏亮,但不是纯白色 

而当我们把这个值除以1000后,画面的颜色与ViewportUV接近

         我们再创建一个SceneTexelSize(场景纹素大小),这也是一个2维数组的值,对应着UV(u,v),uv均为正数,这里u就代表着要在横向偏移一个像素单位需要增加或者减少多少,v也同理

       比如你的屏幕是1920*1080的,那么你屏幕的横向上就有1920个像素,U的取值区间是0~1,那么横向上每个像素就占1/1920≈0.000521,同理纵向上每个像素就占1/1080≈0.000926,那么SceneTexelSize的值就为(0.000521,0.000926)。 

        举个例子,比如现在有个像素点的uv为(0.2,0.6),那么这个像素上方的像素点则为

(0.2,0.6-0.000926),下方则为(0.2,0.6+0.000926),左右同理(因为UE4中uv坐标系原点在左上角,所以这里向上为减,向下为加) 

        SceneTexture:PostProcessInput0(后期处理输入0)节点:这个节点其实就是SceneColor(场景本来的颜色),而SceneColor只能用于材质域为Surface(表面)的材质,所以这里用的是SceneTexture:后期处理输入0 

        然后我们再把算出来的和跟一个近似无穷大的数作比较,如果大于近似无穷大的数则为自定义模具物体的边与外部,给它一个颜色值(这里我用了黄色),如果小于近似无穷大的数则为自定义模具物体内部,给它场景原本的颜色

         从上到下依次是:+u(右侧像素点),-u(左侧像素点),+v(下方像素点),-v(上方像素点)

       这里给了一个Width(宽度)参数,这个参数和SceneTexelSize相乘,就可以调节描边的粗细了(即通过改变偏移的像素数量来控制描边粗细)

       这里的自定义深度输出的值是Color,而Color代表的是一个4维数组,有RGBA四个值,当使用自定义深度时,我们只需要一个值(自定义深度图是一个黑白图,数组中的每个数字都相同),可以用Mask节点取到第一个R值

       同理,SceneTexturePostProcessInput0节点我们只需要取前三个值,因为后处理材质只有一个属性EmissiveColor(自发光颜色),这是个3维数组的值,只需要三个控制颜色的RGB值,不需要透明度(虽然4个数值也能连接使用,但是这样可以节省计算浪费,也可以避免出错)

效果对比

使用前

使用后 

          结果上可以看到,现在把画面分割成了自定义模具物体内部显示的是原本的颜色,物体外部与物体边缘显示的是描边颜色,现在我们需要把物体外部排除掉,让它也显示为原本的颜色

       这里的方法比较多,我们采用《自定义深度模具遮罩》学习的内容来实现,让它作为亮度蒙版与现有结果做一个Lerp差值混合,蒙版内部(即白色部分)为现有结果,蒙版外部(即黑色部分)为原本的颜色(蒙版外部排除掉之后,实际上就是一个内描边) 

 效果

现在的结果就和我们需要的比较接近了,但是我们只需要被遮挡的部分显示描边,没有被遮挡的部分不显示描边,这里需要通过其他节点来判断是否被遮挡 

        SceneDepth(场景深度):当前画面上的像素点和摄像机之间的距离,这是从你看得到的地方开始算的,比如镜头正对着一面墙,墙后有个自定义模具Cube,那么UV(0.5,0.5)获取到的场景深度就是黑色虚线(墙到摄像机之间的距离),跟Cube无关

       CustomDepth(自定义深度):想获得被遮挡的物体离相机的距离,要开启物体上的自定义深度通道,如果在UV对应的像素点方向上有物体开启了自定义深度,即使被遮挡也可以获取到它的场景深度。如果该位置没有物体开启自定义深度,那么得到的值则是无穷大。

       所以我们就可以根据自定义深度(绿色虚线)和场景深度(黑色虚线)的差值来判断是否有东西被挡住(如果有两个开启了自定义深度通道的物体在一条线上的话,那么获取到的CustomDepth是离摄像机更近的那个)

CustomDepth自定义深度-SceneDepth场景深度

       如果开启CustomDepth被挡住,那么CustomDepth>SceneDepth,CustomDepth-SceneDepth=有限值

       如果开启CustomDepth没被挡住,那么CustomDepth=SceneDepth

       如果没有开启CustomDepth,那么CustomDepth-SceneDepth=无穷大

       我们可以用if节点判断CustomDepth-SceneDepth的结果。当结果<=0时,也就是物体没有被遮挡,那么用原本的颜色即SceneTexture后期处理输入0的Color值。当0<结果<9999999时,说明物体开启了自定义深度并且被挡住了,输出之前得到的描边,当结果>9999999时,也就是为正无穷,说明没有物体开启自定义深度通道,也是用原本的颜色,但是由于上一步中我们已经用SceneTexture自定义模具判断是否开启自定义深度通道了,所以我们只需要判断是否遮挡就可以了 

效果

         现在完全达到了我们需要的效果,只有遮挡的部分会显示描边,但是在《自定义深度通道遮罩》中我们知道了,当我们调整自定义深度模具值后,亮度会变化,这会使效果更佳有趣,可是如果我们不需要亮度增加的话,我们只能用较小的自定义深度模具值,那么将不容易进一步对自定义深度的物体进行分级区分从而添加更多的效果 

效果

         所以我们可以用前面判断是否开启自定义深度通道的结论,增加一个if节点判断是否开启自定义深度通道,而且不论自定义深度模具值为多少,都不会增加描边的亮度,我们还可以在描边颜色部分额外乘以一个参数Glow,那么我们可以通过调整这个Glow的数值大小来增加描边的亮度 

描边

【UE】材质描边、外发光、轮廓线_ue描边材质-CSDN博客

新建一个材质函数,便于复用 

打开材质函数,添加一个输入表示宽度

输入类型设置为“函数输入标量”

 

设置一个默认值

获取当前像素在屏幕的位置作为中心点

 输出命名为 “中心点”

通过“SceneTexelSize”函数获取像素大小,也就是1/屏幕像素(每个像素占屏幕像素的比例)

通过如下节点实现向右偏移1个像素单位

添加两个输出分别用于输出左右点的坐标

乘-1得到左边的坐标

通过相同的方法计算出上下两个点的坐标

通过深度的不连续性,计算出物体的边缘,添加“SceneTexture”节点

场景纹理ID设置为“场景深度”

由于深度值比1大因此看到的是一片白

接下来通过卷积计算出物体的边缘(就是中心点乘4再减去相邻像素的和):

 

我们对该节点的输出引脚重新排序

6. 回到材质函数“MF_GETKERNEL”中,重新设置每个输出节点的排序优先级,从上到下为0~4

如下标注的地方之前连错了,改一下:

设置完后记得保存、应用

 7. 回到材质“Mat_outLine”中,做如下连接,此时可以看到物体的边缘都是大于1的值

看到乱闪现象是因为深度差太大,我们把值限制到0~1范围内即可

用场景深度是会影响整个场景的,所以把函数的场景深度改为自定义深度,这样就能针对某一个物体描边了

8. 回到视口中,选中需要显示轮廓的物体,勾选“渲染自定义深度通道”

9.  回到材质“Mat_outLine”中,通过如下节点获取场景本来的颜色

可以看到此时轮廓线已经显示出来了

10. 接下来给轮廓线上个色

在材质中添加一个四维向量参数,用于调整轮廓线颜色

将宽度也设置为参数

11. 打开材质实例“Mat_outLine_Inst”

我们可以通过参数控制轮廓线的宽度和颜色

12.  此时我们可以显示物体的轮廓了,但是也只是外轮廓,其他的边无法显示,如果想显示更多轮廓就需要加一层法线的边缘检测

打开材质“Mat_outLine”,复制一份如下节点

将宽度连上

 将“SceneTexture”节点的场景纹理ID改为“场景法线”

将结果连接到自发光颜色

应用、保存后, 此时可以在视口中可以观察法线的分布

法线有RGB三个值,我们取最大的值用

把计算后的值与深度值相加

通过“step”节点,剔除小于0.4的部分(超过0.4输出为1,小于0.4输出为0)

由于我们只想显示外轮廓,因此这里设置为0.95

添加一个参数用于控制轮廓发光的强度(默认值为1,值越大越亮)

13. 打开材质实例,我们可以通过参数“发光强度”来控制外轮廓的发光强度

14. 此时还存在一个问题,就是如果取消勾选“渲染自定义深度通道”还是会显示法线轮廓

15. 为了解决上述问题,打开材质“Mat_outLine”,复制一份基于深度的边缘检测节点

取核中最小的值

用计算出的值和10^7作比较,如果小于10^7则不显示外发光

此时我们就可以通过勾选“渲染自定义通道”来设置是否显示轮廓线了

自定义深度通道遮罩进阶 

        通过《自定义深度通道遮罩》的学习,我们已经可以得到开启自定义深度通道物体的黑白蒙版遮罩了,但是这个遮罩是无视遮挡的,当我们使用遮罩在后期进行调色或者添加效果时,往往更需要带遮挡的蒙版来进行调色或者添加效果 

        但是在《遮挡物体描边显示》中,我们通过用CustomDepth-SceneDepth来做判断,学会了如何单独给遮挡部分与非遮挡部分不同的颜色值结果

       这里把之前的节点复制过来稍作修改就可以给遮挡的部分与未遮挡的部分单独上色了 

        那么我们可以给遮挡的部分黑色,给没有遮挡的部分白色,给没有开启自定义深度通道的部分黑色,替换掉上面的原本的颜色和红色部分 

        现在我们就可以得到带遮挡的蒙版了,而且这个方法能非常简单的获得被笔刷植物遮挡的物体的带遮挡蒙版(场景中其他的遮挡物体可以通过开启自定义深度模具,调整自定义模具值为0来变成黑色,而笔刷生成的植物无法开启自定义深度模具) 

卡通渲染 

         卡通渲染与正常渲染在画面上的主要区别有三点,一是卡通渲染的阴影没有柔和的过渡而是风格化强烈的,二是画面的色彩从多色阶降到低色阶,减少色阶的丰富程度,三是场景的描边勾线

       经过上面的学习,我们应该开始理解了后期处理材质的本质,就是通过不同的遮罩给画面添加不同的效果,而卡通渲染后期处理材质的本质就是找到阴影的遮罩,给这个遮罩内的部分添加一个比较深的颜色与原本的场景颜色叠加,然后给整体的色彩降低色阶的丰富程度,最后再给场景添加描边勾线 

         我们一步一步来,首先想方法找到阴影的遮罩,阴影产生在原本场景中的背光面,使背光面的颜色变暗,但是场景中往往颜色比较杂,阴影的颜色也会比较杂,不利于观察分离出阴影的遮罩,所以我们先要去掉场景的饱和度

       这里使用Desaturation节点,这个节点的作用是去饱和度,让画面变成黑白灰色 

          通过观察我们可以看到,目前的黑白画面中同一色块的区域阴影部分会出现比非阴影部分颜色更暗的情况,但是对比场景中其他色块区域还不能单纯从明暗上区分哪是阴影哪是非阴影 

        这里要运用到数学的一个理论来解决,一个数字(非0)除以它本身,得到的答案是1,而黑白画面的每一个像素都可以看成是一个0-1的数字,越接近0越黑,越接近1越白,如果我们可以用这个画面除以一个没有阴影、AO、漫反射等影响的原始黑白画面,是不是就能得到相对比较纯净的阴影遮罩了

       大家一定会好奇,如果是一个非0的数除以0的话,会得到什么结果呢?(好吧,可能就我会这么好奇,所以有了下面的题外知识)

       在我的求真探索后,我得到了这样的一个结论:在UE4中,任意一个非0的数除以0会得到一个计算机无法判断的乱码数,正常情况下这个数得到的颜色和0一样但却是一个无穷大的数,但当这个数通过Clamp、Satruate节点运算后,会因为被排除而变成数字1

       Saturate节点(saturate(x)的作用是如果x取值小于0,则返回值为0;如果x取值大于1,则返回值为1;若x在0到1之间,则直接返回x的值)

       Clamp节点则是把所有的取值等比压缩或拉大到0与1之间

       我们可以用Debug来测试一下结果是不是真的是这样,先用常量1连接Debug,输出的值为1.0000006 

 而当我们用常量0连接Debug,输出的值为0000000

 我们用常量1除以常量0,连接Debug后输出的值为llllllll.lllllll,这里我称它为乱码数 

这个乱码数在窗口的显示颜色为黑色,与数值0的显示颜色相同 

当这个乱码数通过Satruate节点限制到0-1后,输出的结果和常量1一样 

 当这个乱码数通过Clamp节点限制到0-1后,输出的结果也和常量1一样 

  一个显示颜色与0相同的乱码数,在经过限制(0~1之间)后数值却变成了1,不禁让我想看看他与一个接近无限大的数比大小的结果,所以有了下面这张图,我用if节点让乱码数与100亿比大小,如果乱码数比100亿大,那么输出数值5,如果乱码数比100亿小,那么输出数值0,最后我们得到的结果是数值5

          这个Debug测试验证了我上面的结论,至于0除以0的话,得到的乱码数为lllllll,与之前的略微不一样,显示颜色还是黑色,但是经过Clamp、Satruate节点限制后,输出的数值为0,大家有兴趣可以自己试一下

       回到我们的正题,为了我们想要的结果,现在需要找到一个没有阴影、AO、漫反射等影响的原始黑白画面来作为我们的分母

        SceneTextureBaseColor(底色)定义的是材质的整体颜色,它接收 Vector3 (RGB) 值,并且每个通道都自动限制在 0 与 1 之间,是一个没有阴影、AO、漫反射等影响的色阶丰富度低的画面

        这个节点输出的结果就是我们想要的,同样的我们给SceneTexture底色节点一个Desaturation节点来去色,让画面变成黑白 

         现在分子和分母都做好了,按照猜想,我们把他们相除就能得到相对比较纯净的阴影遮罩了,我们来试一下

       其中关于天空部分相除后的结果,这里添加了一个Saturate来使数据更精确(这里的天空因为是非0数除以0,应该是乱码数显示黑色,但由于添加了Saturate,天空的乱码数被排除后强制变成了1,所以显示为白色)

        这里额外提一下,由于部分材质球中加入了Metailc金属性、高光度等,当带这些材质的物体放在一个场景中时,相互会有一定的影响,所以会让结果有一定的出入 

                                材质球连接着金属性、高光度、粗糙度 

                                 车辆没有产生阴影的地方显示的颜色也为深色 

                                                            当我们把这几个属性去掉后 

                                车辆的颜色就跟周围环境一样得到了正确的白色 

          现在的阴影部分还是会有一定的明暗深浅,我们用一个if节点来进一步降低色阶的丰富程度(两极分化),用Mask取黑白画面的一维数字与参数(Shadow Cutoff)对比,从而达到阴影分界值的作用,当黑白画面的亮度大于Shadow Cutoff时,我们输出1,当黑白画面的亮度小于Shadow Cutoff时,我们输出0 

        这样就能得到一张纯黑白画面的阴影遮罩蒙版了(只有0和1,相当于两极分化去掉中间的过渡值),同时我们也可以通过控制参数Shadow Cutoff来改变阴影的分界位置 

        得到了阴影遮罩,我们就可以用Lerp节点给黑白两部分分别上色,白色部分可以用色阶丰富程度低的SceneTextureBaseColor(底色),黑色部分可以用一个3维数组参数(Shadow Color)控制,由于SceneTextureBaseColor(底色)是一个4维数组,所以这里要添加一个Mask取RGB值 

        不能说效果有错,只是现在的阴影是一个纯色,并不是很好看,我们希望的阴影是能透出一点原本的颜色的 

        所以这边可以用Shadow Color参数与SceneTextureBaseColor(底色)相乘混合后再给阴影遮罩部分,这样阴影遮罩部分就是变暗过后的底色 

         现在场景中的颜色就是我们想要的结果了,但是由于SceneTextureBaseColor(底色)得到的画面天空部分是黑色,我们要想办法得到天空的遮罩,然后用场景原本的颜色去填充,从而把天空还原出来 

          在上部的《遮挡物体描边显示》中,我们利用了SceneTextureCustomDepth(自定义深度)除以一个很大的数来还原出开启自定义深度通道物体的黑白遮罩蒙版,这边天空没办法开启自定义深度通道,所以我们要用SceneTextureSceneDepth(场景深度)求出整个场景的景深图,因为天空离摄像机最远,所以在与某个比较大的数(比天空离摄像机的距离略小)进行对比的时候,只有天空的部分会比这个数大,我们就能得到天空的黑白遮罩蒙版了 

        接下来就只需要用Lerp节点,通过天空遮罩蒙版作为Alpha,把之前的结果和场景原本的颜色进行混合,就可以把天空还原出来了 

现在已经完成了风格化阴影和降低色阶丰富度,还差一个场景的描边勾线 

        在上部的《遮挡物体描边显示》学习中,我们通过用SceneTextureCustomDepth(自定义深度)计算开启自定义深度通道物体的所有像素点上下左右4个像素深度之和来判断是否为边界,这边我们可以用类似的方法来勾出场景的描边

       我们用SceneTextureSceneDepth(场景深度),场景深度图代表的意思是物体离摄像机越远数字就越大越接近白色,离摄像机越近数字就越小越接近黑色

        为了方便理解,我这边把场景深度图导入AE中进行讲解,这边我们假设右上角的自定义深度值是0.11、0.12、0.13、0.14、0.15、0.41、0.42,在0.15与0.42之间就是场景深度断层的地方 

        当2个相同的数字相减他们的差为0,证明他们在场景中的深度相同,这边我复制一层位置不变,用A层减去B层画面全部变为黑色 

        但是如果我们把一张场景深度图偏一点移像素后再相减,那么在场景深度有断层的附近将会有数值相对较大的差值出现,我们就可以用这种方法得到场景的描边勾线 

        运用之前偏移像素点的方法,以SceneTexelSize作为偏移单位,接着与保存UV各个像素点坐标的 ScreenPosition进行相加,然后输出给SceneTextureSceneDepth的UV来完成场景深度的偏移,最后用原本的场景深度去与偏移后的结果相减 

        但是这边AE中减去的图层向左偏移了,右侧为正数亮面,而UE4中是(-1,0)也向左偏移了,但是右侧为负数暗面,两个结果是相反的,因为UE4中是UV往左偏移的话相当于最终显示的图像是往右移动了,这个可以通过简单的测试验证

       这里我做了一张简易的贴图,方便测试观察 

         把贴图连接到UE4的材质中,并用前面的方法将贴图的UV向左进行偏移,得到的画面却是向右偏移的 

        同样的方法,我们向右偏移,得到了下面这张图 

        当我们把向左偏移和向右偏移的差值结果相加后,就能得到黑白的描边蒙版了(这里AE里的颜色值只有0-1之间,而UE4中支持小于0或大于1的值,所以AE中的结果可能不够精确) 

        下面这张是完整的左右偏移后相加的节点连接图,可以看到,连接在一起后,左右两边的描边清晰可见,而上下的描边却没有 

        这是视窗中的画面,基本把场景的描边勾勒出来了 

        现在的描边只有左右两边,上下是缺失的,我们用同样的方法补齐上下的描边,这样就把场景的描边勾线制作出来了 

         但是这个描边勾线还不是最精确的,因为当在同一平面的场景深度时,线框就没了 

        为了得到更精确的描边勾线,我们可以用SceneTextureSceneNormal(场景法线),可以让细小的凹槽部分(面的朝向不同)也能有颜色上的差异,而颜色的差异也就是数值上的差异 

        可以看到大楼的窗户边缘浮现出了不同的颜色线条,与之前一整面都是黑色的结果不同 

        同样用上面的方法再制作一遍(这边直接复制修改SceneTexture的ID就好了),然后会得到一个法线版本的描边勾线 

        现在画面中增加了不少细节的线条 

完成之后我们用两者(场景深度与场景法线的结果)相比较取更大的一个值输出(有描边勾线的地方值为1,黑色部分为0,为了保留更多的描边勾线所以是取更大的值),就能得到我们想要的结果了,最后添加Saturate节点让过亮的部分限制为1,还可以在限制亮度之前用Multiply(乘以)一个参数(Outline Cutoff)或者Power(乘方)一个参数(Pow)来控制线框的密度(作用都是两极分化,可以消除细暗的描边勾线,也可以是提亮加粗细暗的描边勾线) 

        有了描边勾线的黑白图之后,还是老方法用Lerp节点与之前完成的部分相连接,这里可以给白色部分输入一个3维参数(Outline Color)来控制描边的颜色,黑色部分输入之前完成的部分(这里最好放在制作天空蒙版还原天空颜色之前,因为现在的描边勾线蒙版天空部分也是有线框的,不然需要重新再还原一次天空) 

         

        如果放在天空还原之后,天空这边会多出我们不需要的描边勾线 

         最后我们再把结果连接上我们还原天空颜色的部分就大功告成了,下面是完整的节点和效果 

        通过创建材质实例,我们可以编辑我们的参数来调整最终的效果 

                                        ​​​​​​​        

场景扫描探测  

        这个扫描探测效果很多游戏和动漫中会用到,有了前面的学习基础,制作起来也不难,流程大概是先运用《卡通渲染》中的方法制作场景的描边勾线蒙版,然后给他赋予勾线颜色和辉光,再给场景中添加一个遮罩,遮罩内的显示为描边勾线,遮罩外的显示为场景原本的颜色,最后再排除掉人物本身或者其他需要排除的物体就可以了 

        我们先从卡通渲染的材质中复制一下描边勾线的节点过来(可以把场景深度和场景法线都复制过来,这边我只复制了场景深度的描边勾线) 

这样我们就得到了场景的线框图 

         接着给描边勾线添加颜色和辉光,我们用Multiply相乘,给结果分别乘上Outline Glow和Outline Color参数,这边辉光默认1,给了一个绿色的Color做对比 

        然后我们就需要给场景一个遮罩,用来当做Lerp节点的Alpha通道,遮罩内显示描边勾线,遮罩外显示场景原本的颜色,这里我们用一个SphereMask球形遮罩节点在场景中添加一个球形遮罩来制作这个效果

SphereMask有四个输入参数

A:待检查的位置

B:圆心的位置

Radius:半径

Hardness:硬度,0是完整过渡,100是没有过渡(硬度是一个100的固定值,我们这边控制的是硬度的百分比,也就是0-1)

输出的结果:是一个0~1之间的数(A和B可以1~4维的vector),当A在B之外时,输出0;当A在B的位置时,输出1;A在圆内时,输出0~1,具体取决于是否有硬度以及位置

       简单的说就是检查A的所有位置,与以B为圆心且Radius为半径的圆做交集,A与B的交集部分输出0~1(当Hardness为1时,Mask边缘输出1,当Hardness为0时Mask边缘输出0-1的过渡,当Hradness为0-1时控制的是边缘的过渡区域大小),而B以外且A以内的部分输出0(黑色)

       这里的A实际上就是整个场景的坐标位置,B就是你想生成球形遮罩的圆心,我们用一个简单的测试来帮助理解,我们给A一个WorldPosition绝对世界坐标,然后把角色在场景中位置的三维数值给B,随便给一个半径的数值300,然后控制Hardness数值观察结果(数值分别为0、1、0.8)

       

        当Hardness数值取0时

        球形遮罩颜色偏灰,边缘羽化明显

        当Hardness数值取1时 ,球形遮罩颜色纯白,边缘无羽化,为硬边缘 

当Hardness数值取0.8时 ,球形遮罩中间为纯白色,边缘略带羽化

         可以看到以角色中心位置生成了一个半径300的球形(3D立体),根据Hardness的不同数值,球形边缘的羽化程度不同

       理解了之后我们把它作为Lerp的Alpha,而在《卡通渲染》中用到过SceneTexture后期处理输入0来代表场景原本的颜色,所以蒙版黑色的部分(即Lerp的A)用SceneTexture后期处理输入0接入,蒙版白色的部分(即Lerp的B)用前面的描边勾线接入,这里添加了2个参数节点用来替换Radius与Hardness的常数节点,通过材质实例,可以方便控制与观察效果 

         可以看到已经有了效果的基本雏形了,但是边缘的过渡看着不是很合适,没有边界的感觉,我们可以给球形遮罩边缘也添加一圈描边

 

        我们知道边界是羽化的部分,羽化的地方是一个0-1的值,越接近蒙版边界,这个值越接近0,所以这边可以用if节点,让这个值和0.9以及0比较,小于等于0的值输出0黑色,大于0小于0.9的值输出1白色,大于0.9的值输出0黑色,这样就能把边缘的描边提取出来了(0-0.9的部分)

       但是这样需要用2个if节点,然而我们把这个步骤移到Lerp节点之前的话,Lerp节点会帮我们把“判断是否小于0的”这部分还原成场景原本的颜色(小于等于0的部分就是球形遮罩的外面),所以这里只需要1个if节点判断与0.9的大小关系就好了,然后把得到的边界描边蒙版与最初的整个场景的描边勾线蒙版融合成一个蒙版,这边可以用Max节点,即两个蒙版的白色数值1的部分全部保留,其他为黑色0

          边界就制作好了,可以通过调整参数Hardness或者if节点的B值来控制边界的宽度

        现在我们的角色会受到扫描效果的影响,我们可以用前面学过的知识来把角色或者其他物体排除掉,还原成场景中原本的颜色

       这里我们用Lerp节点,把角色的带遮挡的遮罩作为蒙版,遮罩白色部分为原有结果,黑色部分还原成角色原来的颜色

        现在我们的角色就不受这个扫描探测的效果影响了 

        效果做好了以后,我们怎么去控制这个动画效果,让他慢慢扩散开呢?后期处理材质中的参数没有办法直接加入定序器中K帧做动画,但是材质参数集可以加入定序器K帧,所以我们可以用材质参数集来替换掉后期处理材质中的参数节点,然后到定序器中K帧来实现动画效果

       首先我们先创建一个材质参数集,然后添加我们需要替换掉的Radius参数名称

         然后把材质参数集拖入制作的后期处理材质中替换掉Radius参数 

         接着打开定序器,点开左上角绿色轨道按钮,选择相对应的材质参数集轨道

         这样我们就可以给Radius进行K帧来控制场景扫描探测的动画了 

        当然如果角色需要移动的情况,还需要另外把SphereMask的B值(圆心)加入定序器

       而如果是制作游戏的话,这个效果还可以通过给角色蓝图中添加节点绑定按键来驱动,这里我就不讲解了,直接放一个蓝图的节点(Loc为SphereMask的B值即角色坐标,TimeLine需要双击点开K帧数值跟随时间变化幅度),后期处理材质部分也需要在SphereMask的B值与Radius处做修改,Loc材质参数集获取角色位置输入给SphereMask作为蒙版圆心,Radius材质参数集需要乘以一个倍数(TimeLine输出的数值为0-1,所以如果是600的Radius需要乘以600的常数作为倍数)

       在材质参数集中添加一个新的材质参数Loc作为圆心的位置

         在后期处理材质的球形蒙版处替换掉原本的Loc参数,并用Mask节点取RGB值,在Radius处乘以一个常数600(这边的常数为你需要的球形半径值)

        打开角色的蓝图在事件图标中添加下面的节点(Timeline需要双击点开进行K帧,即0-N秒内,数值从0-1进行变化) 

        注意不要忘了修改Timeline的总长度,否则当你第二次按键想要把扫描探测的动画回收时需要等很久 

高斯模糊 

在UE4中创建高斯模糊后期材质_ue4高斯模糊材质-CSDN博客

[ue4]customNode实现高斯模糊_ue4 高斯散布-CSDN博客

尝试在UE的材质节点中进行高斯模糊_ue模糊节点-CSDN博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1984495.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

免费【2024】springboot 二手图书交易系统的设计与实现

博主介绍&#xff1a;✌CSDN新星计划导师、Java领域优质创作者、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和学生毕业项目实战,高校老师/讲师/同行前辈交流✌ 技术范围&#xff1a;SpringBoot、Vue、SSM、HTML、Jsp、PHP、Nodejs、Python、爬虫、数据可视化…

PyCharm找不到Python了咋办

Python发生了重装的&#xff0c;且新的路径和原有路径不同&#xff0c;就会出现如下的错误&#xff1a; 解决办法&#xff1a; 点开PyCharm菜单的File/Setting 然后&#xff1a; 有上图的提示&#xff0c;说明需要将原来的venv进行清空。 如此操作之后&#xff0c;原来的红色…

交通预测数据文件梳理:PEMS04

文章目录 前言一、PEMS04.csv文件二、adj_PEMS04.pkl文件三、adj_PEMS04_distance.pkl文件四、PEMS04.npz文件 前言 最近做的实验比较多&#xff0c;对于交通预测数据的各种文件和文件中的数据格式理解愈加混乱&#xff0c;因此打算重新做一遍梳理来加深实验数据集的理解&…

【矩阵对角线求和】求一个3*3矩阵对角线元素之和

求一个3*3矩阵对角线元素之和&#xff0c;使用C语言实现 具体代码&#xff1a; #include<stdio.h>int main(){float a[3][3],sum0;printf("请输入3x3矩阵的元素&#xff08;按行输入&#xff09;&#xff1a;\n");for(int i0;i<3;i){for(int j0;j<3;j)…

AD 飞线显示混乱、错位

执行Design->Netlist->Update Free Primitives From Componet Pads

8月6(信息差)

&#x1f30d;华为最便宜小折叠&#xff01;华为nova Flip今晚发布&#xff1a;搭载麒麟8000芯片 从曝光的跑分信息来看&#xff0c;nova Flip将搭载麒麟8000处理器&#xff0c;也就是nova 12 Pro/Ultra的同款&#xff0c;采用8核心的134组合&#xff0c;大核是1颗2.4GHz的Cor…

如何用ai来完成数据库分析(1)

前言 因一些课程设计要写长篇分析报告&#xff0c;这里借用ai做一篇指导教程&#xff0c;分上下两篇。这篇也会教如何让ai给你你想要的答案&#xff0c;众所周知&#xff0c;现在的ai并不智能&#xff0c;不针对各类厂家&#xff0c;但是放出来的确实表象如此。 但其实问法决…

SAP ABAP代码模板CLASS

此模板也使用OO ALV,创建新程序简单&#xff0c;功能包装独立&#xff0c;用到一个独立的CLASS. 1.ALV类 class ZCL_CM_GUI_ALV definitionpublicfinalcreate public .public section.data REPID type SYREPID .data DYNNR type SYDYNNR .data TOOLBAR type CHAR30 .data USE…

Linux中的进程替换

一、理解进程替换 首先&#xff0c;exec* 系列函数能让进程执行新程序&#xff0c;上图我们用到的是 int execl(const char* path, const char* arg, ...)函数&#xff0c;所以相当于执行了 ls -la 指令&#xff0c;这就完成了进程的替换。 本来子进程中存放的是父进程的代码和…

5. 有效的括号

5. 有效的括号 题目题目分析 题目 题目分析 一个很标准的关于栈知识点的应用&#xff0c;首先先初始化一个栈&#xff0c;再遍历字符串s,当匹配到为左边字符串是将其压入栈中&#xff0c;遇到右边字符串时要判断此时的栈顶元素是否与其匹配&#xff0c;若匹配则将栈顶元素弹出&…

GPX格式详解,javascript写入读取GPX示例

还是大剑师兰特&#xff1a;曾是美国某知名大学计算机专业研究生&#xff0c;现为航空航海领域高级前端工程师&#xff1b;CSDN知名博主&#xff0c;GIS领域优质创作者&#xff0c;深耕openlayers、leaflet、mapbox、cesium&#xff0c;canvas&#xff0c;webgl&#xff0c;ech…

如何使用Markdown编辑器

欢迎使用Markdown编辑器 你好&#xff01; 这是你第一次使用 Markdown编辑器 所展示的欢迎页。如果你想学习如何使用Markdown编辑器, 可以仔细阅读这篇文章&#xff0c;了解一下Markdown的基本语法知识。 新的改变 我们对Markdown编辑器进行了一些功能拓展与语法支持&#x…

【PLC】关于子程序功能以及编程过程中的部分心得

博主在使用GX Works对三菱PLC编程的时候用到了子程序功能&#xff0c;这里将使用子程序功能中的一点心得以及编程过程中的部分心得分享给大家。 博主主要对以下几个问题有一些心得&#xff1a; 1、如何调试带有子程序的程序&#xff1f; 2、如何让程序按照计划的顺序去执行&…

【OpenCV C++20 学习笔记】自定义线性滤波-filter2D

自定义线性滤波 原理相关卷积核线性滤波操作 API实例 原理 相关 线性滤波的是指就是相关&#xff0c;即计算图像中的每个部分和卷积核(kernel)的相关结果。 卷积核 卷积核本质上是一个固定大小的系数数组&#xff0c;数组中的某个元素被作为锚点&#xff08;一般是数组的中…

C++之从C过渡(上)

C之从C过渡 前言 暂时告别C语言&#xff0c;我们走进C。对于有C语言基础&#xff0c;初学C的我们来说&#xff0c;在正式学习C的主体内容之前&#xff0c;我们需要先有一个过渡&#xff0c;本文中会总结过渡需要了解的零散知识&#xff0c;主要是语法。 正文 C的第一个程序 …

终于用PC串口显示出esp32 串口输出hello world

硬件&#xff1a; esp32模块 rs232 转ttl 3.3v 电平转换器 3.3v 外接电源 esp32 tx 脚接转换器rx, rx脚接转换器tx esp32 使用uart2 现在就可以用pc作为上位机通过串口控制esp32&#xff0c;用pc串口调试软件作为esp的输出监控器显示esp的各种运算结果。 #include &qu…

使用visual studio2019创建dll导出自定义类

系列文章目录 文章目录 系列文章目录前言一、具体操作步骤1.创建动态链接库工程(DLL)2.头文件声明3.实现文件定义4.生成dll工程5 使用dll总结 前言 程序对动态链接库dll、静态链接库lib想必都很熟悉了&#xff0c;网上也有很多的相关介绍。但网上介绍的一般都是C语言函数介绍&…

javascript 的奇技巧淫二

文章目录 1 、标记模板文字2、使用 Object.entries() 和 Object.fromEntries()3、用于唯一元素的 Set 对象4、对象中的动态属性名称5、使用 bind() 进行函数柯里化6、使用 Array.from() 从类似数组的对象创建数组7、可迭代对象的 for…of 循环8、使用 Promise.all() 实现并发 P…

SpringBoot下载resources目录下的文件

1.引入SpringBoot和hutool依赖 <dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.8.22</version></dependency>2.在项目resources目录下放入模版文件&#xff0c;结构如下&#xff1a…

JavaScript基础(30)_事件的冒泡、事件的委派

事件的冒泡(Bubble) 所谓的冒泡指的是事件的向上传导&#xff0c;当后代元素上的事件被触发时&#xff0c;其祖先元素的“相同事件”也会被触发。 取消事件冒泡 在开发中大部分情况冒泡都是有用的&#xff0c;如果不希望发生事件冒泡可以通过事件对象来取消冒泡。取消冒泡代码…