mirror of
https://github.com/OpenMW/openmw.git
synced 2025-02-06 09:45:33 +00:00
Split RecastMesh into tiles
This commit is contained in:
parent
dbb1d99bff
commit
d2fd9abd51
19 changed files with 328 additions and 88 deletions
|
@ -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),
|
||||
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,
|
||||
|
@ -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),
|
||||
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>({
|
||||
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;
|
||||
|
|
|
@ -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,7 +31,7 @@ namespace DetourNavigator
|
|||
|
||||
NavMeshPtr makeEmptyNavMesh(const Settings& settings);
|
||||
|
||||
UpdateNavMeshStatus updateNavMesh(const osg::Vec3f& agentHalfExtents, const RecastMesh& recastMesh,
|
||||
UpdateNavMeshStatus updateNavMesh(const osg::Vec3f& agentHalfExtents, const RecastMesh* recastMesh,
|
||||
const TilePosition& changedTile, const Settings& settings, NavMeshCacheItem& navMeshCacheItem);
|
||||
}
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
71
components/detournavigator/tilecachedrecastmeshmanager.cpp
Normal file
71
components/detournavigator/tilecachedrecastmeshmanager.cpp
Normal file
|
@ -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();
|
||||
}
|
||||
}
|
31
components/detournavigator/tilecachedrecastmeshmanager.hpp
Normal file
31
components/detournavigator/tilecachedrecastmeshmanager.hpp
Normal file
|
@ -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…
Reference in a new issue