0
点赞
收藏
分享

微信扫一扫

【Unity Shader】Special Effects(三)Shiny 闪亮(UI)


更新日期:2021年9月2日。
Github源码:​​​[点我获取源码]​​

索引

  • ​​Shiny 闪亮​​
  • ​​思路分析​​
  • ​​闪亮区域​​
  • ​​柔和度​​
  • ​​光泽度​​
  • ​​旋转​​
  • ​​闪亮动画​​

Shiny 闪亮

Shiny以另一种方式实现了​​LOGO流光​​,在表现效果上与其相差无几,不同的地方是Shiny不需要指定流光遮罩以及流动的图片纹理等,他是直接通过UV计算出一块区域,然后叠加颜色,以达到亮闪闪的效果,最终的效果图:

【Unity Shader】Special Effects(三)Shiny 闪亮(UI)_插值

思路分析

首先,按照LOGO流光的思路,我们只需要选出一片uv区域,为区域叠加颜色,并使得​​区域的中心越亮​​​,越往​​区域的两边扩散越暗​​,在不考虑动画的情况下,这便是我们想要的区域闪亮效果了。

因为要给人一种一闪而过的感觉,所以我们的​​闪亮区域​​必定是上下贯通(左右移动)或者左右贯通(上下移动)的情况,如上文的最终效果图,闪亮区域便是上下贯通的,进行左右移动达到一闪而过的效果。

闪亮区域

我们先考虑上下贯通的方式,设想中,我们的闪亮区域如下:

【Unity Shader】Special Effects(三)Shiny 闪亮(UI)_LOGO流光_02

我们将​​闪亮的值​​​想象为​​0-1​​,则区域最中心为1(最亮),越往两边扩散就越接近0(最暗):

【Unity Shader】Special Effects(三)Shiny 闪亮(UI)_unity_03


根据经验,很明显我们这里可以使用uv的横坐标来转换至​​闪亮的值​​,已知uv的横坐标值区间如下:

【Unity Shader】Special Effects(三)Shiny 闪亮(UI)_unity_04

那么我们的算法便明确了,即是将区间​​[0,1](也即是uv.x的取值范围)​​​映射为区间​​[0,1,0]​​!

首先,区间​​[0,1]​​​可以进一步抽象为区间​​[0,0.5,1]​​​,然后,先将区间​​[0,0.5,1]​​​映射至区间​​[-1,0,1]​​:

//将区间[0,0.5,1],映射到区间[-1,0,1]
half value1 = uv.x * 2 - 1;

然后再将区间​​[-1,0,1]​​​,通过取绝对值映射到区间​​[1,0,1]​​:

//将区间[0,0.5,1],映射到区间[-1,0,1]
half value1 = uv.x * 2 - 1;
//将区间[-1,0,1],映射到区间[1,0,1]
half value2 = abs(value1);

最后,将区间​​[1,0,1]​​​倒置,便得到我们的所求结果,区间​​[0,1,0]​​:

//将区间[0,0.5,1],映射到区间[-1,0,1]
half value1 = uv.x * 2 - 1;
//将区间[-1,0,1],映射到区间[1,0,1]
half value2 = abs(value1);
//倒置区间[1,0,1],得到区间[0,1,0]
half value3 = 1 - value2;

到这里,得到的值​​value3​​​便是一个根据当前输入的uv.x值,返回的​​闪亮的值​​​,此值的区间为​​[0,1,0]​​,中间亮,两边暗。

柔和度

我们可以使用如下方式将值​​value3 [0,1,0]​​​进行平滑,得到的​​power​​就是我们最终的闪亮强度:

//通过smoothstep将区间[0,1,0]平滑,得到闪亮强度power
half power = smoothstep(0, softness, value3);

这里的​​softness​​​是外部输入的值,我们命名为​​柔和度​​,柔和度为何能够达到平滑效果呢?我们看图分析一下。

首先,当柔和度最低时(这里是0.01),效果上表现为​​完全不柔和​​:

【Unity Shader】Special Effects(三)Shiny 闪亮(UI)_shader_05


我们分析一下公式,将柔和度0.01带入:

//通过smoothstep将区间[0,1,0]平滑,得到闪亮强度power
half power = smoothstep(0, 0.01, value3);

