Split RecastMesh into tiles

pull/541/head
elsid 7 years ago
parent dbb1d99bff
commit d2fd9abd51
No known key found for this signature in database
GPG Key ID: B845CB9FEE18AB40

@ -21,19 +21,23 @@ namespace
struct DetourNavigatorRecastMeshBuilderTest : Test
{
Settings mSettings;
RecastMeshBuilder mBuilder;
TileBounds mBounds;
DetourNavigatorRecastMeshBuilderTest()
: mBuilder(mSettings)
{
mSettings.mRecastScaleFactor = 1.0f;
mSettings.mTrianglesPerChunk = 256;
mBounds.mMin = osg::Vec2f(-std::numeric_limits<float>::max() * std::numeric_limits<float>::epsilon(),
-std::numeric_limits<float>::max() * std::numeric_limits<float>::epsilon());
mBounds.mMax = osg::Vec2f(std::numeric_limits<float>::max() * std::numeric_limits<float>::epsilon(),
std::numeric_limits<float>::max() * std::numeric_limits<float>::epsilon());
}
};
TEST_F(DetourNavigatorRecastMeshBuilderTest, create_for_empty_should_return_empty)
{
const auto recastMesh = mBuilder.create();
RecastMeshBuilder builder(mSettings, mBounds);
const auto recastMesh = builder.create();
EXPECT_EQ(recastMesh->getVertices(), std::vector<float>());
EXPECT_EQ(recastMesh->getIndices(), std::vector<int>());
}
@ -43,8 +47,9 @@ namespace
btTriangleMesh mesh;
mesh.addTriangle(btVector3(-1, -1, 0), btVector3(-1, 1, 0), btVector3(1, -1, 0));
btBvhTriangleMeshShape shape(&mesh, true);
mBuilder.addObject(static_cast<const btCollisionShape&>(shape), btTransform::getIdentity());
const auto recastMesh = mBuilder.create();
RecastMeshBuilder builder(mSettings, mBounds);
builder.addObject(static_cast<const btCollisionShape&>(shape), btTransform::getIdentity());
const auto recastMesh = builder.create();
EXPECT_EQ(recastMesh->getVertices(), std::vector<float>({
1, 0, -1,
-1, 0, 1,
@ -58,9 +63,10 @@ namespace
btTriangleMesh mesh;
mesh.addTriangle(btVector3(-1, -1, 0), btVector3(-1, 1, 0), btVector3(1, -1, 0));
btBvhTriangleMeshShape shape(&mesh, true);
mBuilder.addObject(static_cast<const btCollisionShape&>(shape),
RecastMeshBuilder builder(mSettings, mBounds);
builder.addObject(static_cast<const btCollisionShape&>(shape),
btTransform(btMatrix3x3::getIdentity().scaled(btVector3(1, 2, 3)), btVector3(1, 2, 3)));
const auto recastMesh = mBuilder.create();
const auto recastMesh = builder.create();
EXPECT_EQ(recastMesh->getVertices(), std::vector<float>({
2, 3, 0,
0, 3, 4,
@ -73,8 +79,9 @@ namespace
{
const std::array<btScalar, 4> heightfieldData {{0, 0, 0, 0}};
btHeightfieldTerrainShape shape(2, 2, heightfieldData.data(), 1, 0, 0, 2, PHY_FLOAT, false);
mBuilder.addObject(static_cast<const btCollisionShape&>(shape), btTransform::getIdentity());
const auto recastMesh = mBuilder.create();
RecastMeshBuilder builder(mSettings, mBounds);
builder.addObject(static_cast<const btCollisionShape&>(shape), btTransform::getIdentity());
const auto recastMesh = builder.create();
EXPECT_EQ(recastMesh->getVertices(), std::vector<float>({
-0.5, 0, -0.5,
-0.5, 0, 0.5,
@ -89,8 +96,9 @@ namespace
TEST_F(DetourNavigatorRecastMeshBuilderTest, add_box_shape_should_produce_12_triangles)
{
btBoxShape shape(btVector3(1, 1, 2));
mBuilder.addObject(static_cast<const btCollisionShape&>(shape), btTransform::getIdentity());
const auto recastMesh = mBuilder.create();
RecastMeshBuilder builder(mSettings, mBounds);
builder.addObject(static_cast<const btCollisionShape&>(shape), btTransform::getIdentity());
const auto recastMesh = builder.create();
EXPECT_EQ(recastMesh->getVertices(), std::vector<float>({
1, 2, 1,
-1, 2, 1,
@ -130,8 +138,9 @@ namespace
shape.addChildShape(btTransform::getIdentity(), &triangle1);
shape.addChildShape(btTransform::getIdentity(), &box);
shape.addChildShape(btTransform::getIdentity(), &triangle2);
mBuilder.addObject(static_cast<const btCollisionShape&>(shape), btTransform::getIdentity());
const auto recastMesh = mBuilder.create();
RecastMeshBuilder builder(mSettings, mBounds);
builder.addObject(static_cast<const btCollisionShape&>(shape), btTransform::getIdentity());
const auto recastMesh = builder.create();
EXPECT_EQ(recastMesh->getVertices(), std::vector<float>({
1, 0, -1,
-1, 0, 1,
@ -173,9 +182,10 @@ namespace
btBvhTriangleMeshShape triangle(&mesh, true);
btCompoundShape shape;
shape.addChildShape(btTransform::getIdentity(), &triangle);
mBuilder.addObject(static_cast<const btCollisionShape&>(shape),
btTransform(btMatrix3x3::getIdentity().scaled(btVector3(1, 2, 3)), btVector3(1, 2, 3)));
const auto recastMesh = mBuilder.create();
RecastMeshBuilder builder(mSettings, mBounds);
builder.addObject(static_cast<const btCollisionShape&>(shape),
btTransform(btMatrix3x3::getIdentity().scaled(btVector3(1, 2, 3)), btVector3(1, 2, 3)));
const auto recastMesh = builder.create();
EXPECT_EQ(recastMesh->getVertices(), std::vector<float>({
2, 3, 0,
0, 3, 4,
@ -192,9 +202,10 @@ namespace
btCompoundShape shape;
shape.addChildShape(btTransform(btMatrix3x3::getIdentity().scaled(btVector3(1, 2, 3)), btVector3(1, 2, 3)),
&triangle);
mBuilder.addObject(static_cast<const btCollisionShape&>(shape),
btTransform(btMatrix3x3::getIdentity().scaled(btVector3(1, 2, 3)), btVector3(1, 2, 3)));
const auto recastMesh = mBuilder.create();
RecastMeshBuilder builder(mSettings, mBounds);
builder.addObject(static_cast<const btCollisionShape&>(shape),
btTransform(btMatrix3x3::getIdentity().scaled(btVector3(1, 2, 3)), btVector3(1, 2, 3)));
const auto recastMesh = builder.create();
EXPECT_EQ(recastMesh->getVertices(), std::vector<float>({
3, 12, 2,
1, 12, 10,
@ -202,4 +213,104 @@ namespace
}));
EXPECT_EQ(recastMesh->getIndices(), std::vector<int>({0, 1, 2}));
}
TEST_F(DetourNavigatorRecastMeshBuilderTest, without_bounds_add_transformed_compound_shape_with_transformed_bhv_triangle_shape_should_not_filter_by_bounds)
{
btTriangleMesh mesh;
mesh.addTriangle(btVector3(-1, -1, 0), btVector3(-1, 1, 0), btVector3(1, -1, 0));
mesh.addTriangle(btVector3(-3, -3, 0), btVector3(-3, -2, 0), btVector3(-2, -3, 0));
btBvhTriangleMeshShape shape(&mesh, true);
RecastMeshBuilder builder(mSettings, mBounds);
builder.addObject(static_cast<const btCollisionShape&>(shape), btTransform::getIdentity());
const auto recastMesh = builder.create();
EXPECT_EQ(recastMesh->getVertices(), std::vector<float>({
1, 0, -1,
-1, 0, 1,
-1, 0, -1,
-2, 0, -3,
-3, 0, -2,
-3, 0, -3,
}));
EXPECT_EQ(recastMesh->getIndices(), std::vector<int>({0, 1, 2, 3, 4, 5}));
}
TEST_F(DetourNavigatorRecastMeshBuilderTest, with_bounds_add_transformed_compound_shape_with_transformed_bhv_triangle_shape_should_filter_by_bounds)
{
mSettings.mRecastScaleFactor = 0.1f;
mBounds.mMin = osg::Vec2f(-3, -3) * mSettings.mRecastScaleFactor;
mBounds.mMax = osg::Vec2f(-2, -2) * mSettings.mRecastScaleFactor;
btTriangleMesh mesh;
mesh.addTriangle(btVector3(-1, -1, 0), btVector3(-1, 1, 0), btVector3(1, -1, 0));
mesh.addTriangle(btVector3(-3, -3, 0), btVector3(-3, -2, 0), btVector3(-2, -3, 0));
btBvhTriangleMeshShape shape(&mesh, true);
RecastMeshBuilder builder(mSettings, mBounds);
builder.addObject(static_cast<const btCollisionShape&>(shape), btTransform::getIdentity());
const auto recastMesh = builder.create();
EXPECT_EQ(recastMesh->getVertices(), std::vector<float>({
-0.2f, 0, -0.3f,
-0.3f, 0, -0.2f,
-0.3f, 0, -0.3f,
}));
EXPECT_EQ(recastMesh->getIndices(), std::vector<int>({0, 1, 2}));
}
TEST_F(DetourNavigatorRecastMeshBuilderTest, with_bounds_add_rotated_by_x_bhv_triangle_shape_should_filter_by_bounds)
{
mBounds.mMin = osg::Vec2f(-5, -5);
mBounds.mMax = osg::Vec2f(5, -3);
btTriangleMesh mesh;
mesh.addTriangle(btVector3(0, -1, -1), btVector3(0, -1, -1), btVector3(0, 1, -1));
mesh.addTriangle(btVector3(0, -3, -3), btVector3(0, -3, -2), btVector3(0, -2, -3));
btBvhTriangleMeshShape shape(&mesh, true);
RecastMeshBuilder builder(mSettings, mBounds);
builder.addObject(static_cast<const btCollisionShape&>(shape),
btTransform(btQuaternion(btVector3(1, 0, 0), static_cast<btScalar>(-osg::PI_4))));
const auto recastMesh = builder.create();
EXPECT_EQ(recastMesh->getVertices(), std::vector<float>({
0, -0.70710659027099609375, -3.535533905029296875,
0, 0.707107067108154296875, -3.535533905029296875,
0, 2.384185791015625e-07, -4.24264049530029296875,
}));
EXPECT_EQ(recastMesh->getIndices(), std::vector<int>({0, 1, 2}));
}
TEST_F(DetourNavigatorRecastMeshBuilderTest, with_bounds_add_rotated_by_y_bhv_triangle_shape_should_filter_by_bounds)
{
mBounds.mMin = osg::Vec2f(-5, -5);
mBounds.mMax = osg::Vec2f(-3, 5);
btTriangleMesh mesh;
mesh.addTriangle(btVector3(-1, 0, -1), btVector3(-1, 0, 1), btVector3(1, 0, -1));
mesh.addTriangle(btVector3(-3, 0, -3), btVector3(-3, 0, -2), btVector3(-2, 0, -3));
btBvhTriangleMeshShape shape(&mesh, true);
RecastMeshBuilder builder(mSettings, mBounds);
builder.addObject(static_cast<const btCollisionShape&>(shape),
btTransform(btQuaternion(btVector3(0, 1, 0), static_cast<btScalar>(osg::PI_4))));
const auto recastMesh = builder.create();
EXPECT_EQ(recastMesh->getVertices(), std::vector<float>({
-3.535533905029296875, -0.70710659027099609375, 0,
-3.535533905029296875, 0.707107067108154296875, 0,
-4.24264049530029296875, 2.384185791015625e-07, 0,
}));
EXPECT_EQ(recastMesh->getIndices(), std::vector<int>({0, 1, 2}));
}
TEST_F(DetourNavigatorRecastMeshBuilderTest, with_bounds_add_rotated_by_z_bhv_triangle_shape_should_filter_by_bounds)
{
mBounds.mMin = osg::Vec2f(-5, -5);
mBounds.mMax = osg::Vec2f(-1, -1);
btTriangleMesh mesh;
mesh.addTriangle(btVector3(-1, -1, 0), btVector3(-1, 1, 0), btVector3(1, -1, 0));
mesh.addTriangle(btVector3(-3, -3, 0), btVector3(-3, -2, 0), btVector3(-2, -3, 0));
btBvhTriangleMeshShape shape(&mesh, true);
RecastMeshBuilder builder(mSettings, mBounds);
builder.addObject(static_cast<const btCollisionShape&>(shape),
btTransform(btQuaternion(btVector3(0, 0, 1), static_cast<btScalar>(osg::PI_4))));
const auto recastMesh = builder.create();
EXPECT_EQ(recastMesh->getVertices(), std::vector<float>({
0.707107067108154296875, 0, -3.535533905029296875,
-0.70710659027099609375, 0, -3.535533905029296875,
2.384185791015625e-07, 0, -4.24264049530029296875,
}));
EXPECT_EQ(recastMesh->getIndices(), std::vector<int>({0, 1, 2}));
}
}

@ -168,6 +168,7 @@ add_component_dir(detournavigator
asyncnavmeshupdater
chunkytrimesh
recastmesh
tilecachedrecastmeshmanager
)
set (ESM_UI ${CMAKE_SOURCE_DIR}/files/ui/contentselector.ui

@ -40,8 +40,9 @@ namespace DetourNavigator
return stream << "unknown";
}
AsyncNavMeshUpdater::AsyncNavMeshUpdater(const Settings& settings)
: mSettings(std::cref(settings))
AsyncNavMeshUpdater::AsyncNavMeshUpdater(const Settings& settings, TileCachedRecastMeshManager& recastMeshManager)
: mSettings(settings)
, mRecastMeshManager(recastMeshManager)
, mShouldStop()
, mThread([&] { process(); })
{
@ -57,11 +58,11 @@ namespace DetourNavigator
mThread.join();
}
void AsyncNavMeshUpdater::post(const osg::Vec3f& agentHalfExtents, const std::shared_ptr<RecastMesh>& recastMesh,
void AsyncNavMeshUpdater::post(const osg::Vec3f& agentHalfExtents,
const std::shared_ptr<NavMeshCacheItem>& navMeshCacheItem, const TilePosition& playerTile,
const std::set<TilePosition>& changedTiles)
{
setRecastMesh(recastMesh);
log("post jobs playerTile=", playerTile);
if (changedTiles.empty())
return;
@ -107,9 +108,9 @@ namespace DetourNavigator
setFirstStart(start);
const auto recastMesh = getRecastMesh();
const auto recastMesh = mRecastMeshManager.get().getMesh(job.mChangedTile);
const auto status = updateNavMesh(job.mAgentHalfExtents, *recastMesh, job.mChangedTile, mSettings,
const auto status = updateNavMesh(job.mAgentHalfExtents, recastMesh.get(), job.mChangedTile, mSettings,
*job.mNavMeshCacheItem);
const auto finish = std::chrono::steady_clock::now();
@ -162,18 +163,6 @@ namespace DetourNavigator
writeToFile(*job.mNavMeshCacheItem->mValue.lock(), mSettings.get().mNavMeshPathPrefix, navMeshRevision);
}
std::shared_ptr<RecastMesh> AsyncNavMeshUpdater::getRecastMesh()
{
const std::lock_guard<std::mutex> lock(mRecastMeshMutex);
return mRecastMesh;
}
void AsyncNavMeshUpdater::setRecastMesh(const std::shared_ptr<RecastMesh>& value)
{
const std::lock_guard<std::mutex> lock(mRecastMeshMutex);
mRecastMesh = value;
}
std::chrono::steady_clock::time_point AsyncNavMeshUpdater::getFirstStart()
{
const std::lock_guard<std::mutex> lock(mFirstStartMutex);

@ -2,7 +2,7 @@
#define OPENMW_COMPONENTS_DETOURNAVIGATOR_ASYNCNAVMESHUPDATER_H
#include "navmeshcacheitem.hpp"
#include "recastmesh.hpp"
#include "tilecachedrecastmeshmanager.hpp"
#include "tileposition.hpp"
#include <osg/Vec3f>
@ -25,12 +25,11 @@ namespace DetourNavigator
class AsyncNavMeshUpdater
{
public:
AsyncNavMeshUpdater(const Settings& settings);
AsyncNavMeshUpdater(const Settings& settings, TileCachedRecastMeshManager& recastMeshManager);
~AsyncNavMeshUpdater();
void post(const osg::Vec3f& agentHalfExtents, const std::shared_ptr<RecastMesh>& recastMesh,
const std::shared_ptr<NavMeshCacheItem>& navMeshCacheItem, const TilePosition& playerTile,
const std::set<TilePosition>& changedTiles);
void post(const osg::Vec3f& agentHalfExtents, const std::shared_ptr<NavMeshCacheItem>& mNavMeshCacheItem,
const TilePosition& playerTile, const std::set<TilePosition>& changedTiles);
void wait();
@ -51,13 +50,12 @@ namespace DetourNavigator
using Jobs = std::priority_queue<Job, std::deque<Job>>;
std::reference_wrapper<const Settings> mSettings;
std::reference_wrapper<TileCachedRecastMeshManager> mRecastMeshManager;
std::atomic_bool mShouldStop;
std::mutex mMutex;
std::condition_variable mHasJob;
std::condition_variable mDone;
Jobs mJobs;
std::mutex mRecastMeshMutex;
std::shared_ptr<RecastMesh> mRecastMesh;
std::mutex mFirstStartMutex;
boost::optional<std::chrono::steady_clock::time_point> mFirstStart;
std::thread mThread;
@ -72,10 +70,6 @@ namespace DetourNavigator
void writeDebugFiles(const Job& job, const RecastMesh& recastMesh) const;
std::shared_ptr<RecastMesh> getRecastMesh();
void setRecastMesh(const std::shared_ptr<RecastMesh>& value);
std::chrono::steady_clock::time_point getFirstStart();
void setFirstStart(const std::chrono::steady_clock::time_point& value);

@ -3,9 +3,10 @@
namespace DetourNavigator
{
CachedRecastMeshManager::CachedRecastMeshManager(const Settings& settings)
: mImpl(settings)
{}
CachedRecastMeshManager::CachedRecastMeshManager(const Settings& settings, const TileBounds& bounds)
: mImpl(settings, bounds)
{
}
bool CachedRecastMeshManager::addObject(std::size_t id, const btCollisionShape& shape, const btTransform& transform)
{
@ -29,4 +30,9 @@ namespace DetourNavigator
mCached = mImpl.getMesh();
return mCached;
}
bool CachedRecastMeshManager::isEmpty() const
{
return mImpl.isEmpty();
}
}

@ -10,7 +10,7 @@ namespace DetourNavigator
class CachedRecastMeshManager
{
public:
CachedRecastMeshManager(const Settings& settings);
CachedRecastMeshManager(const Settings& settings, const TileBounds& bounds);
bool addObject(std::size_t id, const btCollisionShape& shape, const btTransform& transform);
@ -18,6 +18,8 @@ namespace DetourNavigator
std::shared_ptr<RecastMesh> getMesh();
bool isEmpty() const;
private:
RecastMeshManager mImpl;
std::shared_ptr<RecastMesh> mCached;

@ -17,7 +17,7 @@ namespace DetourNavigator
template <class Callback>
void getTilesPositions(const osg::Vec3f& aabbMin, const osg::Vec3f& aabbMax,
const Settings& settings, Callback&& callback)
const Settings& settings, Callback&& callback)
{
auto min = toNavMeshCoordinates(settings, aabbMin);
auto max = toNavMeshCoordinates(settings, aabbMax);
@ -42,7 +42,7 @@ namespace DetourNavigator
template <class Callback>
void getTilesPositions(const btCollisionShape& shape, const btTransform& transform,
const Settings& settings, Callback&& callback)
const Settings& settings, Callback&& callback)
{
btVector3 aabbMin;
btVector3 aabbMax;

@ -7,6 +7,7 @@
#include "settings.hpp"
#include "settingsutils.hpp"
#include "sharednavmesh.hpp"
#include "settingsutils.hpp"
#include <DetourNavMesh.h>
#include <DetourNavMeshBuilder.h>
@ -269,8 +270,9 @@ namespace DetourNavigator
return navMesh;
}
UpdateNavMeshStatus updateNavMesh(const osg::Vec3f& agentHalfExtents, const RecastMesh& recastMesh,
const TilePosition& changedTile, const Settings& settings, NavMeshCacheItem& navMeshCacheItem)
UpdateNavMeshStatus updateNavMesh(const osg::Vec3f& agentHalfExtents,
const RecastMesh* recastMesh, const TilePosition& changedTile, const Settings& settings,
NavMeshCacheItem& navMeshCacheItem)
{
log("update NavMesh with mutiple tiles:",
" agentHeight=", std::setprecision(std::numeric_limits<float>::max_exponent10),
@ -298,8 +300,14 @@ namespace DetourNavigator
incRev.mNavMeshChanged = removed;
const auto& boundsMin = recastMesh.getBoundsMin();
const auto& boundsMax = recastMesh.getBoundsMax();
if (!recastMesh)
{
log("ignore add tile: recastMesh is null");
return makeUpdateNavMeshStatus(removed, false);
}
const auto& boundsMin = recastMesh->getBoundsMin();
const auto& boundsMax = recastMesh->getBoundsMax();
if (boundsMin == boundsMax)
{
@ -311,7 +319,7 @@ namespace DetourNavigator
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());
auto navMeshData = makeNavMeshTileData(agentHalfExtents, recastMesh, x, y,
auto navMeshData = makeNavMeshTileData(agentHalfExtents, *recastMesh, x, y,
tileBorderMin, tileBorderMax, settings);
if (!navMeshData.mValue)

@ -4,6 +4,7 @@
#include "settings.hpp"
#include "navmeshcacheitem.hpp"
#include "tileposition.hpp"
#include "tilebounds.hpp"
#include <osg/Vec3f>
@ -30,8 +31,8 @@ namespace DetourNavigator
NavMeshPtr makeEmptyNavMesh(const Settings& settings);
UpdateNavMeshStatus updateNavMesh(const osg::Vec3f& agentHalfExtents, const RecastMesh& recastMesh,
const TilePosition& changedTile, const Settings& settings, NavMeshCacheItem& navMeshCacheItem);
UpdateNavMeshStatus updateNavMesh(const osg::Vec3f& agentHalfExtents, const RecastMesh* recastMesh,
const TilePosition& changedTile, const Settings& settings, NavMeshCacheItem& navMeshCacheItem);
}
#endif

@ -11,11 +11,10 @@ namespace DetourNavigator
{
SharedNavMesh mValue;
std::size_t mGeneration;
std::size_t mRecastMeshRevision;
std::atomic_size_t mNavMeshRevision;
NavMeshCacheItem(const NavMeshPtr& value, std::size_t generation, std::size_t revision)
: mValue(value), mGeneration(generation), mRecastMeshRevision(revision), mNavMeshRevision(0) {}
NavMeshCacheItem(const NavMeshPtr& value, std::size_t generation)
: mValue(value), mGeneration(generation), mNavMeshRevision(0) {}
};
}

@ -3,6 +3,7 @@
#include "exceptions.hpp"
#include "gettilespositions.hpp"
#include "makenavmesh.hpp"
#include "navmeshcacheitem.hpp"
#include "settings.hpp"
#include "sharednavmesh.hpp"
@ -17,14 +18,14 @@ namespace DetourNavigator
NavMeshManager::NavMeshManager(const Settings& settings)
: mSettings(settings)
, mRecastMeshManager(settings)
, mAsyncNavMeshUpdater(settings)
{}
, mAsyncNavMeshUpdater(settings, mRecastMeshManager)
{
}
bool NavMeshManager::addObject(std::size_t id, const btCollisionShape& shape, const btTransform& transform)
{
if (!mRecastMeshManager.addObject(id, shape, transform))
return false;
++mRevision;
addChangedTiles(shape, transform);
return true;
}
@ -34,7 +35,6 @@ namespace DetourNavigator
const auto object = mRecastMeshManager.removeObject(id);
if (!object)
return false;
++mRevision;
addChangedTiles(*object->mShape, object->mTransform);
return true;
}
@ -45,8 +45,7 @@ namespace DetourNavigator
if (cached != mCache.end())
return;
mCache.insert(std::make_pair(agentHalfExtents,
std::make_shared<NavMeshCacheItem>(makeEmptyNavMesh(mSettings), ++mGenerationCounter, mRevision))
);
std::make_shared<NavMeshCacheItem>(makeEmptyNavMesh(mSettings), ++mGenerationCounter)));
log("cache add for agent=", agentHalfExtents);
}
@ -58,18 +57,15 @@ namespace DetourNavigator
void NavMeshManager::update(osg::Vec3f playerPosition, const osg::Vec3f& agentHalfExtents)
{
const auto& cached = getCached(agentHalfExtents);
if (cached->mRecastMeshRevision >= mRevision)
return;
cached->mRecastMeshRevision = mRevision;
const auto changedTiles = mChangedTiles.find(agentHalfExtents);
if (changedTiles != mChangedTiles.end())
{
playerPosition *= mSettings.mRecastScaleFactor;
std::swap(playerPosition.y(), playerPosition.z());
mAsyncNavMeshUpdater.post(agentHalfExtents, mRecastMeshManager.getMesh(), cached,
getTilePosition(mSettings, playerPosition), changedTiles->second);
mAsyncNavMeshUpdater.post(agentHalfExtents, cached, getTilePosition(mSettings, playerPosition),
changedTiles->second);
log("cache update posted for agent=", agentHalfExtents, " changedTiles=", changedTiles->second.size());
mChangedTiles.erase(changedTiles);
log("cache update posted for agent=", agentHalfExtents);
}
}

@ -40,9 +40,8 @@ namespace DetourNavigator
std::map<osg::Vec3f, std::shared_ptr<NavMeshCacheItem>> getNavMeshes() const;
private:
std::size_t mRevision = 0;
const Settings& mSettings;
CachedRecastMeshManager mRecastMeshManager;
TileCachedRecastMeshManager mRecastMeshManager;
std::map<osg::Vec3f, std::shared_ptr<NavMeshCacheItem>> mCache;
std::map<osg::Vec3f, std::set<TilePosition>> mChangedTiles;
AsyncNavMeshUpdater mAsyncNavMeshUpdater;

@ -27,9 +27,13 @@ namespace DetourNavigator
{
using BulletHelpers::makeProcessTriangleCallback;
RecastMeshBuilder::RecastMeshBuilder(const Settings& settings)
RecastMeshBuilder::RecastMeshBuilder(const Settings& settings, const TileBounds& bounds)
: mSettings(settings)
{}
, mBounds(bounds)
{
mBounds.mMin /= mSettings.get().mRecastScaleFactor;
mBounds.mMax /= mSettings.get().mRecastScaleFactor;
}
void RecastMeshBuilder::addObject(const btCollisionShape& shape, const btTransform& transform)
{
@ -54,7 +58,7 @@ namespace DetourNavigator
void RecastMeshBuilder::addObject(const btConcaveShape& shape, const btTransform& transform)
{
return addObject(shape, makeProcessTriangleCallback([&] (btVector3* triangle, int, int)
return addObject(shape, transform, makeProcessTriangleCallback([&] (btVector3* triangle, int, int)
{
for (std::size_t i = 3; i > 0; --i)
addTriangleVertex(transform(triangle[i - 1]));
@ -63,7 +67,7 @@ namespace DetourNavigator
void RecastMeshBuilder::addObject(const btHeightfieldTerrainShape& shape, const btTransform& transform)
{
return addObject(shape, makeProcessTriangleCallback([&] (btVector3* triangle, int, int)
return addObject(shape, transform, makeProcessTriangleCallback([&] (btVector3* triangle, int, int)
{
for (std::size_t i = 0; i < 3; ++i)
addTriangleVertex(transform(triangle[i]));
@ -111,11 +115,29 @@ namespace DetourNavigator
mVertices.clear();
}
void RecastMeshBuilder::addObject(const btConcaveShape& shape, btTriangleCallback&& callback)
void RecastMeshBuilder::addObject(const btConcaveShape& shape, const btTransform& transform,
btTriangleCallback&& callback)
{
btVector3 aabbMin;
btVector3 aabbMax;
shape.getAabb(btTransform::getIdentity(), aabbMin, aabbMax);
const btVector3 boundsMinMin(mBounds.mMin.x(), mBounds.mMin.y(), 0);
const btVector3 boundsMinMax(mBounds.mMin.x(), mBounds.mMax.y(), 0);
const btVector3 boundsMaxMin(mBounds.mMax.x(), mBounds.mMin.y(), 0);
const btVector3 boundsMaxMax(mBounds.mMax.x(), mBounds.mMax.y(), 0);
const auto inversedTransform = transform.inverse();
const auto localBoundsMinMin = inversedTransform(boundsMinMin);
const auto localBoundsMinMax = inversedTransform(boundsMinMax);
const auto localBoundsMaxMin = inversedTransform(boundsMaxMin);
const auto localBoundsMaxMax = inversedTransform(boundsMaxMax);
aabbMin.setX(std::min({localBoundsMinMin.x(), localBoundsMinMax.x(),
localBoundsMaxMin.x(), localBoundsMaxMax.x()}));
aabbMin.setY(std::min({localBoundsMinMin.y(), localBoundsMinMax.y(),
localBoundsMaxMin.y(), localBoundsMaxMax.y()}));
aabbMax.setX(std::max({localBoundsMinMin.x(), localBoundsMinMax.x(),
localBoundsMaxMin.x(), localBoundsMaxMax.x()}));
aabbMax.setY(std::max({localBoundsMinMin.y(), localBoundsMinMax.y(),
localBoundsMaxMin.y(), localBoundsMaxMax.y()}));
shape.processAllTriangles(&callback, aabbMin, aabbMax);
}

@ -2,6 +2,7 @@
#define OPENMW_COMPONENTS_DETOURNAVIGATOR_RECASTMESHBUILDER_H
#include "recastmesh.hpp"
#include "tilebounds.hpp"
class btBoxShape;
class btCollisionShape;
@ -17,7 +18,7 @@ namespace DetourNavigator
class RecastMeshBuilder
{
public:
RecastMeshBuilder(const Settings& settings);
RecastMeshBuilder(const Settings& settings, const TileBounds& bounds);
void addObject(const btCollisionShape& shape, const btTransform& transform);
@ -35,10 +36,11 @@ namespace DetourNavigator
private:
std::reference_wrapper<const Settings> mSettings;
TileBounds mBounds;
std::vector<int> mIndices;
std::vector<float> mVertices;
void addObject(const btConcaveShape& shape, btTriangleCallback&& callback);
void addObject(const btConcaveShape& shape, const btTransform& transform, btTriangleCallback&& callback);
void addTriangleVertex(const btVector3& worldPosition);

@ -4,9 +4,9 @@
namespace DetourNavigator
{
RecastMeshManager::RecastMeshManager(const Settings& settings)
RecastMeshManager::RecastMeshManager(const Settings& settings, const TileBounds& bounds)
: mShouldRebuild(false)
, mMeshBuilder(settings)
, mMeshBuilder(settings, bounds)
{
}
@ -35,6 +35,11 @@ namespace DetourNavigator
return mMeshBuilder.create();
}
bool RecastMeshManager::isEmpty() const
{
return mObjects.empty();
}
void RecastMeshManager::rebuild()
{
if (!mShouldRebuild)

@ -22,7 +22,7 @@ namespace DetourNavigator
btTransform mTransform;
};
RecastMeshManager(const Settings& settings);
RecastMeshManager(const Settings& settings, const TileBounds& bounds);
bool addObject(std::size_t id, const btCollisionShape& shape, const btTransform& transform);
@ -30,6 +30,8 @@ namespace DetourNavigator
std::shared_ptr<RecastMesh> getMesh();
bool isEmpty() const;
private:
bool mShouldRebuild;
RecastMeshBuilder mMeshBuilder;

@ -2,6 +2,7 @@
#define OPENMW_COMPONENTS_DETOURNAVIGATOR_SETTINGSUTILS_H
#include "settings.hpp"
#include "tilebounds.hpp"
#include "tileposition.hpp"
#include "tilebounds.hpp"

@ -0,0 +1,71 @@
#include "tilecachedrecastmeshmanager.hpp"
#include "makenavmesh.hpp"
#include "gettilespositions.hpp"
#include "settingsutils.hpp"
namespace DetourNavigator
{
TileCachedRecastMeshManager::TileCachedRecastMeshManager(const Settings& settings)
: mSettings(settings)
{
}
bool TileCachedRecastMeshManager::addObject(std::size_t id, const btCollisionShape& shape,
const btTransform& transform)
{
bool result = false;
auto& tilesPositions = mObjectsTilesPositions[id];
const auto border = getBorderSize(mSettings);
getTilesPositions(shape, transform, mSettings, [&] (const TilePosition& tilePosition)
{
std::unique_lock<std::mutex> lock(mTilesMutex);
auto tile = mTiles.find(tilePosition);
if (tile == mTiles.end())
{
auto tileBounds = makeTileBounds(mSettings, tilePosition);
tileBounds.mMin -= osg::Vec2f(border, border);
tileBounds.mMax += osg::Vec2f(border, border);
tile = mTiles.insert(std::make_pair(tilePosition,
CachedRecastMeshManager(mSettings, tileBounds))).first;
}
if (tile->second.addObject(id, shape, transform))
{
lock.unlock();
tilesPositions.push_back(tilePosition);
result = true;
}
});
return result;
}
boost::optional<RecastMeshManager::Object> TileCachedRecastMeshManager::removeObject(std::size_t id)
{
const auto object = mObjectsTilesPositions.find(id);
if (object == mObjectsTilesPositions.end())
return boost::none;
boost::optional<RecastMeshManager::Object> result;
for (const auto& tilePosition : object->second)
{
std::unique_lock<std::mutex> lock(mTilesMutex);
const auto tile = mTiles.find(tilePosition);
if (tile == mTiles.end())
continue;
const auto tileResult = tile->second.removeObject(id);
if (tile->second.isEmpty())
mTiles.erase(tile);
lock.unlock();
if (tileResult && !result)
result = tileResult;
}
return result;
}
std::shared_ptr<RecastMesh> TileCachedRecastMeshManager::getMesh(const TilePosition& tilePosition)
{
const std::lock_guard<std::mutex> lock(mTilesMutex);
const auto it = mTiles.find(tilePosition);
if (it == mTiles.end())
return nullptr;
return it->second.getMesh();
}
}

@ -0,0 +1,31 @@
#ifndef OPENMW_COMPONENTS_DETOURNAVIGATOR_TILECACHEDRECASTMESHMANAGER_H
#define OPENMW_COMPONENTS_DETOURNAVIGATOR_TILECACHEDRECASTMESHMANAGER_H
#include "cachedrecastmeshmanager.hpp"
#include "tileposition.hpp"
#include <map>
#include <mutex>
namespace DetourNavigator
{
class TileCachedRecastMeshManager
{
public:
TileCachedRecastMeshManager(const Settings& settings);
bool addObject(std::size_t id, const btCollisionShape& shape, const btTransform& transform);
boost::optional<RecastMeshManager::Object> removeObject(std::size_t id);
std::shared_ptr<RecastMesh> getMesh(const TilePosition& tilePosition);
private:
const Settings& mSettings;
std::mutex mTilesMutex;
std::map<TilePosition, CachedRecastMeshManager> mTiles;
std::unordered_map<std::size_t, std::vector<TilePosition>> mObjectsTilesPositions;
};
}
#endif
Loading…
Cancel
Save