Unit 6: Working with Navmesh
I. Orientation: AI Navigation and Networked 3D Worlds
A navigation mesh (navmesh) is a simplified, convex-polygon representation of the walkable surface of a 3D level, used so that agents can reason about "where can I stand and how do I get there" without testing raw geometry. The technique was popularised by Greg Snook's "Simplified 3D Movement and Pathfinding Using Navigation Meshes" (Game Programming Gems, 2000); Unity's implementation is built on the open-source Recast & Detour libraries (Mikko Mononen, 2009) — Recast bakes the mesh by voxelisation, Detour queries it at runtime. This unit pairs that single-machine AI navigation with networked play, because agent movement is one of the largest sources of replicated state in a multiplayer game.
Assumptions and conventions used throughout:
- Agent abstraction: every agent is a capsule described by radius, height, step height and max slope; the navmesh is baked per agent type, not per character.
- Erosion: the baked surface is shrunk inward by the agent radius, so an agent's centre point can be treated as a dimensionless point during search.
- Polygon, not grid: the search graph nodes are convex polygons; a straight line between any two points inside one polygon is guaranteed walkable.
- Static vs dynamic: baked geometry is static; moving blockers are handled by
NavMeshObstaclecarving, not by re-baking. - Server authority (networking): in a multiplayer build, pathfinding is normally executed only on the server/host; clients receive positions.
- Units: distances in Unity metres, angles in degrees, speeds in m/s, network rates in Hz (ticks or sends per second).
II. Basics of Navmesh
A. The bake pipeline and its parameters
Baking converts arbitrary triangle soup into a walkable polygon mesh through voxelisation.
- Stages: rasterise static geometry into voxels → filter walkable voxel spans by slope and step → build a region/contour set → simplify contours into convex polygons → link neighbouring polygons.
- Agent Radius (default 0.5 m): erodes the walkable area away from walls; halving it doubles the number of narrow gaps agents can enter.
- Agent Height (2 m) and Step Height (0.4 m): clearance test and the maximum ledge an agent may climb without an off-mesh link.
- Max Slope (45°): any triangle steeper than this is discarded as non-walkable.
- Voxel Size (advanced): default is agent radius / 3 ≈ 0.166 m; smaller voxels give finer geometry but a much longer bake and larger data.
- Tile size (256 voxels default): the navmesh is cut into square tiles so a single tile can be rebuilt at runtime instead of the whole level.
B. Runtime components
NavMeshSurface(AI Navigation package): bakes a surface for one Agent Type, withcollectObjectsset to All / Volume / Children, and supportsBuildNavMesh()at runtime.NavMeshAgent: steers a character; key fields arespeed,angularSpeed(120 °/s),acceleration(8 m/s²),stoppingDistance,autoBraking,obstacleAvoidanceTypeandavoidancePriority(0–99, lower value = higher priority).NavMeshObstacle: a moving blocker; with Carve enabled it cuts a hole in the navmesh, re-carving only when it moves more than the Carve Only Stationary threshold (0.1 m default).OffMeshLink/ NavMesh Link: an explicit edge for jumps, ladders and doors, with a cost override so a jump can be made expensive relative to walking.- Areas and costs: up to 32 area types (Walkable = 0, Not Walkable = 1, Jump = 2). An agent's
areaMaskfilters areas; area cost multiplies traversal length (e.g. Water cost 5 makes a 10 m wade equal a 50 m detour).
C. Applications and limitations
- Applications: enemy chase and patrol AI, click-to-move RPG control, crowd flow, spawn-point validity tests via
NavMesh.SamplePosition. - Limitations: 2.5D only (no true overhangs on the same surface without separate layers), no dynamic geometry without carving or tile rebuild, agents are cylinders so no crouching/prone volumes, and off-mesh traversal animation must be authored manually.
III. Path Finding using Navmesh
A. The search algorithm
Detour runs A* over the polygon graph, using polygon centres (or portal midpoints) as node positions.
f(n) = g(n) + h(n)
g(n) = accumulated cost from start to n (length × areaCost)
h(n) = straight-line distance from n to goal // admissible heuristic- Node expansion: the open list is a priority queue ordered by
f; the first polygon containing the goal point terminates the search. - String pulling (funnel algorithm): the raw polygon corridor is converted to a minimal corner list by dragging a funnel of left/right portal endpoints — this is why
NavMeshPath.cornerscontains only turn points, not every polygon. - Steering: the agent moves toward
corners[1], applying local avoidance (RVO-style velocity obstacles) each frame before writingtransform.position.
B. Querying paths in code
[SerializeField] Transform target;
NavMeshAgent agent;
void Start() => agent = GetComponent<NavMeshAgent>();
void Update() {
if (!agent.pathPending &&
agent.remainingDistance > agent.stoppingDistance)
agent.SetDestination(target.position);
}
// Validate before committing
bool CanReach(Vector3 dest) {
var path = new NavMeshPath();
NavMesh.CalculatePath(transform.position, dest, NavMesh.AllAreas, path);
return path.status == NavMeshPathStatus.PathComplete;
}NavMeshPathStatus:PathComplete(goal reached),PathPartial(blocked; ends at nearest point),PathInvalid(no start/end polygon found).NavMesh.SamplePosition(pos, out hit, maxDistance, mask): snaps an arbitrary world point onto the mesh — essential beforeSetDestination, since a click on a wall yields a partial path.agent.Warp(position): teleports and re-links the agent to the correct polygon; settingtransform.positiondirectly desynchronises the internal agent.agent.isStopped/ResetPath(): pause versus discard the corridor.
C. Path quality and failure handling
- Partial paths: treat
PathPartialas "move as close as possible, then re-evaluate", otherwise agents grind against obstacles. - Repath budget: re-issue
SetDestinationonly when the target has moved more than ~1 m, or on a 0.2–0.5 s timer, rather than every frame. - Crowd deadlock: identical
avoidancePriorityon many agents causes jitter; stagger priorities, and raiseobstacleAvoidanceTypeonly for near-camera agents.
IV. Multiplayer Game Development using Photon / Unity Netcode
A. Architecture fundamentals
Both stacks are authoritative-server models over a topology of one host and n clients; the difference is who runs the simulation and how state is replicated.
- Server authority: the server owns AI navmesh agents, health and score; clients send intent (input), not results.
- Replication primitives: state synchronisation (continuous, e.g. transforms) and events (discrete, e.g. "fire").
- Client-side interpolation: clients render remote objects ~100 ms in the past to smooth over packet jitter.
1. Unity Netcode for GameObjects (NGO)
NetworkManagerwith a transport (Unity Transport/UTP) starts Host, Server or Client.NetworkObjectgives a spawned prefab aNetworkObjectIdand an owner;NetworkBehaviourexposes the sync API.
public class Mover : NetworkBehaviour {
NetworkVariable<Vector3> pos = new(writePerm: NetworkVariableWritePermission.Server);
NavMeshAgent agent;
[ServerRpc] // client → server
void MoveServerRpc(Vector3 dest) => agent.SetDestination(dest);
[ClientRpc] // server → all clients
void PlayFxClientRpc() { /* cosmetic only */ }
}NetworkVariable<T>: server-written, client-read, delta-sent at the configured tick rate (default 30 Hz).NetworkTransform: built-in position/rotation sync with per-axis thresholds and interpolation toggle.
2. Photon (PUN 2 / Fusion)
- Connection flow:
PhotonNetwork.ConnectUsingSettings()→ lobby →JoinRandomRoom()/CreateRoom(); a Master Client acts as authority in the relayed room. PhotonView: identity component;photonView.IsMinegates local control.- Serialisation: implement
IPunObservable.OnPhotonSerializeView(stream, info)to write on the owner and read on remotes. - Events:
photonView.RPC("TakeDamage", RpcTarget.All, 10)with the method marked[PunRPC]. - Contrast: PUN relays through Photon Cloud servers (no server code, easy NAT traversal, per-CCU pricing); NGO is self-hosted/Relay-based and gives full control of the server loop and tick.
C. Navmesh in a networked game
- Bake once, run on server: all clients load the same baked navmesh, but only the server ticks
NavMeshAgent; on clients setagent.enabled = falseand drive the visual fromNetworkTransform. - Determinism warning: local avoidance is frame-rate dependent, so two machines simulating the same agent will diverge — never trust parallel simulation for gameplay-critical positions.
- Bandwidth: a full transform is 24–28 bytes; 50 agents at 30 Hz ≈ 40 KB/s per client before compression — the direct motive for the next section.
V. Optimization Techniques
A. Navigation and pathfinding cost
- Bake-time: raise voxel size toward radius/2 for outdoor levels, reduce the number of Agent Types (each type = a full extra mesh), and exclude decorative geometry from
NavMeshSurfacecollection layers. - Runtime rebuild: prefer carving
NavMeshObstacleoverBuildNavMesh(); if you must rebuild, rebuild one tile, not the surface. - Query throttling:
NavMesh.CalculatePathis synchronous — cap requests to k per frame from a queue; useNavMeshQueryin Burst jobs for hundreds of agents. - Distance culling: switch far agents to
updatePosition = falsewith a slower fixed-step tick, and dropobstacleAvoidanceTypetoNoObstacleAvoidancebeyond ~30 m. - Object pooling: reuse agent GameObjects; each
NavMeshAgentenable triggers a polygon re-link.
B. Network traffic and CPU
- Send-rate reduction: replicate at 15–20 Hz plus client interpolation instead of 60 Hz raw.
- Delta and quantisation: send only changed axes; compress rotation to a quaternion "smallest three" (≈4 bytes) and positions to 16-bit fixed point where world bounds allow.
- Interest management: only replicate objects inside a client's relevance radius (
NetworkObject.CheckObjectVisibilityin NGO, interest groups in PUN) — the single largest win in large maps. - Path compression: instead of streaming positions, send the destination once and let clients play a local, non-authoritative agent, correcting on a slow keyframe.
- Batching: merge many small RPCs into one tick payload to avoid per-packet UDP overhead (~28 bytes IP+UDP header per datagram).
C. Profiling discipline
- Measure first: the Profiler's AI / Navigation markers (
NavMeshManager.Update) and the Network module's bytes-in/out per tick identify whether the bottleneck is search, steering or replication. - Typical split: steering and avoidance usually cost more per frame than A* itself, because avoidance runs every frame while a path is computed once.
Did this save you a night before the exam?
LPU Notes is free, and it stays free. Ads cover part of the server bill. The rest comes out of a student's own pocket: the domain, the storage, and keeping the site up through the weeks everyone needs it at once.
The payment button didn't load. An ad blocker or a filtered network is the usual reason. to try again.
Nothing here is ever locked, and nothing unlocks. Chip in only if it was worth it. What it pays for →