Acrylic material in win32 app

2020-07-18 09:01发布

问题:

Microsoft recently revealed their new "fluent" design langauge, and one part of it is the "acrylic" material. This effect makes an element transparent and blurs the background. It can either be applied to a window, such that parts of underlying windows shine though (background acrylic), or to individual elements in the window, so other controls shine through (in-app acrylic). It is conceptually and visually very similar to vibrancy on macOS.

It is implemented as a special Brush in XAML, but I wonder it there is a way to use it (background acrylic) in a regular Win32 app? The effect looks very similar to the blur applied to start menu and taskbar (which is handled by SetWindowCompositionAttribute) which leads me to believe that it might be activatable by a similar flag.

A subquestion: I wonder how it is implemented? Is it just a flag that you can set on a window, and then applied in the DWM (like SetWindowCompositionAttribute, or like Aero Glass in Vista and 7)? Or does UWP have some kind of control over the DWM, and can set shaders to control how it is rendered? Under Vista, when DWM was first introduced, it had common code with WPF, and it actually shared the (DirectX-like) buffers and scene-graph, so tricks like that were possible. The magifier utility could magnify WPF apps sharply like vector images, but that functionality was lost later. The way MS presents "acrylic" on that page (as different layers, and implemented as an XAML brush), leads me to think that you'd somehow have to inject layers into the DWM scenegraph, which would make it harder or impossible to use from Win32.

回答1:

Sciter 4.2 adds support of acrylic backgrounds (on Windows and MacOS):

Acrylic theme and UWP alike controls (CSS styled) in Sciter:

uSciter demo browser, Windows:

uSciter demo browser, MacOS:

Sciter on Windows is an ordinary Win32 application (not UWP).

In order to render that blurbehind it does the following:

Creates window with WS_EX_NOREDIRECTIONBITMAP ex flag.

Calls:

struct WINDOWCOMPOSITIONATTRIBDATA {
  WINDOWCOMPOSITIONATTRIB dwAttrib;
  PVOID                   pvData;
  SIZE_T                  cbData;
};

enum ACCENT_STATE {
  ACCENT_DISABLED = 0,
  ACCENT_ENABLE_GRADIENT = 1,
  ACCENT_ENABLE_TRANSPARENTGRADIENT = 2,
  ACCENT_ENABLE_BLURBEHIND = 3,
  ACCENT_ENABLE_ACRYLIC_BLURBEHIND = 4,
  ACCENT_INVALID_STATE = 5
};

ACCENT_POLICY accent = { ACCENT_ENABLE_ACRYLIC_BLURBEHIND, 0, clr, 0 };
WINDOWCOMPOSITIONATTRIBDATA data;
data.dwAttrib = WCA_ACCENT_POLICY;
data.pvData = &accent;
data.cbData = sizeof(accent);
SetWindowCompositionAttribute(get_hwnd(), &data);

Where clr is AGBR, something like 0xCC000000 for dark blur behind background.

Renders content using Direct2D surface set on DirectComposition Visual attached to window's swap chain using IDXGIFactory2::CreateSwapChainForComposition

Details of all this are a bit murky and COM-verbose, sigh (I am an author of the Sciter).

At least you shall use Direct2D for drawing in order to render something like this.



回答2:

I just found this project that bring acrylic to WPF : https://github.com/bbougot/AcrylicWPF

It seems your hypothesis were good. It uses SetWindowsCompositionAttribute and apply a shader on it.



回答3:

It's effects are created using the Lower level XAML Composition APIs, which uses UWP's XAML Compositor, so I would say that I doubt you will be able to achieve this natively in Win32. If you really want it, you can either take your app across the Desktop Bridge, and convert the UI, or mimic the effects with the technology available today. (Browsers such as Chrome, manage to use bring the Window Chrome further into their app, although I'm not sure how you would achieve the acrylic effect).