【UE·材质篇】用材质编辑器制作环形进度条

环形进度条是在UI开发中非常常见的功能。用材质编辑器来制作环形进度条的教程网上也有不少,然而这些教程大都讲的不清不楚,有些甚至只是把材质编辑器的连线截图贴了上来,对于其中的节点功能、为什么这么连线都没有讲明白。我作为一个新人看这些教程时觉得很困惑。经过一段时间研究后才弄懂了其中的全部细节。本文就是把我在这过程中学到的内容分享。我会尽量讲清楚每一个细节点,包含CustomRotator、VectorToRadialValue、RadialGradientExponential节点、极坐标变换等。如果只是想知道蓝图怎么连直接拉到文末。


思路分析

首先需要先修改材质结果节点的类型。在这里插入图片描述
然后对于环形进度条的效果,我们需要分成两个部分。一部分是完整的圆环,另一部分是让圆环按一定百分比进行裁剪,这个百分比将来需要作为参数暴露出去。在这里插入图片描述


圆环绘制

网上的教程里关于绘制圆环有三种思路,分别是使用贴图、SphereMask、RadialGradientExponential

1.使用贴图

UE4 Circle Gauge Material for UI
在这里插入图片描述
这个方法最简单,把一个圆环贴图放上去即可。优点是圆环的样式可以自定义,甚至可以连圆环都不是。缺点也很明显,通用性差,用这种做法做的圆环外环半径和内环半径的比例是固定的,如果想要另一种比例的圆环就需要再加一张贴图。

2.SphereMask 球形遮罩

【WTF Is? Material - Sphere Mask in Unreal Engine 4
SphereMask节点,球形遮罩。它的常见用法是让物体与球形相交的部分隐藏或显示
在这里插入图片描述
SphereMask有4个参数:

  • A:判断和球形是否相关的坐标数据
  • B:球形的圆心位置
  • Radius:球形半径
  • Hardness:硬度,硬度越高边缘越锐利

这里我们用在UI上也是可以实现环形的效果。做法是先调用一次SphereMask获得外环,再调用一次SphereMask获得内环,外环减去内环即可得到我们需要的结果
在这里插入图片描述
参数设置上,A参数用纹理坐标Texcoord(快捷键U)。B参数使用(0.5,0.5),表示坐标系中间,外环半径和内环半径则需要暴露成参数可以配置,表示占用整个纹理的百分比。硬度保持默认。
在这里插入图片描述

这种做法摆脱了用贴图做的限制,可以自定义外环和内环半径。但是有一个致命的问题,就是边缘的锯齿很严重。我查了一些资料也没有找到怎么把这个锯齿去掉,但是找到了第三种更好的方案来进行绘制圆环。

3.RadialGradientExponential 径向梯度指数

WTF Is? Material: Radial Gradient Exponential in Unreal Engine 4 ( UE4 )
RadialGradientExponential 径向梯度指数。常用于制作从圆心到四周产生渐变的效果
在这里插入图片描述
RadialGradientExponential有5个参数:

  • UV:纹理坐标,默认是没有经过任何变换的纹理坐标
  • CenterPosition:圆心位置,默认(0.5,0.5)
  • Radius:半径占纹理百分比
  • Density:密度,密度越高,产生渐变的区间越小
  • InvertDensity:是否反转计算公式,默认是false

在这里插入图片描述

