A* Pathfinding Project
3.8.9
The A* Pathfinding Project for Unity 3D
|
Navmesh cutting is used for fast recast graph updates. More...
Navmesh cutting is used for fast recast graph updates.
Navmesh cutting is used to cut holes into an existing navmesh generated by a recast graph. Recast graphs usually only allow either just changing parameters on existing nodes (e.g make a whole triangle unwalkable) which is not very flexible or recalculate a whole tile which is pretty slow. With navmesh cutting you can remove (cut) parts of the navmesh that is blocked by obstacles such as a new building in an RTS game however you cannot add anything new to the navmesh or change the positions of the nodes.
The NavmeshCut component uses a 2D shape to cut the navmesh with. A rectangle and circle shape is built in, but you can also specify a custom mesh to use. The custom mesh should be a flat 2D shape like in the image below. The script will then find the contour of that mesh and use that shape as the cut. Make sure that all normals are smooth and that the mesh contains no UV information. Otherwise Unity might split a vertex and then the script will not find the correct contour. You should not use a very high polygon mesh since that will create a lot of nodes in the navmesh graph and slow down pathfinding because of that. For very high polygon meshes it might even cause more suboptimal paths to be generated if it causes many thin triangles to be added to the navmesh.
Note that the shape is not 3D so if you rotate the cut you will see that the 2D shape will be rotated and then just projected down on the XZ plane.
To use a navmesh cut in your scene you need to have a TileHandlerHelper script somewhere in your scene. You should only have one though. That script will take care of checking all the NavmeshCut components to see if they need to update the navmesh.
In the scene view the NavmeshCut looks like an extruded 2D shape because a navmesh cut also has a height. It will only cut the part of the navmesh which it touches. For performance it only checks the bounding boxes of the triangles in the navmesh, so it may cut triangles whoose bounding boxes it intersects even if the triangle does not intersect the extructed shape. However in most cases this does not make a large difference.
It is also possible to set the navmesh cut to dual mode by setting the isDual field to true. This will prevent it from cutting a hole in the navmesh and it will instead just split the navmesh along the border but keep both the interior and the exterior. This can be useful if you for example want to change the penalty of some region which does not neatly line up with the navmesh triangles. It is often combined with the GraphUpdateScene component (however note that the GraphUpdateScene component will not automatically reapply the penalty if the graph is updated again).
By default the navmesh cut does not take rotation or scaling into account. If you want to do that, you can set the useRotation field to true. This is a bit slower, but it is not a very large difference.
Public Types | |
enum | MeshType { Rectangle, Circle, CustomMesh } |
Public Member Functions | |
void | Awake () |
void | ForceUpdate () |
Forces this navmesh cut to update the navmesh. | |
Bounds | GetBounds () |
World space bounds of this cut. | |
void | GetContour (List< List< Pathfinding.ClipperLib.IntPoint > > buffer) |
World space contour of the navmesh cut. | |
void | NotifyUpdated () |
Internal method to notify the NavmeshCut that it has just been used to update the navmesh. | |
void | OnDestroy () |
void | OnDrawGizmos () |
void | OnDrawGizmosSelected () |
void | OnEnable () |
bool | RequiresUpdate () |
Returns true if this object has moved so much that it requires an update. | |
virtual void | UsedForCut () |
Called whenever this navmesh cut is used to update the navmesh. | |
Static Public Member Functions | |
static List< NavmeshCut > | GetAll () |
Returns a list with all NavmeshCut components in the scene. | |
static List< NavmeshCut > | GetAllInRange (Bounds b) |
Get all active instances which intersect the bounds. | |
static Vector3 | IntPointToV3 (Pathfinding.ClipperLib.IntPoint p) |
Converts an IntPoint to a Vector3. | |
static Pathfinding.ClipperLib.IntPoint | V3ToIntPoint (Vector3 p) |
Converts a Vector3 to an IntPoint. | |
Public Attributes | |
Vector3 | center |
float | circleRadius = 1 |
Radius of the circle. | |
int | circleResolution = 6 |
Number of vertices on the circle. | |
bool | cutsAddedGeom = true |
Cuts geometry added by a NavmeshAdd component. | |
float | height = 1 |
The cut will be extruded to this height. | |
bool | isDual |
Only makes a split in the navmesh, but does not remove the geometry to make a hole. | |
Mesh | mesh |
Custom mesh to use. | |
float | meshScale = 1 |
Scale of the custom mesh, if used. | |
Vector2 | rectangleSize = new Vector2(1, 1) |
Size of the rectangle. | |
MeshType | type |
Shape of the cut. | |
float | updateDistance = 0.4f |
Distance between positions to require an update of the navmesh. | |
float | updateRotationDistance = 10 |
How many degrees rotation that is required for an update to the navmesh. | |
bool | useRotation |
Includes rotation in calculations. | |
Static Public Attributes | |
static readonly Color | GizmoColor = new Color(37.0f/255, 184.0f/255, 239.0f/255) |
Protected Attributes | |
Transform | tr |
cached transform component | |
Properties | |
Bounds | LastBounds [get] |
Events | |
static System.Action< NavmeshCut > | OnDestroyCallback |
Called every time a NavmeshCut component is destroyed. | |
Private Member Functions | |
void | CalculateMeshContour () |
Static Private Member Functions | |
static void | AddCut (NavmeshCut obj) |
static bool | Intersects (Bounds b1, Bounds b2) |
True if b1 and b2 intersects. | |
static void | RemoveCut (NavmeshCut obj) |
Private Attributes | |
Vector3[][] | contours |
Bounds | lastBounds |
Mesh | lastMesh |
Vector3 | lastPosition |
Quaternion | lastRotation |
bool | wasEnabled |
Static Private Attributes | |
static List< NavmeshCut > | allCuts = new List<NavmeshCut>() |
static readonly Dictionary < Int2, int > | edges = new Dictionary<Int2, int>() |
Cached variable, to avoid allocations. | |
static readonly Dictionary < int, int > | pointers = new Dictionary<int, int>() |
Cached variable, to avoid allocations. | |
enum MeshType |
|
staticprivate |
void Awake | ( | ) |
|
private |
void ForceUpdate | ( | ) |
Forces this navmesh cut to update the navmesh.
|
static |
Returns a list with all NavmeshCut components in the scene.
|
static |
Get all active instances which intersect the bounds.
Bounds GetBounds | ( | ) |
World space bounds of this cut.
void GetContour | ( | List< List< Pathfinding.ClipperLib.IntPoint > > | buffer | ) |
World space contour of the navmesh cut.
Fills the specified buffer with all contours. The cut may contain several contours which is why the buffer is a list of lists.
|
staticprivate |
True if b1 and b2 intersects.
|
static |
Converts an IntPoint to a Vector3.
This is a lossy conversion.
void NotifyUpdated | ( | ) |
Internal method to notify the NavmeshCut that it has just been used to update the navmesh.
void OnDestroy | ( | ) |
void OnDrawGizmos | ( | ) |
void OnDrawGizmosSelected | ( | ) |
void OnEnable | ( | ) |
|
staticprivate |
bool RequiresUpdate | ( | ) |
Returns true if this object has moved so much that it requires an update.
When an update to the navmesh has been done, call NotifyUpdated to be able to get relavant output from this method again.
|
virtual |
Called whenever this navmesh cut is used to update the navmesh.
Called once for each tile the navmesh cut is in. You can override this method to execute custom actions whenever this happens.
|
static |
Converts a Vector3 to an IntPoint.
This is a lossy conversion.
|
staticprivate |
Vector3 center |
float circleRadius = 1 |
Radius of the circle.
int circleResolution = 6 |
Number of vertices on the circle.
|
private |
bool cutsAddedGeom = true |
Cuts geometry added by a NavmeshAdd component.
You rarely need to change this
Cached variable, to avoid allocations.
|
static |
float height = 1 |
The cut will be extruded to this height.
bool isDual |
Only makes a split in the navmesh, but does not remove the geometry to make a hole.
This is slower than a normal cut
|
private |
|
private |
|
private |
|
private |
Mesh mesh |
Custom mesh to use.
The contour(s) of the mesh will be extracted. If you get the "max perturbations" error when cutting with this, check the normals on the mesh. They should all point in the same direction. Try flipping them if that does not help.
This mesh should only be a 2D surface, not a volume.
float meshScale = 1 |
Scale of the custom mesh, if used.
|
staticprivate |
Cached variable, to avoid allocations.
Vector2 rectangleSize = new Vector2(1, 1) |
Size of the rectangle.
|
protected |
cached transform component
MeshType type |
Shape of the cut.
float updateDistance = 0.4f |
Distance between positions to require an update of the navmesh.
A smaller distance gives better accuracy, but requires more updates when moving the object over time, so it is often slower.
float updateRotationDistance = 10 |
How many degrees rotation that is required for an update to the navmesh.
Should be between 0 and 180.
bool useRotation |
Includes rotation in calculations.
This is slower since a lot more matrix multiplications are needed but gives more flexibility.
|
private |
|
get |
|
static |
Called every time a NavmeshCut component is destroyed.