hippocoder / dotsnav

A fully dynamic planar navmesh Unity package supporting agents of any size

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Video    Demo    Discord    Sponsor

Table of Contents

Introduction

DotsNav is a fully dynamic and robust planar navmesh Unity package built on DOTS. It is fast enough to add and remove many obstacles each frame, supports agents of any size, and can be used through monobehaviours without prior knowledge of DOTS.

DotsNav is in an early stage of development. It passes demanding robustness tests as can be seen in the video and demo, but has not been used beyond developing the demo. DotsNav is known to run as Windows standalone, UWP app and on Android. Apple devices have not been tested.

To support further development consider becoming a sponsor and get access to the beta and development repositories which are a few months ahead of this repository, access tot the private discord channel and votes on the roadmap. The first improvement will be to implement local avoidance by porting rvo2-cs.

Getting Started

Installing the package

Open the package manager and choose Add package from git URL.

Enter the url:

https://github.com/dotsnav/dotsnav.git

Samples can be imported through the package manager.

Navmesh

To create a navmesh attach a DotsNav Navmesh behaviour to a gameobject. The navmesh dimensions will be drawn in the scene view. A top down orthogonal perspective is usually the easiest way to view navmeshes and edit obstacles. Currently only one navmesh is allowed which will be centered around the origin. The value of Expected Verts determines the size of initial allocations.

Conversion to DOTS

Add a Convert to Entity component to the Navmesh so it is converted to DOTS. When using monobehaviours to develop a project choose “Convert and Inject”. Obstacles can then be removed from the navmesh by destroying the associated gameobject. The navmesh can be disposed of similarly.

Obstacles

To create an obstacle add a DotsNav Obstacle behaviour to a different gameobject and make sure it is converted.

Add a few vertices and move them around using the position handle. The edit mode colors can be set in the DotsNav tab in Preferences.

Alternatively an obstacle's Vertices array can be populated through script. Obstacle gameobjects can be scaled, rotated around their y axis, and used as prefabs.

Pathfinder

To enable pathfinding agents first add a DotsNav Pathfinder behaviour and make sure it is converted. The navmesh gameobject is a good place to add the pathfinder, but this is not required.

Agents

Add a DotsNav Agent behaviour to a different gameobject and make sure it is converted.

Renderer

To draw the navmesh while playing, add a DotsNav Renderer component to a gameobject. If the renderer is attached to the camera it can draw in the game view as well as the scene view.

Path Queries

Path queries can be enqueued using DotsNavAgent.FindPath.

Next navmesh update a path will be calculated.

Each navmesh update the direction required to follow the path is calculated using the agent's position.

Using the default settings, invalidated paths are recalculated automatically.

For multiple agents, path finding is performed in parallel.

Creating obstacles from code

Obstacle prefabs are automatically enqueued for insertion when spawned. Alternatively obstacles can be inserted by calling InsertObstacle and providing a list of vertices.

Obstacles can be removed by destroying a previously spawned gameobject, or by calling RemoveObstacle providing an id returned by InsertObstacle.

Getting Started with DOTS

Conversion

The easiest way to get started with DOTS is to do all of the above, but instead use “Convert and Destroy”.

This creates appropriate entities and components. Alternatively you can create entities and components manually, which is described below.

Navmesh

Navmeshes are created by adding a NavmeshComponent to an entity. This allows you to supply the parameters used when the navmesh is created. Destroy the entity to dispose of its resources. There should only be one navmesh at any time.

Obstacles

There are two types of obstacles:

  • Dynamic, these obstacles are associated with an entity through which they can be identified and removed
  • Static, these obstacles can not be removed or identified beyond being static, but can be inserted in bulk

The following archetypes trigger obstacle insertion:

  • Dynamic
    • ObstacleComponent, DynamicBuffer<VertexElement>
    • ObstacleComponent, VertexBlobComponent
  • Static
    • DynamicBuffer<VertexElement>, DynamicBuffer<VertexAmountElement>
    • ObstacleBlobComponent