根据​​smoothstep​​​方法特性,只要输入值​​value3​​​值大于0.01的,都会返回1,赋予​​power​​​,也即是说,经过一轮平滑运算,我们原本的​​value3​​区间:

//扩大区间细节
[0,0.1,0.2,...0.9,1,0.9...0.2,0.1,0]

被转换为了​​power​​区间:

//扩大区间细节
[0,1,1,...1,1,1...1,1,0]

也即是说,极低柔和度使得所有​​稍微有一点亮度​​​的地方,都变为了​​亮度为1​​,这便是柔和度的体现。

反之,当柔和度最高时(这里是1),此平滑运算将返回​​value3​​原值,他本身就是一个带有平滑效果的区间:

【Unity Shader】Special Effects(三)Shiny 闪亮(UI)_闪亮_06

光泽度

由上文我们已经求得了闪亮的亮度值​​power​​​,我们将亮度值乘以一个​​颜色​​​,便得到我们最终的闪亮颜色了,在这里,我们再度引入一个控制参数​​光泽度​​,用他来控制我们输出的颜色值:

//通过光泽度插值得到闪光颜色shinyColor
half3 shinyColor = lerp(fixed3(1, 1, 1), color.rgb, gloss);
//输出最终颜色(原始颜色 + 闪亮颜色)
color.rgb += shinyColor * power;

这里的光泽度​​gloss​​​在​​纯白色​​​与​​本身颜色​​​之间插值,当光泽度为0,闪亮颜色为白色(三通道值相等,乘以​​power​​​后会被降低部分值),任意颜色的三通道​​RGB​​​累加上相同的值后,并不会改变其​​色相​​,也就是说,他该是红色还是红色该是蓝色还是蓝色,看起来就只是整体变亮了一点,没有光泽感:

【Unity Shader】Special Effects(三)Shiny 闪亮(UI)_LOGO流光_07


当光泽度为1时,闪亮颜色为自身颜色,自身颜色累加自身颜色,这就使得红色的地方越红蓝色的地方越蓝,极具光泽感:

【Unity Shader】Special Effects(三)Shiny 闪亮(UI)_shader_08

旋转

如上的计算,我们得到的只是一个垂直的,上下贯通的​​闪亮区域​​,我们想要将他任意旋转,比如下面这样:

【Unity Shader】Special Effects(三)Shiny 闪亮(UI)_shader_09


这样:

【Unity Shader】Special Effects(三)Shiny 闪亮(UI)_插值_10


这样:

【Unity Shader】Special Effects(三)Shiny 闪亮(UI)_插值_11


如何实现这样的效果呢?

我们再回想一下最开始求得闪亮区域的算法:输入一个uv坐标,根据uv坐标的x值求得此坐标点的​​闪亮颜色强度​​。

我们要实现旋转效果,直接将uv坐标​​旋转​​​后再输入,输出的不就是该uv坐标的真实坐标点的​​闪亮颜色强度​​!

所以算法很简单,说干就干,直接转一下uv:

//uv旋转
uv = RotatePoint2(uv, float2(0.5, 0.5), radians(_Rotation));

RotatePoint2的功能是沿着一个圆心,将输入的二维点旋转指定弧度:

//将二维顶点point2,沿着圆心center,顺时针旋转radian弧度
float2 RotatePoint2(float2 point2, float2 center, half radian)
{
half radius = distance(point2, center);
half angle = atan((point2.y - center.y) / (point2.x - center.x)) - radian;
point2.x = cos(angle) * radius + center.x;
point2.y = sin(angle) * radius + center.y;
return point2;
}

算法也即是三角函数,这里就不做详解了。

闪亮动画

要实现闪亮动画,我们只需要改变输入的​​_Position​​​值即可,不需要借助​​_Time​​参数,直接添加一个动画播放器:

【Unity Shader】Special Effects(三)Shiny 闪亮(UI)_unity_12

到此,这个简单的闪亮效果就基本完结了,如果还有不明白的地方可以查阅源码,当然,博客中的代码不一定与源码完全相同,这里的本意只是介绍思路,具体的实现过程中可能有一些语句上的优化,当然核心算法是一样的。


举报

相关推荐

0 条评论