Jump to content
Unity Insider Forum

Error bei Voxel Generierung mit Threads


Tiwaz

Recommended Posts

Hi Leute,

 

ich komm grade irgendwie nicht mehr wirklich weiter bei meinem Voxel Generator und ich wäre echt wahnsinnig dankbar, wenn mir jemand bei der Fehlerbehebung helfen könnte :D

Die Chunks werden (bis auf die Instanzierung selbst) ohne Probleme per externen Thread erstellt, aber die Blockgenerierung (also die Befüllung der Chunks) läuft per Thread irgendwie nicht richtig..

 

Die Update des Chunks sieht folgendermaßen aus:

 

 

void Update()
{
	if (update)
	{
		ThreadPool.QueueUserWorkItem(UpdateChunk);
		SetUpdate(false);
	}
	if (render)
	{
		RenderMesh();
	}
}

public void UpdateChunk(object o = null)
{
	MeshData = new MeshData();
	for (int z = 0; z < ChunkSize; z++)
	{
		for (int y = 0; y < ChunkSize; y++)
		{
			for (int x = 0; x < ChunkSize; x++)
			{
				Blocks[x, y, z].GenerateFaces(this, x, y, z);
			}
		}
	}
	render = true;
}

void RenderMesh()
{
	filter.mesh.Clear();
	filter.mesh.vertices = MeshData.Vertices.ToArray();
	filter.mesh.triangles = MeshData.Triangles.ToArray();
	filter.mesh.uv = MeshData.UVs.ToArray();
	filter.mesh.RecalculateNormals();

	Mesh mesh = new Mesh();
	mesh.vertices = filter.mesh.vertices;
	mesh.triangles = filter.mesh.triangles;
	mesh.RecalculateNormals();
	coll.sharedMesh = mesh;

	render = false;
}

 

 

 

Nach einer ganzen Zeit des Debuggens und Rumprobierens bin ich drauf gekommen, dass der "Fehler" in der GenerateFaces() Methode "entsteht"..

 

 

 

public virtual void GenerateFaces(Chunk chunk, int x, int y, int z)
{
		if (!chunk.GetBlock(x, y, z + 1).IsSolid(Side.South))
		{
			GenerateNorthFace(chunk, x, y, z);
		}
		(...) // Die anderen Faces werden auch noch generiert, aber nach dem gleichen Schema
}

void GenerateNorthFace(Chunk chunk, int x, int y, int z)
{
	chunk.MeshData.AddVertex(new Vector3(x + 1, y, z + 1));
	chunk.MeshData.AddVertex(new Vector3(x + 1, y + 1, z + 1));
	chunk.MeshData.AddVertex(new Vector3(x, y + 1, z + 1));
	chunk.MeshData.AddVertex(new Vector3(x, y, z + 1));

	 // Das steht in einer anderen Methode aber ich hab das jetzt einfach mal hier reinkopiert
	Triangles.Add(Vertices.Count - 4);
	Triangles.Add(Vertices.Count - 3);
	Triangles.Add(Vertices.Count - 2);

	Triangles.Add(Vertices.Count - 4);
	Triangles.Add(Vertices.Count - 2);
	Triangles.Add(Vertices.Count - 1);

	// Die UVs werden hier auch noch geadded und auch diese machen Probleme aber ich denke, dass es an dem gleichen Problem liegt wie auch mit den Triangles
}

 

 

 

Und zwar genauer bei GenerateNorthFace() bzw. die anderen Faces ebenfalls..

chunk.GetBlock() funktioniert tadellos.

 

 

Es werden regelmäßig folgende Errors geworfen:

 

 

 

Failed setting triangles. Some indices are referencing out of bounds vertices. IndexCount: x, VertexCount: irgendwas kleiner x

UnityEngine.Mesh:set_triangles(Int32[])

Chunk:RenderMesh() (at Assets/Scripts/VoxelTerrain/Chunk.cs:84)

Chunk:Update() (at Assets/Scripts/VoxelTerrain/Chunk.cs:60)

 

 

