Jump to content
Unity Insider Forum

NavMesh Agent - die Technik dahinter


Quellcode

Recommended Posts

Hallo Zusammen,

 

bei meinem aktuellen Projekt kommt ich so langsam an den Punkt, wo ich die Welt mit Leben füllen möchte.

Meine NPCs wollte ich ursprünglich mit dem NavMesh Agent von Unity ausstatten.... aber:

- es wird eine sehr große Open World Map

- es gibt viele Straßen und Häuser

- Häuser werden auch begehbar sein (ausnahmslos alle!) ... verschiedene Stockwerke ... Keller!

 

Im Beispiel Keller, wird durch einen "Depth Shader" das Terrain ausgeblendet, so etwas kann der Unity eigene NavMesh Generator natürlich nicht wissen.

Daher würde ich gerne mehrere NavMeshes "Baken" und diese dann verknüpfen. Dazwischen würde ich mit Triggern für Türen / Aufzüge etc. arbeiten.

 

Hierzu würde ich gerne mehr zur Technik des Unity Systems kennen lernen, denn ich weiß nicht wie der "NavMeshAgent" letzten endes das "NavMesh" nutzt.

Die Visualisierung im Editor zeigt ja eine Plane an, aber was steckt dahinter?

Wie berechnet der "Agent" die aktuellen "Waypoints" zwischen Start und Endpunkt?

Könnte man den Unity eigenen "Agent" mit selbst generierten "NavMeshes" verwenden?

Kann Unity von Haus aus mit mehreren NavMeshes umgehen oder bleibt hier nur der komplette Neustart von Grund auf?

 

Vielleicht habt ihr ein paar Ansätze, Tutorials, Links, etc. für mich.

Vielen Dank im Voraus!

 

 

EDIT:

Für die Jenigen, die es interessiert oder vielleich einmal eine ähnliche Frage haben hier eine kurze Info, wie ich es nun löse:

Zunächste habe ich dieses Video Tutorial gefunden, welches in 10 Teilen zu sehen ist.

Es fängt simpel an und geht dann genau auf die Optimierungsmöglichkeiten ein.

https://www.youtube.com/watch?v=-L-WgKMFuhE

Zwar ist hier sogar im Videolink Beispielcode enthalten, aber diese Version muss natürlich noch sehr stark an eure jeweiligen Anwendungsfälle angepasst werden.

Ich habe diesen daher im Endeffekt fast vollständig überarbeitet und bin auch noch nicht fertig.

 

Zur Speicherung der einzelnen Nodes nehme ich zum Start noch immer meine alte Variante (viele Cubes). Dies ist jedoch sehr performant, da ich dies im Editor mache und Ingame kein MeshRenderer aktiv sein wird (in der Zukunft, im Screenshot ist es aktiviert).

Diese Cubes helfen mit die Vector3 Koordinaten zu entnehmen, welche ich dann in eine Node Tilemap speichere (siehe Video).

 

Das ganze läuft sehr gut, auch mit mehreren NPC und bislang ohne Probleme im Punkto Performance :)

Ich nutze dieses Verfahren nur innerhalb von Gebäuden, außerhalb bleibt es beim Unity eigenen NavMeshAgent.

 

Screenshot (Work in Progress):

Blau: Aktueller Path von NPC

Rot: NPC Bereichs Erkennung (Hindernisse)

Grün: freie Fläche

 

Pathfinding.png

Link zu diesem Kommentar
Auf anderen Seiten teilen

Das NavMesh ist im Grunde bloß eine Sammlung von ganz normalen Knoten, die anhand der Polygone / Vertices deiner Meshs generiert werden. Und dein Agent läuft die dann ganz normal A* mäßig ab.

Und ja. Unity kann mehrere NavMeshs miteinander verbinden. Google doch einfach mal rum, was es so alles rund ums NavMesh gibt :)

Link zu diesem Kommentar
Auf anderen Seiten teilen

Danke @Life Is Good, habe auch diesen Link gefunden, welche meiner Meinung nach extrem gut und ausführlich erklärt wie dies abläuft ;-)

http://jceipek.com/Olin-Coding-Tutorials/pathing.html

 

Google immer parallel weiter, wenn ich einen Beitrag poste, aber zum NavMesh von Untiy habe ich noch nichts in dem Bereich gefunden.

Hast du hier vielleicht einen schlauen Link für mich?

 

