recast.adoc 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. = Recast Navigation for JME
  2. :author:
  3. :revnumber:
  4. :revdate: 2016/03/17 20:48
  5. :relfileprefix: ../../
  6. :imagesdir: ../..
  7. ifdef::env-github,env-browser[:outfilesuffix: .adoc]
  8. == What is Recast Navigation
  9. Recast Navigation is C++ library for path-finding in 3D, continuous space. Recast has two big modules:
  10. . Recast
  11. . Detour
  12. === Recast
  13. Recast is state of the art navigation mesh construction tool set for games.
  14. * It is automatic, which means that you can throw any level geometry at it and you will get robust mesh out
  15. * It is fast which means swift turnaround times for level designers
  16. * It is open source so it comes with full source and you can customize it to your heart's content.
  17. === Detour
  18. Recast is accompanied with Detour, path-finding and spatial reasoning toolkit. You can use any navigation mesh with Detour, but of course the data generated with Recast fits perfectly.
  19. Detour offers simple static navigation mesh which is suitable for many simple cases, as well as tiled navigation mesh which allows you to plug in and out pieces of the mesh. The tiled mesh allows you to create systems where you stream new navigation data in and out as the player progresses the level, or you may regenerate tiles as the world changes.
  20. == jNavigation
  21. jNavigation is port Java library for link:https://github.com/memononen/recastnavigation[Recast navigation]. jNavigation is the project in progress, and currently it enables building link:http://en.wikipedia.org/wiki/Navigation_mesh[Navigation meshes] and path-finding for one agent (bot).
  22. == Example
  23. In next code is described how the user should build navigation mesh, and query for it.
  24. [source,java]
  25. ----
  26. // Step 1. Initialize build config.
  27. Config config = new Config();
  28. Mesh mesh = ((Geometry) scene.getChild("terrain")).getMesh();
  29. Vector3f minBounds = RecastBuilder.calculateMinBounds(mesh);
  30. Vector3f maxBounds = RecastBuilder.calculateMaxBounds(mesh);
  31. config.setMaxBounds(maxBounds);
  32. config.setMinBounds(minBounds);
  33. config.setCellSize(0.3f);
  34. config.setCellHeight(0.2f);
  35. config.setWalkableSlopeAngle(45);
  36. config.setWalkableClimb(1);
  37. config.setWalkableHeight(2);
  38. config.setWalkableRadius(2);
  39. config.setMinRegionArea(8);
  40. config.setMergeRegionArea(20);
  41. config.setBorderSize(20);
  42. config.setMaxEdgeLength(12);
  43. config.setMaxVerticesPerPoly(6);
  44. config.setDetailSampleMaxError(1f);
  45. config.setDetailSampleDistance(6);
  46. RecastBuilder.calculateGridWidth(config);
  47. RecastBuilder.calculatesGridHeight(config);
  48. // Step 2. Rasterize input polygon soup.
  49. //context is needed for logging that is not yet fully supported in native library.
  50. //It must NOT be null.
  51. Context context = new Context();
  52. // Allocate voxel heightfield where we rasterize our input data to.
  53. Heightfield heightfield = new Heightfield();
  54. if (!RecastBuilder.createHeightfield(context, heightfield, config)) {
  55. System.out.println("Could not create solid heightfield");
  56. return;
  57. }
  58. // Allocate array that can hold triangle area types.
  59. // In Recast terminology, triangles are what indices in jME is. I left this,
  60. // Find triangles which are walkable based on their slope and rasterize them.
  61. char[] areas = RecastBuilder.markWalkableTriangles(context, config.getWalkableSlopeAngle(), mesh);
  62. RecastBuilder.rasterizeTriangles(context, mesh, areas, heightfield, 20);
  63. // Step 3. Filter walkables surfaces.
  64. // Once all geometry is rasterized, we do initial pass of filtering to
  65. // remove unwanted overhangs caused by the conservative rasterization
  66. // as well as filter spans where the character cannot possibly stand.
  67. RecastBuilder.filterLowHangingWalkableObstacles(context, config.getWalkableClimb(), heightfield);
  68. RecastBuilder.filterLedgeSpans(context, config, heightfield);
  69. RecastBuilder.filterWalkableLowHeightSpans(context, config.getWalkableHeight(), heightfield);
  70. // Step 4. Partition walkable surface to simple regions.
  71. // Compact the heightfield so that it is faster to handle from now on.
  72. // This will result more cache coherent data as well as the neighbours
  73. // between walkable cells will be calculated.
  74. CompactHeightfield compactHeightfield = new CompactHeightfield();
  75. if (!RecastBuilder.buildCompactHeightfield(context, config, heightfield, compactHeightfield)) {
  76. System.out.println("Could not build compact data");
  77. return;
  78. }
  79. if (!RecastBuilder.erodeWalkableArea(context, config.getWalkableRadius(), compactHeightfield)) {
  80. System.out.println("Could not erode");
  81. return;
  82. }
  83. // Partition the heightfield so that we can use simple algorithm later to triangulate the walkable areas.
  84. // There are 3 martitioning methods, each with some pros and cons:
  85. // 1) Watershed partitioning
  86. // - the classic Recast partitioning
  87. // - creates the nicest tessellation
  88. // - usually slowest
  89. // - partitions the heightfield into nice regions without holes or overlaps
  90. // - the are some corner cases where this method creates produces holes and overlaps
  91. // - holes may appear when a small obstacles is close to large open area (triangulation can handle this)
  92. // - overlaps may occur if you have narrow spiral corridors (i.e stairs), this make triangulation to fail
  93. // * generally the best choice if you precompute the nacmesh, use this if you have large open areas
  94. // 2) Monotone partioning
  95. // - fastest
  96. // - partitions the heightfield into regions without holes and overlaps (guaranteed)
  97. // - creates long thin polygons, which sometimes causes paths with detours
  98. // * use this if you want fast navmesh generation
  99. String partitionType = "Sample partition watershed";
  100. if (partitionType.equals("Sample partition watershed")) {
  101. if (!RecastBuilder.buildDistanceField(context, compactHeightfield)) {
  102. System.out.println("Could not build distance field");
  103. return;
  104. }
  105. if (!RecastBuilder.buildRegions(context, compactHeightfield, config)) {
  106. System.out.println("Could not build watershed regions");
  107. return;
  108. }
  109. }
  110. if (partitionType.equals("Sample partition monotone")) {
  111. if (!RecastBuilder.buildRegionsMonotone(context, compactHeightfield, config)) {
  112. System.out.println("Could not build monotone regions");
  113. return;
  114. }
  115. }
  116. // Step 5. Trace and simplify region contours.
  117. // Create contours.
  118. ContourSet contourSet = new ContourSet();
  119. if (!RecastBuilder.buildContours(context, compactHeightfield, 2f, config.getMaxEdgeLength(), contourSet)) {
  120. System.out.println("Could not create contours");
  121. return;
  122. }
  123. // Step 6. Build polygons mesh from contours.
  124. // Build polygon navmesh from the contours.
  125. PolyMesh polyMesh = new PolyMesh();
  126. if (!RecastBuilder.buildPolyMesh(context, contourSet, config.getMaxVertsPerPoly(), polyMesh)) {
  127. System.out.println("Could not triangulate contours");
  128. return;
  129. }
  130. // Step 7. Create detail mesh which allows to access approximate height on each polygon.
  131. PolyMeshDetail polyMeshDetail = new PolyMeshDetail();
  132. if (!RecastBuilder.buildPolyMeshDetail(context, polyMesh, compactHeightfield, config, polyMeshDetail)) {
  133. System.out.println("Could not build detail mesh.");
  134. return;
  135. }
  136. // (Optional) Step 8. Create Detour data from Recast poly mesh.
  137. // The GUI may allow more max points per polygon than Detour can handle.
  138. // Only build the detour navmesh if we do not exceed the limit.
  139. if (config.getMaxVertsPerPoly() > DetourBuilder.VERTS_PER_POLYGON()) {
  140. return;
  141. }
  142. NavMeshCreateParams createParams = new NavMeshCreateParams();
  143. createParams.getData(polyMesh);
  144. createParams.getData(polyMeshDetail);
  145. //setting optional off-mesh connections (in my example there are none)
  146. createParams.getData(config);
  147. createParams.setBuildBvTree(true);
  148. char[] navData = DetourBuilder.createNavMeshData(createParams);
  149. if (navData == null) {
  150. System.out.println("Could not build Detour navmesh.");
  151. return;
  152. }
  153. NavMesh navMesh = new NavMesh();
  154. if (!navMesh.isAllocationSuccessful()) {
  155. System.out.println("Could not create Detour navmesh");
  156. return;
  157. }
  158. Status status;
  159. status = navMesh.init(navData, TileFlags.DT_TILE_FREE_DATA.value());
  160. if (status.isFailed()) {
  161. System.out.println("Could not init Detour navmesh");
  162. return;
  163. }
  164. NavMeshQuery query = new NavMeshQuery();
  165. status = query.init(navMesh, 2048);
  166. if (status.isFailed()) {
  167. System.out.println("Could not init Detour navmesh query");
  168. return;
  169. }
  170. ----
  171. After this (if everything is successful) you can use methods in `query` that was created for path-finding purposes.
  172. == How to get jNavigation
  173. There is 2 ways to get jNavigation:
  174. * as plugin form
  175. * as developmental project
  176. === Plugin
  177. You can download “stable version from link:https://github.com/QuietOne/jNavigationPlugin/tree/master[repository]
  178. === Developmental project
  179. Instructions for downloading and setting it up:
  180. * Download C++ wrapper from link:https://github.com/QuietOne/jNavigation-native[jNavigationNative repository]
  181. * Build downloaded project with C++ compiler
  182. * Download java library from link:https://github.com/QuietOne/jNavigation[jNavigation repository]
  183. * In Java project in class `com.jme3.ai.navigation.utils.RecastJNI.java` change +++<abbr title="Uniform Resource Locator">URL</abbr>+++ to where your build of C++ project is.
  184. [source,java]
  185. ----
  186. static {
  187. // the URL that needs to be changed
  188. System.load(".../jNavigationNative.dll");
  189. }
  190. ----
  191. If there is problem with building C++ project see <<jme3/advanced/building_recast#,link>>.
  192. === Questions & Suggestions
  193. * For question on Recast (C++ library) ask on link:https://groups.google.com/forum/#!forum/recastnavigation[Google groups]
  194. === Source
  195. * link:https://github.com/QuietOne/jNavigationPlugin/tree/master[jNavigation plugin repository]
  196. * link:https://github.com/QuietOne/jNavigation[Developmental jNavigation repository]
  197. * link:https://github.com/QuietOne/jNavigation-native[Developmental jNavigationNative repository]
  198. ==== Useful links
  199. * <<jme3/advanced/building_recast#,How to build the native recast bindings>>
  200. * link:http://www.critterai.org/projects/nmgen_study/[Study: Navigation Mesh Generation]
  201. * link:http://www.stevefsp.org/projects/rcndoc/prod/index.html[Documentation of C++ Recast library] It can be useful for tracing bugs.