Jump to content
Unity Insider Forum

GameObject Instantiate oder GameObject positionieren, wieviele/ wieviel mal pro Frame?


cert

Recommended Posts

Hallo, ich versuche in einem Spiel das Terrain prozedural aufzubauen. Eine einfache Landschaft aus Blöcken ähnlich wie in MineCraft. Das sind eine Menge Blöcke die auch während des Spiels immer wieder hinzu kommen. Ich habe versucht dies in einer Coroutine zu erledigen, doch dies ermöglicht mir nur ca. 10 Blöcke pro Sekunde. Zuerst habe ich versucht per Instantiate die Blöcke hinzu zu fügen. Da dachte ich dies ist evtl. zu langsam und habe es dann per Objekt-Pool probiert - also die Blöcke zum Spielstart erstellt und hinterher nur aktiviert und verschoben. Komischerweise ist auch dies nicht schneller.

 

Sollte es in Unity nicht ohne Probleme ca. 100 oder mehr Blöcke pro Sekunden per Instantiate in die Szene zu bekommen bzw. 1000 Blöcke pro Sekunde durch einfaches "Verschieben"? Es sind ganz einfache Unity-Cubes mit einem Matieral.

Link to comment
Share on other sites

Diese Aufgabe ist nicht ganz so trivial wie diese es zunächst vermuten lässt. Minecraft haut auch nicht überall typische Cubes hin. Da steckt schon sehr viel mehr dahinter um diese einfachen Blöcke zu optimieren.

 

Ich habe nur wenige Ideen, wie man ansatzweise an der Performance drehen kann. Ich würde aber erstmal sämtliche Ansätze sammeln und diese Testen und nach und nach optimieren. Ein Ansatz könnte sein, dass du Cluster von Cubes auf einmal instantiierst als Prefab.

Link to comment
Share on other sites

Soweit ich weiß erstellt Minecraft die einzelnen Chunks nach und nach. Dabei werden diese aber nur im Speicher angelegt.

Wie MarcoMeter schon sagte das ganze Terrain besteht nicht aus Blöcken sondern es wird immer nur die Oberfläche gezeichnet und dementsprechend auch nur generiert. Sobald man einen Block abbaut wird halt das Mesh aktualisiert...

 

Edit: Das kann man auch gut sehen wenn man zb. im Spectatormodus durch die Gegend fliegt. Wenn man unter die Oberfläche fliegt sieht man nur die Hohlräume, würde alles mit Blöcken ausgefüllt sein würde man die Höhlen (Hohlräume) überhaupt nicht erkennen können, weil sonst ne Wand vor einem wäre...

Link to comment
Share on other sites

Genau.. (was meine Vorredner schon so gesagt haben)

Minecraft benutzt da Voxel und dann wird das ganze komplizierter als nur Cubes zu generieren..

Also der Raum wird in Würfel unterteilt (Voxel können prinzipiell jede Form definieren aber die gängigste sind wohl Würfel), wobei das an dieser Stelle noch vollkommen theoretisch also ein Gedankenkonstrukt ist.

Diese Voxel enthalten Daten, im einfachsten Fall solid(Erde) und nonsolid (Luft)

Solche Voxel werden, wie schon gesagt wurde, in Chunks zusammengefasst, üblicherweise so 16x16x16 oder 32x32x32 Voxel (Minecraft hat übrigens Chunks mit den Maßen 16x128x16, was aber eigentlich eher suboptimal ist)

 

Machen wir's mal praktikabler als solid und nonsolid und führen folgende Materialien ein:

Nonsolid (nach wie vor), Erde und als 3. Material Stein.

Dann könnte man das ja kodieren und für Nonsolid eine 0, für Erde 1 und Stein 2 speichern.

Die Werte der Voxel kannst du dann in einem 3D Array (also z.B. int[ , , ]) speichern..

Um solche Werte zu generieren ist es üblich einen Pseudonoise Algorithmus zu benutzen und die Noise-Werte dann auswerten und in Materialien umwandeln. Ein solcher Algorithmus ist der Perlin Algorithmus, den gibt's glaube ich auch in einer Unity-Assembly direkt mit aber soll angeblich nicht besonders gut sein.. ein anderer (schnellerer) ist der Simplex-Algorithmus (nicht zu verwechseln mit dem Optimierungsalgorithmus)

 

Hat man nun einen Chunk befüllt läuft man mit 3 for-schleifen drüber und wertet jedes einzelne Voxel aus und generiert bei soliden Voxeln (deren Materialindex also != 0 ist, da 0 Luft bedeutet) die 6 Seiten des Würfels unabhängig voneinander und checkt bei jeder Seite, ob der angrenzende Voxel dieser Seite solide oder nicht solide ist.

Wenn der Voxel dort solide ist sieht man diese Seite nicht und daher muss die auch nicht generiert werden, ansonsten schon.

Das ist die 1. Optimierung, da NUR die sichtbare Oberfläche generiert wird und du ansonsten keine Meshes und Collider hast.

Den Faces kannst du dann eine Textur zuweisen (idealerweise aus einem Atlas. 2. Optimierung)

 

Danach ist es eigentlich schon fertig generiert..

Da könnte man noch Dinge am Generierungsalgorithmus ändern und zum Beispiel "Greedymeshing" betreiben.

Damit werden große Flächen in 1 Quadrat/2 Triangles zusammengefasst bzw. in die kleinst mögliche Anzahl an Faces.

