Split navigator settings into subtypes

Mostly to distinguish settings that affect properties of the generated navmesh.
This commit is contained in:
elsid 2021-11-06 13:46:43 +01:00
parent 33bb18850d
commit 01c712d5f1
No known key found for this signature in database
GPG key ID: D27B8E8D10A2896B
38 changed files with 327 additions and 304 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -11,7 +11,8 @@
namespace DetourNavigator 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"; const auto path = pathPrefix + "recastmesh" + revision + ".obj";
boost::filesystem::ofstream file(boost::filesystem::path(path), std::ios::out); boost::filesystem::ofstream file(boost::filesystem::path(path), std::ios::out);

View file

@ -70,9 +70,10 @@ namespace DetourNavigator
} }
class RecastMesh; 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); void writeToFile(const dtNavMesh& navMesh, const std::string& pathPrefix, const std::string& revision);
} }

View file

@ -10,7 +10,7 @@
namespace DetourNavigator namespace DetourNavigator
{ {
std::optional<osg::Vec3f> findRandomPointAroundCircle(const dtNavMesh& navMesh, const osg::Vec3f& halfExtents, 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; dtNavMeshQuery navMeshQuery;
if (!initNavMeshQuery(navMeshQuery, navMesh, settings.mMaxNavMeshQueryNodes)) if (!initNavMeshQuery(navMeshQuery, navMesh, settings.mMaxNavMeshQueryNodes))

View file

@ -10,10 +10,10 @@ class dtNavMesh;
namespace DetourNavigator namespace DetourNavigator
{ {
struct Settings; struct DetourSettings;
std::optional<osg::Vec3f> findRandomPointAroundCircle(const dtNavMesh& navMesh, const osg::Vec3f& halfExtents, 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 #endif

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -13,11 +13,11 @@ namespace DetourNavigator
return std::nullopt; return std::nullopt;
const auto settings = navigator.getSettings(); const auto settings = navigator.getSettings();
const auto result = DetourNavigator::findRandomPointAroundCircle(navMesh->lockConst()->getImpl(), const auto result = DetourNavigator::findRandomPointAroundCircle(navMesh->lockConst()->getImpl(),
toNavMeshCoordinates(settings, agentHalfExtents), toNavMeshCoordinates(settings, start), toNavMeshCoordinates(settings.mRecast, agentHalfExtents), toNavMeshCoordinates(settings.mRecast, start),
toNavMeshCoordinates(settings, maxRadius), includeFlags, settings); toNavMeshCoordinates(settings.mRecast, maxRadius), includeFlags, settings.mDetour);
if (!result) if (!result)
return std::nullopt; 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, 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; return std::nullopt;
const auto settings = navigator.getSettings(); const auto settings = navigator.getSettings();
const auto result = DetourNavigator::raycast(navMesh->lockConst()->getImpl(), const auto result = DetourNavigator::raycast(navMesh->lockConst()->getImpl(),
toNavMeshCoordinates(settings, agentHalfExtents), toNavMeshCoordinates(settings, start), toNavMeshCoordinates(settings.mRecast, agentHalfExtents), toNavMeshCoordinates(settings.mRecast, start),
toNavMeshCoordinates(settings, end), includeFlags, settings); toNavMeshCoordinates(settings.mRecast, end), includeFlags, settings.mDetour);
if (!result) if (!result)
return std::nullopt; return std::nullopt;
return fromNavMeshCoordinates(settings, *result); return fromNavMeshCoordinates(settings.mRecast, *result);
} }
} }

View file

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

View file

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

View file

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

View file

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

View file

@ -10,7 +10,7 @@
namespace DetourNavigator namespace DetourNavigator
{ {
std::optional<osg::Vec3f> raycast(const dtNavMesh& navMesh, const osg::Vec3f& halfExtents, 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; dtNavMeshQuery navMeshQuery;
if (!initNavMeshQuery(navMeshQuery, navMesh, settings.mMaxNavMeshQueryNodes)) if (!initNavMeshQuery(navMeshQuery, navMesh, settings.mMaxNavMeshQueryNodes))

View file

@ -10,10 +10,10 @@ class dtNavMesh;
namespace DetourNavigator namespace DetourNavigator
{ {
struct Settings; struct DetourSettings;
std::optional<osg::Vec3f> raycast(const dtNavMesh& navMesh, const osg::Vec3f& halfExtents, 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 #endif

View file

@ -3,43 +3,65 @@
#include <components/settings/settings.hpp> #include <components/settings/settings.hpp>
#include <components/misc/constants.hpp> #include <components/misc/constants.hpp>
#include <algorithm>
namespace DetourNavigator 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 makeSettingsFromSettingsManager()
{ {
Settings navigatorSettings; Settings result;
navigatorSettings.mBorderSize = ::Settings::Manager::getInt("border size", "Navigator"); result.mRecast = makeRecastSettingsFromSettingsManager();
navigatorSettings.mCellHeight = ::Settings::Manager::getFloat("cell height", "Navigator"); result.mDetour = makeDetourSettingsFromSettingsManager();
navigatorSettings.mCellSize = ::Settings::Manager::getFloat("cell size", "Navigator"); result.mMaxTilesNumber = std::max(0, ::Settings::Manager::getInt("max tiles number", "Navigator"));
navigatorSettings.mDetailSampleDist = ::Settings::Manager::getFloat("detail sample dist", "Navigator"); result.mWaitUntilMinDistanceToPlayer = ::Settings::Manager::getInt("wait until min distance to player", "Navigator");
navigatorSettings.mDetailSampleMaxError = ::Settings::Manager::getFloat("detail sample max error", "Navigator"); result.mAsyncNavMeshUpdaterThreads = static_cast<std::size_t>(std::max(0, ::Settings::Manager::getInt("async nav mesh updater threads", "Navigator")));
navigatorSettings.mMaxClimb = Constants::sStepSizeUp; result.mMaxNavMeshTilesCacheSize = static_cast<std::size_t>(std::max(std::int64_t {0}, ::Settings::Manager::getInt64("max nav mesh tiles cache size", "Navigator")));
navigatorSettings.mMaxSimplificationError = ::Settings::Manager::getFloat("max simplification error", "Navigator"); result.mEnableWriteRecastMeshToFile = ::Settings::Manager::getBool("enable write recast mesh to file", "Navigator");
navigatorSettings.mMaxSlope = Constants::sMaxSlope; result.mEnableWriteNavMeshToFile = ::Settings::Manager::getBool("enable write nav mesh to file", "Navigator");
navigatorSettings.mRecastScaleFactor = ::Settings::Manager::getFloat("recast scale factor", "Navigator"); result.mRecastMeshPathPrefix = ::Settings::Manager::getString("recast mesh path prefix", "Navigator");
navigatorSettings.mSwimHeightScale = 0; result.mNavMeshPathPrefix = ::Settings::Manager::getString("nav mesh path prefix", "Navigator");
navigatorSettings.mMaxEdgeLen = ::Settings::Manager::getInt("max edge len", "Navigator"); result.mEnableRecastMeshFileNameRevision = ::Settings::Manager::getBool("enable recast mesh file name revision", "Navigator");
navigatorSettings.mMaxNavMeshQueryNodes = ::Settings::Manager::getInt("max nav mesh query nodes", "Navigator"); result.mEnableNavMeshFileNameRevision = ::Settings::Manager::getBool("enable nav mesh file name revision", "Navigator");
navigatorSettings.mMaxPolys = ::Settings::Manager::getInt("max polygons per tile", "Navigator"); result.mMinUpdateInterval = std::chrono::milliseconds(::Settings::Manager::getInt("min update interval ms", "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; return result;
} }
} }

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -254,9 +254,9 @@ namespace SceneUtil
osg::ref_ptr<osg::Group> group(new osg::Group); osg::ref_ptr<osg::Group> group(new osg::Group);
group->setStateSet(groupStateSet); group->setStateSet(groupStateSet);
constexpr float shift = 10.0f; 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; dtNavMeshQuery navMeshQuery;
navMeshQuery.init(&navMesh, settings.mMaxNavMeshQueryNodes); navMeshQuery.init(&navMesh, settings.mDetour.mMaxNavMeshQueryNodes);
drawMeshTile(&debugDraw, navMesh, &navMeshQuery, &meshTile, DU_DRAWNAVMESH_OFFMESHCONS | DU_DRAWNAVMESH_CLOSEDLIST); drawMeshTile(&debugDraw, navMesh, &navMeshQuery, &meshTile, DU_DRAWNAVMESH_OFFMESHCONS | DU_DRAWNAVMESH_CLOSEDLIST);
return group; return group;

View file

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

View file

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

View file

@ -79,6 +79,15 @@ int Manager::getInt (const std::string& setting, const std::string& category)
return number; 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) bool Manager::getBool (const std::string& setting, const std::string& category)
{ {
const std::string& string = getString(setting, category); const std::string& string = getString(setting, category);

View file

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

View file

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

View file

@ -876,10 +876,10 @@ max polygons per tile = 4096
max verts per poly = 6 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) # 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) # 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) # Number of background threads to update nav mesh (value >= 1)
async nav mesh updater threads = 1 async nav mesh updater threads = 1