2010-01-14 10 views
6

मुझे कुछ एनीमेशन एक ओपनजीएल संदर्भ विंडो में चल रहा है, इसलिए मुझे लगातार इसे फिर से निकालना होगा। तो मैं निम्नलिखित कोड के साथ आया:60 एफपीएस पर .NET Redraw?

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(); 
    } 

यह केवल मुझे 40 एफपीएस देता है। अगर मैं अंतराल को 1 एमएस तक सेट करता हूं, तो मैं 60 प्राप्त कर सकता हूं। तो अन्य 20 एमएस कहां गए? क्या यह सिर्फ टाइमर की खराब शुद्धता या क्या है? क्या होगा यदि मैं जितना संभव हो सके अपने प्रोग्राम को चलाने देना चाहता हूं, क्या ड्रॉ func को लगातार कॉल करने का कोई तरीका है?

उत्तर

7

आप गेम लूप को लागू करने का प्रयास कर सकते हैं।

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); 

, सरल सुंदर, प्रभावी:

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

बुनियादी पाश (थोड़ा अपने मूल संस्करण और पढ़ने में आसानी के लिए नई SDK में संस्करण से संशोधित) । कोई अतिरिक्त आवंटन, कोई अतिरिक्त संग्रह नहीं, यह सिर्फ काम करता है .. कतार में कोई संदेश नहीं होने पर निष्क्रिय घटना आग लगती है, और फिर जब तक कोई संदेश प्रकट नहीं होता है तब तक हैंडलर लगातार लूपिंग करता रहता है, इस स्थिति में यह बंद हो जाता है .. एक बार सभी संदेश संभाला जाता है, निष्क्रिय घटना फिर से निकाल दी जाती है, और प्रक्रिया खत्म हो जाती है।

यह लिंक उस व्यक्ति का वर्णन करता है जो एप्लिकेशन के निष्क्रिय ईवेंट का उपयोग करता है। यह उपयोग का हो सकता है। आप बस अपने आवश्यक एफपीएस को धीमा करने के लिए थोड़ा समय परीक्षण या नींद कर सकते हैं। सबसे सटीक टाइमर के लिए System.Diagnostics.StopWatch क्लास का उपयोग करने का प्रयास करें।

मुझे आशा है कि इससे थोड़ा सा मदद मिलेगी।

+0

अच्छा! 'एप्लिकेशन.इडल' का उपयोग करना 1 एमएस टाइमर से बहुत अधिक सुरुचिपूर्ण लगता है। मुझे कल भी 'स्टॉपवॉच' को आजमाने की ज़रूरत होगी। धन्यवाद! ** संपादित करें: ** असल में, मैंने झूठ बोला। जब आप विंडो का आकार बदल रहे हैं या स्थानांतरित कर रहे हैं, तो ऐसा लगता है कि यह निष्क्रिय हो रहा है, और इस प्रकार रीड्रॉइंग बंद हो जाता है। यह मूल रूप से ड्राइंग की प्राथमिकता को कम करता है। हो सकता है कि मैं न्यूनतम रेड्रा दर लागू करने के लिए टाइमर के साथ रहूंगा ... कोई कारण नहीं कि मैं दोनों विधियों को भी जोड़ नहीं सकता। – mpen

+3

इसके अलावा, स्टॉपवॉच केवल समय के लिए अच्छा है, कॉलबैक घटनाओं के लिए नहीं। – mpen

+3

निष्क्रिय होने पर भी आप अपना टाइमर शुरू करने का प्रयास कर सकते हैं, फिर निष्क्रिय घटना को आग लगने पर फिर से इसे रोकें/जांचें। आप इस तरह से काफी करीब हो सकते हैं। – Nanook

2

विंडोज फॉर्म टाइमर अंततः आपके कंप्यूटर के मानक सिस्टम घड़ी रिज़ॉल्यूशन के लिए संकल्प में सीमित है। यह कंप्यूटर से कंप्यूटर में भिन्न होता है, लेकिन आमतौर पर 1 एमएस और 20 एमएस के बीच होता है।

WinForms में, जब भी आप कोड में टाइमर अंतराल का अनुरोध करते हैं, तो विंडोज केवल गारंटी देगा कि आपके टाइमर को कहा जाएगा और और निर्दिष्ट मिलीसेकंड की संख्या। यह गारंटी नहीं देता है कि आपके टाइमर को आपके द्वारा निर्दिष्ट मिलीसेकंड पर कॉल किया जाएगा।

