Split navigator settings into subtypes

Mostly to distinguish settings that affect properties of the generated navmesh.
pull/3225/head
elsid 3 years ago
parent 33bb18850d
commit 01c712d5f1
No known key found for this signature in database
GPG Key ID: D27B8E8D10A2896B

@ -4,6 +4,7 @@
#include <components/sceneutil/agentpath.hpp>
#include <components/resource/resourcesystem.hpp>
#include <components/resource/scenemanager.hpp>
#include <components/detournavigator/settings.hpp>
#include <osg/PositionAttitudeTransform>
@ -47,7 +48,7 @@ namespace MWRender
if (group != mGroups.end())
mRootNode->removeChild(group->second);
const auto newGroup = SceneUtil::createAgentPathGroup(path, halfExtents, start, end, settings);
const auto newGroup = SceneUtil::createAgentPathGroup(path, halfExtents, start, end, settings.mRecast);
if (newGroup)
{
MWBase::Environment::get().getResourceSystem()->getSceneManager()->recreateShaders(newGroup, "debug");

@ -54,7 +54,7 @@ namespace MWRender
if (it->second.mGeneration != tile->second->getGeneration()
|| it->second.mRevision != tile->second->getRevision())
{
const auto group = SceneUtil::createRecastMeshGroup(*tile->second, settings);
const auto group = SceneUtil::createRecastMeshGroup(*tile->second, settings.mRecast);
MWBase::Environment::get().getResourceSystem()->getSceneManager()->recreateShaders(group, "debug");
group->setNodeMask(Mask_Debug);
mRootNode->removeChild(it->second.mValue);
@ -71,7 +71,7 @@ namespace MWRender
{
if (mGroups.count(tile.first))
continue;
const auto group = SceneUtil::createRecastMeshGroup(*tile.second, settings);
const auto group = SceneUtil::createRecastMeshGroup(*tile.second, settings.mRecast);
MWBase::Environment::get().getResourceSystem()->getSceneManager()->recreateShaders(group, "debug");
group->setNodeMask(Mask_Debug);
mGroups.emplace(tile.first, Group {tile.second->getGeneration(), tile.second->getRevision(), group});

@ -186,7 +186,7 @@ namespace MWWorld
if (Settings::Manager::getBool("enable", "Navigator"))
{
auto navigatorSettings = DetourNavigator::makeSettingsFromSettingsManager();
navigatorSettings.mSwimHeightScale = mSwimHeightScale;
navigatorSettings.mRecast.mSwimHeightScale = mSwimHeightScale;
mNavigator = DetourNavigator::makeNavigator(navigatorSettings);
}
else

@ -21,7 +21,7 @@ namespace
struct DetourNavigatorGetTilesPositionsTest : Test
{
Settings mSettings;
RecastSettings mSettings;
std::vector<TilePosition> mTilesPositions;
CollectTilesPositions mCollect {mTilesPositions};

@ -63,28 +63,28 @@ namespace
mSettings.mEnableWriteNavMeshToFile = false;
mSettings.mEnableRecastMeshFileNameRevision = false;
mSettings.mEnableNavMeshFileNameRevision = false;
mSettings.mBorderSize = 16;
mSettings.mCellHeight = 0.2f;
mSettings.mCellSize = 0.2f;
mSettings.mDetailSampleDist = 6;
mSettings.mDetailSampleMaxError = 1;
mSettings.mMaxClimb = 34;
mSettings.mMaxSimplificationError = 1.3f;
mSettings.mMaxSlope = 49;
mSettings.mRecastScaleFactor = 0.017647058823529415f;
mSettings.mSwimHeightScale = 0.89999997615814208984375f;
mSettings.mMaxEdgeLen = 12;
mSettings.mMaxNavMeshQueryNodes = 2048;
mSettings.mMaxVertsPerPoly = 6;
mSettings.mRegionMergeSize = 20;
mSettings.mRegionMinSize = 8;
mSettings.mTileSize = 64;
mSettings.mRecast.mBorderSize = 16;
mSettings.mRecast.mCellHeight = 0.2f;
mSettings.mRecast.mCellSize = 0.2f;
mSettings.mRecast.mDetailSampleDist = 6;
mSettings.mRecast.mDetailSampleMaxError = 1;
mSettings.mRecast.mMaxClimb = 34;
mSettings.mRecast.mMaxSimplificationError = 1.3f;
mSettings.mRecast.mMaxSlope = 49;
mSettings.mRecast.mRecastScaleFactor = 0.017647058823529415f;
mSettings.mRecast.mSwimHeightScale = 0.89999997615814208984375f;
mSettings.mRecast.mMaxEdgeLen = 12;
mSettings.mDetour.mMaxNavMeshQueryNodes = 2048;
mSettings.mRecast.mMaxVertsPerPoly = 6;
mSettings.mRecast.mRegionMergeArea = 400;
mSettings.mRecast.mRegionMinArea = 64;
mSettings.mRecast.mTileSize = 64;
mSettings.mWaitUntilMinDistanceToPlayer = std::numeric_limits<int>::max();
mSettings.mAsyncNavMeshUpdaterThreads = 1;
mSettings.mMaxNavMeshTilesCacheSize = 1024 * 1024;
mSettings.mMaxPolygonPathSize = 1024;
mSettings.mMaxSmoothPathSize = 1024;
mSettings.mMaxPolys = 4096;
mSettings.mDetour.mMaxPolygonPathSize = 1024;
mSettings.mDetour.mMaxSmoothPathSize = 1024;
mSettings.mDetour.mMaxPolys = 4096;
mSettings.mMaxTilesNumber = 512;
mSettings.mMinUpdateInterval = std::chrono::milliseconds(50);
mNavigator.reset(new NavigatorImpl(mSettings));

@ -11,7 +11,7 @@ namespace
struct DetourNavigatorGetTilePositionTest : Test
{
Settings mSettings;
RecastSettings mSettings;
DetourNavigatorGetTilePositionTest()
{
@ -47,7 +47,7 @@ namespace
struct DetourNavigatorMakeTileBoundsTest : Test
{
Settings mSettings;
RecastSettings mSettings;
DetourNavigatorMakeTileBoundsTest()
{

@ -15,7 +15,7 @@ namespace
struct DetourNavigatorTileCachedRecastMeshManagerTest : Test
{
Settings mSettings;
RecastSettings mSettings;
std::vector<TilePosition> mChangedTiles;
const ObjectTransform mObjectTransform {ESM::Position {{0, 0, 0}, {0, 0, 0}}, 0.0f};
const osg::ref_ptr<const Resource::BulletShape> mShape = new Resource::BulletShape;

@ -404,7 +404,7 @@ namespace DetourNavigator
}
if (recastMesh && mSettings.get().mEnableWriteRecastMeshToFile)
writeToFile(*recastMesh, mSettings.get().mRecastMeshPathPrefix + std::to_string(job.mChangedTile.x())
+ "_" + std::to_string(job.mChangedTile.y()) + "_", recastMeshRevision, mSettings);
+ "_" + std::to_string(job.mChangedTile.y()) + "_", recastMeshRevision, mSettings.get().mRecast);
if (mSettings.get().mEnableWriteNavMeshToFile)
if (const auto shared = job.mNavMeshCacheItem.lock())
writeToFile(shared->lockConst()->getImpl(), mSettings.get().mNavMeshPathPrefix, navMeshRevision);

@ -11,7 +11,8 @@
namespace DetourNavigator
{
void writeToFile(const RecastMesh& recastMesh, const std::string& pathPrefix, const std::string& revision, const Settings& settings)
void writeToFile(const RecastMesh& recastMesh, const std::string& pathPrefix,
const std::string& revision, const RecastSettings& settings)
{
const auto path = pathPrefix + "recastmesh" + revision + ".obj";
boost::filesystem::ofstream file(boost::filesystem::path(path), std::ios::out);

@ -70,9 +70,10 @@ namespace DetourNavigator
}
class RecastMesh;
struct Settings;
struct RecastSettings;
void writeToFile(const RecastMesh& recastMesh, const std::string& pathPrefix, const std::string& revision, const Settings& settings);
void writeToFile(const RecastMesh& recastMesh, const std::string& pathPrefix,
const std::string& revision, const RecastSettings& settings);
void writeToFile(const dtNavMesh& navMesh, const std::string& pathPrefix, const std::string& revision);
}

@ -10,7 +10,7 @@
namespace DetourNavigator
{
std::optional<osg::Vec3f> findRandomPointAroundCircle(const dtNavMesh& navMesh, const osg::Vec3f& halfExtents,
const osg::Vec3f& start, const float maxRadius, const Flags includeFlags, const Settings& settings)
const osg::Vec3f& start, const float maxRadius, const Flags includeFlags, const DetourSettings& settings)
{
dtNavMeshQuery navMeshQuery;
if (!initNavMeshQuery(navMeshQuery, navMesh, settings.mMaxNavMeshQueryNodes))

@ -10,10 +10,10 @@ class dtNavMesh;
namespace DetourNavigator
{
struct Settings;
struct DetourSettings;
std::optional<osg::Vec3f> findRandomPointAroundCircle(const dtNavMesh& navMesh, const osg::Vec3f& halfExtents,
const osg::Vec3f& start, const float maxRadius, const Flags includeFlags, const Settings& settings);
const osg::Vec3f& start, const float maxRadius, const Flags includeFlags, const DetourSettings& settings);
}
#endif

@ -60,7 +60,7 @@ namespace DetourNavigator
class OutputTransformIterator
{
public:
OutputTransformIterator(OutputIterator& impl, const Settings& settings)
explicit OutputTransformIterator(OutputIterator& impl, const RecastSettings& settings)
: mImpl(impl), mSettings(settings)
{
}
@ -91,7 +91,7 @@ namespace DetourNavigator
private:
std::reference_wrapper<OutputIterator> mImpl;
std::reference_wrapper<const Settings> mSettings;
std::reference_wrapper<const RecastSettings> mSettings;
};
inline bool initNavMeshQuery(dtNavMeshQuery& value, const dtNavMesh& navMesh, const int maxNodes)
@ -261,7 +261,7 @@ namespace DetourNavigator
const Settings& settings, float endTolerance, OutputIterator& out)
{
dtNavMeshQuery navMeshQuery;
if (!initNavMeshQuery(navMeshQuery, navMesh, settings.mMaxNavMeshQueryNodes))
if (!initNavMeshQuery(navMeshQuery, navMesh, settings.mDetour.mMaxNavMeshQueryNodes))
return Status::InitNavMeshQueryFailed;
dtQueryFilter queryFilter;
@ -283,7 +283,7 @@ namespace DetourNavigator
if (endRef == 0)
return Status::EndPolygonNotFound;
std::vector<dtPolyRef> polygonPath(settings.mMaxPolygonPathSize);
std::vector<dtPolyRef> polygonPath(settings.mDetour.mMaxPolygonPathSize);
const auto polygonPathSize = findPath(navMeshQuery, startRef, endRef, start, end, queryFilter,
polygonPath.data(), polygonPath.size());
@ -294,9 +294,9 @@ namespace DetourNavigator
return Status::Success;
const bool partialPath = polygonPath[*polygonPathSize - 1] != endRef;
auto outTransform = OutputTransformIterator<OutputIterator>(out, settings);
auto outTransform = OutputTransformIterator<OutputIterator>(out, settings.mRecast);
const Status smoothStatus = makeSmoothPath(navMesh, navMeshQuery, queryFilter, start, end, stepSize,
polygonPath, *polygonPathSize, settings.mMaxSmoothPathSize, outTransform);
polygonPath, *polygonPathSize, settings.mDetour.mMaxSmoothPathSize, outTransform);
if (smoothStatus != Status::Success)
return smoothStatus;

@ -15,7 +15,7 @@ namespace DetourNavigator
{
template <class Callback>
void getTilesPositions(const osg::Vec3f& aabbMin, const osg::Vec3f& aabbMax,
const Settings& settings, Callback&& callback)
const RecastSettings& settings, Callback&& callback)
{
auto min = toNavMeshCoordinates(settings, aabbMin);
auto max = toNavMeshCoordinates(settings, aabbMax);
@ -40,7 +40,7 @@ namespace DetourNavigator
template <class Callback>
void getTilesPositions(const btCollisionShape& shape, const btTransform& transform,
const Settings& settings, Callback&& callback)
const RecastSettings& settings, Callback&& callback)
{
btVector3 aabbMin;
btVector3 aabbMax;
@ -51,7 +51,7 @@ namespace DetourNavigator
template <class Callback>
void getTilesPositions(const int cellSize, const btVector3& shift,
const Settings& settings, Callback&& callback)
const RecastSettings& settings, Callback&& callback)
{
using Misc::Convert::toOsg;

@ -36,32 +36,6 @@ namespace
float mHeight;
};
Rectangle getSwimRectangle(const CellWater& water, const Settings& settings, const osg::Vec3f& agentHalfExtents)
{
if (water.mWater.mCellSize == std::numeric_limits<int>::max())
{
return Rectangle {
TileBounds {
osg::Vec2f(-std::numeric_limits<float>::max(), -std::numeric_limits<float>::max()),
osg::Vec2f(std::numeric_limits<float>::max(), std::numeric_limits<float>::max())
},
toNavMeshCoordinates(settings, getSwimLevel(settings, water.mWater.mLevel, agentHalfExtents.z()))
};
}
else
{
const osg::Vec2f shift = getWaterShift2d(water.mCellPosition, water.mWater.mCellSize);
const float halfCellSize = water.mWater.mCellSize / 2.0f;
return Rectangle {
TileBounds{
toNavMeshCoordinates(settings, shift + osg::Vec2f(-halfCellSize, -halfCellSize)),
toNavMeshCoordinates(settings, shift + osg::Vec2f(halfCellSize, halfCellSize))
},
toNavMeshCoordinates(settings, getSwimLevel(settings, water.mWater.mLevel, agentHalfExtents.z()))
};
}
}
std::vector<float> getOffMeshVerts(const std::vector<OffMeshConnection>& connections)
{
std::vector<float> result;
@ -120,52 +94,46 @@ namespace
return result;
}
rcConfig makeConfig(const osg::Vec3f& agentHalfExtents, const TilePosition& tile, float minZ, float maxZ,
const Settings& settings)
{
rcConfig config;
config.cs = settings.mCellSize;
config.ch = settings.mCellHeight;
config.walkableSlopeAngle = settings.mMaxSlope;
config.walkableHeight = static_cast<int>(std::ceil(getHeight(settings, agentHalfExtents) / config.ch));
config.walkableClimb = static_cast<int>(std::floor(getMaxClimb(settings) / config.ch));
config.walkableRadius = static_cast<int>(std::ceil(getRadius(settings, agentHalfExtents) / config.cs));
config.maxEdgeLen = static_cast<int>(std::round(settings.mMaxEdgeLen / config.cs));
config.maxSimplificationError = settings.mMaxSimplificationError;
config.minRegionArea = settings.mRegionMinSize * settings.mRegionMinSize;
config.mergeRegionArea = settings.mRegionMergeSize * settings.mRegionMergeSize;
config.maxVertsPerPoly = settings.mMaxVertsPerPoly;
config.detailSampleDist = settings.mDetailSampleDist < 0.9f ? 0 : config.cs * settings.mDetailSampleDist;
config.detailSampleMaxError = config.ch * settings.mDetailSampleMaxError;
config.borderSize = settings.mBorderSize;
config.tileSize = settings.mTileSize;
const int size = config.tileSize + config.borderSize * 2;
config.width = size;
config.height = size;
const float halfBoundsSize = size * config.cs * 0.5f;
const osg::Vec2f shift = osg::Vec2f(tile.x() + 0.5f, tile.y() + 0.5f) * getTileSize(settings);
config.bmin[0] = shift.x() - halfBoundsSize;
config.bmin[1] = minZ;
config.bmin[2] = shift.y() - halfBoundsSize;
config.bmax[0] = shift.x() + halfBoundsSize;
config.bmax[1] = maxZ;
config.bmax[2] = shift.y() + halfBoundsSize;
return config;
float getHeight(const RecastSettings& settings,const osg::Vec3f& agentHalfExtents)
{
return 2.0f * agentHalfExtents.z() * settings.mRecastScaleFactor;
}
float getMaxClimb(const RecastSettings& settings)
{
return settings.mMaxClimb * settings.mRecastScaleFactor;
}
float getRadius(const RecastSettings& settings, const osg::Vec3f& agentHalfExtents)
{
return std::max(agentHalfExtents.x(), agentHalfExtents.y()) * std::sqrt(2) * settings.mRecastScaleFactor;
}
float getSwimLevel(const RecastSettings& settings, const float waterLevel, const float agentHalfExtentsZ)
{
return waterLevel - settings.mSwimHeightScale * agentHalfExtentsZ - agentHalfExtentsZ;;
}
void createHeightfield(rcContext& context, rcHeightfield& solid, int width, int height, const float* bmin,
const float* bmax, const float cs, const float ch)
void initHeightfield(rcContext& context, const TilePosition& tilePosition, float minZ, float maxZ,
const RecastSettings& settings, rcHeightfield& solid)
{
const auto result = rcCreateHeightfield(&context, solid, width, height, bmin, bmax, cs, ch);
const int size = settings.mTileSize + settings.mBorderSize * 2;
const int width = size;
const int height = size;
const float halfBoundsSize = size * settings.mCellSize * 0.5f;
const osg::Vec2f shift = osg::Vec2f(tilePosition.x() + 0.5f, tilePosition.y() + 0.5f) * getTileSize(settings);
const osg::Vec3f bmin(shift.x() - halfBoundsSize, minZ, shift.y() - halfBoundsSize);
const osg::Vec3f bmax(shift.x() + halfBoundsSize, maxZ, shift.y() + halfBoundsSize);
const auto result = rcCreateHeightfield(&context, solid, width, height, bmin.ptr(), bmax.ptr(),
settings.mCellSize, settings.mCellHeight);
if (!result)
throw NavigatorException("Failed to create heightfield for navmesh");
}
bool rasterizeTriangles(rcContext& context, const Mesh& mesh, const Settings& settings, const rcConfig& config,
rcHeightfield& solid)
bool rasterizeTriangles(rcContext& context, const Mesh& mesh, const RecastSettings& settings,
const RecastParams& params, rcHeightfield& solid)
{
std::vector<unsigned char> areas(mesh.getAreaTypes().begin(), mesh.getAreaTypes().end());
std::vector<float> vertices = mesh.getVertices();
@ -179,7 +147,7 @@ namespace
rcClearUnwalkableTriangles(
&context,
config.walkableSlopeAngle,
settings.mMaxSlope,
vertices.data(),
static_cast<int>(mesh.getVerticesCount()),
mesh.getIndices().data(),
@ -195,30 +163,18 @@ namespace
areas.data(),
static_cast<int>(areas.size()),
solid,
config.walkableClimb
params.mWalkableClimb
);
}
bool rasterizeTriangles(rcContext& context, const Rectangle& rectangle, const rcConfig& config,
AreaType areaType, rcHeightfield& solid)
bool rasterizeTriangles(rcContext& context, const Rectangle& rectangle, AreaType areaType,
const RecastParams& params, rcHeightfield& solid)
{
const osg::Vec2f tileBoundsMin(
std::clamp(rectangle.mBounds.mMin.x(), config.bmin[0], config.bmax[0]),
std::clamp(rectangle.mBounds.mMin.y(), config.bmin[2], config.bmax[2])
);
const osg::Vec2f tileBoundsMax(
std::clamp(rectangle.mBounds.mMax.x(), config.bmin[0], config.bmax[0]),
std::clamp(rectangle.mBounds.mMax.y(), config.bmin[2], config.bmax[2])
);
if (tileBoundsMax == tileBoundsMin)
return true;
const std::array vertices {
tileBoundsMin.x(), rectangle.mHeight, tileBoundsMin.y(),
tileBoundsMin.x(), rectangle.mHeight, tileBoundsMax.y(),
tileBoundsMax.x(), rectangle.mHeight, tileBoundsMax.y(),
tileBoundsMax.x(), rectangle.mHeight, tileBoundsMin.y(),
rectangle.mBounds.mMin.x(), rectangle.mHeight, rectangle.mBounds.mMin.y(),
rectangle.mBounds.mMin.x(), rectangle.mHeight, rectangle.mBounds.mMax.y(),
rectangle.mBounds.mMax.x(), rectangle.mHeight, rectangle.mBounds.mMax.y(),
rectangle.mBounds.mMax.x(), rectangle.mHeight, rectangle.mBounds.mMin.y(),
};
const std::array indices {
@ -236,31 +192,42 @@ namespace
areas.data(),
static_cast<int>(areas.size()),
solid,
config.walkableClimb
params.mWalkableClimb
);
}
bool rasterizeTriangles(rcContext& context, const osg::Vec3f& agentHalfExtents, const std::vector<CellWater>& water,
const Settings& settings, const rcConfig& config, rcHeightfield& solid)
const RecastSettings& settings, const RecastParams& params, const TileBounds& realTileBounds, rcHeightfield& solid)
{
for (const CellWater& cellWater : water)
{
const Rectangle rectangle = getSwimRectangle(cellWater, settings, agentHalfExtents);
if (!rasterizeTriangles(context, rectangle, config, AreaType_water, solid))
return false;
const TileBounds cellTileBounds = maxCellTileBounds(cellWater.mCellPosition, cellWater.mWater.mCellSize);
if (auto intersection = getIntersection(realTileBounds, cellTileBounds))
{
const Rectangle rectangle {
toNavMeshCoordinates(settings, *intersection),
toNavMeshCoordinates(settings, getSwimLevel(settings, cellWater.mWater.mLevel, agentHalfExtents.z()))
};
if (!rasterizeTriangles(context, rectangle, AreaType_water, params, solid))
return false;
}
}
return true;
}
bool rasterizeTriangles(rcContext& context, const TileBounds& tileBounds, const std::vector<FlatHeightfield>& heightfields,
const Settings& settings, const rcConfig& config, rcHeightfield& solid)
bool rasterizeTriangles(rcContext& context, const TileBounds& realTileBounds, const std::vector<FlatHeightfield>& heightfields,
const RecastSettings& settings, const RecastParams& params, rcHeightfield& solid)
{
for (const FlatHeightfield& heightfield : heightfields)
{
if (auto intersection = getIntersection(tileBounds, maxCellTileBounds(heightfield.mCellPosition, heightfield.mCellSize)))
const TileBounds cellTileBounds = maxCellTileBounds(heightfield.mCellPosition, heightfield.mCellSize);
if (auto intersection = getIntersection(realTileBounds, cellTileBounds))
{
const Rectangle rectangle {*intersection, toNavMeshCoordinates(settings, heightfield.mHeight)};
if (!rasterizeTriangles(context, rectangle, config, AreaType_ground, solid))
const Rectangle rectangle {
toNavMeshCoordinates(settings, *intersection),
toNavMeshCoordinates(settings, heightfield.mHeight)
};
if (!rasterizeTriangles(context, rectangle, AreaType_ground, params, solid))
return false;
}
}
@ -268,27 +235,25 @@ namespace
}
bool rasterizeTriangles(rcContext& context, const std::vector<Heightfield>& heightfields,
const Settings& settings, const rcConfig& config, rcHeightfield& solid)
const RecastSettings& settings, const RecastParams& params, rcHeightfield& solid)
{
using BulletHelpers::makeProcessTriangleCallback;
for (const Heightfield& heightfield : heightfields)
{
const Mesh mesh = makeMesh(heightfield);
if (!rasterizeTriangles(context, mesh, settings, config, solid))
if (!rasterizeTriangles(context, mesh, settings, params, solid))
return false;
}
return true;
}
bool rasterizeTriangles(rcContext& context, const TilePosition& tilePosition, const osg::Vec3f& agentHalfExtents,
const RecastMesh& recastMesh, const rcConfig& config, const Settings& settings, rcHeightfield& solid)
const RecastMesh& recastMesh, const RecastSettings& settings, const RecastParams& params, rcHeightfield& solid)
{
return rasterizeTriangles(context, recastMesh.getMesh(), settings, config, solid)
&& rasterizeTriangles(context, agentHalfExtents, recastMesh.getWater(), settings, config, solid)
&& rasterizeTriangles(context, recastMesh.getHeightfields(), settings, config, solid)
&& rasterizeTriangles(context, makeRealTileBoundsWithBorder(settings, tilePosition),
recastMesh.getFlatHeightfields(), settings, config, solid);
const TileBounds realTileBounds = makeRealTileBoundsWithBorder(settings, tilePosition);
return rasterizeTriangles(context, recastMesh.getMesh(), settings, params, solid)
&& rasterizeTriangles(context, agentHalfExtents, recastMesh.getWater(), settings, params, realTileBounds, solid)
&& rasterizeTriangles(context, recastMesh.getHeightfields(), settings, params, solid)
&& rasterizeTriangles(context, realTileBounds, recastMesh.getFlatHeightfields(), settings, params, solid);
}
void buildCompactHeightfield(rcContext& context, const int walkableHeight, const int walkableClimb,
@ -359,27 +324,25 @@ namespace
polyMesh.flags[i] = getFlag(static_cast<AreaType>(polyMesh.areas[i]));
}
bool fillPolyMesh(rcContext& context, const rcConfig& config, rcHeightfield& solid, rcPolyMesh& polyMesh,
rcPolyMeshDetail& polyMeshDetail)
bool fillPolyMesh(rcContext& context, const RecastSettings& settings, const RecastParams& params,
rcHeightfield& solid, rcPolyMesh& polyMesh, rcPolyMeshDetail& polyMeshDetail)
{
rcCompactHeightfield compact;
compact.dist = nullptr;
buildCompactHeightfield(context, config.walkableHeight, config.walkableClimb, solid, compact);
buildCompactHeightfield(context, params.mWalkableHeight, params.mWalkableClimb, solid, compact);
erodeWalkableArea(context, config.walkableRadius, compact);
erodeWalkableArea(context, params.mWalkableRadius, compact);
buildDistanceField(context, compact);
buildRegions(context, compact, config.borderSize, config.minRegionArea, config.mergeRegionArea);
buildRegions(context, compact, settings.mBorderSize, settings.mRegionMinArea, settings.mRegionMergeArea);
rcContourSet contourSet;
buildContours(context, compact, config.maxSimplificationError, config.maxEdgeLen, contourSet);
buildContours(context, compact, settings.mMaxSimplificationError, params.mMaxEdgeLen, contourSet);
if (contourSet.nconts == 0)
return false;
buildPolyMesh(context, contourSet, config.maxVertsPerPoly, polyMesh);
buildPolyMesh(context, contourSet, settings.mMaxVertsPerPoly, polyMesh);
buildPolyMeshDetail(context, polyMesh, compact, config.detailSampleDist, config.detailSampleMaxError,
polyMeshDetail);
buildPolyMeshDetail(context, polyMesh, compact, params.mSampleDist, params.mSampleMaxError, polyMeshDetail);
setPolyMeshFlags(polyMesh);
@ -395,7 +358,7 @@ namespace
return power;
}
std::pair<float, float> getBoundsByZ(const RecastMesh& recastMesh, const osg::Vec3f& agentHalfExtents, const Settings& settings)
std::pair<float, float> getBoundsByZ(const RecastMesh& recastMesh, const osg::Vec3f& agentHalfExtents, const RecastSettings& settings)
{
float minZ = 0;
float maxZ = 0;
@ -436,39 +399,54 @@ namespace
namespace DetourNavigator
{
RecastParams makeRecastParams(const RecastSettings& settings, const osg::Vec3f& agentHalfExtents)
{
RecastParams result;
result.mWalkableHeight = static_cast<int>(std::ceil(getHeight(settings, agentHalfExtents) / settings.mCellHeight));
result.mWalkableClimb = static_cast<int>(std::floor(getMaxClimb(settings) / settings.mCellHeight));
result.mWalkableRadius = static_cast<int>(std::ceil(getRadius(settings, agentHalfExtents) / settings.mCellSize));
result.mMaxEdgeLen = static_cast<int>(std::round(static_cast<float>(settings.mMaxEdgeLen) / settings.mCellSize));
result.mSampleDist = settings.mDetailSampleDist < 0.9f ? 0 : settings.mCellSize * settings.mDetailSampleDist;
result.mSampleMaxError = settings.mCellHeight * settings.mDetailSampleMaxError;
return result;
}
std::unique_ptr<PreparedNavMeshData> prepareNavMeshTileData(const RecastMesh& recastMesh,
const TilePosition& tilePosition, const osg::Vec3f& agentHalfExtents, const Settings& settings)
const TilePosition& tilePosition, const osg::Vec3f& agentHalfExtents, const RecastSettings& settings)
{
const auto [minZ, maxZ] = getBoundsByZ(recastMesh, agentHalfExtents, settings);
rcContext context;
const auto config = makeConfig(agentHalfExtents, tilePosition, toNavMeshCoordinates(settings, minZ),
toNavMeshCoordinates(settings, maxZ), settings);
rcHeightfield solid;
createHeightfield(context, solid, config.width, config.height, config.bmin, config.bmax, config.cs, config.ch);
initHeightfield(context, tilePosition, toNavMeshCoordinates(settings, minZ),
toNavMeshCoordinates(settings, maxZ), settings, solid);
const RecastParams params = makeRecastParams(settings, agentHalfExtents);
if (!rasterizeTriangles(context, tilePosition, agentHalfExtents, recastMesh, config, settings, solid))
if (!rasterizeTriangles(context, tilePosition, agentHalfExtents, recastMesh, settings, params, solid))
return nullptr;
rcFilterLowHangingWalkableObstacles(&context, config.walkableClimb, solid);
rcFilterLedgeSpans(&context, config.walkableHeight, config.walkableClimb, solid);
rcFilterWalkableLowHeightSpans(&context, config.walkableHeight, solid);
rcFilterLowHangingWalkableObstacles(&context, params.mWalkableClimb, solid);
rcFilterLedgeSpans(&context, params.mWalkableHeight, params.mWalkableClimb, solid);
rcFilterWalkableLowHeightSpans(&context, params.mWalkableHeight, solid);
std::unique_ptr<PreparedNavMeshData> result = std::make_unique<PreparedNavMeshData>();
if (!fillPolyMesh(context, config, solid, result->mPolyMesh, result->mPolyMeshDetail))
if (!fillPolyMesh(context, settings, params, solid, result->mPolyMesh, result->mPolyMeshDetail))
return nullptr;
result->mCellSize = config.cs;
result->mCellHeight = config.ch;
result->mCellSize = settings.mCellSize;
result->mCellHeight = settings.mCellHeight;
return result;
}
NavMeshData makeNavMeshTileData(const PreparedNavMeshData& data,
const std::vector<OffMeshConnection>& offMeshConnections, const osg::Vec3f& agentHalfExtents,
const TilePosition& tile, const Settings& settings)
const TilePosition& tile, const RecastSettings& settings)
{
const auto offMeshConVerts = getOffMeshVerts(offMeshConnections);
const std::vector<float> offMeshConRad(offMeshConnections.size(), getRadius(settings, agentHalfExtents));
@ -524,7 +502,7 @@ namespace DetourNavigator
// Max tiles and max polys affect how the tile IDs are caculated.
// There are 22 bits available for identifying a tile and a polygon.
const int polysAndTilesBits = 22;
const auto polysBits = getMinValuableBitsNumber(settings.mMaxPolys);
const auto polysBits = getMinValuableBitsNumber(settings.mDetour.mMaxPolys);
if (polysBits >= polysAndTilesBits)
throw InvalidArgument("Too many polygons per tile");
@ -533,8 +511,8 @@ namespace DetourNavigator
dtNavMeshParams params;
std::fill_n(params.orig, 3, 0.0f);
params.tileWidth = settings.mTileSize * settings.mCellSize;
params.tileHeight = settings.mTileSize * settings.mCellSize;
params.tileWidth = settings.mRecast.mTileSize * settings.mRecast.mCellSize;
params.tileHeight = settings.mRecast.mTileSize * settings.mRecast.mCellSize;
params.maxTiles = 1 << tilesBits;
params.maxPolys = 1 << polysBits;
@ -558,9 +536,9 @@ namespace DetourNavigator
{
Log(Debug::Debug) << std::fixed << std::setprecision(2) <<
"Update NavMesh with multiple tiles:" <<
" agentHeight=" << getHeight(settings, agentHalfExtents) <<
" agentMaxClimb=" << getMaxClimb(settings) <<
" agentRadius=" << getRadius(settings, agentHalfExtents) <<
" agentHeight=" << getHeight(settings.mRecast, agentHalfExtents) <<
" agentMaxClimb=" << getMaxClimb(settings.mRecast) <<
" agentRadius=" << getRadius(settings.mRecast, agentHalfExtents) <<
" changedTile=(" << changedTile << ")" <<
" playerTile=(" << playerTile << ")" <<
" changedTileDistance=" << getDistance(changedTile, playerTile);
@ -591,7 +569,7 @@ namespace DetourNavigator
if (!cachedNavMeshData)
{
auto prepared = prepareNavMeshTileData(*recastMesh, changedTile, agentHalfExtents, settings);
auto prepared = prepareNavMeshTileData(*recastMesh, changedTile, agentHalfExtents, settings.mRecast);
if (prepared == nullptr)
{
@ -601,7 +579,7 @@ namespace DetourNavigator
if (updateType == UpdateType::Temporary)
return navMeshCacheItem->lock()->updateTile(changedTile, NavMeshTilesCache::Value(),
makeNavMeshTileData(*prepared, offMeshConnections, agentHalfExtents, changedTile, settings));
makeNavMeshTileData(*prepared, offMeshConnections, agentHalfExtents, changedTile, settings.mRecast));
cachedNavMeshData = navMeshTilesCache.set(agentHalfExtents, changedTile, *recastMesh, std::move(prepared));
@ -609,12 +587,12 @@ namespace DetourNavigator
{
Log(Debug::Debug) << "Navigator cache overflow";
return navMeshCacheItem->lock()->updateTile(changedTile, NavMeshTilesCache::Value(),
makeNavMeshTileData(*prepared, offMeshConnections, agentHalfExtents, changedTile, settings));
makeNavMeshTileData(*prepared, offMeshConnections, agentHalfExtents, changedTile, settings.mRecast));
}
}
const auto updateStatus = navMeshCacheItem->lock()->updateTile(changedTile, std::move(cachedNavMeshData),
makeNavMeshTileData(cachedNavMeshData.get(), offMeshConnections, agentHalfExtents, changedTile, settings));
makeNavMeshTileData(cachedNavMeshData.get(), offMeshConnections, agentHalfExtents, changedTile, settings.mRecast));
return UpdateNavMeshStatusBuilder(updateStatus).cached(cached).getResult();
}

@ -22,6 +22,16 @@ namespace DetourNavigator
struct PreparedNavMeshData;
struct NavMeshData;
struct RecastParams
{
float mSampleDist = 0;
float mSampleMaxError = 0;
int mMaxEdgeLen = 0;
int mWalkableClimb = 0;
int mWalkableHeight = 0;
int mWalkableRadius = 0;
};
inline float getLength(const osg::Vec2i& value)
{
return std::sqrt(float(osg::square(value.x()) + osg::square(value.y())));
@ -38,12 +48,14 @@ namespace DetourNavigator
return expectedTilesCount <= maxTiles;
}
RecastParams makeRecastParams(const RecastSettings& settings, const osg::Vec3f& agentHalfExtents);
std::unique_ptr<PreparedNavMeshData> prepareNavMeshTileData(const RecastMesh& recastMesh, const TilePosition& tile,
const Bounds& bounds, const osg::Vec3f& agentHalfExtents, const Settings& settings);
NavMeshData makeNavMeshTileData(const PreparedNavMeshData& data,
const std::vector<OffMeshConnection>& offMeshConnections, const osg::Vec3f& agentHalfExtents,
const TilePosition& tile, const Settings& settings);
const TilePosition& tile, const RecastSettings& settings);
NavMeshPtr makeEmptyNavMesh(const Settings& settings);

@ -53,8 +53,8 @@ namespace DetourNavigator
{
if (addObject(id, static_cast<const ObjectShapes&>(shapes), transform))
{
const osg::Vec3f start = toNavMeshCoordinates(mSettings, shapes.mConnectionStart);
const osg::Vec3f end = toNavMeshCoordinates(mSettings, shapes.mConnectionEnd);
const osg::Vec3f start = toNavMeshCoordinates(mSettings.mRecast, shapes.mConnectionStart);
const osg::Vec3f end = toNavMeshCoordinates(mSettings.mRecast, shapes.mConnectionEnd);
mNavMeshManager.addOffMeshConnection(id, start, end, AreaType_door);
mNavMeshManager.addOffMeshConnection(id, end, start, AreaType_door);
return true;
@ -126,8 +126,8 @@ namespace DetourNavigator
const auto dst = Misc::Convert::makeOsgVec3f(converter.toWorldPoint(pathgrid.mPoints[edge.mV1]));
mNavMeshManager.addOffMeshConnection(
ObjectId(&pathgrid),
toNavMeshCoordinates(mSettings, src),
toNavMeshCoordinates(mSettings, dst),
toNavMeshCoordinates(mSettings.mRecast, src),
toNavMeshCoordinates(mSettings.mRecast, dst),
AreaType_pathgrid
);
}
@ -149,7 +149,7 @@ namespace DetourNavigator
void NavigatorImpl::updatePlayerPosition(const osg::Vec3f& playerPosition)
{
const TilePosition tilePosition = getTilePosition(mSettings, toNavMeshCoordinates(mSettings, playerPosition));
const TilePosition tilePosition = getTilePosition(mSettings.mRecast, toNavMeshCoordinates(mSettings.mRecast, playerPosition));
if (mLastPlayerPosition.has_value() && *mLastPlayerPosition == tilePosition)
return;
update(playerPosition);
@ -225,6 +225,6 @@ namespace DetourNavigator
float NavigatorImpl::getMaxNavmeshAreaRealRadius() const
{
const auto& settings = getSettings();
return getRealTileSize(settings) * getMaxNavmeshAreaRadius(settings);
return getRealTileSize(settings.mRecast) * getMaxNavmeshAreaRadius(settings);
}
}

@ -13,11 +13,11 @@ namespace DetourNavigator
return std::nullopt;
const auto settings = navigator.getSettings();
const auto result = DetourNavigator::findRandomPointAroundCircle(navMesh->lockConst()->getImpl(),
toNavMeshCoordinates(settings, agentHalfExtents), toNavMeshCoordinates(settings, start),
toNavMeshCoordinates(settings, maxRadius), includeFlags, settings);
toNavMeshCoordinates(settings.mRecast, agentHalfExtents), toNavMeshCoordinates(settings.mRecast, start),
toNavMeshCoordinates(settings.mRecast, maxRadius), includeFlags, settings.mDetour);
if (!result)
return std::nullopt;
return std::optional<osg::Vec3f>(fromNavMeshCoordinates(settings, *result));
return std::optional<osg::Vec3f>(fromNavMeshCoordinates(settings.mRecast, *result));
}
std::optional<osg::Vec3f> raycast(const Navigator& navigator, const osg::Vec3f& agentHalfExtents, const osg::Vec3f& start,
@ -28,10 +28,10 @@ namespace DetourNavigator
return std::nullopt;
const auto settings = navigator.getSettings();
const auto result = DetourNavigator::raycast(navMesh->lockConst()->getImpl(),
toNavMeshCoordinates(settings, agentHalfExtents), toNavMeshCoordinates(settings, start),
toNavMeshCoordinates(settings, end), includeFlags, settings);
toNavMeshCoordinates(settings.mRecast, agentHalfExtents), toNavMeshCoordinates(settings.mRecast, start),
toNavMeshCoordinates(settings.mRecast, end), includeFlags, settings.mDetour);
if (!result)
return std::nullopt;
return fromNavMeshCoordinates(settings, *result);
return fromNavMeshCoordinates(settings.mRecast, *result);
}
}