Entities with static archetypes are destroyed after insertion. To remove dynamic entities from the navmesh destroy their associated entity.

PathFinder

Add a PathFinderComponent to an entity. Use the constructor so it is initialized properly. Destroy the entity to dispose of its resources. There should be only one PathFinderComponent at any time.

Agents

Create an entity with the following archetype:

  • AgentComponent
  • DynamicBuffer<PathSegmentElement>
  • DynamicBuffer<TriangleElement>
  • AgentDirectionComponent (optional)
  • AgentDrawComponent (optional)

To trigger path queries set AgentComponent.State to Pending.

Accessing the triangulation

The Navmesh component provides access to the triangulation through the following methods, allowing for traversal of the triangulation and development of additional algorithms:

  • Edge* FindTriangleContainingPoint
  • Vertex* FindClosestVertex

Technical Information

DotsNav uses a Local Clearance Triangulation which reduces path finding using an arbitrary agent radius to a single floating point comparison per expanded edge. It uses a quadedge to represent the triangulation, and a bucketed quadtree for point location.

DotsNav's insertion and removal algorithms are guaranteed to succeed and guarantee closed polygons remain closed, no matter how many intersecting obstacles are inserted or removed. In short, intersections use an existing point chosen to converge on the destination in the rare case no valid point can be created due to the density of the navmesh. When points chosen in this way are not connected directly, A* is used to determine which edges need to be constrained.

Due to the nature of the algorithms involved exact geometric predicates are required for a robust implementation. DotsNav relies on adaptive predicates, only when regular floating point calculations do not provide sufficient precision is the costly exact calculation performed. The predicates are available separately.

DotsNav provides locally optimal search. First, a channel of connected triangles with enough clearance is found using A*. The optimal path given this channel is then found using the funnel algorithm. While channels found are often optimal they are not guaranteed to be. An algorithm to find the optimal channel exists, but can easily take 100 times longer to execute and is not currently implemented. As there are valid use cases for globally optimal search, if only to benchmark cost functions, it is included on the roadmap.

Roadmap

The roadmap will be updated based on feedback.

  • Collision avoidance, port rvo2c#
  • Preferred radius to use where clearance allows
  • Custom cost functions, so agents can prefer to avoid certain conditions
  • Deterministic path finding budget and agent priorities
  • Multiple and overlapping navmeshes and offmesh links
  • Serialization for faster loading of large amounts of obstacles
  • Queries to determine shapes are outside any obstacle
  • Steering behaviours
  • Globally optimal search, very slow but needed to benchmark cost functions
  • Allow for loading or generating and unloading neighbouring chunks of navmesh
  • Hierarchical path finding

Bibliography

  • Dynamic and Robust Local Clearance Triangulations, Kallmann 2014
  • Shortest Paths with Arbitrary Clearance from Navigation Meshes, Kallmann 2010
  • Fully Dynamic Constrained Delaunay Triangulations, Kallmann 2003
  • An Improved Incremental algorithm for constructing restricted Delaunay triangulations, Vigo 1997
  • Incremental Delaunay Triangulation, Lischinski 1994
  • Primitives for the Manipulation of General Subdivisions and the Computation of Voronoi Diagrams, Guibas and Stolfi 1985
  • Adaptive Precision Floating-Point Arithmetic and Fast Robust Predicates for Computational Geometry, Shewchuk 1996

Acknowledgements

I would like to thank Marcello Kallmann for describing the local clearance triangulation including robust and dynamic insertion and removal algorithms, Jonathan Shewchuk for placing his geometric primitives in the public domain, and Govert van Drimmelen for porting them to C#.

About

A fully dynamic planar navmesh Unity package supporting agents of any size

License:zlib License


Languages

Language:C# 99.7%Language:ShaderLab 0.3%