1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-01-16 15:29:55 +00:00

Limit number of NavMesh tiles to add by distance from player tile

This commit is contained in:
elsid 2018-04-21 02:57:01 +03:00
parent d2fd9abd51
commit 4aba0fa85f
No known key found for this signature in database
GPG key ID: B845CB9FEE18AB40
11 changed files with 140 additions and 19 deletions

View file

@ -390,6 +390,10 @@ namespace MWWorld
void Scene::playerMoved(const osg::Vec3f &pos)
{
const auto navigator = MWBase::Environment::get().getWorld()->getNavigator();
const auto player = MWBase::Environment::get().getWorld()->getPlayerPtr();
navigator->update(player.getRefData().getPosition().asVec3());
if (!mCurrentCell || !mCurrentCell->isExterior())
return;

View file

@ -64,13 +64,19 @@ namespace DetourNavigator
{
log("post jobs playerTile=", playerTile);
setPlayerTile(playerTile);
if (changedTiles.empty())
return;
const std::lock_guard<std::mutex> lock(mMutex);
for (const auto& changedTile : changedTiles)
mJobs.push(Job {agentHalfExtents, navMeshCacheItem, changedTile, makePriority(changedTile, playerTile)});
{
if (mPushed[agentHalfExtents].insert(changedTile).second)
mJobs.push(Job {agentHalfExtents, navMeshCacheItem, changedTile,
makePriority(changedTile, playerTile)});
}
mHasJob.notify_all();
}
@ -109,13 +115,14 @@ namespace DetourNavigator
setFirstStart(start);
const auto recastMesh = mRecastMeshManager.get().getMesh(job.mChangedTile);
const auto playerTile = getPlayerTile();
const auto status = updateNavMesh(job.mAgentHalfExtents, recastMesh.get(), job.mChangedTile, mSettings,
*job.mNavMeshCacheItem);
const auto status = updateNavMesh(job.mAgentHalfExtents, recastMesh.get(), job.mChangedTile, playerTile,
mSettings, *job.mNavMeshCacheItem);
const auto finish = std::chrono::steady_clock::now();
writeDebugFiles(job, *recastMesh);
writeDebugFiles(job, recastMesh.get());
using FloatMs = std::chrono::duration<float, std::milli>;
@ -139,10 +146,14 @@ namespace DetourNavigator
log("got ", mJobs.size(), " jobs");
const auto job = mJobs.top();
mJobs.pop();
const auto pushed = mPushed.find(job.mAgentHalfExtents);
pushed->second.erase(job.mChangedTile);
if (pushed->second.empty())
mPushed.erase(pushed);
return job;
}
void AsyncNavMeshUpdater::writeDebugFiles(const Job& job, const RecastMesh& recastMesh) const
void AsyncNavMeshUpdater::writeDebugFiles(const Job& job, const RecastMesh* recastMesh) const
{
std::string revision;
std::string recastMeshRevision;
@ -157,8 +168,8 @@ namespace DetourNavigator
if (mSettings.get().mEnableNavMeshFileNameRevision)
navMeshRevision = revision;
}
if (mSettings.get().mEnableWriteRecastMeshToFile)
writeToFile(recastMesh, mSettings.get().mRecastMeshPathPrefix, recastMeshRevision);
if (recastMesh && mSettings.get().mEnableWriteRecastMeshToFile)
writeToFile(*recastMesh, mSettings.get().mRecastMeshPathPrefix, recastMeshRevision);
if (mSettings.get().mEnableWriteNavMeshToFile)
writeToFile(*job.mNavMeshCacheItem->mValue.lock(), mSettings.get().mNavMeshPathPrefix, navMeshRevision);
}
@ -175,4 +186,16 @@ namespace DetourNavigator
if (!mFirstStart)
mFirstStart = value;
}
TilePosition AsyncNavMeshUpdater::getPlayerTile()
{
const std::lock_guard<std::mutex> lock(mPlayerTileMutex);
return mPlayerTile;
}
void AsyncNavMeshUpdater::setPlayerTile(const TilePosition& value)
{
const std::lock_guard<std::mutex> lock(mPlayerTileMutex);
mPlayerTile = value;
}
}

View file

