我从小就一直在“破解”我最喜欢的游戏之一,并且我设法能够拦截 OpenGL 调用并使用 opengl32.dll 包装器注入 C++ 代码。我已经为此想出了许多很酷的用途,但我目前的目标是在这个旧游戏中实现后处理 glsl 着色器,让它看起来更现代一点。该游戏最初是在 90 年代后期发布的,因此它对 OpenGL 的使用及其渲染代码是有限的/原始的/过时的。
我已经能够通过注入代码来初始化和使用 glsl 着色器程序成功地生成顶点和片段着色器,但我的问题在于产生帧缓冲区/将我的场景渲染到纹理以作为采样器发送到我的片段着色器。据我所知,我制作的纹理通常都是黑色的。
很难找到与我正在做的事情和检查原始 opengl 调用相关的资源(我一直试图通过阅读单帧游戏的 opengl 跟踪来确定在哪里插入代码),所以我没有能够把我的头绕在我做错的事情上。
我尝试将代码放在很多地方,但目前,我在游戏调用后绑定帧缓冲区,wglSwapBuffers()
并且在下一次调用之前立即解除绑定glFlush()
,但我不确定是否设置了多个视口,或矩阵运算,或在这些时间之间创建的任何其他东西都会以某种方式扰乱帧缓冲区。
这是初始化帧缓冲区的代码:
void initFB()
{
/* Texture */
glActiveTexture(GL_TEXTURE0);
glGenTextures(1, &fbo_texture);
glBindTexture(GL_TEXTURE_2D, fbo_texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1920, 1080, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glBindTexture(GL_TEXTURE_2D, 0);
/* Depth buffer */
glGenRenderbuffers(1, &fbo_depth);
glBindRenderbuffer(GL_RENDERBUFFER, fbo_depth);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, 1920, 1080);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, fbo_depth);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
/* Framebuffer to link everything together */
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fbo_texture, 0);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, fbo_depth);
GLenum status;
if ((status = glCheckFramebufferStatus(GL_FRAMEBUFFER)) != GL_FRAMEBUFFER_COMPLETE) {
fprintf(stderr, "glCheckFramebufferStatus: error %p", status);
}
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
这是之后调用的代码wglSwapBuffers
:
GLenum fboBuff[] = { GL_COLOR_ATTACHMENT0 };
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glDrawBuffers(1, fboBuff);
glPushAttrib(GL_VIEWPORT_BIT | GL_ENABLE_BIT);
这是之前调用的代码glFlush()
:
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glPopAttrib(); // Restore our glEnable and glViewport states
... Draw an Overlay containing with fbo texture binded ...
这是单帧的 gl 轨迹。
它有近 800 行,但训练有素的 opengl 眼睛应该能够看到什么时候发出的呼叫。我删除了数百行我至少理解的绘图调用。