{
  "schemaVersion": "0.11.0",
  "canonical": "https://www.pystone.net/notes/unity-navmesh/",
  "atlas": "https://www.pystone.net/?node=unity-navmesh#knowledge-atlas",
  "markdown": "https://www.pystone.net/notes/unity-navmesh.md",
  "context": "https://www.pystone.net/notes/unity-navmesh.context.json",
  "knowledgeVersion": "224c990773de.5fa8af6e39fa",
  "build": {
    "siteCommit": "224c990773de166d23a886306577dd90379529ce",
    "notesCommit": "5fa8af6e39fa3891d1b9b4832bfa6c4e0ecaaf0a",
    "builtAt": "1970-01-01T00:00:00.000Z",
    "version": "224c990773de.5fa8af6e39fa"
  },
  "id": "note:unity-navmesh",
  "slug": "unity-navmesh",
  "title": "NavMesh",
  "type": "note",
  "visibility": "public",
  "idStability": "rename-stable",
  "author": {
    "name": "Perrin Yong",
    "profile": "https://www.pystone.net/profile/"
  },
  "publisher": {
    "name": "Perrin Yong",
    "profile": "https://www.pystone.net/profile/"
  },
  "aliases": [],
  "summary": "NavMesh",
  "contentRole": "unspecified",
  "isMoc": false,
  "mocRecognition": "none",
  "generated": false,
  "attribution": "unspecified",
  "domain": "10-计算机、信息技术与工程",
  "tags": [],
  "mocs": [],
  "contentHash": "2588f549e5aa20e48d33b9f3cb32789f3359e7e3e2139df8894ee0ec8c50f564",
  "assets": [
    {
      "reference": "assets/1620751740246.png",
      "url": "/media/bf3b94b9529a38e63413.png",
      "mediaType": "image/png",
      "contentHash": "bf3b94b9529a38e63413ed7cfd6c8e4cc7054b5d5a2fed76e70c9c2addc0a814",
      "byteLength": 58024,
      "width": 1052,
      "height": 452
    },
    {
      "reference": "assets/1620751750347.png",
      "url": "/media/b285c49ead7c8bf28270.png",
      "mediaType": "image/png",
      "contentHash": "b285c49ead7c8bf28270d9e0e3c53c1346bbb834b4e6b3669af1c181ec52a193",
      "byteLength": 31358,
      "width": 1052,
      "height": 454
    },
    {
      "reference": "assets/1620748376654.png",
      "url": "/media/831cc29e731d5ef872b1.png",
      "mediaType": "image/png",
      "contentHash": "831cc29e731d5ef872b1b2f4401a89721bb430fbd80ccd18cd07df4e91c0dd80",
      "byteLength": 24861,
      "width": 335,
      "height": 250
    },
    {
      "reference": "assets/1620752340467.png",
      "url": "/media/fdcb902cbed2a2881e3b.png",
      "mediaType": "image/png",
      "contentHash": "fdcb902cbed2a2881e3bde97720819f8fb2feb28668868079c572d17251d684c",
      "byteLength": 17020,
      "width": 335,
      "height": 112
    },
    {
      "reference": "assets/1620752593292.png",
      "url": "/media/f5731c44e1dbd0c000df.png",
      "mediaType": "image/png",
      "contentHash": "f5731c44e1dbd0c000df43ec3907d7821595740b19e305e343da99b9f16af08d",
      "byteLength": 17534,
      "width": 335,
      "height": 105
    },
    {
      "reference": "assets/1620752915537.png",
      "url": "/media/f355a7aaa876aad28127.png",
      "mediaType": "image/png",
      "contentHash": "f355a7aaa876aad28127e2441ae2d20c1125ebdc11962353db8d48e562099ebd",
      "byteLength": 6484,
      "width": 148,
      "height": 110
    },
    {
      "reference": "assets/1620753233885.png",
      "url": "/media/d7f6685a3fbc8b24b1bf.png",
      "mediaType": "image/png",
      "contentHash": "d7f6685a3fbc8b24b1bfd4989a373c4ab080d17117671984c5141e84411b68f8",
      "byteLength": 10383,
      "width": 400,
      "height": 195
    },
    {
      "reference": "assets/1620753809200.png",
      "url": "/media/1c4fd50dbdd27c30626a.png",
      "mediaType": "image/png",
      "contentHash": "1c4fd50dbdd27c30626ac0fb64fe320c743614d9dcf9477f58313db905269a6b",
      "byteLength": 24108,
      "width": 335,
      "height": 249
    }
  ],
  "headings": [
    {
      "depth": 1,
      "text": "NavMesh",
      "anchor": "navmesh",
      "citation": "https://www.pystone.net/notes/unity-navmesh/#navmesh"
    },
    {
      "depth": 2,
      "text": "基础知识 - 寻路算法",
      "anchor": "基础知识---寻路算法",
      "citation": "https://www.pystone.net/notes/unity-navmesh/#%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86---%E5%AF%BB%E8%B7%AF%E7%AE%97%E6%B3%95"
    },
    {
      "depth": 3,
      "text": "其他寻路算法",
      "anchor": "其他寻路算法",
      "citation": "https://www.pystone.net/notes/unity-navmesh/#%E5%85%B6%E4%BB%96%E5%AF%BB%E8%B7%AF%E7%AE%97%E6%B3%95"
    },
    {
      "depth": 3,
      "text": "A Star算法",
      "anchor": "a-star算法",
      "citation": "https://www.pystone.net/notes/unity-navmesh/#a-star%E7%AE%97%E6%B3%95"
    },
    {
      "depth": 4,
      "text": "启发函数h(n)",
      "anchor": "启发函数hn",
      "citation": "https://www.pystone.net/notes/unity-navmesh/#%E5%90%AF%E5%8F%91%E5%87%BD%E6%95%B0hn"
    },
    {
      "depth": 2,
      "text": "Unity NavMesh",
      "anchor": "unity-navmesh",
      "citation": "https://www.pystone.net/notes/unity-navmesh/#unity-navmesh"
    },
    {
      "depth": 3,
      "text": "组成",
      "anchor": "组成",
      "citation": "https://www.pystone.net/notes/unity-navmesh/#%E7%BB%84%E6%88%90"
    },
    {
      "depth": 4,
      "text": "NavMesh",
      "anchor": "navmesh-1",
      "citation": "https://www.pystone.net/notes/unity-navmesh/#navmesh-1"
    },
    {
      "depth": 4,
      "text": "Components",
      "anchor": "components",
      "citation": "https://www.pystone.net/notes/unity-navmesh/#components"
    },
    {
      "depth": 3,
      "text": "two problems",
      "anchor": "two-problems",
      "citation": "https://www.pystone.net/notes/unity-navmesh/#two-problems"
    },
    {
      "depth": 3,
      "text": "NavMesh寻路分解",
      "anchor": "navmesh寻路分解",
      "citation": "https://www.pystone.net/notes/unity-navmesh/#navmesh%E5%AF%BB%E8%B7%AF%E5%88%86%E8%A7%A3"
    },
    {
      "depth": 4,
      "text": "Finding Paths",
      "anchor": "finding-paths",
      "citation": "https://www.pystone.net/notes/unity-navmesh/#finding-paths"
    },
    {
      "depth": 4,
      "text": "Following the Path",
      "anchor": "following-the-path",
      "citation": "https://www.pystone.net/notes/unity-navmesh/#following-the-path"
    },
    {
      "depth": 4,
      "text": "Avoiding Obstacles",
      "anchor": "avoiding-obstacles",
      "citation": "https://www.pystone.net/notes/unity-navmesh/#avoiding-obstacles"
    },
    {
      "depth": 4,
      "text": "Moving the Agent",
      "anchor": "moving-the-agent",
      "citation": "https://www.pystone.net/notes/unity-navmesh/#moving-the-agent"
    },
    {
      "depth": 4,
      "text": "Global and Local",
      "anchor": "global-and-local",
      "citation": "https://www.pystone.net/notes/unity-navmesh/#global-and-local"
    },
    {
      "depth": 4,
      "text": "Two Cases for Obstacles",
      "anchor": "two-cases-for-obstacles",
      "citation": "https://www.pystone.net/notes/unity-navmesh/#two-cases-for-obstacles"
    },
    {
      "depth": 5,
      "text": "local obstacle avoidance",
      "anchor": "local-obstacle-avoidance",
      "citation": "https://www.pystone.net/notes/unity-navmesh/#local-obstacle-avoidance"
    },
    {
      "depth": 5,
      "text": "global pathfinding",
      "anchor": "global-pathfinding",
      "citation": "https://www.pystone.net/notes/unity-navmesh/#global-pathfinding"
    },
    {
      "depth": 4,
      "text": "Off-mesh Links",
      "anchor": "off-mesh-links",
      "citation": "https://www.pystone.net/notes/unity-navmesh/#off-mesh-links"
    },
    {
      "depth": 2,
      "text": "实践",
      "anchor": "实践",
      "citation": "https://www.pystone.net/notes/unity-navmesh/#%E5%AE%9E%E8%B7%B5"
    },
    {
      "depth": 3,
      "text": "Building a NavMesh",
      "anchor": "building-a-navmesh",
      "citation": "https://www.pystone.net/notes/unity-navmesh/#building-a-navmesh"
    },
    {
      "depth": 2,
      "text": "Ref",
      "anchor": "ref",
      "citation": "https://www.pystone.net/notes/unity-navmesh/#ref"
    }
  ],
  "claims": [],
  "outgoing": [],
  "incoming": [
    {
      "id": "note:game-graphics-and-runtime",
      "title": "游戏图形与运行时",
      "url": "https://www.pystone.net/notes/game-graphics-and-runtime/",
      "atlas": "https://www.pystone.net/?node=game-graphics-and-runtime#knowledge-atlas",
      "label": "游戏图形与运行时",
      "origin": "explicit",
      "humanReviewed": true,
      "context": "Unity中的“NavMesh”导航项",
      "citation": "https://www.pystone.net/notes/game-graphics-and-runtime/#unity"
    }
  ],
  "contentMarkdown": "# NavMesh\n\n> 创建时间：2021/5/11 23:37\n\n  * NavMesh\n    * 基础知识 - 寻路算法\n      * 其他寻路算法\n      * A Star算法\n        * 启发函数h(n)\n    * Unity NavMesh\n      * 组成\n        * NavMesh\n        * Components\n      * two problems\n      * NavMesh寻路分解\n        * Finding Paths\n        * Following the Path\n        * Avoiding Obstacles\n        * Moving the Agent\n        * Global and Local\n        * Two Cases for Obstacles\n          * local obstacle avoidance\n          * global pathfinding\n        * Off-mesh Links\n    * 实践\n      * Building a NavMesh\n    * Ref\n\n## 基础知识 - 寻路算法\n\n### 其他寻路算法\n\n广度优先（Breadth First）算法 - 从起点开始，首先遍历起点周围邻近的点，然后再遍历已经遍历过的点邻近的点，逐步的向外扩散，直到找到终点。\n\nDijkstra算法 - 加了移动代价的广度优先算法。计算每一个节点距离起点的总移动代价。对于所有待遍历的节点，放入优先队列中会按照代价进行排序。每次都从优先队列中选出代价最小的作为下一个遍历的节点。直到到达终点为止。\n\n> 如果图形为网格图，并且每个节点之间的移动代价是相等的，那么Dijkstra算法将和广度优先算法变得一样。\n\n最佳优先（Best First）算法 - 预先计算出每个节点到终点的距离。与Dijkstra算法类似，我们也使用一个优先队列，但此时以每个节点到达终点的距离作为优先级。从起点开始寻路，每次始终选取到终点移动代价最小（离终点最近）的节点作为下一个遍历的节点。\n\n  * 优点：这样做可以大大加快路径的搜索速度\n\n  * 缺点：如果起点和终点之间存在障碍物，则最佳优先算法找到的很可能不是最短路径\n\n### A Star算法\n=\n\\+\n\\- 节点n的综合优先级。当我们选择下一个要遍历的节点时，我们总会选取综合优先级最高（值最小）的节点。\n\\- 节点n距离起点的代价。\n\\- 节点n距离终点的预计代价，这也就是A*算法的 **启发函数** 。\n\n```csharp\nstring s1 = &quot;Hello &quot;;\nstring s2 = s1;\ns1 += &quot;World&quot;;\n\nSystem.Console.WriteLine(s2);\n//Output: Hello\n\n```\n\n  * 在极端情况下，当启发函数\n始终为0，则将由\n决定节点的优先级，此时算法就退化成了Dijkstra算法。\n\n  * 如果\n始终小于等于节点n到终点的代价，则A*算法保证一定能够找到最短路径。但是当\n的值越小，算法将遍历越多的节点，也就导致算法越慢。\n\n  * 如果\n完全等于节点n到终点的代价，则A*算法将找到最佳路径，并且速度很快。可惜的是，并非所有场景下都能做到这一点。因为在没有达到终点之前，我们很难确切算出距离终点还有多远。\n\n  * 如果\n的值比节点n到终点的代价要大，则A*算法不能保证找到最短路径，不过此时会很快。\n在另外一个极端情况下，如果\n相较于\n大很多，则此时只有\n产生效果，这也就变成了最佳优先搜索。\n\n**通过调节启发函数我们可以控制算法的速度和精确度**\n**在一些情况，我们可能未必需要最短路径，而是希望能够尽快找到一个路径即可**\n\n#### 启发函数h(n)\n\n曼哈顿距离 - 只允许朝上下左右四个方向移动\n\n![Alt text](assets/1620751740246.png)\n\n对角距离 - 允许斜着朝邻近的节点移动\n\n![Alt text](assets/1620751750347.png)\n\n欧几里得距离 - 两个节点之间的直线距离\n\n## Unity NavMesh\n\nThe navigation system allows you to create characters that can intelligently move around the game world, using navigation meshes that are created automatically from your Scene geometry.\n\n### 组成\n\n#### NavMesh\n\n**NavMesh** (short for Navigation Mesh) - a data structure which describes the walkable surfaces of the game world and allows to find path from one walkable location to another in the game world. The data structure is built, or baked, automatically from your level geometry.\n\nThe walkable area is built automatically from the geometry in the scene by testing the locations where the agent can stand. Then the locations are connected to a surface laying on top of the scene geometry. This surface is called the navigation mesh (NavMesh for short).\n\nThe NavMesh stores this surface as **convex polygons**. Convex polygons are a useful representation, since we know that **there are no obstructions between any two points inside a polygon**. In addition to the polygon boundaries, **we store information about which polygons are neighbours to each other**. This allows us to reason about the whole walkable area.\n\n#### Components\n\n**NavMesh Agent component** help you to create characters which avoid each other while moving towards their goal. Agents reason about the game world using the NavMesh and they know how to avoid each other as well as moving obstacles.\n\n**Off-Mesh Link component** allows you to incorporate navigation shortcuts which cannot be represented using a walkable surface. For example, jumping over a ditch or a fence, or opening a door before walking through it, can be all described as Off-mesh links.\n**NavMesh Obstacle component** allows you to describe moving obstacles the agents should avoid while navigating the world.\n\n![Alt text](assets/1620748376654.png)\n\n### two problems\n\n  * how to reason about the level to find the destination - global and static, in that it takes into account the whole scene.\n\n  * how to move there - local and dynamic, it only considers the direction to move and how to prevent collisions with other moving agents.\n\n### NavMesh寻路分解\n\n#### Finding Paths\n\n![Alt text](assets/1620752340467.png)\n\nThe sequence of polygons which describe the path from the start to the destination polygon is called a **corridor**. The agent will reach the destination by always steering towards the next visible corner of the corridor.\n\n#### Following the Path\n\n![Alt text](assets/1620752593292.png)\n\nWhen dealing with multiple agents moving at the same time, they will need to deviate from the original path when avoiding each other. Trying to correct such deviations using a path consisting of line segments soon becomes very difficult and error prone.\n\nSince the agent movement in each frame is quite small, we can use the connectivity of the polygons to fix up the corridor in case we need to take a little detour. Then we quickly find the next visible corner to steer towards.\n\n#### Avoiding Obstacles\n\n![Alt text](assets/1620752915537.png)\n\nThe steering logic takes the position of the next corner and based on that figures out a desired **direction** and **speed** (or velocity) needed to reach the destination. Using the desired velocity to move the agent can lead to collision with other agents.\n\nObstacle avoidance chooses a new velocity which balances between **moving in the desired direction** and **preventing future collisions** with other agents and edges of the navigation mesh. Unity is using **reciprocal velocity obstacles (RVO)** to predict and prevent collisions.\n\n#### Moving the Agent\n\nAt this stage you can feed the velocity from the simulated agent to the animation system to move the character using **root motion** , or let the **navigation system take care of that**.\n\n#### Global and Local\n\n![Alt text](assets/1620753233885.png)\n\n#### Two Cases for Obstacles\n\n##### local obstacle avoidance\n\nWhen an obstacle is moving, it is best handled using local obstacles avoidance. This way the agent can predictively avoid the obstacle.\n\n##### global pathfinding\n\n静态：When the obstacle becomes stationary, and can be considered to block the path of all agents, the obstacles should affect the global navigation, that is, the navigation mesh.\n\n动态改变：Changing the NavMesh is called carving. The process detects which parts of the obstacle touches the NavMesh and carves holes into the NavMesh.\n\n#### Off-mesh Links\n\n![Alt text](assets/1620753809200.png)\n\nThis link can be later accessed when following the path, and the special action can be executed.\n\n## 实践\n\n### Building a NavMesh\n\nNavMesh Baking - collects the Render Meshes and Terrains of all Game Objects which are marked as Navigation Static, and then processes them to create a navigation mesh that approximates the walkable surfaces of the level.\n\n**Window > AI > Navigation**\n\n  1. Select\n\n  2. Check Navigation Static\n\n  3. Adjust\nAgent Radius\nAgent Height\nMax Slope\nStep Height\n\n  4. Click bake\n\n## Ref\n\n<https://developer.aliyun.com/article/685477>\n"
}