@ -56,6 +56,9 @@ namespace DetourNavigator
std::condition_variable mHasJob;
std::condition_variable mDone;
Jobs mJobs;
std::map<osg::Vec3f, std::set<TilePosition>> mPushed;
std::mutex mPlayerTileMutex;
TilePosition mPlayerTile;
std::mutex mFirstStartMutex;
boost::optional<std::chrono::steady_clock::time_point> mFirstStart;
std::thread mThread;
@ -68,11 +71,15 @@ namespace DetourNavigator
void notifyHasJob();
void writeDebugFiles(const Job& job, const RecastMesh& recastMesh) const;
void writeDebugFiles(const Job& job, const RecastMesh* recastMesh) const;
std::chrono::steady_clock::time_point getFirstStart();
void setFirstStart(const std::chrono::steady_clock::time_point& value);
TilePosition getPlayerTile();
void setPlayerTile(const TilePosition& value);
};
}

View file

@ -3,6 +3,7 @@
#include "settings.hpp"
#include "settingsutils.hpp"
#include "tileposition.hpp"
#include <BulletCollision/CollisionShapes/btCollisionShape.h>

View file

@ -270,8 +270,8 @@ namespace DetourNavigator
return navMesh;
}
UpdateNavMeshStatus updateNavMesh(const osg::Vec3f& agentHalfExtents,
const RecastMesh* recastMesh, const TilePosition& changedTile, const Settings& settings,
UpdateNavMeshStatus updateNavMesh(const osg::Vec3f& agentHalfExtents, const RecastMesh* recastMesh,
const TilePosition& changedTile, const TilePosition& playerTile, const Settings& settings,
NavMeshCacheItem& navMeshCacheItem)
{
log("update NavMesh with mutiple tiles:",
@ -281,7 +281,9 @@ namespace DetourNavigator
getMaxClimb(settings),
" agentRadius=", std::setprecision(std::numeric_limits<float>::max_exponent10),
getRadius(settings, agentHalfExtents),
" changedTile=", changedTile);
" changedTile=", changedTile,
" playerTile=", playerTile,
" changedTileDistance=", getDistance(changedTile, playerTile));
auto& navMesh = navMeshCacheItem.mValue;
const auto& params = *navMesh.lock()->getParams();
@ -315,6 +317,13 @@ namespace DetourNavigator
return makeUpdateNavMeshStatus(removed, false);
}
const auto maxTiles = navMesh.lock()->getParams()->maxTiles;
if (!shouldAddTile(changedTile, playerTile, maxTiles))
{
log("ignore add tile: too far from player");
return makeUpdateNavMeshStatus(removed, false);
}
const auto tileBounds = makeTileBounds(settings, changedTile);
const osg::Vec3f tileBorderMin(tileBounds.mMin.x(), boundsMin.y() - 1, tileBounds.mMin.y());
const osg::Vec3f tileBorderMax(tileBounds.mMax.x(), boundsMax.y() + 1, tileBounds.mMax.y());

View file

@ -29,10 +29,27 @@ namespace DetourNavigator
replaced
};
inline float getLength(const osg::Vec2i& value)
{
return std::sqrt(float(osg::square(value.x()) + osg::square(value.y())));
}
inline float getDistance(const TilePosition& lhs, const TilePosition& rhs)
{
return getLength(lhs - rhs);
}
inline bool shouldAddTile(const TilePosition& changedTile, const TilePosition& playerTile, int maxTiles)
{
const auto expectedTilesCount = std::ceil(osg::PI * osg::square(getDistance(changedTile, playerTile)));
return expectedTilesCount * 3 <= maxTiles;
}
NavMeshPtr makeEmptyNavMesh(const Settings& settings);
UpdateNavMeshStatus updateNavMesh(const osg::Vec3f& agentHalfExtents, const RecastMesh* recastMesh,
const TilePosition& changedTile, const Settings& settings, NavMeshCacheItem& navMeshCacheItem);
const TilePosition& changedTile, const TilePosition& playerTile, const Settings& settings,
NavMeshCacheItem& navMeshCacheItem);
}
#endif

View file