Und auch:

 

 

 

ArgumentException: Destination array was not long enough. Check destIndex and length, and the array's lower bounds

System.Array.Copy (.../System/Array.cs:977)

System.Array.Copy (.../System/Array.cs:936)

System.Collections.Generic.List`1[unityEngine.Vector3].ToArray () (.../System.Collections.Generic/List.cs:593)

Chunk.RenderMesh () (at Assets/Scripts/VoxelTerrain/Chunk.cs:81)

Chunk.Update () (at Assets/Scripts/VoxelTerrain/Chunk.cs:58)

 

 

 

 

Zeile 81 in RenderMesh ist "filter.mesh.vertices = MeshData.Vertices.ToArray();"

Zeile 84 in RenderMesh ist "filter.mesh.RecalculateNormals;"

 

Wenn ich das alles aber ohne den Thread mache funktioniert alles wunderbar.. Nur bricht die Framerate hald dann doch spürbar ein.. (immer noch über 30fps aber trotzdem inakzeptabel)

also wenn ich:

	if (update)
	{
		ThreadPool.QueueUserWorkItem(UpdateChunk);
		SetUpdate(false);
	}

zu dem hier ändere:

	if (update)
	{
		UpdateChunk();
		SetUpdate(false);
	}

 

 

Und da bin ich jetzt ziemlich verwirrt..

Es wird nämlich nie ein Error geworfen, außer die, die ich jetzt gepostet habe und die kann ich auch irgendwie meistens nicht catchen.. manchmal aber dann irgendwie schon, keine Ahnung warum..

Die werden dann immer in der Console geworfen und das Spiel wird pausiert (fahre ich mit dem Spiel fort, generiert es übrigens wieder ein paar und es wirft neue Fehler + Pause)

 

Die Errors müssten ja eigentlich dadurch entstehen, dass in RenderMesh() das Mesh erzeugt wird und währenddessen MeshData verändert wird, richtig?

Aber MeshData wird ja eigentlich nur im ThreadPool konfiguriert und der Main Thread agiert ja damit erst dann, wenn der andere Thread mit der Generierung fertig ist? o.O

Und da es nur den Main Thread und 1 anderen Thread pro Chunk gibt, der auch nur seinen eigenen Chunk bearbeitet, kann es ja eigentlich auch nicht sein, dass sich da was überschneidet oder doch? o.O

 

Falls ich irgendwas wichtiges vergessen hab einfach sagen, dann poste ich es nach, ist ja schon viertel nach 2 und bin müde also sry ^^

 

@edit:

Ich hab übrigens auch mal versucht Locks an diverse Stellen zu setzen, z.B. dass ich MeshData während der RenderMesh Methode locke (was ja sowieso keinen Performanceimpact haben sollte) aber das klappt auch nicht..

Dann wird es wahrscheinlich daran liegen, dass eben der Thread seit dem letzten Schritt verändert wurde :o

 

Ahja.. Und MeshData und Block erben von nichts, Chunk allerdings von MonoBehaviour.. falls das interessant ist ^^

 

Und was vllt noch interessant wäre:

Es ist prinzipiell egal wie groß ich das Terrain zu Beginn generieren lasse, ob 1x1, 16x16 oder YxY Chunks.. Es funktioniert immer vollkommen richtig, obwohl ich die Chunks per Thread befüllen lasse..

Das Problem tritt nur auf, wenn ich die Chunks dann dynamisch hinzufügen lasse..

Das mache ich übrigens so, dass ich in der World einfach eine Update laufen lasse, die eine Liste mit Positionen abarbeitet, an die ein Chunk generiert werden soll..

Vielleicht liegt hier der Hund begraben, aber ich wüsste nicht warum..

 

@edit2:

Ich hab das jetzt mal umgeschrieben, sodass ich zur Chunkgenerierung jetzt auch die Methode benutze, die ich in der Start() aufrufe um das Startterrain zu generieren, aber es macht keinen Unterschied..

 

Hab auch mal probiert die Blöcke (und auch diverses anderes) zu locken aber ohne Erfolg..

Da die Vertices und UVs Arrays die gleiche Länge haben müssen und der Triangles Count ein Vielfaches von 3 sein muss, hab ich mal die MeshDaten zwischengespeichert und die Arrays dann auf die Bedingungen überprüft.. Aber ich bekomme trotzdem den "Destination array was not long enough." Error ._.

 

Ich bin mittlerweile irgendwie am Ende meines Lateins ^^

Link zu diesem Kommentar
Auf anderen Seiten teilen

Was mich verwirrt, ist, dass das ohne Threads keine Fehler wirft. Meine erste Vermutung war, dass z.B. so was hier

chunk.MeshData.AddVertex(new Vector3(x + 1, y, z + 1));

 

die zulässigen x- und z-Werte überschreitet, da du das ja bis x < chunkSize einschränkst und x+1 dann genau chunkSize wäre (bei Null-basierten Arrays gerne mal ein Problem). Die Definition der Arrays hast du uns nicht gezeigt. Aber das müsste dann auch krachen, wenn das nicht im Thread läuft.

 

Für eine weitere Analyse fehlen mir hier allerdings zu viel Infos. Gerade Thread-Themen haben die unangenehme Eigenschaft, extrem fies in der Fehlersuche zu sein. Auch wenn du weiter hier versuchst, Sachen zu beschreiben, fürchte ich, dass du so nicht weiterkommst und nur Zeit verplemperst.

 

Ich kann dir momentan nur anbieten, den Fehler mal auf meiner Maschine zu suchen, wenn du das willst. Dazu benötige ich allerdings alle Assets.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Folgende Sache:

 

Wie verhinderst du dass während er grade am Updaten ist noch ein Update (UpdateChunk) gemacht wird?

SetUpdate(false) verhindert ja den nächsten updateStep, was aber wenn sich da was am Chunk ändert und wieder ein Update anstößt?

 

Kannst du die genauen Umstände nochmal beschreiben bei dem der Fehler auftritt?

Link zu diesem Kommentar
Auf anderen Seiten teilen

Es lag tatsächlich daran, dass er sich geupdatet hat, während er bereits am Updaten war :o

Daran hab ich irgendwie gar nicht gedacht ._.

Denn wenn ein Chunk erzeugt wird lasse ich alle umliegenden Chunks nochmal updaten. Ansonsten bleiben Faces, am Chunkrand unsichtbar.

Das war das Problem ^^

Danke Mark! :)

 

Jetzt hab ich zwar wieder einen alten Bug, den ich schon behoben geglaubt habe, aber der wird denke ich mehr so das Problem sein, hoffe ich ^^ (Der ist jetzt behoben)

 

@Hrungdak

Ich schränke den VerticesCount nicht ein.

Dachte die Codezeilen wären klar ^^

 

Also MeshData enthält, wie der Name schon sagt, die Daten des Meshs und das Mesh hat pro Seite 4 Vertices und 2 Triangles (=> 6 Indices) und in der GenerateXFace() Methode lasse ich eben die Vertices und Triangle Indizes hinzufügen ^^

Unity hat da nur was dagegen wenn ein Mesh mehr als 65000 Vertices hat aber ich schränke da gar nichts ein ^^

Das hat auch nichts mit dem Blockarray zu tun ^^

 

@edit:

Ich hab's jetzt (fast) komplett bugfrei bekommen :)

Ein kleiner Bug ist noch drin, wodurch gelegentlich ein Error geworfen wird, den ich allerdings ganz leicht catchen und behandeln kann ohne, dass der Spieler etwas davon merkt oder die Performance/Memory leiden muss, also ist das vorerst verkraftbar ^^

Jetzt erst mal wieder ein bisschen Zocken, das Hirn entspannen lassen und wenn ich mich für den nächsten Schritt in der Terrain Generierung entschieden habe (es ist noch soo viel zu tun ._.) mache ich weiter ^^

Link zu diesem Kommentar
Auf anderen Seiten teilen

Archiviert

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

×
×
  • Neu erstellen...