我想为完整的 Windows 桌面添加动态视频效果。
我希望能够将屏幕变成灰色,斜切边缘并添加一些扫描线,使其看起来像一个旧的 CRT 屏幕,或者使屏幕出现故障,就像他们在不懂技术的电影中显示被黑系统一样,等等。
效果本身超出了这个问题的范围。这个问题是如何应用它们,即如何获取Windows 生成的桌面图像,应用我的效果,并在同一显示器上呈现结果。
我知道几种可能有效的方法。
它们都有缺点:复杂性、驱动程序签名要求、复杂的设置。有什么更好的方法来实现我想要的吗?
1 非常难,不同的 API 太多。
\n\n2 困难的部分是制作假显示器。如果您\xe2\x80\x99ll 购买一个名为 \xe2\x80\x9cHDMI 虚拟插头\xe2\x80\x9d 的 10 美元设备,它将变得相对简单,具有 100% 记录的 API。使用桌面复制 API 获取显示器 1 的纹理,应用您想要的任何效果并在显示器 2 上显示。如果您想要良好的性能,您最好完全在 GPU 上实现处理,例如使用自定义像素着色器渲染四边形。
\n\n3 可以,但是很难做到。
\n\n还有\xe2\x80\x99s另一种方式。它\xe2\x80\x99的实现很棘手,并且使用未记录的API,但根据我的经验相当可靠,至少在Windows 7上是如此。编写一个将自身注入到dwm.exe中的DLL。\xe2\x80\x99 是一个 Windows 进程 \xe2\x80\x9c 桌面窗口管理器\xe2\x80\x9d,它组成了桌面上可见的任何内容。DLL注入后,创建一个新线程,在该线程中调用D3D11CreateDeviceAndSwapChain,然后使用例如MinHook来拦截Present
,并且最好还拦截接口ResizeBuffers
的方法IDXGISwapChain
。如果成功,dwm.exe 将在每次呈现框架或桌面分辨率更改时调用 DLL 中的函数。然后,在当前的函数中,您可以做您的事情,例如添加另一个渲染通道来实现您的效果,然后调用原始实现以实际将结果呈现到桌面。
这在理论上很容易,但在实践中实施起来却相当棘手。例如\xe2\x80\x99很难调试dwm.exe,你\xe2\x80\x99必须依赖日志记录,或者可能使用带有远程调试器的虚拟机。此外,这也不能跨 Windows 版本移植。另一个限制是,它不适用于视频游戏等全屏应用程序,它们会绕过 dwm.exe。对于视频游戏,仅适用于 \xe2\x80\x9c 无边框全屏窗口\xe2\x80\x9d 游戏内设置。
\n\n更新:另一种方法,更简单。创建一个具有每像素透明度的最顶层全屏窗口。操作系统支持它们数十年,设置WS_EX_LAYERED
和WS_EX_TRANSPARENT
扩展样式位。你将无法进行灰度处理,因为你只能覆盖你的东西,而不能读取下面的内容,但边缘、扫描线和毛刺是完全可行的。为了获得最佳性能,请使用一些以 GPU 为中心的 API 来渲染该窗口,例如 C++ 中的 Direct2D 或 D3D。\xe2\x80\x99s 也更容易调试,可以使用 2 个显示器,也可以定位透明窗口,使其占据角落的一个矩形,为 IDE 留下足够的屏幕空间。这是一个例子(不是我的)。
要在窗口上捕获和重绘桌面,您不能错过方便的窗口放大工具。
您想要创建的是它的全屏版本,并进行自定义处理以使其看起来像您想要的那样。
幸运的是,有一个 GitHub包含它的工作源代码
您会注意到全屏文件中有一个函数:
//
// FUNCTION: SetColorGrayscaleState()
//
// PURPOSE: Either apply grayscale to all colors on the screen, or restore the original colors.
//
void SetColorGrayscaleState(_In_ BOOL fGrayscaleOn)
{
// Apply the color matrix required to either invert the screen colors or to show the regular colors.
PMAGCOLOREFFECT pEffect = (fGrayscaleOn ? &g_MagEffectGrayscale : &g_MagEffectIdentity);
MagSetFullscreenColorEffect(pEffect);
}
Run Code Online (Sandbox Code Playgroud)
这为您解决如何影响绘制回窗口的像素提供了相当坚实的基础。
要使此窗口可点击,您需要使用类似以下代码行的内容来创建它:
HWND hWnd = CreateWindowEx(WS_EX_LAYERED|WS_EX_TRANSPARENT, cName, wTitle, NULL, 0, 0, 640, 480, NULL, 0, GetModuleHandle(NULL), 0);
Run Code Online (Sandbox Code Playgroud)
这里重要的部分是WS_EX_LAYERED|WS_EX_TRANSPARENT
标志组合。
来自微软文档:
不重要。但是,如果分层窗口具有 WS_EX_TRANSPARENT 扩展窗口样式,则分层窗口的形状将被忽略,并且鼠标事件将传递到分层窗口下方的其他窗口。
有了这个基础,以及如何构建点击窗口的知识,您应该能够编写一个程序来更改颜色/向桌面前面的全屏窗口添加一些工件。
我用这种方式制作的所有程序的 FPS 都比您的本机桌面低,但对于一个看起来很酷的程序来说应该还是不错的。
归档时间: |
|
查看次数: |
1294 次 |
最近记录: |