@ -56,17 +56,45 @@ namespace DetourNavigator
void NavMeshManager::update(osg::Vec3f playerPosition, const osg::Vec3f& agentHalfExtents)
{
playerPosition *= mSettings.mRecastScaleFactor;
std::swap(playerPosition.y(), playerPosition.z());
const auto playerTile = getTilePosition(mSettings, playerPosition);
if (mLastRecastMeshManagerRevision >= mRecastMeshManager.getRevision() && mPlayerTile
&& *mPlayerTile == playerTile)
return;
mLastRecastMeshManagerRevision = mRecastMeshManager.getRevision();
mPlayerTile = playerTile;
std::set<TilePosition> tilesToPost;
const auto& cached = getCached(agentHalfExtents);
const auto changedTiles = mChangedTiles.find(agentHalfExtents);
if (changedTiles != mChangedTiles.end())
{
playerPosition *= mSettings.mRecastScaleFactor;
std::swap(playerPosition.y(), playerPosition.z());
mAsyncNavMeshUpdater.post(agentHalfExtents, cached, getTilePosition(mSettings, playerPosition),
changedTiles->second);
log("cache update posted for agent=", agentHalfExtents, " changedTiles=", changedTiles->second.size());
mChangedTiles.erase(changedTiles);
const auto locked = cached->mValue.lock();
if (changedTiles != mChangedTiles.end())
{
for (const auto& tile : changedTiles->second)
if (locked->getTileAt(tile.x(), tile.y(), 0))
tilesToPost.insert(tile);
for (const auto& tile : tilesToPost)
changedTiles->second.erase(tile);
if (changedTiles->second.empty())
mChangedTiles.erase(changedTiles);
}
const auto maxTiles = locked->getParams()->maxTiles;
mRecastMeshManager.forEachTilePosition([&] (const TilePosition& tile)
{
if (tilesToPost.count(tile))
return;
const auto shouldAdd = shouldAddTile(tile, playerTile, maxTiles);
const auto presentInNavMesh = bool(locked->getTileAt(tile.x(), tile.y(), 0));
if ((shouldAdd && !presentInNavMesh) || (!shouldAdd && presentInNavMesh))
tilesToPost.insert(tile);
});
}
mAsyncNavMeshUpdater.post(agentHalfExtents, cached, playerTile, tilesToPost);
log("cache update posted for agent=", agentHalfExtents,
" playerTile=", *mPlayerTile,
" recastMeshManagerRevision=", mLastRecastMeshManagerRevision,
" changedTiles=", changedTiles->second.size());
}
void NavMeshManager::wait()

View file

@ -46,6 +46,8 @@ namespace DetourNavigator
std::map<osg::Vec3f, std::set<TilePosition>> mChangedTiles;
AsyncNavMeshUpdater mAsyncNavMeshUpdater;
std::size_t mGenerationCounter = 0;
boost::optional<TilePosition> mPlayerTile;
std::size_t mLastRecastMeshManagerRevision = 0;
void addChangedTiles(const btCollisionShape& shape, const btTransform& transform);

View file

@ -6,6 +6,8 @@
#include "tileposition.hpp"
#include "tilebounds.hpp"
#include <osg/Vec2f>
#include <osg/Vec2i>
#include <osg/Vec3f>
#include <utility>

View file

@ -35,6 +35,8 @@ namespace DetourNavigator
result = true;
}
});
if (result)
++mRevision;
return result;
}
@ -57,6 +59,8 @@ namespace DetourNavigator
if (tileResult && !result)
result = tileResult;
}
if (result)
++mRevision;
return result;
}
@ -68,4 +72,15 @@ namespace DetourNavigator
return nullptr;
return it->second.getMesh();
}
bool TileCachedRecastMeshManager::hasTile(const TilePosition& tilePosition)
{
const std::lock_guard<std::mutex> lock(mTilesMutex);
return mTiles.count(tilePosition);
}
std::size_t TileCachedRecastMeshManager::getRevision() const
{
return mRevision;
}
}

View file

@ -20,11 +20,24 @@ namespace DetourNavigator
std::shared_ptr<RecastMesh> getMesh(const TilePosition& tilePosition);
bool hasTile(const TilePosition& tilePosition);
template <class Function>
void forEachTilePosition(Function&& function)
{
const std::lock_guard<std::mutex> lock(mTilesMutex);
for (const auto& tile : mTiles)
function(tile.first);
}
std::size_t getRevision() const;
private:
const Settings& mSettings;
std::mutex mTilesMutex;
std::map<TilePosition, CachedRecastMeshManager> mTiles;
std::unordered_map<std::size_t, std::vector<TilePosition>> mObjectsTilesPositions;
std::size_t mRevision = 0;
};
}