Ich überlege auch Indoor mein eigenes System zu nutzen und aufzubauen und Outdoor nach wie vor die Unity eigene Technik zu verwenden.

Link zu diesem Kommentar
Auf anderen Seiten teilen

vor 2 Stunden schrieb Life Is Good:

https://docs.unity3d.com/Manual/class-NavMeshLink.html

Klar. Mach was auch immer du für dein Projekt als angemessen empfindest.

Erst einmal danke für den Link, dazu noch eine Frage.

Es ist immernoch "ein Mesh" oder? Also wenn man auf den Reiter "Navigation" klickt kann man nur die gesamte Szene baken?

Dies stelle ich mir bei einer Open World Map problematisch vor.

 

Und wenn ich bewegliche Hindernisse habe, berechnet Unity das ganze Mesh neu soweit meine bisherigen Tests zeigten. Darum ist dies einfach nicht performant.

Gibt es hier noch eine Möglichkeit diese NavMeshes zB auf verschiedene Bereiche zu unterteilen?

 

Meine aktuelle Indoor Alternative wäre eine "TileMap" mit "Cubes" welche dann immer bei TriggerEnter bzw Exit den Status von "frei" zu "belegt" anpassen.

In einem meiner größeren Gebäude, sind dies jedoch 1.250 "Cubes" > Wegpunkte ... vermutlich wird dies auch nicht gerade super schnell am Ende :-(

Link zu diesem Kommentar
Auf anderen Seiten teilen

Hiermit kannst du mehrere NavMeshs in der selben Szene haben:
https://github.com/Unity-Technologies/NavMeshComponents

(Falls das noch nicht mit Unity mitkommt, hab das NavMesh schon ne Weile lang nicht mehr benutzt)

vor 9 Stunden schrieb Quellcode:

Und wenn ich bewegliche Hindernisse habe, berechnet Unity das ganze Mesh neu soweit meine bisherigen Tests zeigten. Darum ist dies einfach nicht performant.

Es schneidet einfach die Fläche raus, die dein Hinderniss besetzt. Unter Umständen kann das dazu führen, dass es neuberechnet werden muss, ja. Ich glaube aber nicht, dass das gesamte NavMesh neuberechnet wird. (ich hab's aber auch nicht getestet) NavMeshs sind aber generell auch eher weniger für dynamische Umgebungen geeignet.

 

vor 9 Stunden schrieb Quellcode:

Meine aktuelle Indoor Alternative wäre eine "TileMap" mit "Cubes" welche dann immer bei TriggerEnter bzw Exit den Status von "frei" zu "belegt" anpassen.

In einem meiner größeren Gebäude, sind dies jedoch 1.250 "Cubes" > Wegpunkte ... vermutlich wird dies auch nicht gerade super schnell am Ende :-(

Das letzte was du machen willst, ist 1250 Trigger nur dafür in deiner Szene zu haben :)
Du kannst also entweder einfach das NavMesh nutzen, normale Waypoints selbst überall in deiner Welt verteilen oder du musst dich nun mal mit Pathfinding auseinander setzen.
So ein Open World Spiel entwickelt sich nun mal nicht von selbst!

Link zu diesem Kommentar
Auf anderen Seiten teilen

vor 11 Stunden schrieb Quellcode:

Und wenn ich bewegliche Hindernisse habe, (...)

Meine aktuelle Indoor Alternative wäre eine "TileMap" mit "Cubes" welche dann immer bei TriggerEnter bzw Exit den Status von "frei" zu "belegt" anpassen.

In einem meiner größeren Gebäude, sind dies jedoch 1.250 "Cubes" > Wegpunkte ... vermutlich wird dies auch nicht gerade super schnell am Ende :-(

Wie bewegen sich die Hindernisse denn? Sind es Spieler/NPCs die über Rigidbodys oder CharacterController oder so hin und hergehen? Oder sind es tatsächlich Gegenstände die z.B. der Spieler verschieben/platzieren kann?
Falls letzteres der Fall ist, würde ich denke ich die Bewegung an die Tilemap knüpfen. Gegenstand wie nach XY verschoben -> Gridposition XY wird belegt (und die Ursprungsposition jeweils wieder freigegeben)
Grundsätzlich könntest du bei Bewegungen von Hindernissen auch immer die Position prüfen und die auf die TileMap mappen und dann updaten
So etwa 

if(wasMoved){
	Vector2 newGridPosition = ConvertGlobalPositionToGridPosition(transform.position);
	grid[(int)newGridPosition.x][(int)newGridPosition.y] = TileState.Occupied;
	grid[(int)previousGridPosition.x][(int)previousGridPostion.y] = TileState.Free;
	previousGridPosition = gridPosition;
}

Theoretisch dürfte das mit quasi allem gehen, sofern die Position in eine TileMap/Grid Position konvertiert werden kann.

Link zu diesem Kommentar
Auf anderen Seiten teilen

vor 16 Stunden schrieb Life Is Good:

Hiermit kannst du mehrere NavMeshs in der selben Szene haben:
https://github.com/Unity-Technologies/NavMeshComponents

(Falls das noch nicht mit Unity mitkommt, hab das NavMesh schon ne Weile lang nicht mehr benutzt)

Es schneidet einfach die Fläche raus, die dein Hinderniss besetzt. Unter Umständen kann das dazu führen, dass es neuberechnet werden muss, ja. Ich glaube aber nicht, dass das gesamte NavMesh neuberechnet wird. (ich hab's aber auch nicht getestet) NavMeshs sind aber generell auch eher weniger für dynamische Umgebungen geeignet.

 

Das letzte was du machen willst, ist 1250 Trigger nur dafür in deiner Szene zu haben :)
Du kannst also entweder einfach das NavMesh nutzen, normale Waypoints selbst überall in deiner Welt verteilen oder du musst dich nun mal mit Pathfinding auseinander setzen.
So ein Open World Spiel entwickelt sich nun mal nicht von selbst!

Okay, ich werde meinen Tests mit dem Unity eigenen NavMesh nochmal ausbauen. Wenn dies wirklich nur Teilbereiche neu berechnet dann wäre vielleicht damit alles zu lösen.

Naja, 1250 ... pro Stockwerk ... in einem einzigen großen Gebäude... denke es wären später gute 3-4k im Player Umfeld (Rest wird nachgeladen).

 

Wobei dies überaschend genial schnell klappt bislang.. auch ein Test mit über 10k lief problemfrei - ich rendere die Meshes ja nicht, nutze nur den Collider!

Und kein ständiges Update, nur OnEnter und OnExit...

 

Das wird auch ein Langzeit Projekt, ich rechne die nächsten Jahre nicht mit der völligen Fertigstellung ;-)

 

 

vor 14 Stunden schrieb Tiwaz:

Wie bewegen sich die Hindernisse denn? Sind es Spieler/NPCs die über Rigidbodys oder CharacterController oder so hin und hergehen? Oder sind es tatsächlich Gegenstände die z.B. der Spieler verschieben/platzieren kann?
Falls letzteres der Fall ist, würde ich denke ich die Bewegung an die Tilemap knüpfen. Gegenstand wie nach XY verschoben -> Gridposition XY wird belegt (und die Ursprungsposition jeweils wieder freigegeben)
Grundsätzlich könntest du bei Bewegungen von Hindernissen auch immer die Position prüfen und die auf die TileMap mappen und dann updaten
So etwa 


if(wasMoved){
	Vector2 newGridPosition = ConvertGlobalPositionToGridPosition(transform.position);
	grid[(int)newGridPosition.x][(int)newGridPosition.y] = TileState.Occupied;
	grid[(int)previousGridPosition.x][(int)previousGridPostion.y] = TileState.Free;
	previousGridPosition = gridPosition;
}

Theoretisch dürfte das mit quasi allem gehen, sofern die Position in eine TileMap/Grid Position konvertiert werden kann.

Diese Tilemap habe ich aktuell ja bereits in Form der Cubes. Für einen Pathfinding Durchlauf, werden diese Cube Daten jedoch auf X und Z Achse als Tilemap gespeichert mit dem

State 0 (frei) bzw 1 (belegt).

Die Objekte sind frei vom Spieler und teilweise auch von den NPCs zu bewegen. Also ändern sich die Positionen ggf. sehr schnell.

NPCs selbst belegen nur "einen Teil" des Bereichs, sodass hier keine ständige Neuberechnung notwendig ist wenn mehrere NPC den selben Raum durchqueren.

 

Hier bin ich noch am austesten welche Zugriffsmethode und Speicherung (List, Dictionary, ...) am besten dafür geeignet ist.

 

Link zu diesem Kommentar
Auf anderen Seiten teilen

Archiviert

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

×
×
  • Neu erstellen...