ऐसा इसलिए है क्योंकि विंडोज एक समय-साझा करने वाला ओएस है, वास्तविक समय नहीं। अन्य प्रक्रियाओं और धागे को समवर्ती रूप से चलाने के लिए निर्धारित किया जाएगा और इसलिए आपके थ्रेड को प्रोसेसर के उपयोग के लिए नियमित रूप से प्रतीक्षा करने के लिए मजबूर किया जाएगा। इसलिए आपको WinForms टाइमर कोड नहीं लिखना चाहिए जो सटीक अंतराल या मिलीसेकंड में देरी पर निर्भर करता है।

आपकी स्थिति में, अंतराल को 1 एमएस तक सेट करना वाकई विंडोज़ को इस टाइमर को जितनी बार हो सके ट्रिगर करने के लिए कह रहा है। जैसा कि आपने देखा है यह निश्चित रूप से 1 एमएस (60 एफपीएस = लगभग 17 एमएस) से काफी कम है।

यदि आपको अधिक सटीक और उच्च रिज़ॉल्यूशन टाइमर की आवश्यकता है, तो यदि आपका हार्डवेयर इसका समर्थन करता है, तो Windows API उच्च रिज़ॉल्यूशन/प्रदर्शन टाइमर प्रदान करता है, How to use the high resolution timer देखें। इसका एक दोष यह है कि उच्च प्रदर्शन का समर्थन करने के लिए आपके एप्लिकेशन CPU उपयोग में वृद्धि होगी।

कुल मिलाकर मुझे लगता है कि आप हार्डवेयर/सिस्टम स्वतंत्र गेम लूप को लागू करने से बेहतर हैं। इस तरह आपके दृश्य की अनुमानित एनीमेशन वास्तविक फ्रेम दर प्राप्त किए बिना निरंतर दिखाई देता है।अधिक जानकारी के लिए these articles एक अच्छी पृष्ठभूमि दें।

3

आप जो कर रहे हैं उसके आधार पर, डब्ल्यूपीएफ और उसके एनीमेशन समर्थन पर एक नज़र डालें, यह एक बेहतर समाधान हो सकता है जो WinForms में अपनी खुद की आकलन लिख रहा है।

डायरेक्टएक्स का उपयोग करने पर विचार करें क्योंकि अब इसमें .NET wrapper है और यह बहुत तेज है, हालांकि WPF या WinForms का उपयोग करना मुश्किल है।

लगातार अपने ड्रा फ़ंक्शन को कॉल करने के लिए:

  • रीपेंट विधि में ड्राइंग करते
  • रीपेंट विधि के अंत में जोड़ें BeginInvoke
  • कर प्रतिनिधि आप BeginInvoke के लिए पारित में, अमान्य आप जिस नियंत्रण को चित्रित कर रहे हैं

हालांकि आपके उपयोगकर्ता आपको अपने कंप्यूटर को मारना पसंद नहीं कर सकते हैं!

एप्लिकेशन.इडल भी एक और अच्छा विकल्प है, हालांकि मुझे लगता है कि विंडोज़ की आवश्यकता होने पर विंडोज़ उस दर को धीमा कर देगा जब यह आवश्यक हो तो डब्लूएमपीएंट संदेश भेज देगा।

+0

मैंने यह भी पता लगाया कि ड्राइंग के बाद सही अमान्य करने से टाइमर विधि की तुलना में बहुत अधिक फ्रेम दर उत्पन्न होती है (कुछ कारणों से 65 एफपीएस टाइमर के साथ उच्चतम मूल्य था)। –

-1

मैं लाइन में दिए गए नमूना कोड में देखा है:

timer.Interval = 1000/60; 

यह पूर्णांक विभाजन के संचालन का उपयोग करता है, तो परिणाम पूर्णांक बढ़ा दिया जाएगा और ठीक 16.6666ms नहीं होगा, लेकिन 17ms । इसलिए टाइमर स्क्रीन रीफ्रेश की तुलना में बड़ी टिक बनाते हैं।

+0

इंटीजर डिवीजन truncates, राउंड नहीं। 1000/60 इस प्रकार 16 है ([सबूत] (https://repl.it/GGNW/0))। यदि टाइमर सटीक था तो मुझे ~ 62.5 एफपीएस मिलना चाहिए। – mpen

+0

ओह। मैं इसके बारे में भूल गया हूँ। लेकिन वैसे भी, यदि यह 16ms है, तो टिकों को मॉनिटर के साथ सिंक्रनाइज़ नहीं किया जाता है। – Dennis

+1

यह मॉनिटर पर निर्भर करता है। बहुत यकीन है कि यह gsync/freesync के साथ कोई समस्या नहीं है, लेकिन परवाह किए बिना, मुझे पूरा यकीन है कि 'टाइमर। अंतराल' यहां जवाब नहीं है। – mpen

संबंधित मुद्दे