NavigationMesh.cpp 46 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371
  1. //
  2. // Copyright (c) 2008-2015 the Urho3D project.
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to deal
  6. // in the Software without restriction, including without limitation the rights
  7. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. // copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20. // THE SOFTWARE.
  21. //
  22. #ifdef URHO3D_PHYSICS
  23. #include "../Physics/CollisionShape.h"
  24. #endif
  25. #include "../Core/Context.h"
  26. #include "../Graphics/DebugRenderer.h"
  27. #include "../Graphics/Drawable.h"
  28. #include "../Navigation/DynamicNavigationMesh.h"
  29. #include "../Graphics/Geometry.h"
  30. #include "../IO/Log.h"
  31. #include "../IO/MemoryBuffer.h"
  32. #include "../Graphics/Model.h"
  33. #include "../Navigation/NavArea.h"
  34. #include "../Navigation/NavBuildData.h"
  35. #include "../Navigation/Navigable.h"
  36. #include "../Navigation/NavigationEvents.h"
  37. #include "../Navigation/NavigationMesh.h"
  38. #include "../Navigation/Obstacle.h"
  39. #include "../Navigation/OffMeshConnection.h"
  40. #include "../Core/Profiler.h"
  41. #include "../Scene/Scene.h"
  42. #include "../Graphics/StaticModel.h"
  43. #include "../Graphics/TerrainPatch.h"
  44. #include "../IO/VectorBuffer.h"
  45. #include <cfloat>
  46. #include <Detour/DetourNavMesh.h>
  47. #include <Detour/DetourNavMeshBuilder.h>
  48. #include <Detour/DetourNavMeshQuery.h>
  49. #include <Recast/Recast.h>
  50. #include "../Navigation/CrowdAgent.h"
  51. #include "../Navigation/DetourCrowdManager.h"
  52. #include "../DebugNew.h"
  53. namespace Urho3D
  54. {
  55. const char* navmeshPartitionTypeNames[] =
  56. {
  57. "watershed",
  58. "monotone",
  59. 0
  60. };
  61. const char* NAVIGATION_CATEGORY = "Navigation";
  62. static const int DEFAULT_TILE_SIZE = 128;
  63. static const float DEFAULT_CELL_SIZE = 0.3f;
  64. static const float DEFAULT_CELL_HEIGHT = 0.2f;
  65. static const float DEFAULT_AGENT_HEIGHT = 2.0f;
  66. static const float DEFAULT_AGENT_RADIUS = 0.6f;
  67. static const float DEFAULT_AGENT_MAX_CLIMB = 0.9f;
  68. static const float DEFAULT_AGENT_MAX_SLOPE = 45.0f;
  69. static const float DEFAULT_REGION_MIN_SIZE = 8.0f;
  70. static const float DEFAULT_REGION_MERGE_SIZE = 20.0f;
  71. static const float DEFAULT_EDGE_MAX_LENGTH = 12.0f;
  72. static const float DEFAULT_EDGE_MAX_ERROR = 1.3f;
  73. static const float DEFAULT_DETAIL_SAMPLE_DISTANCE = 6.0f;
  74. static const float DEFAULT_DETAIL_SAMPLE_MAX_ERROR = 1.0f;
  75. static const int MAX_POLYS = 2048;
  76. /// Temporary data for finding a path.
  77. struct FindPathData
  78. {
  79. // Polygons.
  80. dtPolyRef polys_[MAX_POLYS];
  81. // Polygons on the path.
  82. dtPolyRef pathPolys_[MAX_POLYS];
  83. // Points on the path.
  84. Vector3 pathPoints_[MAX_POLYS];
  85. // Flags on the path.
  86. unsigned char pathFlags_[MAX_POLYS];
  87. // Area Ids on the path.
  88. unsigned char pathAreras_[MAX_POLYS];
  89. };
  90. NavigationMesh::NavigationMesh(Context* context) :
  91. Component(context),
  92. navMesh_(0),
  93. navMeshQuery_(0),
  94. queryFilter_(new dtQueryFilter()),
  95. pathData_(new FindPathData()),
  96. tileSize_(DEFAULT_TILE_SIZE),
  97. cellSize_(DEFAULT_CELL_SIZE),
  98. cellHeight_(DEFAULT_CELL_HEIGHT),
  99. agentHeight_(DEFAULT_AGENT_HEIGHT),
  100. agentRadius_(DEFAULT_AGENT_RADIUS),
  101. agentMaxClimb_(DEFAULT_AGENT_MAX_CLIMB),
  102. agentMaxSlope_(DEFAULT_AGENT_MAX_SLOPE),
  103. regionMinSize_(DEFAULT_REGION_MIN_SIZE),
  104. regionMergeSize_(DEFAULT_REGION_MERGE_SIZE),
  105. edgeMaxLength_(DEFAULT_EDGE_MAX_LENGTH),
  106. edgeMaxError_(DEFAULT_EDGE_MAX_ERROR),
  107. detailSampleDistance_(DEFAULT_DETAIL_SAMPLE_DISTANCE),
  108. detailSampleMaxError_(DEFAULT_DETAIL_SAMPLE_MAX_ERROR),
  109. padding_(Vector3::ONE),
  110. numTilesX_(0),
  111. numTilesZ_(0),
  112. partitionType_(NAVMESH_PARTITION_WATERSHED),
  113. keepInterResults_(false),
  114. drawOffMeshConnections_(false),
  115. drawNavAreas_(false)
  116. {
  117. }
  118. NavigationMesh::~NavigationMesh()
  119. {
  120. ReleaseNavigationMesh();
  121. delete queryFilter_;
  122. queryFilter_ = 0;
  123. delete pathData_;
  124. pathData_ = 0;
  125. }
  126. void NavigationMesh::RegisterObject(Context* context)
  127. {
  128. context->RegisterFactory<NavigationMesh>(NAVIGATION_CATEGORY);
  129. ACCESSOR_ATTRIBUTE("Tile Size", GetTileSize, SetTileSize, int, DEFAULT_TILE_SIZE, AM_DEFAULT);
  130. ACCESSOR_ATTRIBUTE("Cell Size", GetCellSize, SetCellSize, float, DEFAULT_CELL_SIZE, AM_DEFAULT);
  131. ACCESSOR_ATTRIBUTE("Cell Height", GetCellHeight, SetCellHeight, float, DEFAULT_CELL_HEIGHT, AM_DEFAULT);
  132. ACCESSOR_ATTRIBUTE("Agent Height", GetAgentHeight, SetAgentHeight, float, DEFAULT_AGENT_HEIGHT, AM_DEFAULT);
  133. ACCESSOR_ATTRIBUTE("Agent Radius", GetAgentRadius, SetAgentRadius, float, DEFAULT_AGENT_RADIUS, AM_DEFAULT);
  134. ACCESSOR_ATTRIBUTE("Agent Max Climb", GetAgentMaxClimb, SetAgentMaxClimb, float, DEFAULT_AGENT_MAX_CLIMB, AM_DEFAULT);
  135. ACCESSOR_ATTRIBUTE("Agent Max Slope", GetAgentMaxSlope, SetAgentMaxSlope, float, DEFAULT_AGENT_MAX_SLOPE, AM_DEFAULT);
  136. ACCESSOR_ATTRIBUTE("Region Min Size", GetRegionMinSize, SetRegionMinSize, float, DEFAULT_REGION_MIN_SIZE, AM_DEFAULT);
  137. ACCESSOR_ATTRIBUTE("Region Merge Size", GetRegionMergeSize, SetRegionMergeSize, float, DEFAULT_REGION_MERGE_SIZE, AM_DEFAULT);
  138. ACCESSOR_ATTRIBUTE("Edge Max Length", GetEdgeMaxLength, SetEdgeMaxLength, float, DEFAULT_EDGE_MAX_LENGTH, AM_DEFAULT);
  139. ACCESSOR_ATTRIBUTE("Edge Max Error", GetEdgeMaxError, SetEdgeMaxError, float, DEFAULT_EDGE_MAX_ERROR, AM_DEFAULT);
  140. ACCESSOR_ATTRIBUTE("Detail Sample Distance", GetDetailSampleDistance, SetDetailSampleDistance, float, DEFAULT_DETAIL_SAMPLE_DISTANCE, AM_DEFAULT);
  141. ACCESSOR_ATTRIBUTE("Detail Sample Max Error", GetDetailSampleMaxError, SetDetailSampleMaxError, float, DEFAULT_DETAIL_SAMPLE_MAX_ERROR, AM_DEFAULT);
  142. ACCESSOR_ATTRIBUTE("Bounding Box Padding", GetPadding, SetPadding, Vector3, Vector3::ONE, AM_DEFAULT);
  143. MIXED_ACCESSOR_ATTRIBUTE("Navigation Data", GetNavigationDataAttr, SetNavigationDataAttr, PODVector<unsigned char>, Variant::emptyBuffer, AM_FILE | AM_NOEDIT);
  144. ENUM_ACCESSOR_ATTRIBUTE("Partition Type", GetPartitionType, SetPartitionType, NavmeshPartitionType, navmeshPartitionTypeNames, NAVMESH_PARTITION_WATERSHED, AM_DEFAULT);
  145. }
  146. void NavigationMesh::DrawDebugGeometry(DebugRenderer* debug, bool depthTest)
  147. {
  148. if (!debug || !navMesh_ || !node_)
  149. return;
  150. const Matrix3x4& worldTransform = node_->GetWorldTransform();
  151. const dtNavMesh* navMesh = navMesh_;
  152. for (int z = 0; z < numTilesZ_; ++z)
  153. {
  154. for (int x = 0; x < numTilesX_; ++x)
  155. {
  156. for (int i = 0; i < 128; ++i)
  157. {
  158. const dtMeshTile* tile = navMesh->getTileAt(x, z, i);
  159. if (!tile)
  160. continue;
  161. for (int i = 0; i < tile->header->polyCount; ++i)
  162. {
  163. dtPoly* poly = tile->polys + i;
  164. for (unsigned j = 0; j < poly->vertCount; ++j)
  165. {
  166. debug->AddLine(
  167. worldTransform * *reinterpret_cast<const Vector3*>(&tile->verts[poly->verts[j] * 3]),
  168. worldTransform * *reinterpret_cast<const Vector3*>(&tile->verts[poly->verts[(j + 1) % poly->vertCount] * 3]),
  169. Color::YELLOW,
  170. depthTest
  171. );
  172. }
  173. }
  174. }
  175. }
  176. }
  177. Scene* scene = GetScene();
  178. if (scene)
  179. {
  180. // Draw OffMeshConnection components
  181. if (drawOffMeshConnections_)
  182. {
  183. PODVector<Node*> connections;
  184. scene->GetChildrenWithComponent<OffMeshConnection>(connections, true);
  185. for (unsigned i = 0; i < connections.Size(); ++i)
  186. {
  187. OffMeshConnection* connection = connections[i]->GetComponent<OffMeshConnection>();
  188. if (connection && connection->IsEnabledEffective())
  189. connection->DrawDebugGeometry(debug, depthTest);
  190. }
  191. }
  192. // Draw NavArea components
  193. if (drawNavAreas_)
  194. {
  195. PODVector<Node*> areas;
  196. scene->GetChildrenWithComponent<NavArea>(areas, true);
  197. for (unsigned i = 0; i < areas.Size(); ++i)
  198. {
  199. NavArea* area = areas[i]->GetComponent<NavArea>();
  200. if (area && area->IsEnabledEffective())
  201. area->DrawDebugGeometry(debug, depthTest);
  202. }
  203. }
  204. }
  205. }
  206. void NavigationMesh::SetMeshName(const String& newName)
  207. {
  208. meshName_ = newName;
  209. }
  210. void NavigationMesh::SetTileSize(int size)
  211. {
  212. tileSize_ = Max(size, 16);
  213. MarkNetworkUpdate();
  214. }
  215. void NavigationMesh::SetCellSize(float size)
  216. {
  217. cellSize_ = Max(size, M_EPSILON);
  218. MarkNetworkUpdate();
  219. }
  220. void NavigationMesh::SetCellHeight(float height)
  221. {
  222. cellHeight_ = Max(height, M_EPSILON);
  223. MarkNetworkUpdate();
  224. }
  225. void NavigationMesh::SetAgentHeight(float height)
  226. {
  227. agentHeight_ = Max(height, M_EPSILON);
  228. MarkNetworkUpdate();
  229. }
  230. void NavigationMesh::SetAgentRadius(float radius)
  231. {
  232. agentRadius_ = Max(radius, M_EPSILON);
  233. MarkNetworkUpdate();
  234. }
  235. void NavigationMesh::SetAgentMaxClimb(float maxClimb)
  236. {
  237. agentMaxClimb_ = Max(maxClimb, M_EPSILON);
  238. MarkNetworkUpdate();
  239. }
  240. void NavigationMesh::SetAgentMaxSlope(float maxSlope)
  241. {
  242. agentMaxSlope_ = Max(maxSlope, 0.0f);
  243. MarkNetworkUpdate();
  244. }
  245. void NavigationMesh::SetRegionMinSize(float size)
  246. {
  247. regionMinSize_ = Max(size, M_EPSILON);
  248. MarkNetworkUpdate();
  249. }
  250. void NavigationMesh::SetRegionMergeSize(float size)
  251. {
  252. regionMergeSize_ = Max(size, M_EPSILON);
  253. MarkNetworkUpdate();
  254. }
  255. void NavigationMesh::SetEdgeMaxLength(float length)
  256. {
  257. edgeMaxLength_ = Max(length, M_EPSILON);
  258. MarkNetworkUpdate();
  259. }
  260. void NavigationMesh::SetEdgeMaxError(float error)
  261. {
  262. edgeMaxError_ = Max(error, M_EPSILON);
  263. MarkNetworkUpdate();
  264. }
  265. void NavigationMesh::SetDetailSampleDistance(float distance)
  266. {
  267. detailSampleDistance_ = Max(distance, M_EPSILON);
  268. MarkNetworkUpdate();
  269. }
  270. void NavigationMesh::SetDetailSampleMaxError(float error)
  271. {
  272. detailSampleMaxError_ = Max(error, M_EPSILON);
  273. MarkNetworkUpdate();
  274. }
  275. void NavigationMesh::SetPadding(const Vector3& padding)
  276. {
  277. padding_ = padding;
  278. MarkNetworkUpdate();
  279. }
  280. bool NavigationMesh::Build()
  281. {
  282. PROFILE(BuildNavigationMesh);
  283. // Release existing navigation data and zero the bounding box
  284. ReleaseNavigationMesh();
  285. if (!node_)
  286. return false;
  287. if (!node_->GetWorldScale().Equals(Vector3::ONE))
  288. LOGWARNING("Navigation mesh root node has scaling. Agent parameters may not work as intended");
  289. Vector<NavigationGeometryInfo> geometryList;
  290. CollectGeometries(geometryList);
  291. if (geometryList.Empty())
  292. return true; // Nothing to do
  293. // Build the combined bounding box
  294. for (unsigned i = 0; i < geometryList.Size(); ++i)
  295. boundingBox_.Merge(geometryList[i].boundingBox_);
  296. // Expand bounding box by padding
  297. boundingBox_.min_ -= padding_;
  298. boundingBox_.max_ += padding_;
  299. {
  300. PROFILE(BuildNavigationMesh);
  301. // Calculate number of tiles
  302. int gridW = 0, gridH = 0;
  303. float tileEdgeLength = (float)tileSize_ * cellSize_;
  304. rcCalcGridSize(&boundingBox_.min_.x_, &boundingBox_.max_.x_, cellSize_, &gridW, &gridH);
  305. numTilesX_ = (gridW + tileSize_ - 1) / tileSize_;
  306. numTilesZ_ = (gridH + tileSize_ - 1) / tileSize_;
  307. // Calculate max. number of tiles and polygons, 22 bits available to identify both tile & polygon within tile
  308. unsigned maxTiles = NextPowerOfTwo(numTilesX_ * numTilesZ_);
  309. unsigned tileBits = 0;
  310. unsigned temp = maxTiles;
  311. while (temp > 1)
  312. {
  313. temp >>= 1;
  314. ++tileBits;
  315. }
  316. unsigned maxPolys = 1 << (22 - tileBits);
  317. dtNavMeshParams params;
  318. rcVcopy(params.orig, &boundingBox_.min_.x_);
  319. params.tileWidth = tileEdgeLength;
  320. params.tileHeight = tileEdgeLength;
  321. params.maxTiles = maxTiles;
  322. params.maxPolys = maxPolys;
  323. navMesh_ = dtAllocNavMesh();
  324. if (!navMesh_)
  325. {
  326. LOGERROR("Could not allocate navigation mesh");
  327. return false;
  328. }
  329. if (dtStatusFailed(navMesh_->init(&params)))
  330. {
  331. LOGERROR("Could not initialize navigation mesh");
  332. ReleaseNavigationMesh();
  333. return false;
  334. }
  335. // Build each tile
  336. unsigned numTiles = 0;
  337. for (int z = 0; z < numTilesZ_; ++z)
  338. {
  339. for (int x = 0; x < numTilesX_; ++x)
  340. {
  341. if (BuildTile(geometryList, x, z))
  342. ++numTiles;
  343. }
  344. }
  345. LOGDEBUG("Built navigation mesh with " + String(numTiles) + " tiles");
  346. // Send a notification event to concerned parties that we've been fully rebuilt
  347. {
  348. using namespace NavigationMeshRebuilt;
  349. VariantMap& buildEventParams = GetContext()->GetEventDataMap();
  350. buildEventParams[P_NODE] = node_;
  351. buildEventParams[P_MESH] = this;
  352. SendEvent(E_NAVIGATION_MESH_REBUILT, buildEventParams);
  353. }
  354. return true;
  355. }
  356. }
  357. bool NavigationMesh::Build(const BoundingBox& boundingBox)
  358. {
  359. PROFILE(BuildPartialNavigationMesh);
  360. if (!node_)
  361. return false;
  362. if (!navMesh_)
  363. {
  364. LOGERROR("Navigation mesh must first be built fully before it can be partially rebuilt");
  365. return false;
  366. }
  367. if (!node_->GetWorldScale().Equals(Vector3::ONE))
  368. LOGWARNING("Navigation mesh root node has scaling. Agent parameters may not work as intended");
  369. BoundingBox localSpaceBox = boundingBox.Transformed(node_->GetWorldTransform().Inverse());
  370. float tileEdgeLength = (float)tileSize_ * cellSize_;
  371. Vector<NavigationGeometryInfo> geometryList;
  372. CollectGeometries(geometryList);
  373. int sx = Clamp((int)((localSpaceBox.min_.x_ - boundingBox_.min_.x_) / tileEdgeLength), 0, numTilesX_ - 1);
  374. int sz = Clamp((int)((localSpaceBox.min_.z_ - boundingBox_.min_.z_) / tileEdgeLength), 0, numTilesZ_ - 1);
  375. int ex = Clamp((int)((localSpaceBox.max_.x_ - boundingBox_.min_.x_) / tileEdgeLength), 0, numTilesX_ - 1);
  376. int ez = Clamp((int)((localSpaceBox.max_.z_ - boundingBox_.min_.z_) / tileEdgeLength), 0, numTilesZ_ - 1);
  377. unsigned numTiles = 0;
  378. for (int z = sz; z <= ez; ++z)
  379. {
  380. for (int x = sx; x <= ex; ++x)
  381. {
  382. if (BuildTile(geometryList, x, z))
  383. ++numTiles;
  384. }
  385. }
  386. LOGDEBUG("Rebuilt " + String(numTiles) + " tiles of the navigation mesh");
  387. return true;
  388. }
  389. Vector3 NavigationMesh::FindNearestPoint(const Vector3& point, const Vector3& extents)
  390. {
  391. if(!InitializeQuery())
  392. return point;
  393. const Matrix3x4& transform = node_->GetWorldTransform();
  394. Matrix3x4 inverse = transform.Inverse();
  395. Vector3 localPoint = inverse * point;
  396. Vector3 nearestPoint;
  397. dtPolyRef pointRef;
  398. navMeshQuery_->findNearestPoly(&localPoint.x_, &extents.x_, queryFilter_, &pointRef, &nearestPoint.x_);
  399. if (!pointRef)
  400. return point;
  401. return transform*nearestPoint;
  402. }
  403. Vector3 NavigationMesh::MoveAlongSurface(const Vector3& start, const Vector3& end, const Vector3& extents, int maxVisited)
  404. {
  405. if (!InitializeQuery())
  406. return end;
  407. const Matrix3x4& transform = node_->GetWorldTransform();
  408. Matrix3x4 inverse = transform.Inverse();
  409. Vector3 localStart = inverse * start;
  410. Vector3 localEnd = inverse * end;
  411. dtPolyRef startRef;
  412. navMeshQuery_->findNearestPoly(&localStart.x_, &extents.x_, queryFilter_, &startRef, 0);
  413. if (!startRef)
  414. return end;
  415. Vector3 resultPos;
  416. int visitedCount = 0;
  417. maxVisited = Max(maxVisited, 0);
  418. PODVector<dtPolyRef> visited(maxVisited);
  419. navMeshQuery_->moveAlongSurface(startRef, &localStart.x_, &localEnd.x_, queryFilter_, &resultPos.x_, maxVisited ?
  420. &visited[0] : (dtPolyRef*)0, &visitedCount, maxVisited);
  421. return transform * resultPos;
  422. }
  423. void NavigationMesh::FindPath(PODVector<Vector3>& dest, const Vector3& start, const Vector3& end, const Vector3& extents)
  424. {
  425. PROFILE(FindPath);
  426. dest.Clear();
  427. if (!InitializeQuery())
  428. return;
  429. // Navigation data is in local space. Transform path points from world to local
  430. const Matrix3x4& transform = node_->GetWorldTransform();
  431. Matrix3x4 inverse = transform.Inverse();
  432. Vector3 localStart = inverse * start;
  433. Vector3 localEnd = inverse * end;
  434. dtPolyRef startRef;
  435. dtPolyRef endRef;
  436. navMeshQuery_->findNearestPoly(&localStart.x_, &extents.x_, queryFilter_, &startRef, 0);
  437. navMeshQuery_->findNearestPoly(&localEnd.x_, &extents.x_, queryFilter_, &endRef, 0);
  438. if (!startRef || !endRef)
  439. return;
  440. int numPolys = 0;
  441. int numPathPoints = 0;
  442. navMeshQuery_->findPath(startRef, endRef, &localStart.x_, &localEnd.x_, queryFilter_, pathData_->polys_, &numPolys,
  443. MAX_POLYS);
  444. if (!numPolys)
  445. return;
  446. Vector3 actualLocalEnd = localEnd;
  447. // If full path was not found, clamp end point to the end polygon
  448. if (pathData_->polys_[numPolys - 1] != endRef)
  449. navMeshQuery_->closestPointOnPoly(pathData_->polys_[numPolys - 1], &localEnd.x_, &actualLocalEnd.x_, 0);
  450. navMeshQuery_->findStraightPath(&localStart.x_, &actualLocalEnd.x_, pathData_->polys_, numPolys,
  451. &pathData_->pathPoints_[0].x_, pathData_->pathFlags_, pathData_->pathPolys_, &numPathPoints, MAX_POLYS);
  452. // Transform path result back to world space
  453. for (int i = 0; i < numPathPoints; ++i)
  454. dest.Push(transform * pathData_->pathPoints_[i]);
  455. }
  456. Vector3 NavigationMesh::GetRandomPoint()
  457. {
  458. if (!InitializeQuery())
  459. return Vector3::ZERO;
  460. dtPolyRef polyRef;
  461. Vector3 point(Vector3::ZERO);
  462. navMeshQuery_->findRandomPoint(queryFilter_, Random, &polyRef, &point.x_);
  463. return node_->GetWorldTransform() * point;
  464. }
  465. Vector3 NavigationMesh::GetRandomPointInCircle(const Vector3& center, float radius, const Vector3& extents)
  466. {
  467. if (!InitializeQuery())
  468. return center;
  469. const Matrix3x4& transform = node_->GetWorldTransform();
  470. Matrix3x4 inverse = transform.Inverse();
  471. Vector3 localCenter = inverse * center;
  472. dtPolyRef startRef;
  473. navMeshQuery_->findNearestPoly(&localCenter.x_, &extents.x_, queryFilter_, &startRef, 0);
  474. if (!startRef)
  475. return center;
  476. dtPolyRef polyRef;
  477. Vector3 point(localCenter);
  478. navMeshQuery_->findRandomPointAroundCircle(startRef, &localCenter.x_, radius, queryFilter_, Random, &polyRef, &point.x_);
  479. return transform * point;
  480. }
  481. float NavigationMesh::GetDistanceToWall(const Vector3& point, float radius, const Vector3& extents)
  482. {
  483. if (!InitializeQuery())
  484. return radius;
  485. const Matrix3x4& transform = node_->GetWorldTransform();
  486. Matrix3x4 inverse = transform.Inverse();
  487. Vector3 localPoint = inverse * point;
  488. dtPolyRef startRef;
  489. navMeshQuery_->findNearestPoly(&localPoint.x_, &extents.x_, queryFilter_, &startRef, 0);
  490. if (!startRef)
  491. return radius;
  492. float hitDist = radius;
  493. Vector3 hitPos;
  494. Vector3 hitNormal;
  495. navMeshQuery_->findDistanceToWall(startRef, &localPoint.x_, radius, queryFilter_, &hitDist, &hitPos.x_, &hitNormal.x_);
  496. return hitDist;
  497. }
  498. Vector3 NavigationMesh::Raycast(const Vector3& start, const Vector3& end, const Vector3& extents)
  499. {
  500. if (!InitializeQuery())
  501. return end;
  502. const Matrix3x4& transform = node_->GetWorldTransform();
  503. Matrix3x4 inverse = transform.Inverse();
  504. Vector3 localStart = inverse * start;
  505. Vector3 localEnd = inverse * end;
  506. dtPolyRef startRef;
  507. navMeshQuery_->findNearestPoly(&localStart.x_, &extents.x_, queryFilter_, &startRef, 0);
  508. if (!startRef)
  509. return end;
  510. Vector3 localHitNormal;
  511. float t;
  512. int numPolys;
  513. navMeshQuery_->raycast(startRef, &localStart.x_, &localEnd.x_, queryFilter_, &t, &localHitNormal.x_, pathData_->polys_, &numPolys, MAX_POLYS);
  514. if (t == FLT_MAX)
  515. t = 1.0f;
  516. return start.Lerp(end, t);
  517. }
  518. void NavigationMesh::DrawDebugGeometry(bool depthTest)
  519. {
  520. Scene* scene = GetScene();
  521. if (scene)
  522. {
  523. DebugRenderer* debug = scene->GetComponent<DebugRenderer>();
  524. if (debug)
  525. DrawDebugGeometry(debug, depthTest);
  526. }
  527. }
  528. void NavigationMesh::SetAreaCost(unsigned areaID, float cost)
  529. {
  530. if (queryFilter_)
  531. queryFilter_->setAreaCost((int)areaID, cost);
  532. }
  533. BoundingBox NavigationMesh::GetWorldBoundingBox() const
  534. {
  535. return node_ ? boundingBox_.Transformed(node_->GetWorldTransform()) : boundingBox_;
  536. }
  537. float NavigationMesh::GetAreaCost(unsigned areaID) const
  538. {
  539. if (queryFilter_)
  540. return queryFilter_->getAreaCost((int)areaID);
  541. return 1.0f;
  542. }
  543. void NavigationMesh::SetNavigationDataAttr(const PODVector<unsigned char>& value)
  544. {
  545. ReleaseNavigationMesh();
  546. if (value.Empty())
  547. return;
  548. MemoryBuffer buffer(value);
  549. boundingBox_ = buffer.ReadBoundingBox();
  550. numTilesX_ = buffer.ReadInt();
  551. numTilesZ_ = buffer.ReadInt();
  552. dtNavMeshParams params;
  553. rcVcopy(params.orig, &boundingBox_.min_.x_);
  554. params.tileWidth = buffer.ReadFloat();
  555. params.tileHeight = buffer.ReadFloat();
  556. params.maxTiles = buffer.ReadInt();
  557. params.maxPolys = buffer.ReadInt();
  558. navMesh_ = dtAllocNavMesh();
  559. if (!navMesh_)
  560. {
  561. LOGERROR("Could not allocate navigation mesh");
  562. return;
  563. }
  564. if (dtStatusFailed(navMesh_->init(&params)))
  565. {
  566. LOGERROR("Could not initialize navigation mesh");
  567. ReleaseNavigationMesh();
  568. return;
  569. }
  570. unsigned numTiles = 0;
  571. while (!buffer.IsEof())
  572. {
  573. /*int x =*/ buffer.ReadInt();
  574. /*int z =*/ buffer.ReadInt();
  575. /*dtTileRef tileRef =*/ buffer.ReadUInt();
  576. unsigned navDataSize = buffer.ReadUInt();
  577. unsigned char* navData = (unsigned char*)dtAlloc(navDataSize, DT_ALLOC_PERM);
  578. if (!navData)
  579. {
  580. LOGERROR("Could not allocate data for navigation mesh tile");
  581. return;
  582. }
  583. buffer.Read(navData, navDataSize);
  584. if (dtStatusFailed(navMesh_->addTile(navData, navDataSize, DT_TILE_FREE_DATA, 0, 0)))
  585. {
  586. LOGERROR("Failed to add navigation mesh tile");
  587. dtFree(navData);
  588. return;
  589. }
  590. else
  591. ++numTiles;
  592. }
  593. LOGDEBUG("Created navigation mesh with " + String(numTiles) + " tiles from serialized data");
  594. }
  595. PODVector<unsigned char> NavigationMesh::GetNavigationDataAttr() const
  596. {
  597. VectorBuffer ret;
  598. if (navMesh_)
  599. {
  600. ret.WriteBoundingBox(boundingBox_);
  601. ret.WriteInt(numTilesX_);
  602. ret.WriteInt(numTilesZ_);
  603. const dtNavMeshParams* params = navMesh_->getParams();
  604. ret.WriteFloat(params->tileWidth);
  605. ret.WriteFloat(params->tileHeight);
  606. ret.WriteInt(params->maxTiles);
  607. ret.WriteInt(params->maxPolys);
  608. const dtNavMesh* navMesh = navMesh_;
  609. for (int z = 0; z < numTilesZ_; ++z)
  610. {
  611. for (int x = 0; x < numTilesX_; ++x)
  612. {
  613. const dtMeshTile* tile = navMesh->getTileAt(x, z, 0);
  614. if (!tile)
  615. continue;
  616. ret.WriteInt(x);
  617. ret.WriteInt(z);
  618. ret.WriteUInt(navMesh->getTileRef(tile));
  619. ret.WriteUInt(tile->dataSize);
  620. ret.Write(tile->data, tile->dataSize);
  621. }
  622. }
  623. }
  624. return ret.GetBuffer();
  625. }
  626. void NavigationMesh::CollectGeometries(Vector<NavigationGeometryInfo>& geometryList)
  627. {
  628. PROFILE(CollectNavigationGeometry);
  629. // Get Navigable components from child nodes, not from whole scene. This makes it possible to partition
  630. // the scene into several navigation meshes
  631. PODVector<Navigable*> navigables;
  632. node_->GetComponents<Navigable>(navigables, true);
  633. HashSet<Node*> processedNodes;
  634. for (unsigned i = 0; i < navigables.Size(); ++i)
  635. {
  636. if (navigables[i]->IsEnabledEffective())
  637. CollectGeometries(geometryList, navigables[i]->GetNode(), processedNodes, navigables[i]->IsRecursive());
  638. }
  639. // Get offmesh connections
  640. Matrix3x4 inverse = node_->GetWorldTransform().Inverse();
  641. PODVector<OffMeshConnection*> connections;
  642. node_->GetComponents<OffMeshConnection>(connections, true);
  643. for (unsigned i = 0; i < connections.Size(); ++i)
  644. {
  645. OffMeshConnection* connection = connections[i];
  646. if (connection->IsEnabledEffective() && connection->GetEndPoint())
  647. {
  648. const Matrix3x4& transform = connection->GetNode()->GetWorldTransform();
  649. NavigationGeometryInfo info;
  650. info.component_ = connection;
  651. info.boundingBox_ = BoundingBox(Sphere(transform.Translation(), connection->GetRadius())).Transformed(inverse);
  652. geometryList.Push(info);
  653. }
  654. }
  655. // Get nav area volumes
  656. PODVector<NavArea*> navAreas;
  657. node_->GetComponents<NavArea>(navAreas, true);
  658. for (unsigned i = 0; i < navAreas.Size(); ++i)
  659. {
  660. NavArea* area = navAreas[i];
  661. // Ignore disabled AND any areas that have no meaningful settings
  662. if (area->IsEnabledEffective() && area->GetAreaID() != 0)
  663. {
  664. NavigationGeometryInfo info;
  665. info.component_ = area;
  666. info.boundingBox_ = area->GetWorldBoundingBox();
  667. geometryList.Push(info);
  668. }
  669. }
  670. }
  671. void NavigationMesh::CollectGeometries(Vector<NavigationGeometryInfo>& geometryList, Node* node, HashSet<Node*>& processedNodes, bool recursive)
  672. {
  673. // Make sure nodes are not included twice
  674. if (processedNodes.Contains(node))
  675. return;
  676. // Exclude obstacles from consideration
  677. if (node->HasComponent<Obstacle>())
  678. return;
  679. processedNodes.Insert(node);
  680. Matrix3x4 inverse = node_->GetWorldTransform().Inverse();
  681. #ifdef URHO3D_PHYSICS
  682. // Prefer compatible physics collision shapes (triangle mesh, convex hull, box) if found.
  683. // Then fallback to visible geometry
  684. PODVector<CollisionShape*> collisionShapes;
  685. node->GetComponents<CollisionShape>(collisionShapes);
  686. bool collisionShapeFound = false;
  687. for (unsigned i = 0; i < collisionShapes.Size(); ++i)
  688. {
  689. CollisionShape* shape = collisionShapes[i];
  690. if (!shape->IsEnabledEffective())
  691. continue;
  692. ShapeType type = shape->GetShapeType();
  693. if ((type == SHAPE_BOX || type == SHAPE_TRIANGLEMESH || type == SHAPE_CONVEXHULL) && shape->GetCollisionShape())
  694. {
  695. Matrix3x4 shapeTransform(shape->GetPosition(), shape->GetRotation(), shape->GetSize());
  696. NavigationGeometryInfo info;
  697. info.component_ = shape;
  698. info.transform_ = inverse * node->GetWorldTransform() * shapeTransform;
  699. info.boundingBox_ = shape->GetWorldBoundingBox().Transformed(inverse);
  700. geometryList.Push(info);
  701. collisionShapeFound = true;
  702. }
  703. }
  704. if (!collisionShapeFound)
  705. #endif
  706. {
  707. PODVector<Drawable*> drawables;
  708. node->GetDerivedComponents<Drawable>(drawables);
  709. for (unsigned i = 0; i < drawables.Size(); ++i)
  710. {
  711. /// \todo Evaluate whether should handle other types. Now StaticModel & TerrainPatch are supported, others skipped
  712. Drawable* drawable = drawables[i];
  713. if (!drawable->IsEnabledEffective())
  714. continue;
  715. NavigationGeometryInfo info;
  716. if (drawable->GetType() == StaticModel::GetTypeStatic())
  717. info.lodLevel_ = static_cast<StaticModel*>(drawable)->GetOcclusionLodLevel();
  718. else if (drawable->GetType() == TerrainPatch::GetTypeStatic())
  719. info.lodLevel_ = 0;
  720. else
  721. continue;
  722. info.component_ = drawable;
  723. info.transform_ = inverse * node->GetWorldTransform();
  724. info.boundingBox_ = drawable->GetWorldBoundingBox().Transformed(inverse);
  725. geometryList.Push(info);
  726. }
  727. }
  728. if (recursive)
  729. {
  730. const Vector<SharedPtr<Node> >& children = node->GetChildren();
  731. for(unsigned i = 0; i < children.Size(); ++i)
  732. CollectGeometries(geometryList, children[i], processedNodes, recursive);
  733. }
  734. }
  735. void NavigationMesh::GetTileGeometry(NavBuildData* build, Vector<NavigationGeometryInfo>& geometryList, BoundingBox& box)
  736. {
  737. Matrix3x4 inverse = node_->GetWorldTransform().Inverse();
  738. for (unsigned i = 0; i < geometryList.Size(); ++i)
  739. {
  740. if (box.IsInsideFast(geometryList[i].boundingBox_) != OUTSIDE)
  741. {
  742. const Matrix3x4& transform = geometryList[i].transform_;
  743. if (geometryList[i].component_->GetType() == OffMeshConnection::GetTypeStatic())
  744. {
  745. OffMeshConnection* connection = static_cast<OffMeshConnection*>(geometryList[i].component_);
  746. Vector3 start = inverse * connection->GetNode()->GetWorldPosition();
  747. Vector3 end = inverse * connection->GetEndPoint()->GetWorldPosition();
  748. build->offMeshVertices_.Push(start);
  749. build->offMeshVertices_.Push(end);
  750. build->offMeshRadii_.Push(connection->GetRadius());
  751. build->offMeshFlags_.Push(connection->GetMask());
  752. build->offMeshAreas_.Push((unsigned char)connection->GetAreaID());
  753. build->offMeshDir_.Push(connection->IsBidirectional() ? DT_OFFMESH_CON_BIDIR : 0);
  754. continue;
  755. }
  756. else if (geometryList[i].component_->GetType() == NavArea::GetTypeStatic())
  757. {
  758. NavArea* area = static_cast<NavArea*>(geometryList[i].component_);
  759. NavAreaStub stub;
  760. stub.areaID_ = (unsigned char)area->GetAreaID();
  761. stub.bounds_ = area->GetWorldBoundingBox();
  762. build->navAreas_.Push(stub);
  763. continue;
  764. }
  765. #ifdef URHO3D_PHYSICS
  766. CollisionShape* shape = dynamic_cast<CollisionShape*>(geometryList[i].component_);
  767. if (shape)
  768. {
  769. switch (shape->GetShapeType())
  770. {
  771. case SHAPE_TRIANGLEMESH:
  772. {
  773. Model* model = shape->GetModel();
  774. if (!model)
  775. continue;
  776. unsigned lodLevel = shape->GetLodLevel();
  777. for (unsigned j = 0; j < model->GetNumGeometries(); ++j)
  778. AddTriMeshGeometry(build, model->GetGeometry(j, lodLevel), transform);
  779. }
  780. break;
  781. case SHAPE_CONVEXHULL:
  782. {
  783. ConvexData* data = static_cast<ConvexData*>(shape->GetGeometryData());
  784. if (!data)
  785. continue;
  786. unsigned numVertices = data->vertexCount_;
  787. unsigned numIndices = data->indexCount_;
  788. unsigned destVertexStart = build->vertices_.Size();
  789. for (unsigned j = 0; j < numVertices; ++j)
  790. build->vertices_.Push(transform * data->vertexData_[j]);
  791. for (unsigned j = 0; j < numIndices; ++j)
  792. build->indices_.Push(data->indexData_[j] + destVertexStart);
  793. }
  794. break;
  795. case SHAPE_BOX:
  796. {
  797. unsigned destVertexStart = build->vertices_.Size();
  798. build->vertices_.Push(transform * Vector3(-0.5f, 0.5f, -0.5f));
  799. build->vertices_.Push(transform * Vector3(0.5f, 0.5f, -0.5f));
  800. build->vertices_.Push(transform * Vector3(0.5f, -0.5f, -0.5f));
  801. build->vertices_.Push(transform * Vector3(-0.5f, -0.5f, -0.5f));
  802. build->vertices_.Push(transform * Vector3(-0.5f, 0.5f, 0.5f));
  803. build->vertices_.Push(transform * Vector3(0.5f, 0.5f, 0.5f));
  804. build->vertices_.Push(transform * Vector3(0.5f, -0.5f, 0.5f));
  805. build->vertices_.Push(transform * Vector3(-0.5f, -0.5f, 0.5f));
  806. const unsigned indices[] = {
  807. 0, 1, 2, 0, 2, 3, 1, 5, 6, 1, 6, 2, 4, 5, 1, 4, 1, 0, 5, 4, 7, 5, 7, 6,
  808. 4, 0, 3, 4, 3, 7, 1, 0, 4, 1, 4, 5
  809. };
  810. for (unsigned j = 0; j < 36; ++j)
  811. build->indices_.Push(indices[j] + destVertexStart);
  812. }
  813. break;
  814. default:
  815. break;
  816. }
  817. continue;
  818. }
  819. #endif
  820. Drawable* drawable = dynamic_cast<Drawable*>(geometryList[i].component_);
  821. if (drawable)
  822. {
  823. const Vector<SourceBatch>& batches = drawable->GetBatches();
  824. for (unsigned j = 0; j < batches.Size(); ++j)
  825. AddTriMeshGeometry(build, drawable->GetLodGeometry(j, geometryList[i].lodLevel_), transform);
  826. }
  827. }
  828. }
  829. }
  830. void NavigationMesh::AddTriMeshGeometry(NavBuildData* build, Geometry* geometry, const Matrix3x4& transform)
  831. {
  832. if (!geometry)
  833. return;
  834. const unsigned char* vertexData;
  835. const unsigned char* indexData;
  836. unsigned vertexSize;
  837. unsigned indexSize;
  838. unsigned elementMask;
  839. geometry->GetRawData(vertexData, vertexSize, indexData, indexSize, elementMask);
  840. if (!vertexData || !indexData || (elementMask & MASK_POSITION) == 0)
  841. return;
  842. unsigned srcIndexStart = geometry->GetIndexStart();
  843. unsigned srcIndexCount = geometry->GetIndexCount();
  844. unsigned srcVertexStart = geometry->GetVertexStart();
  845. unsigned srcVertexCount = geometry->GetVertexCount();
  846. if (!srcIndexCount)
  847. return;
  848. unsigned destVertexStart = build->vertices_.Size();
  849. for (unsigned k = srcVertexStart; k < srcVertexStart + srcVertexCount; ++k)
  850. {
  851. Vector3 vertex = transform * *((const Vector3*)(&vertexData[k * vertexSize]));
  852. build->vertices_.Push(vertex);
  853. }
  854. // Copy remapped indices
  855. if (indexSize == sizeof(unsigned short))
  856. {
  857. const unsigned short* indices = ((const unsigned short*)indexData) + srcIndexStart;
  858. const unsigned short* indicesEnd = indices + srcIndexCount;
  859. while (indices < indicesEnd)
  860. {
  861. build->indices_.Push(*indices - srcVertexStart + destVertexStart);
  862. ++indices;
  863. }
  864. }
  865. else
  866. {
  867. const unsigned* indices = ((const unsigned*)indexData) + srcIndexStart;
  868. const unsigned* indicesEnd = indices + srcIndexCount;
  869. while (indices < indicesEnd)
  870. {
  871. build->indices_.Push(*indices - srcVertexStart + destVertexStart);
  872. ++indices;
  873. }
  874. }
  875. }
  876. bool NavigationMesh::BuildTile(Vector<NavigationGeometryInfo>& geometryList, int x, int z)
  877. {
  878. PROFILE(BuildNavigationMeshTile);
  879. // Remove previous tile (if any)
  880. navMesh_->removeTile(navMesh_->getTileRefAt(x, z, 0), 0, 0);
  881. float tileEdgeLength = (float)tileSize_ * cellSize_;
  882. BoundingBox tileBoundingBox(Vector3(
  883. boundingBox_.min_.x_ + tileEdgeLength * (float)x,
  884. boundingBox_.min_.y_,
  885. boundingBox_.min_.z_ + tileEdgeLength * (float)z
  886. ),
  887. Vector3(
  888. boundingBox_.min_.x_ + tileEdgeLength * (float)(x + 1),
  889. boundingBox_.max_.y_,
  890. boundingBox_.min_.z_ + tileEdgeLength * (float)(z + 1)
  891. ));
  892. SimpleNavBuildData build;
  893. rcConfig cfg;
  894. memset(&cfg, 0, sizeof cfg);
  895. cfg.cs = cellSize_;
  896. cfg.ch = cellHeight_;
  897. cfg.walkableSlopeAngle = agentMaxSlope_;
  898. cfg.walkableHeight = (int)ceilf(agentHeight_ / cfg.ch);
  899. cfg.walkableClimb = (int)floorf(agentMaxClimb_ / cfg.ch);
  900. cfg.walkableRadius = (int)ceilf(agentRadius_ / cfg.cs);
  901. cfg.maxEdgeLen = (int)(edgeMaxLength_ / cellSize_);
  902. cfg.maxSimplificationError = edgeMaxError_;
  903. cfg.minRegionArea = (int)sqrtf(regionMinSize_);
  904. cfg.mergeRegionArea = (int)sqrtf(regionMergeSize_);
  905. cfg.maxVertsPerPoly = 6;
  906. cfg.tileSize = tileSize_;
  907. cfg.borderSize = cfg.walkableRadius + 3; // Add padding
  908. cfg.width = cfg.tileSize + cfg.borderSize * 2;
  909. cfg.height = cfg.tileSize + cfg.borderSize * 2;
  910. cfg.detailSampleDist = detailSampleDistance_ < 0.9f ? 0.0f : cellSize_ * detailSampleDistance_;
  911. cfg.detailSampleMaxError = cellHeight_ * detailSampleMaxError_;
  912. rcVcopy(cfg.bmin, &tileBoundingBox.min_.x_);
  913. rcVcopy(cfg.bmax, &tileBoundingBox.max_.x_);
  914. cfg.bmin[0] -= cfg.borderSize * cfg.cs;
  915. cfg.bmin[2] -= cfg.borderSize * cfg.cs;
  916. cfg.bmax[0] += cfg.borderSize * cfg.cs;
  917. cfg.bmax[2] += cfg.borderSize * cfg.cs;
  918. BoundingBox expandedBox(*reinterpret_cast<Vector3*>(cfg.bmin), *reinterpret_cast<Vector3*>(cfg.bmax));
  919. GetTileGeometry(&build, geometryList, expandedBox);
  920. if (build.vertices_.Empty() || build.indices_.Empty())
  921. return true; // Nothing to do
  922. build.heightField_ = rcAllocHeightfield();
  923. if (!build.heightField_)
  924. {
  925. LOGERROR("Could not allocate heightfield");
  926. return false;
  927. }
  928. if (!rcCreateHeightfield(build.ctx_, *build.heightField_, cfg.width, cfg.height, cfg.bmin, cfg.bmax, cfg.cs,
  929. cfg.ch))
  930. {
  931. LOGERROR("Could not create heightfield");
  932. return false;
  933. }
  934. unsigned numTriangles = build.indices_.Size() / 3;
  935. SharedArrayPtr<unsigned char> triAreas(new unsigned char[numTriangles]);
  936. memset(triAreas.Get(), 0, numTriangles);
  937. rcMarkWalkableTriangles(build.ctx_, cfg.walkableSlopeAngle, &build.vertices_[0].x_, build.vertices_.Size(),
  938. &build.indices_[0], numTriangles, triAreas.Get());
  939. rcRasterizeTriangles(build.ctx_, &build.vertices_[0].x_, build.vertices_.Size(), &build.indices_[0],
  940. triAreas.Get(), numTriangles, *build.heightField_, cfg.walkableClimb);
  941. rcFilterLowHangingWalkableObstacles(build.ctx_, cfg.walkableClimb, *build.heightField_);
  942. rcFilterWalkableLowHeightSpans(build.ctx_, cfg.walkableHeight, *build.heightField_);
  943. rcFilterLedgeSpans(build.ctx_, cfg.walkableHeight, cfg.walkableClimb, *build.heightField_);
  944. build.compactHeightField_ = rcAllocCompactHeightfield();
  945. if (!build.compactHeightField_)
  946. {
  947. LOGERROR("Could not allocate create compact heightfield");
  948. return false;
  949. }
  950. if (!rcBuildCompactHeightfield(build.ctx_, cfg.walkableHeight, cfg.walkableClimb, *build.heightField_,
  951. *build.compactHeightField_))
  952. {
  953. LOGERROR("Could not build compact heightfield");
  954. return false;
  955. }
  956. if (!rcErodeWalkableArea(build.ctx_, cfg.walkableRadius, *build.compactHeightField_))
  957. {
  958. LOGERROR("Could not erode compact heightfield");
  959. return false;
  960. }
  961. // Mark area volumes
  962. for (unsigned i = 0; i < build.navAreas_.Size(); ++i)
  963. rcMarkBoxArea(build.ctx_, &build.navAreas_[i].bounds_.min_.x_, &build.navAreas_[i].bounds_.max_.x_, build.navAreas_[i].areaID_, *build.compactHeightField_);
  964. if (this->partitionType_ == NAVMESH_PARTITION_WATERSHED)
  965. {
  966. if (!rcBuildDistanceField(build.ctx_, *build.compactHeightField_))
  967. {
  968. LOGERROR("Could not build distance field");
  969. return false;
  970. }
  971. if (!rcBuildRegions(build.ctx_, *build.compactHeightField_, cfg.borderSize, cfg.minRegionArea,
  972. cfg.mergeRegionArea))
  973. {
  974. LOGERROR("Could not build regions");
  975. return false;
  976. }
  977. }
  978. else
  979. {
  980. if (!rcBuildRegionsMonotone(build.ctx_, *build.compactHeightField_, cfg.borderSize, cfg.minRegionArea, cfg.mergeRegionArea))
  981. {
  982. LOGERROR("Could not build monotone regions");
  983. return false;
  984. }
  985. }
  986. build.contourSet_ = rcAllocContourSet();
  987. if (!build.contourSet_)
  988. {
  989. LOGERROR("Could not allocate contour set");
  990. return false;
  991. }
  992. if (!rcBuildContours(build.ctx_, *build.compactHeightField_, cfg.maxSimplificationError, cfg.maxEdgeLen,
  993. *build.contourSet_))
  994. {
  995. LOGERROR("Could not create contours");
  996. return false;
  997. }
  998. build.polyMesh_ = rcAllocPolyMesh();
  999. if (!build.polyMesh_)
  1000. {
  1001. LOGERROR("Could not allocate poly mesh");
  1002. return false;
  1003. }
  1004. if (!rcBuildPolyMesh(build.ctx_, *build.contourSet_, cfg.maxVertsPerPoly, *build.polyMesh_))
  1005. {
  1006. LOGERROR("Could not triangulate contours");
  1007. return false;
  1008. }
  1009. build.polyMeshDetail_ = rcAllocPolyMeshDetail();
  1010. if (!build.polyMeshDetail_)
  1011. {
  1012. LOGERROR("Could not allocate detail mesh");
  1013. return false;
  1014. }
  1015. if (!rcBuildPolyMeshDetail(build.ctx_, *build.polyMesh_, *build.compactHeightField_, cfg.detailSampleDist,
  1016. cfg.detailSampleMaxError, *build.polyMeshDetail_))
  1017. {
  1018. LOGERROR("Could not build detail mesh");
  1019. return false;
  1020. }
  1021. // Set polygon flags
  1022. /// \todo Assignment of flags from navigation areas?
  1023. for (int i = 0; i < build.polyMesh_->npolys; ++i)
  1024. {
  1025. if (build.polyMesh_->areas[i] != RC_NULL_AREA)
  1026. build.polyMesh_->flags[i] = 0x1;
  1027. }
  1028. unsigned char* navData = 0;
  1029. int navDataSize = 0;
  1030. dtNavMeshCreateParams params;
  1031. memset(&params, 0, sizeof params);
  1032. params.verts = build.polyMesh_->verts;
  1033. params.vertCount = build.polyMesh_->nverts;
  1034. params.polys = build.polyMesh_->polys;
  1035. params.polyAreas = build.polyMesh_->areas;
  1036. params.polyFlags = build.polyMesh_->flags;
  1037. params.polyCount = build.polyMesh_->npolys;
  1038. params.nvp = build.polyMesh_->nvp;
  1039. params.detailMeshes = build.polyMeshDetail_->meshes;
  1040. params.detailVerts = build.polyMeshDetail_->verts;
  1041. params.detailVertsCount = build.polyMeshDetail_->nverts;
  1042. params.detailTris = build.polyMeshDetail_->tris;
  1043. params.detailTriCount = build.polyMeshDetail_->ntris;
  1044. params.walkableHeight = agentHeight_;
  1045. params.walkableRadius = agentRadius_;
  1046. params.walkableClimb = agentMaxClimb_;
  1047. params.tileX = x;
  1048. params.tileY = z;
  1049. rcVcopy(params.bmin, build.polyMesh_->bmin);
  1050. rcVcopy(params.bmax, build.polyMesh_->bmax);
  1051. params.cs = cfg.cs;
  1052. params.ch = cfg.ch;
  1053. params.buildBvTree = true;
  1054. // Add off-mesh connections if have them
  1055. if (build.offMeshRadii_.Size())
  1056. {
  1057. params.offMeshConCount = build.offMeshRadii_.Size();
  1058. params.offMeshConVerts = &build.offMeshVertices_[0].x_;
  1059. params.offMeshConRad = &build.offMeshRadii_[0];
  1060. params.offMeshConFlags = &build.offMeshFlags_[0];
  1061. params.offMeshConAreas = &build.offMeshAreas_[0];
  1062. params.offMeshConDir = &build.offMeshDir_[0];
  1063. }
  1064. if (!dtCreateNavMeshData(&params, &navData, &navDataSize))
  1065. {
  1066. LOGERROR("Could not build navigation mesh tile data");
  1067. return false;
  1068. }
  1069. if (dtStatusFailed(navMesh_->addTile(navData, navDataSize, DT_TILE_FREE_DATA, 0, 0)))
  1070. {
  1071. LOGERROR("Failed to add navigation mesh tile");
  1072. dtFree(navData);
  1073. return false;
  1074. }
  1075. // Send a notification of the rebuild of this tile to anyone interested
  1076. {
  1077. using namespace NavigationAreaRebuilt;
  1078. VariantMap& eventData = GetContext()->GetEventDataMap();
  1079. eventData[P_NODE] = GetNode();
  1080. eventData[P_MESH] = this;
  1081. eventData[P_BOUNDSMIN] = Variant(tileBoundingBox.min_);
  1082. eventData[P_BOUNDSMAX] = Variant(tileBoundingBox.max_);
  1083. SendEvent(E_NAVIGATION_AREA_REBUILT, eventData);
  1084. }
  1085. return true;
  1086. }
  1087. bool NavigationMesh::InitializeQuery()
  1088. {
  1089. if (!navMesh_ || !node_)
  1090. return false;
  1091. if (navMeshQuery_)
  1092. return true;
  1093. navMeshQuery_ = dtAllocNavMeshQuery();
  1094. if (!navMeshQuery_)
  1095. {
  1096. LOGERROR("Could not create navigation mesh query");
  1097. return false;
  1098. }
  1099. if (dtStatusFailed(navMeshQuery_->init(navMesh_, MAX_POLYS)))
  1100. {
  1101. LOGERROR("Could not init navigation mesh query");
  1102. return false;
  1103. }
  1104. return true;
  1105. }
  1106. void NavigationMesh::ReleaseNavigationMesh()
  1107. {
  1108. dtFreeNavMesh(navMesh_);
  1109. navMesh_ = 0;
  1110. dtFreeNavMeshQuery(navMeshQuery_);
  1111. navMeshQuery_ = 0;
  1112. numTilesX_ = 0;
  1113. numTilesZ_ = 0;
  1114. boundingBox_.min_ = boundingBox_.max_ = Vector3::ZERO;
  1115. boundingBox_.defined_ = false;
  1116. }
  1117. void NavigationMesh::SetPartitionType(NavmeshPartitionType ptype)
  1118. {
  1119. partitionType_ = ptype;
  1120. MarkNetworkUpdate();
  1121. }
  1122. void RegisterNavigationLibrary(Context* context)
  1123. {
  1124. Navigable::RegisterObject(context);
  1125. NavigationMesh::RegisterObject(context);
  1126. OffMeshConnection::RegisterObject(context);
  1127. CrowdAgent::RegisterObject(context);
  1128. DetourCrowdManager::RegisterObject(context);
  1129. DynamicNavigationMesh::RegisterObject(context);
  1130. Obstacle::RegisterObject(context);
  1131. NavArea::RegisterObject(context);
  1132. }
  1133. }