VSync

  • VB.NET

Es gibt 28 Antworten in diesem Thema. Der letzte Beitrag () ist von Krissel095.

    Ich hab ein kleines Problem, ist nicht besonders schwerwiegend, aber ich finds nur etwas störend.

    Ich lasse mehrere Dinge in einer Paint-Sub zeichnen

    VB.NET-Quellcode

    1. Private Sub Form1_Paint(...)
    2. ' Blaaa
    3. Me.Invalidate()
    4. End Sub


    Nun..damit die CPU nicht vollkommen überlastet ist, habe ich ein Threading.Thread.Sleep(10) eingebaut, damit die FPS ungefähr bei 60 liegen.
    Das Problem ist nur, wenn die Funktion etwas länger braucht, gehen die Frames in den Keller. Das finde ich persönlich für ziemlich ungünstig.
    Deshalb dachte ich mir, dass ich eine Constant-FPS-Funktion einbaue.

    Dabei habe ich leider keinen Ansatz, wie ich es anstellen könnte die FPS gescheit konstant zu halten.
    Wäre über jeden Ansatz erfreut.
    Wie wär's, wenn du einen Backbuffer verwendest (Bitmap) und dein Zeug da draufmalst.
    Das Ganze könnte in einem zweiten Thread laufen, und alle 10 Millisekunden würde der Backbuffer auf das Formular kopiert werden.
    Beachte aber, dass die Bilder damit sehr unfertig aussehen und wichtige Teile fehlen können.
    Jo. Aber generell sollte immer alles gezeichnet werden, so ein halbes Bild würde den Spieler sicherlich verwirren.

    Und btw. ist der Plural von "sheep" sheep.
    Nein. Der Framedrop der Bild-Methode ist noch viel schlimmer.
    Ich habe so normal 68 FPS. Maximiere ich die Anwendung sinds noch 13 FPS.
    Bei der Paint-Methode habe ich da noch 30 FPS.
    Könnte ich das mit der FastGraphicsLib schneller hinbekommen?

    //Ma gucken ob ich mit OpenGL/DirectX per IrrLicht eine bessere Performance bekomme.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „AliveDevil“ ()

    Ja weiß ich :P
    Evtl. wäre DirectX noch etwas, was ich nutzen kann.
    Und wenn das ungünstig ist..nehme ich SlimDX :P
    Nur ich möchte nicht so viele Anforderungen für die Engine haben (XNA, .NET FW 4, DX 9)
    Derzeit ists schon .NET FW 4.
    Wenn ich das richtig verstehe sieht deine Zeichnroutine etwa so/ähnlich aus:

    VB.NET-Quellcode

    1. Private Sub Form1_Paint(...)
    2. ' Blaaa => deine Zeichenroutine?
    3. Thread.sleep(10)
    4. Me.Invalidate()
    5. End Sub


    Das ist eine sehr schlechte konstruktion... Das Paint-Event sollte man nur nutzen wenn man Daten "dauerhaft" anzeigen möchte - sie sollen sich automatisch neuzeichnen wenn eine andere Form über den Zeichenbereich bewegt wird, etc. Ich kann da jetzt noch viel erzählen, worauf ich hinaus will: Das Paint-Event ist für einen Nutzungszweck ungeeignet:
    Das Paint-Event wird von überall aufgerufen (neuzeichnen weil hier ne Form drüber bewegt wurde, weil sich dort die formgröße verändert hat, etc) und dann kommst du noch mit deiner dauerschleife in form von me.invaldiate... dass das an der Performance knabbert ist kein wunder^^

    Ich würde hier das Paint-Event außer acht lassen und .createGraphics verwenden. Du zeichnest Ohne hin 60 mal in der Sekunde neu - da ist es zu vernachlässigen ob ein Teilweise ungültiges Bild an den entsprechenden stellen gezielt neugezeichnet wird - in spätetestens 0,016 Sekunden kommt das nächste...
    Warum also nicht die zeichenroutine von einem Thread ausführen lassen, der so ausgebremst wird, dass er 60 umdrehungen schafft? Du könntest ja mittels stopwatch messen wie lange er für 10 Frames braucht und anhand diesem Wert hochrechnen wie lange die Thread.Sleep-Pause zwischen den Frames sein muss...

    "Vsync" wirst du nur erreichen indem du ALLES auf einen Buffer zeichnest (wie schon gesagt Bitmap, gibt da bestimmt performantere möglichkeiten) und diesen dann ausgibtst


    EDIT: SFML zeichnet übrigens (soweit ich das noch in erinnerung habe) nur Grafiken. Linien, Kreise etc wirst du nicht sooo einfach auf den Bildschirm bekommen..
    Hmm..das wird immer schlimmer :P

    VB.NET-Quellcode

    1. Private Sub drawBuffer()
    2. Using g = Me.CreateGraphics()
    3. Do
    4. g.Clear(Color.Black)
    5. halt.Reset()
    6. If (backBuff IsNot Nothing) Then
    7. g.DrawImage(backBuff, New Point(0, 0))
    8. End If
    9. halt.Set()
    10. Loop
    11. End Using
    12. End Sub

    Da habe ich ~6 Frames pro Sekunde.
    Somit fällt Threaded weg.
    Gäbe es sonst noch einen Weg?
    Nein.
    Da ich mich mit XNA noch nicht beschäftigt habe, werde ich es damit sicherlich nicht machen.
    Außerdem weiß ich da nicht, wie ich einfach mal ne Ressource aus einem anderen Programm zeichnen kann.
    Mein Programm ist ja eig. nur die Darstellung und der Hintergrund für andere Spiele.

    Deshalb brauch ich auch eine einfache Darstellungsengine.
    Sowas wie GDI..
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Public Class Form1
    2. Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    3. Timer1.Interval = 1000
    4. Timer1.Start()
    5. End Sub
    6. Private Sub Form1_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseMove
    7. loc = e.Location
    8. End Sub
    9. Public WithEvents Timer1 As New Timer
    10. Public WithEvents FD As New FrameDrawer(Me.CreateGraphics)
    11. Dim loc As Point = New Point(9, 9)
    12. Dim f As Integer = 0 'für die FPS-Zahl zu berechnen
    13. Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
    14. Me.Text = "SleepTimer: " & FD.Pause.ToString & " FPS: " & f.ToString
    15. f = 0
    16. End Sub
    17. Public VirtuelleDauerZeichenroutine As Integer = 0
    18. Private Sub NumericUpDown1_ValueChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles NumericUpDown1.ValueChanged
    19. VirtuelleDauerZeichenroutine = NumericUpDown1.Value
    20. End Sub
    21. Sub Zeichenroutine(ByVal gra As Graphics) Handles FD.Draw 'Hier wird gezeichnet
    22. f += 1 'zählt die aufrufe um die FPS-Zahl zu berechnen/beweisen
    23. gra.Clear(Color.White)
    24. gra.FillEllipse(Brushes.Black, loc.X - 5, loc.Y - 5, 10, 10)
    25. Threading.Thread.Sleep(VirtuelleDauerZeichenroutine)
    26. End Sub
    27. End Class
    28. Public Class FrameDrawer
    29. Public Sub New(ByVal gra As Graphics)
    30. g = gra
    31. Dim t As New Threading.Thread(AddressOf DrawLoop)
    32. t.Start()
    33. End Sub
    34. Dim g As Graphics = Nothing
    35. Public Event Draw(ByVal gra As Graphics)
    36. Public Ziel_FPS As Integer = 60
    37. Public Pause As Integer = 1
    38. Public Sub DrawLoop()
    39. Do
    40. Dim sw As New Stopwatch
    41. sw.Start()
    42. For i = 0 To 9
    43. RaiseEvent Draw(g)
    44. If Pause >= 0 Then Threading.Thread.Sleep(Pause)
    45. Next
    46. sw.Stop()
    47. Dim t As Integer = sw.ElapsedMilliseconds - 10 * Pause
    48. Dim pnew As Integer = CInt((1000 - ((Ziel_FPS / 10) * t)) / Ziel_FPS) 'solange darf die pause sein...
    49. If pnew >= 0 Then Pause = pnew Else Pause = 0
    50. Loop
    51. End Sub
    52. End Class


    Hau das in den Code einer Forms-Anwendung und füge eine NummericUpDown-Control hinzu. Das Teil ruft konstant die Zeichnroutine auf. Du kannst die Ziel_FPS zahl festlegen und das ding macht den rest indem es die Zeichenroutine gezielt ausbremst (fallst erforderlich). Mit NummericUpDown1 kannst du die Ausführungszeit der Zeichenroutine "virtuell" verzögern - nur als beweis, dass es funktioniert.

    Achso, das teil ist nicht ausgereift und schmiert beim sclhließen ab. Du musst es eben noch ausbessern und erweitern.. ist nur eine demonstration

    lg^^