前面几个参数都不用说,后面两个Density和InvertDensity需要对RadialGradientExponential 的底层理解才能知道什么意思。我们可以双击RadialGradientExponential 看到它的实现。在这里插入图片描述
RadialGradientExponential 又有一个关键函数ExponentialDensity。它里面是一个在D3D和OpenGL经常用来制作起雾效果的指数梯度函数。对于起雾效果,如果直接用lerp函数来制作的话效果不够真实。【OpenGL 3D Game Tutorial 16: Fog】下图是lerp函数效果。
在这里插入图片描述所以通常使用指数函数来做。公式如图,其中:

  • distance表示距离
  • density密度,密度越高,不可见的区域越大
  • gradient梯度,梯度越大,从可见区域到不可见区域变化速度越快
    在这里插入图片描述
    同样条件下,密度变高的对比图:
    在这里插入图片描述
    在这里插入图片描述
    同样条件下,梯度变大的对比图:
    在这里插入图片描述
    在这里插入图片描述
    D3D封装的公式里D3DFOG_EXP2 梯度固定成2,另一个公式D3DFOG_EXP里梯度为1。【Fog Formulas (Direct3D 9)】UE里面ExponentialDensity函数提供了使用梯度为1还是2的选项,默认使用2。
    在这里插入图片描述
    那么现在回到RadialGradientExponential 函数,Density的作用我已经讲了。来看InvertDensity如果为true是什么情况。
    在这里插入图片描述
    看上去确实是有渐变效果,但是和false的情况差别较大,false的情况只有在边缘才有渐变的效果不太一样。这是因为InvertDensity为true时,直接使用了指数梯度函数把UV坐标与圆心的距离占半径百分比当成distance代入公式,然后把结果作为输出。
    它的函数图像是长这样的(density为3),它衰减的很快。【在线绘制函数图像
    在这里插入图片描述
    当InvertDensity为false时,计算公式发生了变化为(其中x为UV坐标与圆心的距离占半径百分比):
    在这里插入图片描述
    函数图像长这样(density为3),大概在0.4的时候开始衰减,也就是半径的百分之40左右,跟我们看得的情况一样:
    在这里插入图片描述
    在这里插入图片描述
    可以看到RadialGradientExponential有个Switch节点根据InvertDensity不同来使用不同公式:
    在这里插入图片描述
    讲了这么多RadialGradientExponential的底层实现,其实这个节点用起来很简单,为了实现我们的圆环效果,只要把密度调高到看不到渐变就行了(图中案例为70)。这种方法做出来的圆环最完美,没有锯齿
    在这里插入图片描述

按角度裁剪功能实现

1.如何看懂节点的Preview图

在讲裁剪功能之前,我想先讲节点的Preview图怎么看。在使用UE的材质编辑器时,可以点击Preview展开看到节点的Preview图,上面是一堆颜色,新手学习时很容易迷惑。
在这里插入图片描述
我们都知道颜色有RGBA四种通道信息,那么在二维直角坐标系下,如果要表示(1,1)坐标,对应的颜色就是(1,1,0)即黄色,绿色(0,1,0)代表的就是(0,1)坐标。那么TexCoord这个节点表示的纹理坐标,因为原点在左上角,范围是0到1所以它的颜色就是这样。这个是基础中的基础。
在这里插入图片描述
那么看看我们前面画的圆环,为什么Preview图是红色的,材质预览窗口却是白色的
在这里插入图片描述
因为我们用Sphere也好,RadialGradientExponential也好,输出的结果都是一维变量。比如说结果是1,那么在Preview图里用颜色来表示就是(1,0,0)也就是红色。当我们把一维变量连到FinalColor(四维向量)输入引脚,此时发生了数据类型转换,UE会帮我们把一维变量构造成四维向量,也就是1变成了(1,1,1,1)。所以结果是白色的。
这两个案例都算还好,现在我们来个有亿点难度的案例。这个图代表什么意思我稍后揭晓。
在这里插入图片描述

2.极坐标和VectorToRadialValue

极坐标就是指用半径和角度来表示一个点。半径指的是点到原点的距离,角度指的是点与原点连线与x轴的夹角。极坐标和直角坐标关系为:

  • x = rcos(θ)
  • y = rsin(θ)

