C# Opengl Hook Swapbuffer 添加插值帧

标签 c# opengl hook screenshot interpolation

我正在尝试以 60Fps 而不是 30Fps 运行游戏。游戏锁定为 30fps,因此我可以达到 60fps 的唯一方法是帧插值。

对于插值部分,我将使用 OpenCV,我找到了 this pretty good article .

此游戏使用 OpenGL。经过一番研究,我发现最好的抓屏方式是hook SwapBuffer函数。所以我选择 Hook 游戏来抓取屏幕并将它们发送到另一个应用程序,这将实时播放游戏并顺便添加插值帧以达到 60 FPS(如果你有更好的主意,我完全打开!)

我开始编写我的新 dll。我使用 C# 编写代码,并选择 EasyHook 来注入(inject)我的 DLL。

Hooking 运行良好,现在非常酷 =D。

但是,我现在卡住了,因为我完全不知道如何从游戏中抓取屏幕。

我尝试使用 OpenGL.NetSharpGL ,但我无法弄清楚我应该如何获取实际的 OpenGL 上下文以使用 glReadPixel!

这是我的实际代码:

using System;
using System.Runtime.InteropServices;


namespace Hook
{
    public class ServerInterface : MarshalByRefObject
    {
        public void IsInstalled(int clientPID)
        {
            Console.WriteLine("This programm has injected dll into process {0}.\r\n", clientPID);
        }

        public void ReportMessage(int clientPID, string message)
        {
            Console.WriteLine(message);
        }

        public void ReportException(Exception e)
        {
            Console.WriteLine("The target process has reported an error:\r\n" + e.ToString());
        }

        public void Ping()
        {
            Console.WriteLine("Ping !");
        }
    }


    //Point d'entrée
    public class InjectionEntryPoint : EasyHook.IEntryPoint
    {
        //Serveur :
        ServerInterface server = null;

        public InjectionEntryPoint(EasyHook.RemoteHooking.IContext context, string channelName)
        {
            //Constructeur
            //Objectif : vérifier si la communication entre les deux programmes peut etre établit
            server = EasyHook.RemoteHooking.IpcConnectClient<ServerInterface>(channelName);
            server.Ping();

        }

        public void Run(EasyHook.RemoteHooking.IContext context, string channelName)
        {

            try
            {
                var SwapBuffersHook = EasyHook.LocalHook.Create(EasyHook.LocalHook.GetProcAddress("opengl32.dll", "wglSwapBuffers"), new SwapBuffers_Delegate(SwapBuffers_Hook), this);
                SwapBuffersHook.ThreadACL.SetExclusiveACL(new Int32[] { 0 });
                server.ReportMessage(EasyHook.RemoteHooking.GetCurrentProcessId(), "SwapBuffers Hooked");
            }
            catch (Exception ExtInfo)
            {
                server.ReportException(ExtInfo);
                return;
            }

            server.IsInstalled(EasyHook.RemoteHooking.GetCurrentProcessId());

            EasyHook.RemoteHooking.WakeUpProcess();

            //Waiting years
            while( true)
            {
                System.Threading.Thread.Sleep(10000);
            }


            // Finalise cleanup of hooks
            EasyHook.LocalHook.Release();

        }


        //Deleguate
        [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode, SetLastError = true)]
        delegate IntPtr SwapBuffers_Delegate(IntPtr hdc);

        //Original
        [DllImport("opengl32.dll", CharSet = CharSet.Unicode, SetLastError = true, CallingConvention = CallingConvention.StdCall)]
        static extern IntPtr wglSwapBuffers(IntPtr hdc);

        //Hook function
        public IntPtr SwapBuffers_Hook(IntPtr hdc)
        {

            server.ReportMessage(EasyHook.RemoteHooking.GetCurrentProcessId(),  "I'm in SwapBuffers =DDDD");

            //Here I need to grab frames

            //Return
            return wglSwapBuffers(hdc);
        }
    }
}

最佳答案

我怀疑您能否提高游戏的 FPS。顺便说一句,有一些可能性。

你在做什么是正确的方法。您只是错过了创建要显示的中间框架的 GL 代码(我建议使用当前的 GL 上下文在进程中创建它)。

问题是在执行 SwapBuffers 命令时显示视频帧。这是您 Hook 的那个,但问问自己和程序:为什么每秒调用 30 次 SwapBuffers

如果答案是“因为应用程序使用定时器挂起执行”,你就不能轻易解决这个问题:你的钩子(Hook)必须与应用程序一起工作,因此你需要了解应用程序如何休眠。

如果答案是“因为应用程序正在利用 WGL_EXT_swap_control”,那么您有一种可能性:

  • 设置 wglSwapIntervalEXT(1)(因为应用程序调用了 wglSwapIntervalEXT(2) 以获得与 V-Sync 同步的 30 FPS。可能这只需要一次
  • 在你的钩子(Hook)中,抓取两帧,然后在每隔一帧对它们进行插值(因此你的问题)。在每个钩子(Hook)执行时,您需要渲染插值帧,然后交换;然后渲染下一个原始帧,然后交换。

如何创建插值帧?如果您通过 CPU 进行操作,请将 glReadPixels 与后台缓冲区 (GL_BACK) 一起用作读取帧缓冲区(使用 glDrawBuffers)。这将下载帧缓冲区绑定(bind)的内容。然后使用混合方程得到插值像素。

关于C# Opengl Hook Swapbuffer 添加插值帧,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43877395/

相关文章:

c# - 在 C# 中,分贝的幅度总是返回 NaN

c# - .net WinForms 控件验证 - 如何显式验证所有控件

c - opengl glDrawElements 问题

opengl - 如何在OpenGL中旋转2D正方形?

c++ - 窗口 Hook 问题

c# - 简单的注入(inject)器防止锁定容器

c++ - 为什么我无法在 Visual Studio 之外运行 OpenGL 程序?

react-native - React Redux 的 useSelector 不更新 expo react-native 上的商店状态

delphi - 创建文件 Hook

c# - 如何让我的应用程序在加载但未在前台运行时发送通知?