Type 1 can cause the AI to become stuck when a link is established within a hole that is too short. Testing revealed that any link beyond this length, wether its on a hole or gap, does not cause the AI to become stuck. Updated default.
The mesh data from the game's BVH4 tree does not appear to have a fixed triangle winding order, making it nearly impossible to generate correct navmeshes while using the decoded BVH4 data. Fixing the sign enables us to generate the navmesh over the game's collision data properly rather than using the render mesh. This change does not appear to have a negative effect on the generated NavMesh.
These changes seem to yield better results for the larger maps. The improvements are minimal however. This change is probably more noticable on tile cache.
In recastnavigation/recastnavigation@15ebb8bd25 the change was made to use detail polygons, but it appears that after this change, the bounding volume gets build under the polygons, especially if the polygons's Z are equal on all vertices. Flooring the mins and ceiling the maxs appears to yield correct behavior in all scenarios by making sure the bounding volume always encases its respective polygon.
Reverse engineered the last types that were mostly unused and unneeded by the navmesh. But to properly implement the destructor it had to go in. Cells and hints now get freed as well and we can now rely on our own destructor for the navmesh data allocated by the game.
This was required as a cell height of 2.0 is too low for the map "mp_rr_canyonlands_64k_x_64k". This particular level is very large, and has another level far underneath; its the old firing range. In order to ensure full coverage on Z, the cell height must be increased. After the change in commit b3946e924aeea05f65f9fcba5e9043771d14af23, the new cell height actually produces more accurate and consistent results accross all levels.
If an off-mesh connection has a base link, but no land link, there will be an invalid link as we never process there. These links must be removed. Due to this change, the link flagging had to be moved to a separate loop as we would otherwise store the dead link in the file (it won't cause a crash as it has been unlinked, but there is no reason it should be stored). Also improved the detection of external off-mesh connections landing on our current tile, instead of doing a position lookup just decode the polyref and check if the index equals our current tile.
The Hull_s::height field is actually Hull_s::stepHeight. This results in much better navigation and prevents entities "popping" into air as they shouldn't be able to walk over some obstacles.
After the implementation of brush intersection detection in commit 6fa5080fe51e2ea118f2cf4f922bcb6e815b3a9f, we return out as soon as we have a hit, even when tmin is provided. But if tmin is provided, the caller is interested in finding the closest intersection so we must go over the input mesh as well. This fixes a bug of raycasts going through geometry when there's a brush behind it.
External references were never updated. Especially when the tile we process doesn't own an off-mesh connection, but does have one landing on it. After this patch, the navmesh passes all tests in game and all polygons appear to be remapped correctly when using all features of the Detour NavMesh (single step verification). Also no issues reported from address sanitizer after several tests on extremely large and complicated navmeshes.
- Off-mesh connections should always be linked to target poly's first. Also set the linked flag on titanfall navmeshes as this is necessary during the pruning stage.
- When connecting off-mesh links, we need to iterate over tiles using m_maxTiles, not m_tileCount as m_tileCount counts the number of added tiles, while m_maxTiles contains the maximum tiles in the lookup array, there can be empties in between.
- Radians to degrees and visa versa has been moved to a simple inline function, but during this, a regression was made where it was accidentally inverted in dtCalcOffMeshRefYaw and dtCalcOffMeshRefPos.
- rdCalcSubEdgeArea2D could return false when tmin > tmax, which prevents the link from being established, but tmin can be larger than tmax when the detail edge equals the main edge. The issue we wanted to prevent where the triangle had an inverted winding order has been fixed in commit 1e48d8abd9e604a384e65cf633b62f4e11737d35.
- In dtNavMesh::connectTraverseLinks, the extraneous dot product check has been removed; this is now handled by the user installed dtTraverseLinkConnectParams::getTraverseType and dtTraverseLinkConnectParams::getTraverseType.
- In dtNavMesh::connectTraverseLinks, when we ran out of links in the land tile, we would still continue the traversal of all its detail edges and polygons. We now break out of all loops to move on to the next tile as we can not establish any traverse link when there are no free ones available.
In commit a2d5d52dc4e571388b9b86f21e40a5110a69665e, the logic has been adjusted to build the polygon in the right order in the algorithm itself, but some indices are incorrect causing bad tesselation. The issue is somewhere in RecastMesh.cpp, writing polygon indices in the incorrect order '0, 3, 2, 1' instead of '3, 2, 1, 0'. Reverted to using "REVERSE_DIRECTION 0" for RecastMesh.cpp.
Additional notes, tesselation appears correct when building the mesh with the layered partitioner, monotone and watershed causes bad tesselation. The vertex order is however still incorrect.
Flood-fill assign instead to make sure all polygon islands are mapped to a contiguous range of group id's on the first pass. This is required as we will otherwise reach the DT_MAX_POLY_GROUP_COUNT limit on complex and large geometry before the prune pass while we don't have DT_MAX_POLY_GROUP_COUNT polygon islands inside the navmesh. Also implemented poly group overflow protection and simplified the API.
Defaults have been fine tuned and now generated much better results, especially in narrow area's such as small buildings and corridors. Previously, there usually were gaps in between door frames and tunnels.
Polyrefs may become invalid as we remove dead polygons and reindex the remainders. If the polyref is invalid, skip the link as it will be thrown out anyways. Issue was found using address sanitizer on level mp_rr_desertlands_64k_x_64k.
The algorithm goes over each polygon in the tile and only keeps polygons and associated data if they don't originate from an unlinked polygon island (DT_UNLINKED_POLY_GROUP). The algorithm also drops all data associated to the polygons such as the detail meshes, cells, links, verts and detail (if not used by other polygons), off-mesh links that are dead (not having the DT_POLYFLAGS_JUMP_LINKED flag), and rebuilds the BVTree.
This algorithm reduced the file size of a navmesh generated for the map mp_rr_desertlands_64k_x_64k by over 50% (209mb to 97mb) while keeping it functionally identical.
Some additional updates that were required to make this work:
* dtCalcTraverseTableSize now return NULL if there are 2 or less polygroups.
* unionTraverseLinkedPolyGroups will not run if parameters instruct it to collapse groups, it will also not run if the disjoint set doesn't contain any poly groups.
* dtCreateTraverseTableData will not allocate traverse tables if there are 2 or less polygroups, as dtCalcTraverseTableSize will now always return 0 in this case. This is an enforcement of an optimization from the engine itself as there is no point in allocating and doing lookups on a table with only 2 groups (unlinked and linked), and linked will always be reachable and unlinked can't be reached in the first place.
The reason why the BVTree's appeared under the polygon was because we were rendering and calculating them incorrectly. After fixing this, they now appeared above the polygons. This offset is not necessary as it causes BVTree's to build incorrectly.
Larger levels require watershed as some complex geometry (buildings with multiple floors) will exceed the maximum number of allowed sweep scans when building regions.
dtNavMesh::getTileCount returns the total number of added tiles, the issue with this is that if the navmesh gets pruned, that means disabling unlinked polygons and removing dead tiles, then some tile instances in the m_tiles array may become empty. Less tiles will be installed and since there are null tiles in between, we won't be traversing each tile.