有没有想知道什么时候屏幕更新/刷新(OpenGL或DirectX可能?)

我目前有一个用c#编写的应用程序(使用.NET),要求我在用户在屏幕上看到图像时立即启动计时器,直到他们用按键响应。

现在我意识到,考虑到监视器输入滞后和响应时间,键盘物理发送消息所需的时间,处理它的操作系统等,实际上这非常困难。

但我正在尽我所能将其降低到大部分是一个恒定的错误(响应时间结果将用于比较一个用户与下一个用户,因此常量错误不是真正的问题)。 然而,令人烦恼的障碍是由监视器刷新率引起的变量,正如我在调用和完成onPaint消息时收集的那样,这并不意味着图像实际上已经被处理并从图形缓冲区发送了?

不幸的是,时间限制和其他承诺实际上会限制我在c#for Windows中继续执行此任务。

所以我想知道的是,如果可以在屏幕更新时使用OpenGL或DirectX来创建事件,那么在OpenGL或DirectX中处理所有绘图还是更好?

之前给我的另一个建议是关于V-Sync,如果我关闭它是一旦它被绘制后发送的图像? 而不是以与显示器刷新率同步的设定速率发送图像?

您必须在单独的线程中渲染图形,以便:

  • 使用垂直同步可以精确计时图像的有效显示。
  • 获取用户输入的精确计时(因为用户界面与渲染循环不在同一个线程上)。

初始化Direct3D以在渲染期间启用VSync:

 // DirectX example presentParams.SwapEffect = SwapEffect.Discard; presentParams.BackBufferCount = 1; presentParams.PresentationInterval = PresentInterval.One; device = new Device(... 

在单独的线程中执行渲染:

 Thread renderThread = new Thread(RenderLoop); renderThread.Start(); shouldDisplayImageEvent = new AutoResetEvent(); 

然后使用以下渲染循环:

 void RenderLoop() { while(applicationActive) { device.BeginScene(); // Other rendering task if (shouldDisplayImageEvent.WaitOne(0)) { // Render image // ... userResponseStopwatch = new Stopwatch(); userResponseStopwatch.Start(); } device.EndScene(); device.Present(); } } 

然后处理用户输入:

 void OnUserInput(object sender, EventArgs e) { if (userResponseStopwatch != null) { userResponseStopwatch.Stop(); float userResponseDuration = userResponseStopwatch.ElapsedMillisecond - 1000 / device.DisplayMode.RefreshRate - displayDeviceDelayConstant; userResponseStopwatch = null; } } 

现在,您可以使用shouldDisplayImageEvent.Set()事件触发器根据需要显示图像并启动秒表。

首先在应用程序空闲循环上启用VSync:

 // DirectX example presentParams.SwapEffect = SwapEffect.Discard; presentParams.BackBufferCount = 1; presentParams.PresentationInterval = PresentInterval.One; device = new Device(... Application.Idle += new EventHandler(OnApplicationIdle); // More on this here : http://blogs.msdn.com/tmiller/archive/2005/05/05/415008.aspx internal void OnApplicationIdle(object sender, EventArgs e) { Msg msg = new Msg(); while (true) { if (PeekMessage(out msg, IntPtr.Zero, 0, 0, 0)) break; } // Clearing render // ... if (displayImage) { // Render image // ... renderTime = DateTime.now(); } device.Present(); } 

启用vsync后device.Presentfunction将阻塞,直到下一帧同步,因此如果计算renderTime和用户输入时间之间的时间并移除显示设备延迟+ 16.67ms,则应该得到用户响应延迟。