Split makeNavMeshTileData

pull/1633/head
elsid 6 years ago
parent fb655cb04f
commit 0f6a64ad54
No known key found for this signature in database
GPG Key ID: B845CB9FEE18AB40

@ -0,0 +1,20 @@
#ifndef OPENMW_COMPONENTS_DETOURNAVIGATOR_BOUNDS_H
#define OPENMW_COMPONENTS_DETOURNAVIGATOR_BOUNDS_H
#include <osg/Vec3f>
namespace DetourNavigator
{
struct Bounds
{
osg::Vec3f mMin;
osg::Vec3f mMax;
};
inline bool isEmpty(const Bounds& value)
{
return value.mMin == value.mMax;
}
}
#endif

@ -102,82 +102,9 @@ namespace
return result;
}
void createHeightfield(rcContext& context, rcHeightfield& solid, int width, int height, const float* bmin,
const float* bmax, const float cs, const float ch)
{
const auto result = rcCreateHeightfield(&context, solid, width, height, bmin, bmax, cs, ch);
if (!result)
throw NavigatorException("Failed to create heightfield for navmesh");
}
void buildCompactHeightfield(rcContext& context, const int walkableHeight, const int walkableClimb,
rcHeightfield& solid, rcCompactHeightfield& compact)
{
const auto result = rcBuildCompactHeightfield(&context, walkableHeight,
walkableClimb, solid, compact);
if (!result)
throw NavigatorException("Failed to build compact heightfield for navmesh");
}
void erodeWalkableArea(rcContext& context, int walkableRadius, rcCompactHeightfield& compact)
{
const auto result = rcErodeWalkableArea(&context, walkableRadius, compact);
if (!result)
throw NavigatorException("Failed to erode walkable area for navmesh");
}
void buildDistanceField(rcContext& context, rcCompactHeightfield& compact)
{
const auto result = rcBuildDistanceField(&context, compact);
if (!result)
throw NavigatorException("Failed to build distance field for navmesh");
}
void buildRegions(rcContext& context, rcCompactHeightfield& compact, const int borderSize,
const int minRegionArea, const int mergeRegionArea)
{
const auto result = rcBuildRegions(&context, compact, borderSize, minRegionArea, mergeRegionArea);
if (!result)
throw NavigatorException("Failed to build distance field for navmesh");
}
void buildContours(rcContext& context, rcCompactHeightfield& compact, const float maxError, const int maxEdgeLen,
rcContourSet& contourSet, const int buildFlags = RC_CONTOUR_TESS_WALL_EDGES)
{
const auto result = rcBuildContours(&context, compact, maxError, maxEdgeLen, contourSet, buildFlags);
if (!result)
throw NavigatorException("Failed to build contours for navmesh");
}
void buildPolyMesh(rcContext& context, rcContourSet& contourSet, const int maxVertsPerPoly, rcPolyMesh& polyMesh)
{
const auto result = rcBuildPolyMesh(&context, contourSet, maxVertsPerPoly, polyMesh);
if (!result)
throw NavigatorException("Failed to build poly mesh for navmesh");
}
void buildPolyMeshDetail(rcContext& context, const rcPolyMesh& polyMesh, const rcCompactHeightfield& compact,
const float sampleDist, const float sampleMaxError, rcPolyMeshDetail& polyMeshDetail)
rcConfig makeConfig(const osg::Vec3f& agentHalfExtents, const osg::Vec3f& boundsMin, const osg::Vec3f& boundsMax,
const Settings& settings)
{
const auto result = rcBuildPolyMeshDetail(&context, polyMesh, compact, sampleDist, sampleMaxError,
polyMeshDetail);
if (!result)
throw NavigatorException("Failed to build detail poly mesh for navmesh");
}
NavMeshData makeNavMeshTileData(const osg::Vec3f& agentHalfExtents, const RecastMesh& recastMesh,
const std::vector<OffMeshConnection>& offMeshConnections, const int tileX, const int tileY,
const osg::Vec3f& boundsMin, const osg::Vec3f& boundsMax, const Settings& settings)
{
rcContext context;
rcConfig config;
config.cs = settings.mCellSize;
@ -203,9 +130,20 @@ namespace
config.bmax[0] += getBorderSize(settings);
config.bmax[2] += getBorderSize(settings);
rcHeightfield solid;
createHeightfield(context, solid, config.width, config.height, config.bmin, config.bmax, config.cs, config.ch);
return config;
}
void createHeightfield(rcContext& context, rcHeightfield& solid, int width, int height, const float* bmin,
const float* bmax, const float cs, const float ch)
{
const auto result = rcCreateHeightfield(&context, solid, width, height, bmin, bmax, cs, ch);
if (!result)
throw NavigatorException("Failed to create heightfield for navmesh");
}
bool rasterizeSolidObjectsTriangles(rcContext& context, const RecastMesh& recastMesh, const rcConfig& config,
rcHeightfield& solid)
{
const auto& chunkyMesh = recastMesh.getChunkyTriMesh();
std::vector<unsigned char> areas(chunkyMesh.getMaxTrisPerChunk(), AreaType_null);
@ -215,7 +153,7 @@ namespace
chunkyMesh.getChunksOverlappingRect(Rect {tileBoundsMin, tileBoundsMax}, std::back_inserter(cids));
if (cids.empty())
return NavMeshData();
return false;
for (const auto cid : cids)
{
@ -265,8 +203,12 @@ namespace
if (!trianglesRasterized)
throw NavigatorException("Failed to create rasterize triangles from recast mesh for navmesh");
}
return true;
}
void rasterizeWaterTriangles(rcContext& context, const osg::Vec3f& agentHalfExtents, const RecastMesh& recastMesh,
const Settings& settings, const rcConfig& config, rcHeightfield& solid)
{
const std::array<unsigned char, 2> areas {{AreaType_water, AreaType_water}};
@ -320,14 +262,92 @@ namespace
}
}
rcFilterLowHangingWalkableObstacles(&context, config.walkableClimb, solid);
rcFilterLedgeSpans(&context, config.walkableHeight, config.walkableClimb, solid);
rcFilterWalkableLowHeightSpans(&context, config.walkableHeight, solid);
bool rasterizeTriangles(rcContext& context, const osg::Vec3f& agentHalfExtents, const RecastMesh& recastMesh,
const rcConfig& config, const Settings& settings, rcHeightfield& solid)
{
if (!rasterizeSolidObjectsTriangles(context, recastMesh, config, solid))
return false;
rcPolyMesh polyMesh;
rcPolyMeshDetail polyMeshDetail;
initPolyMeshDetail(polyMeshDetail);
const PolyMeshDetailStackPtr polyMeshDetailPtr(&polyMeshDetail);
rasterizeWaterTriangles(context, agentHalfExtents, recastMesh, settings, config, solid);
return true;
}
void buildCompactHeightfield(rcContext& context, const int walkableHeight, const int walkableClimb,
rcHeightfield& solid, rcCompactHeightfield& compact)
{
const auto result = rcBuildCompactHeightfield(&context, walkableHeight,
walkableClimb, solid, compact);
if (!result)
throw NavigatorException("Failed to build compact heightfield for navmesh");
}
void erodeWalkableArea(rcContext& context, int walkableRadius, rcCompactHeightfield& compact)
{
const auto result = rcErodeWalkableArea(&context, walkableRadius, compact);
if (!result)
throw NavigatorException("Failed to erode walkable area for navmesh");
}
void buildDistanceField(rcContext& context, rcCompactHeightfield& compact)
{
const auto result = rcBuildDistanceField(&context, compact);
if (!result)
throw NavigatorException("Failed to build distance field for navmesh");
}
void buildRegions(rcContext& context, rcCompactHeightfield& compact, const int borderSize,
const int minRegionArea, const int mergeRegionArea)
{
const auto result = rcBuildRegions(&context, compact, borderSize, minRegionArea, mergeRegionArea);
if (!result)
throw NavigatorException("Failed to build distance field for navmesh");
}
void buildContours(rcContext& context, rcCompactHeightfield& compact, const float maxError, const int maxEdgeLen,
rcContourSet& contourSet, const int buildFlags = RC_CONTOUR_TESS_WALL_EDGES)
{
const auto result = rcBuildContours(&context, compact, maxError, maxEdgeLen, contourSet, buildFlags);
if (!result)
throw NavigatorException("Failed to build contours for navmesh");
}
void buildPolyMesh(rcContext& context, rcContourSet& contourSet, const int maxVertsPerPoly, rcPolyMesh& polyMesh)
{
const auto result = rcBuildPolyMesh(&context, contourSet, maxVertsPerPoly, polyMesh);
if (!result)
throw NavigatorException("Failed to build poly mesh for navmesh");
}
void buildPolyMeshDetail(rcContext& context, const rcPolyMesh& polyMesh, const rcCompactHeightfield& compact,
const float sampleDist, const float sampleMaxError, rcPolyMeshDetail& polyMeshDetail)
{
const auto result = rcBuildPolyMeshDetail(&context, polyMesh, compact, sampleDist, sampleMaxError,
polyMeshDetail);
if (!result)
throw NavigatorException("Failed to build detail poly mesh for navmesh");
}
void setPolyMeshFlags(rcPolyMesh& polyMesh)
{
for (int i = 0; i < polyMesh.npolys; ++i)
{
if (polyMesh.areas[i] == AreaType_ground)
polyMesh.flags[i] = Flag_walk;
else if (polyMesh.areas[i] == AreaType_water)
polyMesh.flags[i] = Flag_swim;
}
}
bool fillPolyMesh(rcContext& context, const rcConfig& config, rcHeightfield& solid, rcPolyMesh& polyMesh,
rcPolyMeshDetail& polyMeshDetail)
{
rcCompactHeightfield compact;
buildCompactHeightfield(context, config.walkableHeight, config.walkableClimb, solid, compact);
@ -340,21 +360,41 @@ namespace
buildContours(context, compact, config.maxSimplificationError, config.maxEdgeLen, contourSet);
if (contourSet.nconts == 0)
return NavMeshData();
return false;
buildPolyMesh(context, contourSet, config.maxVertsPerPoly, polyMesh);
buildPolyMeshDetail(context, polyMesh, compact, config.detailSampleDist, config.detailSampleMaxError,
polyMeshDetail);
setPolyMeshFlags(polyMesh);
return true;
}
for (int i = 0; i < polyMesh.npolys; ++i)
NavMeshData makeNavMeshTileData(const osg::Vec3f& agentHalfExtents, const RecastMesh& recastMesh,
const std::vector<OffMeshConnection>& offMeshConnections, const TilePosition& tile,
const osg::Vec3f& boundsMin, const osg::Vec3f& boundsMax, const Settings& settings)
{
if (polyMesh.areas[i] == AreaType_ground)
polyMesh.flags[i] = Flag_walk;
else if (polyMesh.areas[i] == AreaType_water)
polyMesh.flags[i] = Flag_swim;
}
rcContext context;
const auto config = makeConfig(agentHalfExtents, boundsMin, boundsMax, settings);
rcHeightfield solid;
createHeightfield(context, solid, config.width, config.height, config.bmin, config.bmax, config.cs, config.ch);
if (!rasterizeTriangles(context, agentHalfExtents, recastMesh, config, settings, solid))
return NavMeshData();
rcFilterLowHangingWalkableObstacles(&context, config.walkableClimb, solid);
rcFilterLedgeSpans(&context, config.walkableHeight, config.walkableClimb, solid);
rcFilterWalkableLowHeightSpans(&context, config.walkableHeight, solid);
rcPolyMesh polyMesh;
rcPolyMeshDetail polyMeshDetail;
initPolyMeshDetail(polyMeshDetail);
const PolyMeshDetailStackPtr polyMeshDetailPtr(&polyMeshDetail);
if (!fillPolyMesh(context, config, solid, polyMesh, polyMeshDetail))
return NavMeshData();
const auto offMeshConVerts = getOffMeshVerts(offMeshConnections);
const std::vector<float> offMeshConRad(offMeshConnections.size(), getRadius(settings, agentHalfExtents));
@ -391,8 +431,8 @@ namespace
params.ch = config.ch;
params.buildBvTree = true;
params.userId = 0;
params.tileX = tileX;
params.tileY = tileY;
params.tileX = tile.x();
params.tileY = tile.y();
params.tileLayer = 0;
unsigned char* navMeshData;
@ -483,17 +523,16 @@ namespace DetourNavigator
return removeTile();
}
auto boundsMin = recastMesh->getBoundsMin();
auto boundsMax = recastMesh->getBoundsMax();
auto recastMeshBounds = recastMesh->getBounds();
for (const auto& water : recastMesh->getWater())
{
const auto bounds = getWaterBounds(water, settings, agentHalfExtents);
boundsMin.y() = std::min(boundsMin.y(), bounds.mMin.y());
boundsMax.y() = std::max(boundsMax.y(), bounds.mMax.y());
const auto waterBounds = getWaterBounds(water, settings, agentHalfExtents);
recastMeshBounds.mMin.y() = std::min(recastMeshBounds.mMin.y(), waterBounds.mMin.y());
recastMeshBounds.mMax.y() = std::max(recastMeshBounds.mMax.y(), waterBounds.mMax.y());
}
if (boundsMin == boundsMax)
if (isEmpty(recastMeshBounds))
{
log("ignore add tile: recastMesh is empty");
return removeTile();
@ -510,10 +549,10 @@ namespace DetourNavigator
if (!cachedNavMeshData)
{
const auto tileBounds = makeTileBounds(settings, changedTile);
const osg::Vec3f tileBorderMin(tileBounds.mMin.x(), boundsMin.y() - 1, tileBounds.mMin.y());
const osg::Vec3f tileBorderMax(tileBounds.mMax.x(), boundsMax.y() + 1, tileBounds.mMax.y());
const osg::Vec3f tileBorderMin(tileBounds.mMin.x(), recastMeshBounds.mMin.y() - 1, tileBounds.mMin.y());
const osg::Vec3f tileBorderMax(tileBounds.mMax.x(), recastMeshBounds.mMax.y() + 1, tileBounds.mMax.y());
auto navMeshData = makeNavMeshTileData(agentHalfExtents, *recastMesh, offMeshConnections, x, y,
auto navMeshData = makeNavMeshTileData(agentHalfExtents, *recastMesh, offMeshConnections, changedTile,
tileBorderMin, tileBorderMax, settings);
if (!navMeshData.mValue)

@ -17,6 +17,6 @@ namespace DetourNavigator
throw InvalidArgument("Number of flags doesn't match number of triangles: triangles="
+ std::to_string(getTrianglesCount()) + ", areaTypes=" + std::to_string(mAreaTypes.size()));
if (getVerticesCount())
rcCalcBounds(mVertices.data(), static_cast<int>(getVerticesCount()), mBoundsMin.ptr(), mBoundsMax.ptr());
rcCalcBounds(mVertices.data(), static_cast<int>(getVerticesCount()), mBounds.mMin.ptr(), mBounds.mMax.ptr());
}
}

@ -3,6 +3,7 @@
#include "areatype.hpp"
#include "chunkytrimesh.hpp"
#include "bounds.hpp"
#include <memory>
#include <string>
@ -61,14 +62,9 @@ namespace DetourNavigator
return mChunkyTriMesh;
}
const osg::Vec3f& getBoundsMin() const
const Bounds& getBounds() const
{
return mBoundsMin;
}
const osg::Vec3f& getBoundsMax() const
{
return mBoundsMax;
return mBounds;
}
private:
@ -77,8 +73,7 @@ namespace DetourNavigator
std::vector<AreaType> mAreaTypes;
std::vector<Water> mWater;
ChunkyTriMesh mChunkyTriMesh;
osg::Vec3f mBoundsMin;
osg::Vec3f mBoundsMax;
Bounds mBounds;
};
}

Loading…
Cancel
Save