Ist aber schon komplexer..

 

Es gibt einige Blogs und Tutorials im Inet, die Minecraft-artige Terraingeneratoren sehr gut erklären.

Eins der besten, wenn nicht das beste, ist finde ich dieses hier:

http://alexstv.com/i.../voxel-tutorial

Link to comment
Share on other sites

Ok, danke euch für die Infos. Ich lese mir das Voxel-Tutorial einmal durch.

 

Ich arbeite mit CombineMeshes um nicht so viele einzelne Blöcke zu haben. Mit CombineMeshes sollten doch auch alle überflüssigen "Seiten" entfernt werden, richtig?

 

Also meine gedachte Lösung:

1. Objekt-Pool mit Blöcken beim Start erstellen (alle Objekte deaktiviert)

2. Einige Blöcke aus dem Pool an die gewünschte Position verschieben und aktivieren

3. Diese Blöcke dann per CombineMeshes mit evtl. bereits vorhandenem Objekt zu einem Objekt mit max. 30.000 Vertices kombinieren

4. Falls Vertices > 30.000 dann neues Objekt erstellen

 

CombineMeshes kann ja als Coroutine laufen. Das verschieben der Blöcke (z.B. 50 Stück) dauert komischerweise aber schon zu lange. Sollte das nicht nur minimalste Rechenleistung benötigen?

Link to comment
Share on other sites

Ich arbeite mit CombineMeshes um nicht so viele einzelne Blöcke zu haben. Mit CombineMeshes sollten doch auch alle überflüssigen "Seiten" entfernt werden, richtig?

Nein

CombineMeshes verbindet alle Meshes in 1 großes Mesh, ohne irgendwas damit zu machen.(also verschwinden unnötige Faces nicht wie von Zauberhand.. wie auch?)

Und alles in 1 großes Mesh zu packen ist genau das Gegenteil von dem was du mit Chunks erreichen willst, also solltest du das ganz schleunigst aus deinem Code nehmen ^^

 

Also meine gedachte Lösung:

1. Objekt-Pool mit Blöcken beim Start erstellen (alle Objekte deaktiviert)

2. Einige Blöcke aus dem Pool an die gewünschte Position verschieben und aktivieren

3. Diese Blöcke dann per CombineMeshes mit evtl. bereits vorhandenem Objekt zu einem Objekt mit max. 30.000 Vertices kombinieren

4. Falls Vertices > 30.000 dann neues Objekt erstellen

 

CombineMeshes kann ja als Coroutine laufen. Das verschieben der Blöcke (z.B. 50 Stück) dauert komischerweise aber schon zu lange. Sollte das nicht nur minimalste Rechenleistung benötigen?

Also wie schon gesagt ist CombineMeshes schlecht für dein Vorhaben..

Außerdem solltest du wenn dann die Chunks poolen, deren Voxel du dann berechnen lässt und das Mesh dann dynamisch generierst..

Es heißt nicht umsonst "prozedural generiertes Terrain"..

Du generierst das Mesh zu Laufzeit prozedural und nicht indem du Primitive irgendwie anordnest.

Ich meine oke, es geht schon aber ist alles andere als praktikabel und das merkst du ja auch ^^

Und nur weil CombineMesh in einer Coroutine läuft wird es nicht schneller..

Coroutinen laufen im Unity Mainthread, also bringt es dir keinen Performancezugewinn. Coroutinen sind nur da um auf einfache Art und Weise Dinge "außerhalb" des Update-Loops laufen zu lassen.

 

Also verabschiede dich am besten direkt von deiner Lösung, weil sie alles andere als optimal ist (wie du ja auch selber siehst)

Mach lieber das Tutorial durch das ich verlinkt habe.

Das Vorgehen ist dabei eigentlich so mitunter das Beste im Bezug auf Minecraft-Terrain.

Es kann an vielen Stellen optimiert werden aber es ist zum einen schon sehr schnell und zum anderen handelt es sich ja dabei um ein Tutorial, also steht Performance im Hintergrund..

 

post-3240-0-32484100-1466339289_thumb.png

Hab mal eben einen Screenshot aus meiner Voxelengine gemacht.

Das Terrain hat einen Durchmesser von 24 Chunks, was 384m entspricht.

Sieht ein bisschen Kacke aus, was aber daran liegt, dass ich eigentlich überhaupt keine BlockyTerrains generieren will, daher ist mein Algorithmus nicht besonders gut darauf angepasst, sodass die Normals nicht stimmen etc.

Jedenfalls wurde das Terrain im Main Thread in unter 4 Sekunden generiert. (also Singlethreaded)

Blockyterrains sind in der Regel nicht besonders schwer zu generieren bzw. es fallen viele Berechnungen weg, die ich jetzt hier mache (wie gesagt, das Terrain sollte eigentlich nicht Blocky sein), womit man so ein Terrain bestimmt in unter 2 Sekunden generieren könnte.

Nur damit du mal eine Vorstellung bekommst wie schnell das gehen kann.

Dabei ist das übrigens auch noch nicht wirklich Optimiert.. Ich versuche so viele unnötige Berechnungen wie möglich zu vermeiden, allerdings hab ich hald noch keine richtigen Optimierungen wie Compressions, etc angewandt, weil ich meinen Algorithmus noch überarbeite.. Das Projekt schläft aber derzeit wieder..

Link to comment
Share on other sites

Archived

This topic is now archived and is closed to further replies.

×
×
  • Create New...