VectorToRadialValue 直角坐标转成极坐标。有2个参数,和3个输出。
在这里插入图片描述

  • Vector or UVs:要转换的纹理坐标或者二维向量
  • Swizzle Coordinate Output:是否交换RadialCoordinates输出的xy值
  • RadialCoordinates:极坐标,xy值为(角度占360度的百分比,半径),Swizzle以后为(半径,角度占360度的百分比
  • Vector Converted to Angle角度占360度的百分比
  • Linear Distance:半径

VectorToRadialValue 的内部实现比较简单,即根据直角坐标求极坐标。公式如下:
在这里插入图片描述
算出来的角度为弧度,然后除以2π,再取小数,算出来结果为度数占360的百分比。
在这里插入图片描述
现在我们直接把TexCoord纹理坐标和VectorToRadialValue的输入相连,同时把RadialCoordinates作为材质的输出。
在这里插入图片描述
会得到这样的颜色:
在这里插入图片描述
很明显不是我们想要的。我们把纹理坐标放大两倍,再减一。在这里插入图片描述
然后再和VectorToRadialValue的输入相连,同时把RadialCoordinates作为材质的输出。这个颜色图就是我们前面提到的。为什么看上去那么怪是因为它x轴分量是角度占360百分比,y轴分量是半径。而从黄色到绿色有一个剧变是因为极坐标从(1,1)变成了(0,1)。而(1,1,0)是黄色,(0,1,0)是绿色。
在这里插入图片描述
这个案例中我们不需要半径只需要角度,因此输出节点应该连接VectorConverted to Angle。同时为了实现按百分比截取的功能,把输出加上我们需要的百分比p。这样的话区间就会从(0,1)变成(p,1+p)。最后再向下取整(Floor函数),这样的话(p,1)之间的区间都是0,(1,1+p)之间的区间都是1。
在这里插入图片描述
输出的结果再与圆环相乘。
在这里插入图片描述


细节完善

到这里大部分功能已经实现差不多了,剩下还有一些细节需要添加。
首先我们需要把环形起点进行旋转,因为在使用的时候不一定是在左边从0开始的。
在这里插入图片描述

1.CustomRotator

CustomRotator,逆时针旋转纹理坐标。有三个参数:

  • UVs:纹理坐标
  • Rotation Center:旋转中心,默认(0.5,0.5)
  • RotationAngle需要旋转的角度占360度百分比

这里我们角度暴露成参数。然后需要保证TexCoord的UTiling和VTiling都是1结果才是正确的。根据矩阵的知识,先进行乘法再进行旋转和先旋转再乘法结果是完全不一样的。如果先乘以2再进行旋转,需要把旋转中心改成(1,1)。
在这里插入图片描述

2.顺时针的支持

之前的做法,随着百分比的增大,进度条是逆时针进行增加的。如果像改成顺时针,把x轴不变,y轴乘以-1。
在这里插入图片描述

3.颜色和透明度支持

把最后结果乘以颜色,作为材质的FinalColor输出。把最后结果乘以透明度作为Opacity输出。
在这里插入图片描述


完整蓝图

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
最后右键材质制作MaterialInstance,打开MaterialInstance把参数勾选上,赋值给Image控件。

在这里插入图片描述
在UMG中的使用案例:
在这里插入图片描述


总结

虽然本文只是实现了环形进度条的功能,但是我其实讲了相当多的东西。从开头绘制圆环的三种方式:使用贴图、球形遮罩节点、径向梯度指数节点。其中对径向梯度指数节点的底层实现进行了剖析,对指数梯度函数进行说明,包含密度和梯度的影响
接着我对颜色Preview图进行了介绍,方便后续在连线时看懂节点的输出值。然后又对VectorToRadialValue极坐标变换进行了讲解。最后再回到环形进度条材质的制作。
内容还是比较多的,也是好久没写这么干的文章了。


关于作者

  • 水曜日鸡,喜欢ACG的游戏程序员。曾参与索尼中国之星项目《硬核机甲》的开发。 目前在某大厂做UE4项目。

CSDN博客:https://blog.csdn.net/j756915370
知乎专栏:https://zhuanlan.zhihu.com/c_1241442143220363264
游戏同行聊天群:891809847

Guess you like

Origin blog.csdn.net/j756915370/article/details/119345114