我试图在3D桌面游戏中绘制自定义opengl叠加层(例如蒸汽就是这样)。 这个叠加应该基本上能够显示用户的一些变量的状态 可以通过按某些键来影响。把它想象成一个游戏训练师。 目标是首先在屏幕上的特定点绘制一些基元。后来我想要一个漂亮的外观" gui"游戏窗口中的组件。 游戏使用" SwapBuffers"来自GDI32.dll的方法。 目前,我能够将自定义DLL文件注入到游戏中并挂钩" SwapBuffers"方法。 我的第一个想法是将叠加的图形插入到该函数中。这可以通过将3D绘图模式从游戏切换到2d来完成,然后在屏幕上绘制2d覆盖并再次将其切换回来,如下所示:
//SwapBuffers_HOOK (HDC)
glPushMatrix();
glLoadIdentity();
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glOrtho(0.0, 640, 480, 0.0, 1.0, -1.0);
//"OVERLAY"
glBegin(GL_QUADS);
glColor3f(1.0f, 1.0f, 1.0f);
glVertex2f(0, 0);
glVertex2f(0.5f, 0);
glVertex2f(0.5f, 0.5f);
glVertex2f(0.0f, 0.5f);
glEnd();
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
SwapBuffers_OLD(HDC);
然而,这对游戏根本没有任何影响。
任何类似的提示,源代码或教程也值得赞赏。 顺便说一下,这场比赛是反击1.6并且我不打算在网上作弊。
感谢。
编辑:
我可以设法通过使用由“derHass”提出的新的opengl上下文在游戏的窗口中绘制一个简单的矩形。这是我做的:
//1. At the beginning of the hooked gdiSwapBuffers(HDC hdc) method save the old context
GLboolean gdiSwapBuffersHOOKED(HDC hdc) {
HGLRC oldContext = wglGetCurrentContext();
//2. If the new context has not been already created - create it
//(we need the "hdc" parameter for the current window, so the initialition
//process is happening in this method - anyone has a better solution?)
//Then set the new context to the current one.
if (!contextCreated) {
thisContext = wglCreateContext(hdc);
wglMakeCurrent(hdc, thisContext);
initContext();
}
else {
wglMakeCurrent(hdc, thisContext);
}
//Draw the quad in the new context and switch back to the old one.
drawContext();
wglMakeCurrent(hdc, oldContext);
return gdiSwapBuffersOLD(hdc);
}
GLvoid drawContext() {
glColor3f(1.0f, 0, 0);
glBegin(GL_QUADS);
glVertex2f(0,190.0f);
glVertex2f(100.0f, 190.0f);
glVertex2f(100.0f,290.0f);
glVertex2f(0, 290.0f);
glEnd();
}
GLvoid initContext() {
contextCreated = true;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0.0, 640, 480, 0.0, 1.0, -1.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glClearColor(0, 0, 0, 1.0);
}
结果如下: cs overlay example 它仍然非常简单,但我会尝试添加更多细节,文本等。
感谢。
答案 0 :(得分:1)
如果游戏使用的是OpenGL,那么原则上可以选择挂钩SwapBuffers
。从理论上讲,可能存在各种不同的drawable,您可能必须在交换缓冲区函数中决定哪一个是正确的修改。
但是这种OpenGL拦截存在一些问题:
OpenGL是一个状态机。应用程序可能已经修改了任何GL状态变量。您提供的代码远非完整,无法保证绘制内容。例如,如果应用程序恰好启用了着色器,则所有矩阵设置可能都没有效果,并且屏幕上真正显示的内容取决于着色器。
如果进行深度测试,您的碎片可能会落后于已绘制的碎片。如果启用了多边形剔除,则对于当前剔除模式,您的图元可能会被错误地蜿蜒。如果颜色蒙版设置为GL_FALSE
或者绘图缓冲区未设置到您期望的位置,则不会显示任何内容。
另请注意,您尝试“重置”矩阵也是错误的。您似乎假设当前矩阵模式为GL_MODELVIEW
。但事实并非如此。它也可以是GL_PROJECTION
或GL_TEXTURE
。您还可以在不首先加载标识的情况下将glOrtho
应用于当前投影矩阵,因此仅此一项就是没有任何内容出现在屏幕上的好理由。
由于OpenGL是状态机,您还必须恢复所触摸的所有状态。你已经尝试使用矩阵堆栈push / pop。但是,例如,您无法恢复精确的矩阵模式。正如您在1中看到的那样,将需要更多的状态更改,因此恢复它将更加复杂。由于您使用的是旧版OpenGL,因此glPushAttrib()
可能会派上用场。
SwapBuffers
不是GL函数,而是操作系统的API之一。它得到一个drawable作为参数,并且只间接引用任何GL上下文。 当另一个GL上下文绑定到线程时,或者根本没有GL上下文时,可能会调用它。如果你想安全地玩它,你还必须截取GL上下文创建函数以及MakeCurrent
。在最糟糕的情况下(尽管非常不可能),应用程序在调用SwapBuffers
时将GL上下文绑定到另一个线程,因此在钩子函数中没有任何变化可以到达上下文。
将所有这些放在一起会打开另一种选择:您可以创建自己的GL上下文,在挂钩的SwapBuffers
调用期间临时绑定它并再次恢复原始绑定。这样,您根本不会干扰应用程序的GL状态。您仍然可以扩充应用程序渲染的图像内容,因为帧缓冲区是drawable的一部分,而不是GL上下文。这样做可能会对性能产生负面影响,但它可能会非常小,以至于您甚至都不会注意到它。
由于您只想为单个特定应用程序执行此操作,因此另一种方法是通过观察应用程序在SwapBuffers调用期间实际设置的GL状态来找出所需的最小状态更改。像apitrace这样的工具可以帮助您。