@ -37,9 +37,9 @@ namespace DetourNavigator
if (navMesh == nullptr)
return Status::NavMeshNotFound;
const auto settings = navigator.getSettings();
return findSmoothPath(navMesh->lockConst()->getImpl(), toNavMeshCoordinates(settings, agentHalfExtents),
toNavMeshCoordinates(settings, stepSize), toNavMeshCoordinates(settings, start),
toNavMeshCoordinates(settings, end), includeFlags, areaCosts, settings, endTolerance, out);
return findSmoothPath(navMesh->lockConst()->getImpl(), toNavMeshCoordinates(settings.mRecast, agentHalfExtents),
toNavMeshCoordinates(settings.mRecast, stepSize), toNavMeshCoordinates(settings.mRecast, start),
toNavMeshCoordinates(settings.mRecast, end), includeFlags, areaCosts, settings, endTolerance, out);
}
/**

@ -43,8 +43,8 @@ namespace DetourNavigator
{
NavMeshManager::NavMeshManager(const Settings& settings)
: mSettings(settings)
, mRecastMeshManager(settings)
, mOffMeshConnectionsManager(settings)
, mRecastMeshManager(mSettings.mRecast)
, mOffMeshConnectionsManager(mSettings.mRecast)
, mAsyncNavMeshUpdater(settings, mRecastMeshManager, mOffMeshConnectionsManager)
{}
@ -140,8 +140,8 @@ namespace DetourNavigator
{
mOffMeshConnectionsManager.add(id, OffMeshConnection {start, end, areaType});
const auto startTilePosition = getTilePosition(mSettings, start);
const auto endTilePosition = getTilePosition(mSettings, end);
const auto startTilePosition = getTilePosition(mSettings.mRecast, start);
const auto endTilePosition = getTilePosition(mSettings.mRecast, end);
addChangedTile(startTilePosition, ChangeType::add);
@ -158,7 +158,7 @@ namespace DetourNavigator
void NavMeshManager::update(const osg::Vec3f& playerPosition, const osg::Vec3f& agentHalfExtents)
{
const auto playerTile = getTilePosition(mSettings, toNavMeshCoordinates(mSettings, playerPosition));
const auto playerTile = getTilePosition(mSettings.mRecast, toNavMeshCoordinates(mSettings.mRecast, playerPosition));
auto& lastRevision = mLastRecastMeshManagerRevision[agentHalfExtents];
auto lastPlayerTile = mPlayerTile.find(agentHalfExtents);
if (lastRevision == mRecastMeshManager.getRevision() && lastPlayerTile != mPlayerTile.end()
@ -251,7 +251,7 @@ namespace DetourNavigator
void NavMeshManager::addChangedTiles(const btCollisionShape& shape, const btTransform& transform,
const ChangeType changeType)
{
getTilesPositions(shape, transform, mSettings,
getTilesPositions(shape, transform, mSettings.mRecast,
[&] (const TilePosition& v) { addChangedTile(v, changeType); });
}
@ -261,7 +261,7 @@ namespace DetourNavigator
if (cellSize == std::numeric_limits<int>::max())
return;
getTilesPositions(cellSize, shift, mSettings,
getTilesPositions(cellSize, shift, mSettings.mRecast,
[&] (const TilePosition& v) { addChangedTile(v, changeType); });
}

@ -11,7 +11,7 @@
namespace DetourNavigator
{
OffMeshConnectionsManager::OffMeshConnectionsManager(const Settings& settings)
OffMeshConnectionsManager::OffMeshConnectionsManager(const RecastSettings& settings)
: mSettings(settings)
{}

@ -18,7 +18,7 @@ namespace DetourNavigator
class OffMeshConnectionsManager
{
public:
OffMeshConnectionsManager(const Settings& settings);
explicit OffMeshConnectionsManager(const RecastSettings& settings);
void add(const ObjectId id, const OffMeshConnection& value);
@ -33,7 +33,7 @@ namespace DetourNavigator
std::map<TilePosition, std::unordered_set<ObjectId>> mByTilePosition;
};
const Settings& mSettings;
const RecastSettings& mSettings;
Misc::ScopeGuarded<Values> mValues;
};
}

@ -10,7 +10,7 @@
namespace DetourNavigator
{
std::optional<osg::Vec3f> raycast(const dtNavMesh& navMesh, const osg::Vec3f& halfExtents,
const osg::Vec3f& start, const osg::Vec3f& end, const Flags includeFlags, const Settings& settings)
const osg::Vec3f& start, const osg::Vec3f& end, const Flags includeFlags, const DetourSettings& settings)
{
dtNavMeshQuery navMeshQuery;
if (!initNavMeshQuery(navMeshQuery, navMesh, settings.mMaxNavMeshQueryNodes))

@ -10,10 +10,10 @@ class dtNavMesh;
namespace DetourNavigator
{
struct Settings;
struct DetourSettings;
std::optional<osg::Vec3f> raycast(const dtNavMesh& navMesh, const osg::Vec3f& halfExtents,
const osg::Vec3f& start, const osg::Vec3f& end, const Flags includeFlags, const Settings& settings);
const osg::Vec3f& start, const osg::Vec3f& end, const Flags includeFlags, const DetourSettings& settings);
}
#endif

@ -3,43 +3,65 @@
#include <components/settings/settings.hpp>
#include <components/misc/constants.hpp>
#include <algorithm>
namespace DetourNavigator
{
RecastSettings makeRecastSettingsFromSettingsManager()
{
constexpr float epsilon = std::numeric_limits<float>::epsilon();
RecastSettings result;
result.mBorderSize = std::max(0, ::Settings::Manager::getInt("border size", "Navigator"));
result.mCellHeight = std::max(epsilon, ::Settings::Manager::getFloat("cell height", "Navigator"));
result.mCellSize = std::max(epsilon, ::Settings::Manager::getFloat("cell size", "Navigator"));
result.mDetailSampleDist = std::max(0.0f, ::Settings::Manager::getFloat("detail sample dist", "Navigator"));
result.mDetailSampleMaxError = std::max(0.0f, ::Settings::Manager::getFloat("detail sample max error", "Navigator"));
result.mMaxClimb = Constants::sStepSizeUp;
result.mMaxSimplificationError = std::max(0.0f, ::Settings::Manager::getFloat("max simplification error", "Navigator"));
result.mMaxSlope = Constants::sMaxSlope;
result.mRecastScaleFactor = std::max(epsilon, ::Settings::Manager::getFloat("recast scale factor", "Navigator"));
result.mSwimHeightScale = 0;
result.mMaxEdgeLen = std::max(0, ::Settings::Manager::getInt("max edge len", "Navigator"));
result.mMaxVertsPerPoly = std::max(3, ::Settings::Manager::getInt("max verts per poly", "Navigator"));
result.mRegionMergeArea = std::max(0, ::Settings::Manager::getInt("region merge area", "Navigator"));
result.mRegionMinArea = std::max(0, ::Settings::Manager::getInt("region min area", "Navigator"));
result.mTileSize = std::max(1, ::Settings::Manager::getInt("tile size", "Navigator"));
return result;
}
DetourSettings makeDetourSettingsFromSettingsManager()
{
DetourSettings result;
result.mMaxNavMeshQueryNodes = std::clamp(::Settings::Manager::getInt("max nav mesh query nodes", "Navigator"), 1, 65535);
result.mMaxPolys = std::clamp(::Settings::Manager::getInt("max polygons per tile", "Navigator"), 1, (1 << 22) - 1);
result.mMaxPolygonPathSize = static_cast<std::size_t>(std::max(0, ::Settings::Manager::getInt("max polygon path size", "Navigator")));
result.mMaxSmoothPathSize = static_cast<std::size_t>(std::max(0, ::Settings::Manager::getInt("max smooth path size", "Navigator")));
return result;
}
Settings makeSettingsFromSettingsManager()
{
Settings navigatorSettings;
navigatorSettings.mBorderSize = ::Settings::Manager::getInt("border size", "Navigator");
navigatorSettings.mCellHeight = ::Settings::Manager::getFloat("cell height", "Navigator");
navigatorSettings.mCellSize = ::Settings::Manager::getFloat("cell size", "Navigator");
navigatorSettings.mDetailSampleDist = ::Settings::Manager::getFloat("detail sample dist", "Navigator");
navigatorSettings.mDetailSampleMaxError = ::Settings::Manager::getFloat("detail sample max error", "Navigator");
navigatorSettings.mMaxClimb = Constants::sStepSizeUp;
navigatorSettings.mMaxSimplificationError = ::Settings::Manager::getFloat("max simplification error", "Navigator");
navigatorSettings.mMaxSlope = Constants::sMaxSlope;
navigatorSettings.mRecastScaleFactor = ::Settings::Manager::getFloat("recast scale factor", "Navigator");
navigatorSettings.mSwimHeightScale = 0;
navigatorSettings.mMaxEdgeLen = ::Settings::Manager::getInt("max edge len", "Navigator");
navigatorSettings.mMaxNavMeshQueryNodes = ::Settings::Manager::getInt("max nav mesh query nodes", "Navigator");
navigatorSettings.mMaxPolys = ::Settings::Manager::getInt("max polygons per tile", "Navigator");
navigatorSettings.mMaxTilesNumber = ::Settings::Manager::getInt("max tiles number", "Navigator");
navigatorSettings.mMaxVertsPerPoly = ::Settings::Manager::getInt("max verts per poly", "Navigator");
navigatorSettings.mRegionMergeSize = ::Settings::Manager::getInt("region merge size", "Navigator");
navigatorSettings.mRegionMinSize = ::Settings::Manager::getInt("region min size", "Navigator");
navigatorSettings.mTileSize = ::Settings::Manager::getInt("tile size", "Navigator");
navigatorSettings.mWaitUntilMinDistanceToPlayer = ::Settings::Manager::getInt("wait until min distance to player", "Navigator");
navigatorSettings.mAsyncNavMeshUpdaterThreads = static_cast<std::size_t>(::Settings::Manager::getInt("async nav mesh updater threads", "Navigator"));
navigatorSettings.mMaxNavMeshTilesCacheSize = static_cast<std::size_t>(::Settings::Manager::getInt("max nav mesh tiles cache size", "Navigator"));
navigatorSettings.mMaxPolygonPathSize = static_cast<std::size_t>(::Settings::Manager::getInt("max polygon path size", "Navigator"));
navigatorSettings.mMaxSmoothPathSize = static_cast<std::size_t>(::Settings::Manager::getInt("max smooth path size", "Navigator"));
navigatorSettings.mEnableWriteRecastMeshToFile = ::Settings::Manager::getBool("enable write recast mesh to file", "Navigator");
navigatorSettings.mEnableWriteNavMeshToFile = ::Settings::Manager::getBool("enable write nav mesh to file", "Navigator");
navigatorSettings.mRecastMeshPathPrefix = ::Settings::Manager::getString("recast mesh path prefix", "Navigator");
navigatorSettings.mNavMeshPathPrefix = ::Settings::Manager::getString("nav mesh path prefix", "Navigator");
navigatorSettings.mEnableRecastMeshFileNameRevision = ::Settings::Manager::getBool("enable recast mesh file name revision", "Navigator");
navigatorSettings.mEnableNavMeshFileNameRevision = ::Settings::Manager::getBool("enable nav mesh file name revision", "Navigator");
navigatorSettings.mMinUpdateInterval = std::chrono::milliseconds(::Settings::Manager::getInt("min update interval ms", "Navigator"));
return navigatorSettings;
Settings result;
result.mRecast = makeRecastSettingsFromSettingsManager();
result.mDetour = makeDetourSettingsFromSettingsManager();
result.mMaxTilesNumber = std::max(0, ::Settings::Manager::getInt("max tiles number", "Navigator"));
result.mWaitUntilMinDistanceToPlayer = ::Settings::Manager::getInt("wait until min distance to player", "Navigator");
result.mAsyncNavMeshUpdaterThreads = static_cast<std::size_t>(std::max(0, ::Settings::Manager::getInt("async nav mesh updater threads", "Navigator")));
result.mMaxNavMeshTilesCacheSize = static_cast<std::size_t>(std::max(std::int64_t {0}, ::Settings::Manager::getInt64("max nav mesh tiles cache size", "Navigator")));
result.mEnableWriteRecastMeshToFile = ::Settings::Manager::getBool("enable write recast mesh to file", "Navigator");
result.mEnableWriteNavMeshToFile = ::Settings::Manager::getBool("enable write nav mesh to file", "Navigator");
result.mRecastMeshPathPrefix = ::Settings::Manager::getString("recast mesh path prefix", "Navigator");
result.mNavMeshPathPrefix = ::Settings::Manager::getString("nav mesh path prefix", "Navigator");
result.mEnableRecastMeshFileNameRevision = ::Settings::Manager::getBool("enable recast mesh file name revision", "Navigator");
result.mEnableNavMeshFileNameRevision = ::Settings::Manager::getBool("enable nav mesh file name revision", "Navigator");
result.mMinUpdateInterval = std::chrono::milliseconds(::Settings::Manager::getInt("min update interval ms", "Navigator"));
return result;
}
}

@ -6,12 +6,8 @@
namespace DetourNavigator
{
struct Settings
struct RecastSettings
{
bool mEnableWriteRecastMeshToFile = false;
bool mEnableWriteNavMeshToFile = false;
bool mEnableRecastMeshFileNameRevision = false;
bool mEnableNavMeshFileNameRevision = false;
float mCellHeight = 0;
float mCellSize = 0;
float mDetailSampleDist = 0;
@ -23,23 +19,41 @@ namespace DetourNavigator
float mSwimHeightScale = 0;
int mBorderSize = 0;
int mMaxEdgeLen = 0;
int mMaxNavMeshQueryNodes = 0;
int mMaxPolys = 0;
int mMaxTilesNumber = 0;
int mMaxVertsPerPoly = 0;
int mRegionMergeSize = 0;
int mRegionMinSize = 0;
int mRegionMergeArea = 0;
int mRegionMinArea = 0;
int mTileSize = 0;
};
struct DetourSettings
{
int mMaxPolys = 0;
int mMaxNavMeshQueryNodes = 0;
std::size_t mMaxPolygonPathSize = 0;
std::size_t mMaxSmoothPathSize = 0;
};
struct Settings
{
bool mEnableWriteRecastMeshToFile = false;
bool mEnableWriteNavMeshToFile = false;
bool mEnableRecastMeshFileNameRevision = false;
bool mEnableNavMeshFileNameRevision = false;
RecastSettings mRecast;
DetourSettings mDetour;
int mWaitUntilMinDistanceToPlayer = 0;
int mMaxTilesNumber = 0;
std::size_t mAsyncNavMeshUpdaterThreads = 0;
std::size_t mMaxNavMeshTilesCacheSize = 0;
std::size_t mMaxPolygonPathSize = 0;
std::size_t mMaxSmoothPathSize = 0;
std::string mRecastMeshPathPrefix;
std::string mNavMeshPathPrefix;
std::chrono::milliseconds mMinUpdateInterval;
};
RecastSettings makeRecastSettingsFromSettingsManager();
DetourSettings makeDetourSettingsFromSettingsManager();
Settings makeSettingsFromSettingsManager();
}

@ -4,12 +4,8 @@
#include "settings.hpp"
#include "tilebounds.hpp"
#include "tileposition.hpp"
#include "tilebounds.hpp"
#include <LinearMath/btTransform.h>
#include <osg/Vec2f>
#include <osg/Vec2i>
#include <osg/Vec3f>
#include <algorithm>
@ -17,38 +13,31 @@
namespace DetourNavigator
{
inline float getHeight(const Settings& settings,const osg::Vec3f& agentHalfExtents)
{
return 2.0f * agentHalfExtents.z() * settings.mRecastScaleFactor;
}
inline float getMaxClimb(const Settings& settings)
{
return settings.mMaxClimb * settings.mRecastScaleFactor;
}
inline float getRadius(const Settings& settings, const osg::Vec3f& agentHalfExtents)
{
return std::max(agentHalfExtents.x(), agentHalfExtents.y()) * std::sqrt(2) * settings.mRecastScaleFactor;
}
inline float toNavMeshCoordinates(const Settings& settings, float value)
inline float toNavMeshCoordinates(const RecastSettings& settings, float value)
{
return value * settings.mRecastScaleFactor;
}
inline osg::Vec2f toNavMeshCoordinates(const Settings& settings, osg::Vec2f position)
inline osg::Vec2f toNavMeshCoordinates(const RecastSettings& settings, osg::Vec2f position)
{
return position * settings.mRecastScaleFactor;
}
inline osg::Vec3f toNavMeshCoordinates(const Settings& settings, osg::Vec3f position)
inline osg::Vec3f toNavMeshCoordinates(const RecastSettings& settings, osg::Vec3f position)
{
std::swap(position.y(), position.z());
return position * settings.mRecastScaleFactor;
}
inline osg::Vec3f fromNavMeshCoordinates(const Settings& settings, osg::Vec3f position)
inline TileBounds toNavMeshCoordinates(const RecastSettings& settings, const TileBounds& value)
{
return TileBounds {
toNavMeshCoordinates(settings, value.mMin),
toNavMeshCoordinates(settings, value.mMax)
};
}
inline osg::Vec3f fromNavMeshCoordinates(const RecastSettings& settings, osg::Vec3f position)
{
const auto factor = 1.0f / settings.mRecastScaleFactor;
position *= factor;
@ -56,12 +45,12 @@ namespace DetourNavigator
return position;
}
inline float getTileSize(const Settings& settings)
inline float getTileSize(const RecastSettings& settings)
{
return static_cast<float>(settings.mTileSize) * settings.mCellSize;
}
inline TilePosition getTilePosition(const Settings& settings, const osg::Vec3f& position)
inline TilePosition getTilePosition(const RecastSettings& settings, const osg::Vec3f& position)
{
return TilePosition(
static_cast<int>(std::floor(position.x() / getTileSize(settings))),
@ -69,7 +58,7 @@ namespace DetourNavigator
);
}
inline TileBounds makeTileBounds(const Settings& settings, const TilePosition& tilePosition)
inline TileBounds makeTileBounds(const RecastSettings& settings, const TilePosition& tilePosition)
{
return TileBounds {
osg::Vec2f(tilePosition.x(), tilePosition.y()) * getTileSize(settings),
@ -77,17 +66,12 @@ namespace DetourNavigator
};
}
inline float getBorderSize(const Settings& settings)
inline float getBorderSize(const RecastSettings& settings)
{
return static_cast<float>(settings.mBorderSize) * settings.mCellSize;
}
inline float getSwimLevel(const Settings& settings, const float waterLevel, const float agentHalfExtentsZ)
{
return waterLevel - settings.mSwimHeightScale * agentHalfExtentsZ - agentHalfExtentsZ;;
}
inline float getRealTileSize(const Settings& settings)
inline float getRealTileSize(const RecastSettings& settings)
{
return settings.mTileSize * settings.mCellSize / settings.mRecastScaleFactor;
}
@ -97,7 +81,7 @@ namespace DetourNavigator
return std::floor(std::sqrt(settings.mMaxTilesNumber / osg::PI)) - 1;
}
inline TileBounds makeRealTileBoundsWithBorder(const Settings& settings, const TilePosition& tilePosition)
inline TileBounds makeRealTileBoundsWithBorder(const RecastSettings& settings, const TilePosition& tilePosition)
{
TileBounds result = makeTileBounds(settings, tilePosition);
const float border = getBorderSize(settings);

@ -10,7 +10,7 @@
namespace DetourNavigator
{
TileCachedRecastMeshManager::TileCachedRecastMeshManager(const Settings& settings)
TileCachedRecastMeshManager::TileCachedRecastMeshManager(const RecastSettings& settings)
: mSettings(settings)
{}

@ -20,7 +20,7 @@ namespace DetourNavigator
class TileCachedRecastMeshManager
{
public:
TileCachedRecastMeshManager(const Settings& settings);
explicit TileCachedRecastMeshManager(const RecastSettings& settings);
bool addObject(const ObjectId id, const CollisionShape& shape, const btTransform& transform,
const AreaType areaType);
@ -102,7 +102,7 @@ namespace DetourNavigator
private:
using TilesMap = std::map<TilePosition, std::shared_ptr<CachedRecastMeshManager>>;
const Settings& mSettings;
const RecastSettings& mSettings;
Misc::ScopeGuarded<TilesMap> mTiles;
std::unordered_map<ObjectId, std::vector<TilePosition>> mObjectsTilesPositions;
std::map<osg::Vec2i, std::vector<TilePosition>> mWaterTilesPositions;

@ -37,7 +37,7 @@ namespace SceneUtil
{
osg::ref_ptr<osg::Group> createAgentPathGroup(const std::deque<osg::Vec3f>& path,
const osg::Vec3f& halfExtents, const osg::Vec3f& start, const osg::Vec3f& end,
const DetourNavigator::Settings& settings)
const DetourNavigator::RecastSettings& settings)
{
using namespace DetourNavigator;

@ -13,14 +13,14 @@ namespace osg
namespace DetourNavigator
{
struct Settings;
struct RecastSettings;
}
namespace SceneUtil
{
osg::ref_ptr<osg::Group> createAgentPathGroup(const std::deque<osg::Vec3f>& path,
const osg::Vec3f& halfExtents, const osg::Vec3f& start, const osg::Vec3f& end,
const DetourNavigator::Settings& settings);
const DetourNavigator::RecastSettings& settings);
}
#endif

@ -254,9 +254,9 @@ namespace SceneUtil
osg::ref_ptr<osg::Group> group(new osg::Group);
group->setStateSet(groupStateSet);
constexpr float shift = 10.0f;
DebugDraw debugDraw(*group, debugDrawStateSet, osg::Vec3f(0, 0, shift), 1.0f / settings.mRecastScaleFactor);
DebugDraw debugDraw(*group, debugDrawStateSet, osg::Vec3f(0, 0, shift), 1.0f / settings.mRecast.mRecastScaleFactor);
dtNavMeshQuery navMeshQuery;
navMeshQuery.init(&navMesh, settings.mMaxNavMeshQueryNodes);
navMeshQuery.init(&navMesh, settings.mDetour.mMaxNavMeshQueryNodes);
drawMeshTile(&debugDraw, navMesh, &navMeshQuery, &meshTile, DU_DRAWNAVMESH_OFFMESHCONS | DU_DRAWNAVMESH_CLOSEDLIST);
return group;

@ -42,7 +42,7 @@ namespace
namespace SceneUtil
{
osg::ref_ptr<osg::Group> createRecastMeshGroup(const DetourNavigator::RecastMesh& recastMesh,
const DetourNavigator::Settings& settings)
const DetourNavigator::RecastSettings& settings)
{
using namespace DetourNavigator;

@ -11,13 +11,13 @@ namespace osg
namespace DetourNavigator
{
class RecastMesh;
struct Settings;
struct RecastSettings;
}
namespace SceneUtil
{
osg::ref_ptr<osg::Group> createRecastMeshGroup(const DetourNavigator::RecastMesh& recastMesh,
const DetourNavigator::Settings& settings);
const DetourNavigator::RecastSettings& settings);
}
#endif

@ -79,6 +79,15 @@ int Manager::getInt (const std::string& setting, const std::string& category)
return number;
}
std::int64_t Manager::getInt64 (const std::string& setting, const std::string& category)
{
const std::string& value = getString(setting, category);
std::stringstream stream(value);
std::size_t number = 0;
stream >> number;
return number;
}
bool Manager::getBool (const std::string& setting, const std::string& category)
{
const std::string& string = getString(setting, category);

@ -51,6 +51,7 @@ namespace Settings
///< returns the list of changed settings intersecting with the filter
static int getInt (const std::string& setting, const std::string& category);
static std::int64_t getInt64 (const std::string& setting, const std::string& category);
static float getFloat (const std::string& setting, const std::string& category);
static double getDouble (const std::string& setting, const std::string& category);
static std::string getString (const std::string& setting, const std::string& category);

@ -365,20 +365,20 @@ max verts per poly
The maximum number of vertices allowed for polygons generated during the contour to polygon conversion process.
region merge size
region merge area
-----------------
:Type: integer
:Range: >= 0
:Default: 20
:Default: 400
Any regions with a span count smaller than this value will, if possible, be merged with larger regions.
region min size
region min area
---------------
:Type: integer
:Range: >= 0
:Default: 8
:Default: 64
The minimum number of cells allowed to form isolated island areas.

@ -876,10 +876,10 @@ max polygons per tile = 4096
max verts per poly = 6
# Any regions with a span count smaller than this value will, if possible, be merged with larger regions. (value >= 0)
region merge size = 20
region merge area = 400
# The minimum number of cells allowed to form isolated island areas. (value >= 0)
region min size = 8
region min area = 64
# Number of background threads to update nav mesh (value >= 1)
async nav mesh updater threads = 1

Loading…
Cancel
Save