[Unity Shader] Special Effects (2) BorderFlow border flow (UI)

Updated: August 23, 2021.
Github source code: [Click me to get the source code]

BorderFlow border flow

The effect of UI frame flow is very common, and the implementation ideas are also varied. I will not post those examples on the Internet here, and directly look at our final renderings:
insert image description here

Idea analysis

streamer area

We first define the area (cyan) that is flowing in the four directions of up, down, left, and right 流光区域as the other definition 非流光区域, which is essentially 流光区域a superimposed one 流光颜色(比如这里的青色), 非流光区域and it can be output according to the normal color of the image.

So how do we determine which ones are 流光区域?

This is actually very simple. We can see from the rendering above that it 流光区域is actually just a rectangular area, so how to determine a rectangular area?

In a two-dimensional plane, as long as one (the center point of the rectangle) is determined , and 中心点then the sum is determined , a fixed rectangular area can be obtained (we do not consider rotation).宽度高度

As we all know, image rendering is a process of continuous input and output. Here we don't need to determine the 流光区域real value immediately. We only need to formulate a rule, which 流光区域can be defined in real time according to the input value and the rules we formulate. How about the rules? formulate? Let's continue to look back.

The center point of the streamer area

By repeatedly studying the renderings, we found 流光区域that the position is not fixed, it will flow in a clockwise direction continuously, with the 上、右streamers as a group, 下、左and the streamers as a group, the rules are as follows:

(Top, Right) The streamer flows from 上方的左侧the start 向右, when it reaches the right boundary, it moves from 右方的上侧the start 向下again, and when it reaches the lower boundary, the flow stops (the streamer starts from the upper left again because of the loop animation used here), another group ( Bottom, left) The streamers are the same, and the direction is still clockwise.

insert image description here
If the entire flowing process is defined as x=1, then 左上角it is x=0, 右上角it is x=0.5, 右下角it is x=1, as shown in the figure below, the entire streamer 活动轨迹:

insert image description here
Then, consider the streamer area as one again 矩形, and the x-coordinate of the center point of the rectangle (that is, the center point of the streamer area) can be determined, and that is xthe value (activity track) above.

As for the y value of the center point, it is not difficult to find that the streamers in the four directions of up, down, left, and right are all close to the edge, and the four edge coordinates of the image are all known (uv coordinate system), so the value can obviously be ydirectly Find out:

For example, the y value of the center point of the upper streamer area = 1 - the height of the streamer area * 0.5

From this, the center point of the streamer area is obtained as:
insert image description here

The width and height of the streamer area

The rules of the center point are determined, so let's look 宽度at the sum 高度.

By studying the renderings again, we can clearly find that the width and height of the streamer area have no rules at all, the height can be any value (of course not greater than the height of the image), and the width is the same.

In other words, we can directly define the value of the 宽度sum as an input variable.高度

Define streamer area

The idea is clear, and then we directly write the code to define the streamer area, first set the input value:

	Properties
	{
    
    
		//流光位置:上文中流光的活动轨迹(0-1),也即是流光区域中心点的x坐标
		//由于流光区域中心点的y坐标可以通过厚度求得,所以这里不设直接输入
		_FlowPos("流光位置", Range(0, 1)) = 0
		_FlowWidth("流光区域宽度", Range(0, 1)) = 0.3
		_FlowThickness("流光区域高度", Range(0, 1)) = 0.03
	}

Then according to the rules in our previous article, calculate the real 矩形区域location of the streamer area (here is 上边框an example):

//根据规则,流光位置(_FlowPos)在0-0.5时,上边框的流光从左侧流动到右侧
//所以这里求出流光区域中心点的x坐标在整个上边框所占的比例 ratio 
half ratio = smoothstep(0, 0.5, _FlowPos);

Then map the x-coordinate ratio ratio of the center point of the streamer area to the real position on the image:

//half realXPos = lerp(0, 1, ratio);
half realXPos = lerp(_FlowWidth * -0.5, 1 + _FlowWidth * 0.5, ratio);
half realYPos = 1 - _FlowThickness * 0.5;

Some people here may not understand, the real x value of the upper border from left to right should be 0-1 (comment that line), why is there another value here?

It's very simple, just look at the picture and you will understand:

insert image description here
Because stretching half of the left and right sides of the upper border area 流光区域宽度will give people a streamer 从无到有, 从整到零a transition flow process, so that half of the streamer will not be displayed on the image at the beginning.

So far, we have calculated 流光区域the center point, and the known 宽度, 高度, can already determine a rectangular area, then as long as the uv coordinates are in the pixel of this area, the streamer effect will be superimposed, otherwise it will be ignored.

streamer effect

