.NET Redraw at 60 FPS?

I have an animation running in the OpenGL context window, so I need to redraw it constantly. So I came up with the following code:

void InitializeRedrawTimer() { var timer = new Timer(); timer.Interval = 1000 / 60; timer.Tick += new EventHandler(timer_Tick); timer.Start(); } void timer_Tick(object sender, EventArgs e) { glWin.Draw(); } 

It only gives me 40 FPS. If I set the interval to 1 ms, then I can reach 60. So where is the remaining 20 ms? Is it just due to poor timer accuracy or what? What if I want my program to work as fast as possible, is there a way to constantly call the draw func function?

+6
c # winforms
source share
4 answers

You can try to implement a game cycle.

http://blogs.msdn.com/tmiller/archive/2005/05/05/415008.aspx

The main loop (slightly modified from its original version and the version in the new SDK for readability):

 public void MainLoop() { // Hook the application's idle event System.Windows.Forms.Application.Idle += new EventHandler(OnApplicationIdle); System.Windows.Forms.Application.Run(myForm); } private void OnApplicationIdle(object sender, EventArgs e) { while (AppStillIdle) { // Render a frame during idle time (no messages are waiting) UpdateEnvironment(); Render3DEnvironment(); } } private bool AppStillIdle { get { NativeMethods.Message msg; return !NativeMethods.PeekMessage(out msg, IntPtr.Zero, 0, 0, 0); } } //And the declarations for those two native methods members: [StructLayout(LayoutKind.Sequential)] public struct Message { public IntPtr hWnd; public WindowMessage msg; public IntPtr wParam; public IntPtr lParam; public uint time; public System.Drawing.Point p; } [System.Security.SuppressUnmanagedCodeSecurity] // We won't use this maliciously [DllImport("User32.dll", CharSet=CharSet.Auto)] public static extern bool PeekMessage(out Message msg, IntPtr hWnd, uint messageFilterMin, uint messageFilterMax, uint flags); 

Simple, elegant, efficient. No extra distributions, no extra collections, it just works. The Idle event is fired when there are no messages in the queue in the queue, and then the handler continues cyclically continuously until a message appears, in which case it stops. After all messages have been processed, an unoccupied event is triggered again, and the process begins.

This link describes the one that uses the application Idle event. This may be helpful. You can just do a little time test or fall asleep to slow it down to the required frames. Try using the System.Diagnostics.StopWatch class for the most accurate timer.

Hope this helps a bit.

+7
source share

Depending on what you are doing , take a look at WPF and animation support, this may be the best solution that writes your own amimations to WinForms.

We’ll also consider using DirectX, as it now has a .NET shell and is very fast, however it’s more difficult to use WPF or WinForms.

To continuously call the drawing function:

  • Make a drawing in the repaint method
  • Add at the end of the repaint method do BeginInvoke
  • As a delegate, you switched to BeginInvoke, an invalid control that you draw.

However, your users may not like the fact that you are killing their computer!

Application.Idle is also another good option, however I like that windows will slow down the speed of sending WmPaint messages if necessary.

+3
source share

The Windows Forms timer is ultimately limited by the resolution of the standard system clock resolution of your computer. It depends on the computer and the computer, but usually ranges from 1 ms to 20 ms.

In WinForms, whenever you request a timer interval in your code, Windows ensures that your timer is not called more often , and then the number of milliseconds is indicated. This does not guarantee that your timer will be called in exactly the specified milliseconds.

This is due to the fact that Windows is an OS that runs on time, and not in real time. Other processes and threads are scheduled to be launched at the same time, and therefore your thread will be forced to regularly wait for processor usage. Therefore, you should not write WinForms timer code, which depends on the exact intervals or delays in milliseconds.

In your situation, setting the interval to 1 ms really just tells Windows to start this timer as often as it can. As you have seen, this is definitely much less common than 1 ms (60 frames per second = about 17 ms).

If you need a more accurate and higher resolution timer, the Windows API provides high resolution / performance timers, if your equipment supports it, see How to do it, use a high resolution timer . The disadvantage of this is that the use of your application processor will be increased to support higher performance.

In general, I think that you are better off implementing a hardware / system independent game loop. In this way, the perceived animation of your scene becomes constant regardless of the actual frame rate achieved. For more information, these articles provide a good background.

+2
source share

I noticed in this example the code in the line:

 timer.Interval = 1000 / 60; 

It uses an integer division operation, so the result will be rounded to the nearest integer and not exactly 16.6666ms, but 17ms. Therefore, the timer does greater ticks than updating the screen.

-one
source share

All Articles