New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
experimental acrylic brush implementation. #4043
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also need to implement a solid color fallback for Direct2D
@@ -653,6 +671,36 @@ private void ConfigureVisualBrush(ref PaintWrapper paintWrapper, IVisualBrush vi | |||
} | |||
} | |||
|
|||
static SKColor SimpleColorBurn(SKColor bg, SKColor fg) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need to calculate that color properly, that code was here only for example purposes
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed, as we cant, you need a blending function that can work with the background bitmap. we dont have access to this.
Maybe for in - app acrylic in future.
var noiseOpcity = 0.06 * brush.Opacity; | ||
|
||
var tintColor = acrylicBrush.TintColor; | ||
var excl = new SKColor(255, 255, 255, (byte)(255 * 0.1)); | ||
var tint = new SKColor(tintColor.R, tintColor.G, tintColor.B, (byte)(255 * ((tintColor.A / 255.0) * acrylicBrush.Opacity))); | ||
|
||
tint = SimpleColorBurn(excl, tint); | ||
|
||
using (var tintShader = SKShader.CreateColor(tint)) | ||
using (var noiseShader = | ||
SKShader.CreatePerlinNoiseTurbulence(15.876f, 15.876f, 2, 0.76829314f) | ||
.WithColorFilter(CreateAlphaColorFilter(noiseOpcity))) | ||
using (var compose = SKShader.CreateCompose(tintShader, noiseShader)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@danwalmsley I have tried with noise texture and noise looks good now. I don't really think, if it's great idea to ship png file with every application as WinUI does (or ship embedded instead?), but I am not sure, if it is easy to generate consistently good noise in runtime.
I have compared this brush with "Acrylic" application from MS Store and WinUI's Xaml Controls Gallery. Also I have set AccentPolicy.GradientColor value to 0x01000000 for windows (in other way acrylic background with transparent brush looks too "white"). But I haven't tested it with luminosity, because Acrylic app and WinUI XAML app doesn't have options for this. I can create simple one tomorrow evening.
With better noise and app background it already looks great for me (except gradient on top from undocumented api). But if we want acrylic with same effect as in UWP (I don't think if this is necessary), I have found also two small issues:
- With UWP Acrylic I can set any TintOpacity, and with 100% value it will looks like solid color without any effects. But with Avalonia TintOpacity=100% still is partially transparent (it seems like GetTintOpacityModifier should work only in pair with GetEffectiveLuminosityColor, and returns 1.0d on older OS, where luminosity is not available).
- In UWP Brush with TintOpacity=100% doesn't have 10% of white - it still has clear solid color (FF0000 for Red tint). So it seems like "excl" (10% of white) should also depend on TintOpacity, or also needs luminosity?
var noiseOpcity = 0.06 * brush.Opacity; | |
var tintColor = acrylicBrush.TintColor; | |
var excl = new SKColor(255, 255, 255, (byte)(255 * 0.1)); | |
var tint = new SKColor(tintColor.R, tintColor.G, tintColor.B, (byte)(255 * ((tintColor.A / 255.0) * acrylicBrush.Opacity))); | |
tint = SimpleColorBurn(excl, tint); | |
using (var tintShader = SKShader.CreateColor(tint)) | |
using (var noiseShader = | |
SKShader.CreatePerlinNoiseTurbulence(15.876f, 15.876f, 2, 0.76829314f) | |
.WithColorFilter(CreateAlphaColorFilter(noiseOpcity))) | |
using (var compose = SKShader.CreateCompose(tintShader, noiseShader)) | |
var noiseOpcity = 0.02 * brush.Opacity; | |
var tintColor = acrylicBrush.TintColor; | |
var excl = new SKColor(255, 255, 255, (byte)(255 * 0.1)); | |
var tint = new SKColor(tintColor.R, tintColor.G, tintColor.B, (byte)(255 * ((tintColor.A / 255.0) * acrylicBrush.Opacity))); | |
tint = SimpleColorBurn(excl, tint); | |
using (var tintShader = SKShader.CreateColor(tint)) | |
using (var bitmap = SKBitmap.Decode("noise.png")) | |
using (var noiseShader = SKShader.CreateBitmap(bitmap, SKShaderTileMode.Repeat, SKShaderTileMode.Repeat) | |
.WithColorFilter(CreateAlphaColorFilter(noiseOpcity))) | |
using (var compose = SKShader.CreateCompose(tintShader, noiseShader)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed the way acrylic works significantly... we will not be able to achieve identical results to UWP unfortunately. (At least for BackDrop acrylic, inapp acrylic will be possible in future and identical results to uwp is reasonable)
We can also make the result fairly consistent across platforms and blur radius (which is platform dependent) will need some adjustment factor depending on what the platform provides in the window.
So we have:
<HostBackDrop> - not accessible
<HostProvidedBlur> - not controlable
<TracingPaperLayer> - #xx7f7f7f makes the backdrop more opaque on platforms that cant do this for us.
<TintLayer> - Adds the tint colour, blended with the tracing paper layer.
<NoiseLayer> - Adds the texture blended with the TintLayer.
…l-acrylic-brush # Conflicts: # samples/ControlCatalog/MainWindow.xaml
…l-acrylic-brush # Conflicts: # src/Avalonia.Visuals/Rendering/SceneGraph/DeferredDrawingContextImpl.cs
# Conflicts: # samples/ControlCatalog/MainWindow.xaml
…om/AvaloniaUI/Avalonia into feature/experimental-acrylic-brush
What does the pull request do?
What is the current behavior?
What is the updated/expected behavior with this PR?
How was the solution implemented (if it's not obvious)?
Checklist
Breaking changes
Fixed issues