Researcher at Microsoft MVP Labs
Chen Jinhua <br>Microsoft Most Valuable Professional (MVP) (Windows Development direction), focusing on .NET development, with more than ten years of client development experience. Passionate about blogging and sharing experiences with WPF, UWP, and Azure DevOps.
fusion effect
There is a trick to achieve a fusion effect in CSS that uses a blur filter (blur) and a contrast filter (contrast) to make two elements that are close together appear to "stick" together, as shown in the following image:
I've always been interested in this effect and always wanted to play it myself, of course, on the Xaml platform I'm familiar with. In this article I will introduce how to use Win2D to achieve fusion effect in UWP / WinUI 3.
Use Win2D to achieve fusion effect
Win2D is a very simple to use low-level graphics Windows Runtime API. It leverages the power of Direct2D and integrates seamlessly with UWP and WinUI 3's Xaml to get a beautiful interface with powerful rendering. The Nuget installation scripts for UWP and WinUI 3 versions are:
Install-Package Win2D.uwp -Version 1.26.0
Install-Package Microsoft.Graphics.Win2D -Version 1.0.3.1
After installation, add the CanvasControl to the XAML tree and subscribe to the CanvasControl.CreateResources event. This event is fired once when the CanvasControl is initialized for the first time. The resources needed for drawing can be created in this event. Now I need to draw two circles and apply Effect to both circles, so I initialized some resources with the following code:
private ICanvasBrush _leftBrush;
private ICanvasBrush _rightBrush;
private ICanvasImage _image;
private GaussianBlurEffect _blurEffect;
private void OnCreateResource(CanvasControl sender, CanvasCreateResourcesEventArgs args)
{
_leftBrush = new CanvasSolidColorBrush(sender, Colors.Black);
_rightBrush = new CanvasSolidColorBrush(sender, Colors.Blue);
_blurEffect = new GaussianBlurEffect
{
BlurAmount = 20f
};
_image = new ColorMatrixEffect
{
ColorMatrix = new Matrix5x4
{
M11 = 1,
M12 = 0,
M13 = 0,
M14 = 0,
M21 = 0,
M22 = 1,
M23 = 0,
M24 = 0,
M31 = 0,
M32 = 0,
M33 = 1,
M34 = 0,
M41 = 0,
M42 = 0,
M43 = 0,
M44 = 18,
M51 = 0,
M52 = 0,
M53 = 0,
M54 = -7
},
Source = _blurEffect
};
}
In the above code, I created two CanvasSolidColorBrush, one blue and one black, as well as a GaussianBlurEffect and a ColorMatrixEffect, the former as the source of the latter. Unlike CSS, Win2D does not use ContrastEffect, but uses ColorMatrixEffect to achieve fusion effects (as for the parameter settings in ColorMatrixEffect will be explained in the next section). Next, subscribe to the CanvasControl's SizeChanged event and get its midpoint in real time:
private void OnCanvasSizeChanged(object sender, SizeChangedEventArgs e)
{
_centerPoint = Canvas.ActualSize / 2;
}
Finally, subscribe to the CanvasControl.Draw event, which fires once when the CanvasControl becomes visible for the first time, and then fires again when its contents need to be redrawn. The following code draws two circles using the previously created resource when Draw is triggered.
private void OnDraw(CanvasControl sender, CanvasDrawEventArgs args)
{
var source = new CanvasCommandList(sender);
using (var drawingSession = source.CreateDrawingSession())
{
drawingSession.FillCircle(_centerPoint + new Vector2(-75, 0), 100, _leftBrush);
drawingSession.FillCircle(_centerPoint + new Vector2(75, 0), 60, _rightBrush);
}
_blurEffect.Source = source;
args.DrawingSession.DrawImage(_image);
}
The above code first creates a CanvasCommandList, then uses it to create a DrawingSession and draws two circles with the FillCircle of the DrawingSession. Next, pass CanvasCommandList as the input source to GaussianBlurEffect for Gaussian blurring, and this GaussianBlurEffect is the input source of ColorMatrixEffect, which is equivalent to applying ColorMatrixEffect once to the original image after applying GaussianBlurEffect once. Finally, use CanvasDrawEventArgs.DrawImage to output the ColorMatrixEffect to the UI. The final effect is as follows:
If the CanvasControl.Invalidate function is called at the end of OnDraw, the CanvasControl can be redrawn to achieve the animation effect. Using this method, plus some calculations, you can achieve an animation of the fusion effect:
The principle of fusion effect in Win2D
The above code achieves the fusion effect, but when I want to change the color and play some new tricks, I found a strange situation. For example, I changed the two Brushes to IndianRed (205, 92, 92) and PaleVioletRed (219, 112, 147 ), the two circles turned into hollow circles:
It's pretty cool and there's a lot of ways to play it, but it's not what I'm expecting right now. Then I found that as long as the value of one of the three RGB channels of the color used is not 0 or 255, the color of the fusion effect will be changed, that is, Blue(0, 0, 255) will not change, IndianRed(205, 92, 92) becomes (255, 255, 255). That said, right now I have no way of accurately controlling the color of the fusion effect. To solve this problem, we need to start with the principle of fusion effect.
▍GaussianBlurEffect
The fusion effect uses GaussianBlurEffect and ColorMatrixEffect two Effects, let's talk about GaussianBlurEffect first. GaussianBlurEffect is the Gaussian blur effect, which uses a normal distribution to calculate the transformation of each pixel in the image, and the value of each pixel is the weighted average of the values of surrounding adjacent pixels. The value of the original pixel has the largest Gaussian distribution value, so it has the largest weight, and the weight of adjacent pixels becomes smaller and smaller as the distance from the original pixel becomes further and further.
On the left is the image without any Effect applied, and on the right is the image with Gaussian Blur applied. Gaussian Blur blurs the edges of the two circles, adding a circle of semi-transparent pixels. Carefully observe the junction of the two black circles. Since the value of each pixel of the Gaussian blur is the weighted average of the surrounding adjacent pixel values, the pixels at the junction are affected by the left and right circles at the same time, resulting in a sticking effect. .
▍ColorMatrixEffect
The second step of the fusion effect is to increase the contrast of the image, and smear the semi-transparent pixels whose alpha value exceeds a certain threshold in the above right image to be completely opaque. At this time, ColorMatrixEffect is used.
ColorMatrixEffect modifies the color of an image using Matrix5x4. The default value of this Matrix5x4 is:
var identity = new Matrix5x4
{
M11 = 1, M12 = 0, M13 = 0, M14 = 0,
M21 = 0, M22 = 1, M23 = 0, M24 = 0,
M31 = 0, M32 = 0, M33 = 1, M34 = 0,
M41 = 0, M42 = 0, M43 = 0, M44 = 1,
M51 = 0, M52 = 0, M53 = 0, M54 = 0
};
By modifying this matrix, the four ARGB channels of each pixel of the output image can be controlled. The specific formula is:
result.R = (src.R * matrix.M11) + (src.G * matrix.M21) + (src.B * matrix.M31) + (src.A * matrix.M41) + matrix.M51
result.G = (src.R * matrix.M12) + (src.G * matrix.M22) + (src.B * matrix.M32) + (src.A * matrix.M42) + matrix.M52
result.B = (src.R * matrix.M13) + (src.G * matrix.M23) + (src.B * matrix.M33) + (src.A * matrix.M43) + matrix.M53
result.A = (src.R * matrix.M14) + (src.G * matrix.M24) + (src.B * matrix.M34) + (src.A * matrix.M44) + matrix.M54
Suppose I need to change the alpha index of all pixels in the image to 0, according to the above formula, just set matrix.M44 to 0.
Now let's go back and look at the ColorMatrixEffect that achieves the fusion effect in the previous article. The first three columns of the matrix keep the default values unchanged, that is, the three RGB channels are unchanged, M44 is set to 18, and M54 is set to -7. According to the formula, each pixel is transformed as follows:
result.A = (src.A * 18) -7
Enter this formula into the calculator's plot to get the following graph.
It can be seen that the output of this formula is almost a straight line perpendicular to the X-axis. Taking this line as a distinction, the result of the X value on the left side of the line is 0, and the result on the right side of the line is 1. This is an obvious binarization operation. When this ColorMatrixEffect is applied to the image produced by the previous Gaussian blur, the pixels with an alpha channel greater than 0 produced by the Gaussian blur will either become clear or disappear (only the pixels with an alpha value between 0.39 and 0.45 remain). Translucent, to de-alias the edges of the shape), so that where the two circles meet before is clear and smooth, which achieves the blending effect.
▍ClampOutput
But this ColorMatrixEffect is not a true binarization, but converts the alpha channel to a value much larger than 1 or much smaller than 0. When Alpha is much greater than 1, the pixel will become transparent or white on the UI. The reason should be because Win2D image effects use direct and pre-multiplied alpha mixing, so Win2D does something like the following in a certain link:
result.R = source.R * source.A;
result.G = source.G * source.A;
result.B = source.B * source.A;
result.A = source.A;
As a result, when the Alpha value is much greater than 1, the three RGB values are either 0 or 1. That is, Blue(0, 0, 255) will still be Blue(0, 0, 255) after applying this ColorMatrixEffect, and IndianRed(205, 92, 92) will become (255, 255, 255). To deal with this situation, Win2D provides the ClampOutput property in part of the Effect. When it is set to True, the output of the Effect is kept in the range [0, 1]. Applied to the ColorMatrixEffect above, it ensures that the output alpha channel does not exceed the [0, 1] range, avoiding any side effects other than modifying the transparency.
For more information on premultiplication, see this article:
at last
After setting ColorMatrixEffect.ClampOutput to True, Win2D can use any color to achieve the fusion effect, so there are more ways to play, such as the following:
Although I have done some things with Win2D before, this really touched my knowledge blind spot, especially the use of CanvasAnimatedControl and CanvasControl, so I asked my friend Huohuo to teach a lot of key codes and concepts, thank him for his guidance.
source code
- https://github.com/DinoChan/uwp_design_and_animation_lab
- https://github.com/DinoChan/winui3_design_and_animation_lab
References
- CSS filter tricks and details you don't know
- cnbluefire_GooeyButton
- https://github.com/Microsoft/Win2D
- Color Matrix Effect - Win32 apps Microsoft Docs
- ColorMatrixEffect Class
- GaussianBlurEffect Class
Microsoft Most Valuable Professional (MVP)
The Microsoft Most Valuable Professional is a global award given to third-party technology professionals by Microsoft Corporation. For 29 years, technology community leaders around the world have received this award for sharing their expertise and experience in technology communities both online and offline.
MVPs are a carefully selected team of experts who represent the most skilled and intelligent minds, passionate and helpful experts who are deeply invested in the community. MVP is committed to helping others and maximizing the use of Microsoft technologies by Microsoft technical community users by speaking, forum Q&A, creating websites, writing blogs, sharing videos, open source projects, organizing conferences, etc. For more details, please visit the official website: https://mvp.microsoft.com/zh-cn
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。