在 Win32 应用程序中模拟丙烯酸

11
Microsoft最近宣布Fluent Design中的玻璃材质Acrylic。它只能在XAML/UWP中使用,但看起来非常类似于玻璃,除了可以任意着色并且可以应用于飞过控件以及应用程序的独立窗口中。
“配方”使其看起来好像是XAML本身实现的,而不是暴露给更广泛的系统。

Microsoft's recipe for making acrylic: background, blue, blend, tint, noise

有一篇相关的SO问题证实了这一点(它缺乏具体的技术答案,但意味着亚克力不像玻璃那样可以通过WinAPI获得。)

如何在普通的Win32应用程序中模仿这个效果?使用玻璃和混合吗?(使用哪些API,以及Win10秋季更新的玻璃API中有哪些Win7中没有的功能?)如果应用程序是使用Win32创建的,但使用DirectX表面进行渲染,是否会开启更多的可能性?


这个问题有一些截图,可以更好地展示噪音效果。 - zett42
4个回答

10

正如 @zett42 回答的那样,我认为它是使用 DirectComposition 实现的。

一点历史:在 Vista 中,微软推出了桌面窗口管理器 DWM,它是桌面的合成引擎。使用 DWM,窗口绘制到纹理上,然后在 DWM 中组合。好处是你可以获得花哨的效果,如 3D 动画、透明度等,并且所有内容都是双缓冲的,因此没有渲染伪影。

DWM 最初基于 MIL(媒体集成层),我认为这是一个场景图 API。有趣的是,在那个时候引入的 WPF 也使用了 MIL。这真的很酷,因为 DWM 可以看到 WPF 窗口的场景图,当它产生效果时,例如缩放窗口,它会将其视为向量而不是位图,因此可以缩放而无伪影。然而,在某个时刻微软分叉了在 WPF 中使用的 MIL 版本,这种集成失去了。

快进几年到 Windows 8。微软推出了新的“Metro”应用程序(后来是“Modern”,现在是“UWP”)。在幕后,这些现代应用程序使用了一个新的合成 API,即 DirectComposition。该 API 也可用于 Win32 应用程序,现在 DWM 本身也使用了它。如果您查看公共的 DWM 函数,则一些与 MIL 相关的函数已被弃用,因此支持我的理论,即 MS 转向了 DC 而不是 MIL。因此,现在我们处于初始情况,应用程序以及 DWM 使用相同的基础设施,我们可以轻松地添加一些有趣的效果。

在某个时刻,微软推出了由 IDCompositionDevice3 接口提供的 DirectComposition 的新混合效果。其中包括高斯模糊效果,但也包括噪音、色调和其他必要的效果。我找到了一种方法可以在我的窗口中应用这些效果,但我不知道如何将它们应用到我的窗口上。不幸的是,我现在无法访问我的代码,等我可以时我会更新我的答案。

我基于这篇文章进行了探索:DirectComposition高效Alpha混合窗口。基本上,你有一个与屏幕对应的“设备”,以及与你的窗口内容相对应的“可视化”。你需要更改的是:
  • 你的设备可以为你创建效果。记得用QueryInterface将其转换为IDCompositionDevice3
  • 然后,你就可以在IDCompositionVisual3上调用SetEffect了。

但是,正如我所说的,这只适用于窗口的内容。我认为必须有一种秘密API可以从DWM获取当前窗口的父级可视化对象,之后只需在该可视化对象上调用SetEffect即可获得效果。如果有人熟练使用调试器,应该可以通过跟踪使用Acyllic效果的UWP应用程序来找到该API。

作为尝试,我会看看GetWindowCompositionAttribute函数。它最近增加了一些听起来很有趣的标志,比如WCA_VISUAL_OWNER。


1
在UWP中,它被公开为CreateHostBackdropBrush -- 它似乎确实围绕着dcomp.dll浮动 -- 但遗憾的是微软没有立即计划将HostBackdropBrush添加到DirectComposition API集中。 :( - melak47
你的“随意尝试”似乎是正确的,因为另一个答案指出有一个新的标志 ACCENT_ENABLE_ACRYLICBLURBEHIND = 4 - zett42

9
Rafael Rivera发布了一个小型演示应用程序,展示如何在桌面应用程序中使用Acrylic Blur,自从Windows 10 v1803(Build 17134.x - RS4 - April 2018 Update)以来。基本上,枚举AccentState有一个新条目ACCENT_ENABLE_ACRYLICBLURBEHIND = 4。请参考以下链接查看演示应用程序:https://github.com/riverar/sample-win32-acrylicblur。图片如下:enter image description here

1
相关的文档化 Win32 API 调用是 DwmSetWindowAttribute(),它与未记录的 SetWindowCompositionAttribute() 相同,只是参数传递方式不同。示例的相关代码可以在 MainWindow.xaml.cs 中找到。 - zett42
ACCENT_ENABLE_ACRYLICBLURBEHIND的模糊半径比使用ACCENT_ENABLE_BLURBEHIND更大,但与UWP中的亚克力画笔不完全相同。(UWP仍具有更大的模糊半径和其他组件) - Grant Howard

5
我认为可以使用Win32 API来模拟这个效果,或者至少创建一个类似的结果。
  • 模糊和着色可以使用未记录的SetWindowCompositionAttribute()实现,您已经提供了链接。该功能必须由DWM提供,即使对于XAML实现也是如此。
  • 我不确定排除混合应该做什么,至少从微软页面上缩小的截图来看,它似乎是可以忽略的。
  • 噪声纹理应该很容易做到,因为它可能只是alpha混合... 嗯... 噪声。使用随机生成器或者一些perlin noise function
你也可以考虑使用直接合成,可能与扩展窗口样式WS_EX_NOREDIRECTIONBITMAP结合使用,如文章"使用Windows合成引擎进行高性能窗口分层"所述。我尚未使用过这项技术,但文章指出XAML基于Direct Composition,应该开启所有可能性。

DirectComposition是我以前没有接触过的东西(它在Win10中是新的吗?)肯定看起来是正确的选择。谢谢! - David
@DavidM DirectComposition是在Windows 8中引入的。 - zett42

3
在最新的 Windows 10 设备中,我们可以结合 DWM API 和 Direct Composition API 来重新创建 Win32 中的亚克力效果。在更新的 Windows 中,我们可以将 DWM 缩略图的内容复制到 IDComposition 可视化对象中,并将其用于创建亚克力背景。
然后,可以将背景传递给 IDCompositionGaussianBlurEffect来模糊背景。
这是一个可行的示例:Win32 Acrylic Effect 但我强烈不建议在生产环境中使用该方法。

知道这点真是太好了,谢谢。为什么你不推荐它用于生产环境呢?而且这个功能在窗口上与普通的Win32控件一起使用效果如何,比如“覆盖”亚克力效果? - David
1
我不建议在生产环境中使用它,因为这些是微软内部使用的私有API。因此,它们可能随时被更改或删除,而不需要任何事先通知。 - trickymind

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接