The superposition 流光效果process is simple. First of all, we still want 流光效果the brightness and color to be variable, so we add input parameters again:

	Properties
	{
    
    
		//流光位置:上文中流光的活动轨迹(0-1),也即是流光区域中心点的x坐标
		//由于流光区域中心点的y坐标可以通过厚度求得,所以这里不设直接输入
		_FlowPos("流光位置", Range(0, 1)) = 0
		_FlowWidth("流光区域宽度", Range(0, 1)) = 0.3
		_FlowThickness("流光区域厚度", Range(0, 1)) = 0.03

		_FlowColor("流光颜色", Color) = (1,1,1)
		_FlowBrightness("流光亮度", Range(0, 1)) = 1
	}

Next, we judge whether the uv coordinates of the currently input pixel 流光区域矩形are included . If they are, they will be superimposed 流光颜色, 流光亮度and if they are not, they will be output as they are.

	//IsInRect:求一个二维点是否在一个矩形内
	//第一个参数为一个矩形(half4 格式,四个值分别为【矩形中心点x坐标,矩形中心点y坐标,矩形宽度,矩形高度】)
	//第二个参数为指定的二维点
	//返回值:当输入的二维点在矩形区域内时,返回1,否则返回0
	//在这里我们将亮度 _FlowBrightness * IsInRect的返回值,使得在流光区域内的返回亮度值,不在的返回0
	half brightness = IsInRect(half4(realXPos , realYPos , _FlowWidth, _FlowThickness), uv) * _FlowBrightness;
	//将流光颜色叠加到主颜色,如果不在流光区域内,则上方求得的亮度为0,则叠加无效
	color.rgb += color.a * brightness * _FlowColor;

Then, after finding a top border, the algorithm of the other three borders is the same, but the 流光区域location 矩形定义is slightly different (for example, when calculating the right border, _FlowWidth will become the height, and _FlowThickness will become the width), so I won’t go into details here.

How to find a 2D point in a rectangle

Here is IsInRectthe specific implementation of , which is actually very simple, just look at the algorithm to understand:

//求一个点是否在指定方形区域内
fixed IsInRect(half4 rect, half2 point2)
{
    
    
	half width = rect.z * 0.5;
	half height = rect.w * 0.5;
	//如果点的位置没有超过方形区域左边界
	fixed left = step(rect.x - width, point2.x);
	//如果点的位置没有超过方形区域右边界
	fixed right = step(point2.x, rect.x + width);
	//如果点的位置没有超过方形区域上边界
	fixed up = step(rect.y - height, point2.y);
	//如果点的位置没有超过方形区域下边界
	fixed down = step(point2.y, rect.y + height);
	//则点在方形区域内(任何一边不满足,都将返回0)
	return left * right * up * down;
}

Smoothing of the streamer effect

Let's look back at the effect picture again, and we will find 流光区域that it presents a smooth effect (upper border) that fades from right to left, that is, it gives people a flow 速度感:

insert image description here
How can this be achieved? Let's still look at the code and get it done in one line:

	//IsInRect:求一个二维点是否在一个矩形内
	//第一个参数为一个矩形(half4 格式,四个值分别为【矩形中心点x坐标,矩形中心点y坐标,矩形宽度,矩形高度】)
	//第二个参数为指定的二维点
	//返回值:当输入的二维点在矩形区域内时,返回1,否则返回0
	//在这里我们将亮度 _FlowBrightness * IsInRect的返回值,使得在流光区域内的返回亮度值,不在的返回0
	half brightness = IsInRect(half4(realXPos , realYPos , _FlowWidth, _FlowThickness), uv) * _FlowBrightness;
	//【新增的行】将流光区域平滑(使得越靠近区域右侧,流光强度越接近1,越靠近区域左侧,流光强度越接近0)
	brightness *= smoothstep(0, _FlowWidth, uv.x - realXPos + _FlowWidth * 0.5);
	//将流光颜色叠加到主颜色,如果不在流光区域内,则上方求得的亮度为0,则叠加无效
	color.rgb += color.a * brightness * _FlowColor;

In the calculation here uv.x - realXPos + _FlowWidth * 0.5, the x coordinate of uv is mapped to (0,1), so that the point located at the point 流光区域最左侧, 映射为0thus generating a smooth interval effect, this smooth interval * brightness, and the superimposed streamer color is smoothed Effect.流光区域最右侧映射为1

streamer animation

To realize streamer animation, obviously we only need to change the input _FlowPosvalue, without using _Timeparameters, directly add an animation player:

insert image description here
At this point, the simple border flow effect is basically over. If there is still something you don’t understand, you can refer to the source code. Of course, the code in the blog may not be exactly the same as the source code. The original intention here is just to introduce ideas. In the specific implementation process There may be some statement optimization, of course the core algorithm is the same.

Guess you like

Origin blog.csdn.net/qq992817263/article/details/119868285