Minecraft Clone OpenGL Async Chunk Loading

  • VB.NET
  • .NET (FX) 4.5–4.8

Es gibt 5 Antworten in diesem Thema. Der letzte Beitrag () ist von jvbsl.

    Minecraft Clone OpenGL Async Chunk Loading

    Hi Leute,

    ich bin immernoch dabei meinen Minecraft-Client zu schreiben. Funzt bis jetzt auch ziemlich gut bis auf die Tatsache dass der Chunk-Loader trotz Optimierungen ziemlich lahm ist. Ich Arbeite mit GL.NewList(), GL.GenList() und GL.CallList(). Jedes mal, wenn ein Chunk hinzugefügt wird, wird er auf die sections aufgeteilt und dann dem SectionRenderer übergeben. Wenn der SectionRenderer feststellt, dass die Displaylist noch nicht existiert, legt er sie neu an, und das dauert. Ich habe mir überlegt das Multithreaded zu machen, ungefähr so:

    VB.NET-Quellcode

    1. Public Sub RenderSection(ByRef section As Section)
    2. If Not processor.IsAlive Then 'Processor ist der Thread Public processor As New Thread(AddressOf ChunkProcessor) With {.IsBackground = True}
    3. processor.Start()
    4. End If
    5. If section.needsRebuild Then
    6. section.needsRebuild = False
    7. queue.Enqueue(section)
    8. End If
    9. If section.list <> -1 Then
    10. GL.CallList(section.list)
    11. End If
    12. End Sub
    13. Public Sub ChunkProcessor()
    14. While True
    15. SyncLock synclockx
    16. Dim sec As Section
    17. If queue.TryDequeue(sec) And sec IsNot Nothing Then
    18. RebuildSection(sec)
    19. End If
    20. End SyncLock
    21. End While
    22. End Sub
    23. Public Sub RebuildSection(ByRef section As Section)
    24. section.needsRebuild = False
    25. section.list = GL.GenLists(2)
    26. GL.NewList(section.list, ListMode.Compile)
    27. TheGame.textureManager.BindAtlas()
    28. t.Init()
    29. chunk = section.Chunk
    30. For x As Integer = 0 To 15
    31. For y As Integer = 0 To 15
    32. For z As Integer = 0 To 15
    33. absoluteX = chunk.worldX + x
    34. absoluteY = section.yIndex * 16 + y
    35. absoluteZ = chunk.worldZ + z
    36. tile = GetBlock(x, y, absoluteY, z, section)
    37. If tile <> 0 Then
    38. yPos = Not IsTile(x, y + 1, absoluteY + 1, z, section)
    39. yNeg = Not IsTile(x, y - 1, absoluteY - 1, z, section)
    40. zNeg = Not IsTile(x, y, absoluteY, z - 1, section)
    41. zPos = Not IsTile(x, y, absoluteY, z + 1, section)
    42. xNeg = Not IsTile(x - 1, y, absoluteY, z, section)
    43. xPos = Not IsTile(x + 1, y, absoluteY, z, section)
    44. t.RenderCube(tile, absoluteX, absoluteY, absoluteZ, yPos, yNeg, xNeg, xPos, zNeg, zPos)
    45. End If
    46. Next
    47. Next
    48. Next
    49. t.Flush()
    50. GL.EndList()
    51. End Sub


    So jetzt läuft alles Lag-Frei, konstant 190-200fps (das Maximum was ich eingestellt habe), aber er rendert nix mehr außer der Skybox.
    Was mach ich hier falsch? Geht das nicht bei GL, dass man das Multithreaded oder ist irgendwo anders mein Code Faul?
    Hoffe ihr könnt mir helfen :D

    LG
    Twometer
    An Error 404 occurred while loading signature...
    Das Problem liegt beim "Multithreading". Du musst dem Thread den Kontext übergeben, bevor dieser etwas laden kann.
    Es sollte sowas wie GL.MakeCurrent() sein.

    Nachtrag: Eine Alternative ist, wenn du einen weiteren OpenGL Kontext erzeugst und dann mit den ShareLists arbeitest. Mit diesen kannst du kontextübergreifend agieren.

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

    Hi,
    erstmal danke für deine Hilfe. Ich habe jetzt probiert mit MakeCurrent zu arbeiten, bekomme aber den Fehler Failed to make context 65537 current. Error: 170. Durch googlen hab ich herausgefunden, dass ich im Haupt-Thread erst den Context freigeben muss, damit ich ihn wieder Current machen kann im Loader-Thread. Aber wie soll ich das machen bei meinem ChunkProcessor:

    VB.NET-Quellcode

    1. Public Sub ChunkProcessor()
    2. While True
    3. Dim sec As Section
    4. If queue.TryDequeue(sec) Then
    5. TheGame.MakeCurrent() 'Das Kracht
    6. RebuildSection(sec)
    7. End If
    8. End While
    9. End Sub


    Ich bräuchte sowas wie

    VB.NET-Quellcode

    1. Public Sub ChunkProcessor()
    2. While True
    3. Dim sec As Section
    4. If queue.TryDequeue(sec) Then
    5. SwitchToMainThread()
    6. TheGame.Context.MakeCurrent(Nothing) 'Freigeben
    7. ResumeWorkerThread()
    8. TheGame.MakeCurrent()
    9. RebuildSection(sec)
    10. End If
    11. End While
    12. End Sub


    aber das geht meines Wissens nach ja nicht?


    //EDIT: @3Angle Ich habe mal nach ShareLists und so gesucht, aber mit OpenTK gibt's das nicht mehr :/


    LG
    Twometer
    ----------------

    Ich habe jetzt festgestellt, dass das so nicht gut ist, aber gibt es keine Möglichkeit das asynchron zu rendern? Ich meine im echten MC gehts ja auch deswegen muss es ja irgendeine Möglichkeit geben. Ich bin schon ewig jetzt am herumprobieren wie das gehen soll, aber nix funktioniert, hab auch schon tausende sachen gegoogelt :(

    An Error 404 occurred while loading signature...

    Dieser Beitrag wurde bereits 8 mal editiert, zuletzt von „Twometer“ ()

    Asynchron zu rendern? Davon habe ich noch nie gehört, bzw. was verstehst du darunter?

    Ich habe mir deinen Quellcode nicht angeschaut, daher kann ich dir schwierig was dazu sagen.
    Man kann den Kontext nicht gleichzeitig zwei Threads übergeben. Der leichteste Weg dies zu lösen ist, wenn man ein zweites GameWindow in OpenTK erstellt und den Kontext initialisiert, ohne dabei die Startmethode .Run zu verwenden. Ich rate dir auch dazu beide Kontexte zu erstellen, ohne irgendwas geladen zu haben. Nach der Erzeugung deines ersten ("Haupt-") kontext, rufst du .MakeCurrent auf.

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

    Hi,
    was ich damit gemeint hab war, das das erstellen von DisplayLists bei mir lang dauert und ich das deshalb aus Performancegründen asynchron machen will.

    Deinen Vorschlag werde ich mir mal angucken ob das so geht wie Ich meine

    Twometer
    An Error 404 occurred while loading signature...
    Verwende vbos, das erstellen der vertexdaten kannst du ohne Probleme auf der cpu parallelisieren, jedoch gibt es wenig sinn gl calls parallelisieren zu wollen, da das immer kurz vor der gpu synchronisiert wird und erst dann vom Treiber entschieden wird, was er parallel machen kann.
    Wenn du den Aufruf aber nicht in dem ui thread machen möchtest, so geht mit context sharing(kann auch opentk)
    Jedoch gehen dabei z.b. keine VAOs.
    Außerdem musst du natürlich nur die Oberflächen vertices generieren (kp ob du das bereits machst)
    Ich wollte auch mal ne total überflüssige Signatur:
    ---Leer---