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

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

Shiny 闪亮

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

思路分析

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

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

闪亮区域

我们先考虑上下贯通的方式,设想中,我们的闪亮区域如下:
在这里插入图片描述

我们将闪亮的值想象为0-1,则区域最中心为1(最亮),越往两边扩散就越接近0(最暗):
在这里插入图片描述
根据经验,很明显我们这里可以使用uv的横坐标来转换至闪亮的值,已知uv的横坐标值区间如下:
在这里插入图片描述

那么我们的算法便明确了,即是将区间[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),效果上表现为完全不柔和

在这里插入图片描述
我们分析一下公式,将柔和度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原值,他本身就是一个带有平滑效果的区间:
在这里插入图片描述

光泽度

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

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

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

旋转

如上的计算,我们得到的只是一个垂直的,上下贯通的闪亮区域,我们想要将他任意旋转,比如下面这样:
在这里插入图片描述
这样:
在这里插入图片描述
这样:
在这里插入图片描述
如何实现这样的效果呢?

我们再回想一下最开始求得闪亮区域的算法:输入一个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参数,直接添加一个动画播放器:

在这里插入图片描述

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

猜你喜欢

转载自blog.csdn.net/qq992817263/article/details/120066411