Jump to content
Unity Insider Forum

Ein Versuch: Voxel Terrain / Prozedurale Mesh Erstellung


schoen08

Recommended Posts

Schneller und schneller und schneller! Ich habe die Noise Generierung neu geschrieben, ausgelegt auf die Verwendung von Threads. Die neuen Zeiten:

 

Bei einer Karte von 512*512*128 Blöcken:

Noise-Generierung: 5.28 Sekunden

Lichtberechung: 2.62 Sekunden

Aufbauen der Meshes: 9.99 Sekunden

Gesamt: 18.53 Sekunden

 

Das ist bezogen auf einen 16*16*128 Chunk:

Noise: 0.182 Sekunden

Licht: 0.081 Sekunden

Aufbau: 0.312 Sekunden

 

Bei den Werten ist zu beachten, das mein Laptop von der Leistung hinter ForTheRecords liegt - das waren immer so um die 5 Sekunden länger. Mal sehen, was er für Werte herausbekommt :)

Link zu diesem Kommentar
Auf anderen Seiten teilen

Mitlerweile gehts ans Ausbügeln der Details. Aber erstmal noch ein paar Zeiten:

 

928x928x128:

Noise: 10.7s

Licht: 5.8s

Meshes: 25.1s

Gesamt: 41.6s

 

512x512x128:

Noise: 3.44s

Licht: 1.88s

Meshes: 7.6s

Gesamt: 13.0s

 

Wie ihr seht sind wir mittlerweile richtig schnell geworden :)

 

Schön wärs wenns ab jetzt fehlerfrei wäre, aber ihr kennt das ja :(

 

Die beiden Probleme haben mit der neuen Warteschlange zu tun die ich eingeführt habe. Diese Warteschlange speichert die Actions, die die letztendliche Zuweisung der Meshdaten machen. Ursprünglich hatte ich den Aufruf der Funktionen in der Update-Methode, doch hat dies bei hohen Drawdistances schnell die Framerate gesenkt. Jetzt wird das entnehmen der Actions in einem Thread erledigt, der dies alle 20ms tut und dann an Marrrks Dispatcher weitergibt.

 

Problem 1: Microlags

Egal wie hoch die Drawdistance oder das Intervall des Threads ist, die Microlags sind da und sie sind spürbar. Sie entstehen wenn eine neue Reihe Chunks, die gerade in Sichtweite kommen, erzeugt werden - sprich die Meshdaten zugewiesen werden.

 

Problem 2:

In seltenen Fällen passiert es, dass Chunks nicht erstellt werden. Da ist dann ein Quadratisches Loch im Boden. Da der Chunk nachweislich nicht aktiv gelöscht wurde, glaube ich, dass es daran liegt, dass eine Action aus der Warteschlange nicht ausgeführt wurde. Woran kann es liegen, dass eine Action nicht ausgeführt wird. Die Code-Logik verbietet das eigentlich. Hier mal die Methode:

 

 

public void manageActionQueueInThread(){
 while (!actionQueueManagingThreadShouldStop) {
  if (actionQueue.Count > 0) {
 try {
   UnityThreadHelper.Dispatcher.Dispatch(actionQueue.Dequeue ());
 } catch (System.Exception e) {
   Debug.LogWarning (e);
 }
  }
  System.Threading.Thread.Sleep(interval);
 }
}

 

 

Am ThreadingHelper liegt es nicht, da der Fehler auch entstand, als das Entnehmen und Aufrufen aus der Queue noch in der Update-Methode geschah.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Ist das im Script drinne das auf einen GameObject liegt also hälst du den Hauptthread immer an ? Oder ist das aus der Klasse die in einen eigenen Thread läuft ?

 

Thread.Sleep(int MS) ist eine static Methode die den zum Aufruf aktiven thread für n Millisekunden pausiert. Der Hauptthread wird also soweit ich weiss nicht pausiert.

 

Thread actionQueueManagingThread = New Thread(new ThreadStart(manageActionQueueInThread));
actionQueueManagingThread.Start();

Link zu diesem Kommentar
Auf anderen Seiten teilen

So, Problem 2 ist gelöst. Es lag anscheinend - "anscheinend" weil das Problem so selten aufgetreten ist, dass ich nicht genau sagen kann ob es weg ist, aber bisher ist es nicht wieder gekommen - daran, dass die System.Collections.Generic.Queue nicht Threadsicher ist. Jetzt ist jeder Aufruf der Warteschlange in einem lock(actionQueue){} block.

 

Problem 1 besteht immer noch und ich bekomm es einfach nicht hin. :( Ich hab mit den Anzahl Actions pro Intervall, Zeitabstand zwischen den Intervallen und der Renderdistance gespielt, aber keine Wertekombination war zufriedenstellend. Ich hab sogar versucht das Intervall dynamisch von der Time.deltaTime abhängig zu machen. Aber egal was ich mache die Lags bleiben. Dabei werden die Collider noch nichtmal mehr erzeugt und der Aufruf der Action nimmt nur zwischen 2,5 ms und 0,5 ms in Anspruch, je nachdem wie viele Vertices drin sind. Klippen brauchen 2,5 ms. Normale Grasflächen 0,5ms.

 

System.Action action=new System.Action(()=>{
mesh = this.GetComponent<MeshFilter>().mesh;
col = this.GetComponent<MeshCollider>();
mesh.vertices=verts;
mesh.triangles=tris;
mesh.colors32=colors;
mesh.uv=uvs;

mesh.Optimize();
mesh.RecalculateNormals();
});

 

Anregungen, Ideen, Lösungsvorschläge, Lösungen. Ich nehm alles dankend an!

Link zu diesem Kommentar
Auf anderen Seiten teilen

  • 1 year later...

Hi,

 

habe in den letzten Wochen auch ein Voxelterrain gebaut, welches bereits mehrere Threads für das Generieren und Löschen von Blöcken verwendet. Das funktioniert auch super flüssig und ohne Framedrops.

 

Ich bin allerdings zu doof um einen Algorithmus zu bauen der mir mein Array so mit 0en und 1en füllt, dass ich eine kleine hügelige Landschaft hab. Mag mir da wer helfen?

 

  //Blöcke Initialisieren
	weltBlocke = new WeltBlock[256, 32, 256];
	float frequenz = weltBlocke.GetLength(1);
	byte bodenHoehe = 0;
	for (int x = 0; x < weltBlocke.GetLength(0); x++)
	{
		for (int y = 0; y < weltBlocke.GetLength(2); y++)
		{
			bodenHoehe = (byte)((PerlinSimplexNoise.noise(x, y) * frequenz));
			for (int z = weltBlocke.GetLength(1)-1; z > -1; z--)
			{
				weltBlocke[x, z, y] = new WeltBlock();
				if (z <= bodenHoehe)
				{
					weltBlocke[x, z, y].Blockart = 1;
				}
				else
				{
					weltBlocke[x, z, y].Blockart = 0;
				}
			}
		}
	}

 

c48c57pk.png

Link zu diesem Kommentar
Auf anderen Seiten teilen

Archiviert

Dieses Thema ist jetzt archiviert und für weitere Antworten gesperrt.

×
×
  • Neu erstellen...