在 3D 全屏应用程序上叠加

Posted

技术标签:

【中文标题】在 3D 全屏应用程序上叠加【英文标题】:Overlaying on a 3D fullscreen application 【发布时间】:2010-10-29 21:15:11 【问题描述】:

我想在第 3 方全屏 Windows 应用程序上显示一些自定义图形。

你玩过 Steam 游戏吗?它有一个可执行文件 GameOverlayUI.exe,可让您从游戏中访问 Steam 窗口。 (GUI 元素看起来是自定义绘制的,我不知道这是否有必要;但它们在游戏中看起来与在桌面上完全一样。)它甚至可以将游戏图形“变暗”背景。

我想知道如何编写这样的应用程序。

我还想知道解决方案的范围有多大。你能对所有 OpenGL 应用程序使用一种方法吗?对于所有 Direct3D 减去 DirectDraw 应用程序?对于所有全屏 Windows 应用程序?

我正在寻找更“现代”和通用的解决方案 - 覆盖命令提示符或 320x240 索引颜色应用程序不是问题。

编辑:一些澄清:全屏应用程序不是我的。它可以是任何东西。最有可能的是,这将是一个 3D 游戏。我想在游戏图形的顶部显示屏幕右下角的数字时钟。如果可能的话,我想避免诸如注入代码或调试进程之类的技巧。

【问题讨论】:

【参考方案1】:

好吧,这是另一个例子。 Xfire 是一个聊天程序,它将其界面叠加到游戏中,因此您可以在玩游戏时接收消息。他们这样做的方法是在进程内存级别编辑 d3d/opengl DLL,例如注入程序集跳转。我知道这一点是因为他们的方法导致我的 mod 崩溃,而我实际上看到了他们注入 d3d9.dll 的奇怪汇编代码。

Xfire 是如何做到的:

    定位游戏进程 在其进程内存中搜索 d3d.dll/opengl.dll 向进程中注入一个包含自定义接口逻辑的 DLL 通过在进程内存中找到的 d3d/opengl 函数中手动编写程序集跳转将接口的函数连接到程序流

没有其他可以想象的方法,因为您需要劫持属于该游戏的图形设备。我敢打赌 Steam 的做法与 Xfire 相同。所以,是的,除非有人创建了一个有用的库来完成您在低级别需要做的所有事情,否则没有简单的方法来做到这一点。

您还询问了如何调暗叠加层下的游戏图形。这只是一个简单的DrawPrimitive 调用,用于在屏幕上绘制一个填充的透明矩形。

【讨论】:

在多人游戏需要像 Punkbuster 这样的反作弊软件时要小心!将自定义库注入到正在运行的游戏中被认为是侵入性游戏操纵和作弊。程序(如 Xfire、Teamspeak Overlay 等)已列入白名单,不会再导致违规违规行为,但这是由反作弊供应商完成的学习过程,在您的程序无法运行的地方可能会很耗时有效使用。【参考方案2】:

用完整代码创建了一个 Gist here

这是一门非常深奥的艺术,有几种方法可以做到这一点。我更喜欢所谓的Direct3D Wrapper。自从我这样做以来已经有好几年了,但我曾经用一个游戏做到过。我可能遗漏了一些细节,但我只是希望说明这个想法。

所有 Direct3D9 游戏都需要在屏幕渲染并准备好绘制后调用IDirect3DDevice9::EndScene。所以理论上,我们可以将自定义代码放在EndScene 中,在游戏中绘制我们想要的东西。我们通过为游戏创建一个看起来像 IDirect3DDevice9 的类来做到这一点,但它实际上只是一个将所有函数调用转发到真实类的包装器。所以现在,在我们的自定义类中,EndScene 的包装函数如下所示:

HRESULT IDirect3DDevice9::EndScene()

   // draw overlays here

   realDevice.EndScene();

然后我们将其编译成一个名为 d3d9.dll 的 DLL,并将其放入游戏可执行文件的目录中。真正的 d3d9.dll 应该在 /system32 文件夹中,但游戏首先在当前目录中查找,然后加载我们的。游戏加载后,它使用我们的 DLL 创建包装类的实例。现在每次调用EndScene 时,都会执行我们的代码以在屏幕上绘制我们想要的内容。

我认为您可以使用 OpenGL 尝试相同的原理。但是为了防止篡改,我认为一些现代游戏会尝试防止这种情况发生。

【讨论】:

是否有我可以在 c# 应用程序中使用代码的包装器?谢谢【参考方案3】:

我一直在考虑这个问题。对于 OpenGL,我会将 WGL 的 SwapBuffers 与 Detours 挂钩,在游戏结束后绘制我的东西,然后自己交换缓冲区。

【讨论】:

【参考方案4】:

我已经使用 DirectX 和 WPF 视口完成了叠加(实际上是一样的),使用叠加在 3D 可视化之上绘制了一些不错的 2D GDI+ 内容。

我通过使用“实际”可视化顶部的面板进行管理,将颜色设置为透明,除了我想要覆盖的位。工作得很好,但是将单击、拖动和其他事件通过“绘图”层传递到 3D 控件有点痛苦。

【讨论】:

如果我的问题不清楚,我很抱歉:在我的情况下,“实际”可视化是由第 3 方应用程序绘制的。我曾经在单个应用程序的上下文中完成了您所说的操作。我不知道您的答案是否与两个不同的应用程序相关;如果是,我将如何在全屏父级的上下文中创建子面板? @moobaa - 你能详细说明如何在第一部分和第三方应用程序之间使用这种技术吗?

以上是关于在 3D 全屏应用程序上叠加的主要内容,如果未能解决你的问题,请参考以下文章

为啥 Direct3D 应用程序在全屏模式下表现更好?

HTML5 3D全屏相册动画

在 Vision 识别的坐标上叠加 3D 对象的最佳方式

检测全屏 Direct3D 应用程序

Unity3d 多个camera画面叠加

使用 R 绘制带有等高线图叠加的 3D 曲面图