Recast: add option for collapsing linked polygon groups

This is necessary for navmeshes with more than UINT16_MAX polygon islands. Building navmeshes for mp_rr_desertlands_64k_x_64k will hit this limit.
This commit is contained in:
Kawe Mazidjatari 2024-10-13 14:36:09 +02:00
parent dedcf4f94f
commit 248a652a15
4 changed files with 48 additions and 25 deletions

View File

@ -131,6 +131,7 @@ Editor::Editor() :
m_filterLedgeSpans(true),
m_filterWalkableLowHeightSpans(true),
m_traverseRayDynamicOffset(true),
m_collapseLinkedPolyGroups(true),
m_buildBvTree(true),
m_selectedNavMeshType(NAVMESH_SMALL),
m_loadedNavMeshType(NAVMESH_SMALL),
@ -420,6 +421,8 @@ void Editor::handleCommonSettings()
if (ImGui::CollapsingHeader("Traverse Table Fine Tuner"))
renderTraverseTableFineTuners();
ImGui::Checkbox("Collapse Linked Poly Groups", &m_collapseLinkedPolyGroups);
if (ImGui::Checkbox("Dynamic Traverse Ray Offset", &m_traverseRayDynamicOffset))
m_traverseLinkDrawParams.dynamicOffset = m_traverseRayDynamicOffset;
@ -827,6 +830,7 @@ void Editor::createTraverseTableParams(dtTraverseTableCreateParams* params)
params->tableCount = NavMesh_GetTraverseTableCountForNavMeshType(m_selectedNavMeshType);
params->navMeshType = m_selectedNavMeshType;
params->canTraverse = animTypeSupportsTraverseLink;
params->collapseGroups = m_collapseLinkedPolyGroups;
}
void Editor::buildStaticPathingData()

View File

@ -239,6 +239,7 @@ protected:
bool m_filterLedgeSpans;
bool m_filterWalkableLowHeightSpans;
bool m_traverseRayDynamicOffset;
bool m_collapseLinkedPolyGroups;
bool m_buildBvTree;
int m_minTileBits;

View File

@ -207,6 +207,10 @@ struct dtTraverseTableCreateParams
///< The user installed callback which is used to determine if an animType
/// can use this traverse link.
bool (*canTraverse)(const dtTraverseTableCreateParams* params, const dtLink* link, const int tableIndex);
///< Collapses all unique linked poly groups into #DT_FIRST_USABLE_POLY_GROUP.
/// Must be set if there are more than UINT16_MAX polygon islands.
bool collapseGroups;
};
/// Builds navigation mesh disjoint poly groups from the provided parameters.

View File

@ -298,6 +298,14 @@ bool dtCreateDisjointPolyGroups(const dtTraverseTableCreateParams* params)
dtPoly& poly = tile->polys[j];
unsigned int plink = poly.firstLink;
if (params->collapseGroups)
{
if (plink != DT_NULL_LINK)
poly.groupId = DT_FIRST_USABLE_POLY_GROUP;
continue;
}
// Off-mesh connections need their own ID's, skip the assignment
// here since else we will be marking 2 (or more) poly islands
// under the same group id.
@ -359,7 +367,10 @@ bool dtCreateDisjointPolyGroups(const dtTraverseTableCreateParams* params)
dtPoly& poly = tile->polys[j];
if (poly.groupId != DT_UNLINKED_POLY_GROUP)
{
const int id = set.find(poly.groupId);
const int id = params->collapseGroups
? DT_FIRST_USABLE_POLY_GROUP
: set.find(poly.groupId);
poly.groupId = (unsigned short)id;
}
}
@ -437,35 +448,38 @@ bool dtUpdateDisjointPolyGroups(const dtTraverseTableCreateParams* params)
tile->header->userId = 0;
}
// Gather all unique polygroups and map them to a contiguous range.
std::map<unsigned short, unsigned short> groupMap;
set.init(DT_FIRST_USABLE_POLY_GROUP);
for (int i = 0; i < nav->getMaxTiles(); ++i)
if (!params->collapseGroups)
{
dtMeshTile* tile = nav->getTile(i);
if (!tile || !tile->header || !tile->dataSize) continue;
const int pcount = tile->header->polyCount;
for (int j = 0; j < pcount; j++)
// Gather all unique polygroups and map them to a contiguous range.
std::map<unsigned short, unsigned short> groupMap;
set.init(DT_FIRST_USABLE_POLY_GROUP);
for (int i = 0; i < nav->getMaxTiles(); ++i)
{
dtPoly& poly = tile->polys[j];
unsigned short oldId = poly.groupId;
if (oldId != DT_UNLINKED_POLY_GROUP && groupMap.find(oldId) == groupMap.end())
groupMap[oldId] = (unsigned short)set.insertNew();
dtMeshTile* tile = nav->getTile(i);
if (!tile || !tile->header || !tile->dataSize) continue;
const int pcount = tile->header->polyCount;
for (int j = 0; j < pcount; j++)
{
dtPoly& poly = tile->polys[j];
unsigned short oldId = poly.groupId;
if (oldId != DT_UNLINKED_POLY_GROUP && groupMap.find(oldId) == groupMap.end())
groupMap[oldId] = (unsigned short)set.insertNew();
}
}
}
// Fourth pass to apply the new mapping to all polys.
for (int i = 0; i < nav->getMaxTiles(); ++i)
{
dtMeshTile* tile = nav->getTile(i);
if (!tile || !tile->header || !tile->dataSize) continue;
const int pcount = tile->header->polyCount;
for (int j = 0; j < pcount; j++)
// Fourth pass to apply the new mapping to all polys.
for (int i = 0; i < nav->getMaxTiles(); ++i)
{
dtPoly& poly = tile->polys[j];
if (poly.groupId != DT_UNLINKED_POLY_GROUP)
poly.groupId = groupMap[poly.groupId];
dtMeshTile* tile = nav->getTile(i);
if (!tile || !tile->header || !tile->dataSize) continue;
const int pcount = tile->header->polyCount;
for (int j = 0; j < pcount; j++)
{
dtPoly& poly = tile->polys[j];
if (poly.groupId != DT_UNLINKED_POLY_GROUP)
poly.groupId = groupMap[poly.groupId];
}
}
}