mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-19 21:23:52 +00:00
Support water for NavMesh
This commit is contained in:
parent
72f211ef28
commit
c95cea414c
27 changed files with 633 additions and 79 deletions
|
@ -282,6 +282,9 @@ namespace MWWorld
|
|||
mPhysics->remove(ptr);
|
||||
}
|
||||
|
||||
const auto cellX = (*iter)->getCell()->getGridX();
|
||||
const auto cellY = (*iter)->getCell()->getGridY();
|
||||
|
||||
if ((*iter)->getCell()->isExterior())
|
||||
{
|
||||
const ESM::Land* land =
|
||||
|
@ -291,14 +294,15 @@ namespace MWWorld
|
|||
);
|
||||
if (land && land->mDataTypes&ESM::Land::DATA_VHGT)
|
||||
{
|
||||
const auto cellX = (*iter)->getCell()->getGridX();
|
||||
const auto cellY = (*iter)->getCell()->getGridY();
|
||||
if (const auto heightField = mPhysics->getHeightField(cellX, cellY))
|
||||
navigator->removeObject(reinterpret_cast<std::size_t>(heightField));
|
||||
mPhysics->removeHeightField(cellX, cellY);
|
||||
}
|
||||
}
|
||||
|
||||
if ((*iter)->getCell()->hasWater())
|
||||
navigator->removeWater(osg::Vec2i(cellX, cellY));
|
||||
|
||||
navigator->update(player.getRefData().getPosition().asVec3());
|
||||
|
||||
MWBase::Environment::get().getMechanicsManager()->drop (*iter);
|
||||
|
@ -326,11 +330,12 @@ namespace MWWorld
|
|||
|
||||
const auto navigator = MWBase::Environment::get().getWorld()->getNavigator();
|
||||
|
||||
const int cellX = cell->getCell()->getGridX();
|
||||
const int cellY = cell->getCell()->getGridY();
|
||||
|
||||
// Load terrain physics first...
|
||||
if (cell->getCell()->isExterior())
|
||||
{
|
||||
int cellX = cell->getCell()->getGridX();
|
||||
int cellY = cell->getCell()->getGridY();
|
||||
osg::ref_ptr<const ESMTerrain::LandObject> land = mRendering.getLandManager()->getLand(cellX, cellY);
|
||||
const ESM::Land::LandData* data = land ? land->getData(ESM::Land::DATA_VHGT) : 0;
|
||||
if (data)
|
||||
|
@ -368,6 +373,18 @@ namespace MWWorld
|
|||
{
|
||||
mPhysics->enableWater(waterLevel);
|
||||
mRendering.setWaterHeight(waterLevel);
|
||||
|
||||
if (cell->getCell()->isExterior())
|
||||
{
|
||||
if (const auto heightField = mPhysics->getHeightField(cellX, cellY))
|
||||
navigator->addWater(osg::Vec2i(cellX, cellY), ESM::Land::REAL_SIZE,
|
||||
cell->getWaterLevel(), heightField->getCollisionObject()->getWorldTransform());
|
||||
}
|
||||
else
|
||||
{
|
||||
navigator->addWater(osg::Vec2i(cellX, cellY), std::numeric_limits<int>::max(),
|
||||
cell->getWaterLevel(), btTransform::getIdentity());
|
||||
}
|
||||
}
|
||||
else
|
||||
mPhysics->disableWater();
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include <set>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace osg
|
||||
{
|
||||
|
@ -27,6 +28,11 @@ namespace Loading
|
|||
class Listener;
|
||||
}
|
||||
|
||||
namespace DetourNavigator
|
||||
{
|
||||
class Water;
|
||||
}
|
||||
|
||||
namespace MWRender
|
||||
{
|
||||
class SkyManager;
|
||||
|
|
|
@ -168,42 +168,6 @@ namespace MWWorld
|
|||
mLevitationEnabled(true), mGoToJail(false), mDaysInPrison(0),
|
||||
mPlayerTraveling(false), mPlayerInJail(false), mSpellPreloadTimer(0.f)
|
||||
{
|
||||
mPhysics.reset(new MWPhysics::PhysicsSystem(resourceSystem, rootNode));
|
||||
|
||||
DetourNavigator::Settings navigatorSettings;
|
||||
navigatorSettings.mBorderSize = Settings::Manager::getInt("border size", "Navigator");
|
||||
navigatorSettings.mCellHeight = Settings::Manager::getFloat("cell height", "Navigator");
|
||||
navigatorSettings.mCellSize = Settings::Manager::getFloat("cell size", "Navigator");
|
||||
navigatorSettings.mDetailSampleDist = Settings::Manager::getFloat("detail sample dist", "Navigator");
|
||||
navigatorSettings.mDetailSampleMaxError = Settings::Manager::getFloat("detail sample max error", "Navigator");
|
||||
navigatorSettings.mMaxClimb = MWPhysics::sStepSizeUp;
|
||||
navigatorSettings.mMaxSimplificationError = Settings::Manager::getFloat("max simplification error", "Navigator");
|
||||
navigatorSettings.mMaxSlope = MWPhysics::sMaxSlope;
|
||||
navigatorSettings.mRecastScaleFactor = Settings::Manager::getFloat("recast scale factor", "Navigator");
|
||||
navigatorSettings.mMaxEdgeLen = Settings::Manager::getInt("max edge len", "Navigator");
|
||||
navigatorSettings.mMaxNavMeshQueryNodes = Settings::Manager::getInt("max nav mesh query nodes", "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.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.mTrianglesPerChunk = static_cast<std::size_t>(Settings::Manager::getInt("triangles per chunk", "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");
|
||||
if (Settings::Manager::getBool("enable log", "Navigator"))
|
||||
DetourNavigator::Log::instance().setSink(std::unique_ptr<DetourNavigator::FileSink>(
|
||||
new DetourNavigator::FileSink(Settings::Manager::getString("log path", "Navigator"))));
|
||||
mNavigator.reset(new DetourNavigator::Navigator(navigatorSettings));
|
||||
|
||||
mRendering.reset(new MWRender::RenderingManager(viewer, rootNode, resourceSystem, workQueue, &mFallback, resourcePath, *mNavigator));
|
||||
mProjectileManager.reset(new ProjectileManager(mRendering->getLightRoot(), resourceSystem, mRendering.get(), mPhysics.get()));
|
||||
mRendering->preloadCommonAssets();
|
||||
|
||||
mEsm.resize(contentFiles.size());
|
||||
Loading::Listener* listener = MWBase::Environment::get().getWindowManager()->getLoadingScreen();
|
||||
listener->loadingOn();
|
||||
|
@ -232,6 +196,43 @@ namespace MWWorld
|
|||
|
||||
mSwimHeightScale = mStore.get<ESM::GameSetting>().find("fSwimHeightScale")->mValue.getFloat();
|
||||
|
||||
mPhysics.reset(new MWPhysics::PhysicsSystem(resourceSystem, rootNode));
|
||||
|
||||
DetourNavigator::Settings navigatorSettings;
|
||||
navigatorSettings.mBorderSize = Settings::Manager::getInt("border size", "Navigator");
|
||||
navigatorSettings.mCellHeight = Settings::Manager::getFloat("cell height", "Navigator");
|
||||
navigatorSettings.mCellSize = Settings::Manager::getFloat("cell size", "Navigator");
|
||||
navigatorSettings.mDetailSampleDist = Settings::Manager::getFloat("detail sample dist", "Navigator");
|
||||
navigatorSettings.mDetailSampleMaxError = Settings::Manager::getFloat("detail sample max error", "Navigator");
|
||||
navigatorSettings.mMaxClimb = MWPhysics::sStepSizeUp;
|
||||
navigatorSettings.mMaxSimplificationError = Settings::Manager::getFloat("max simplification error", "Navigator");
|
||||
navigatorSettings.mMaxSlope = MWPhysics::sMaxSlope;
|
||||
navigatorSettings.mRecastScaleFactor = Settings::Manager::getFloat("recast scale factor", "Navigator");
|
||||
navigatorSettings.mSwimHeightScale = mSwimHeightScale;
|
||||
navigatorSettings.mMaxEdgeLen = Settings::Manager::getInt("max edge len", "Navigator");
|
||||
navigatorSettings.mMaxNavMeshQueryNodes = Settings::Manager::getInt("max nav mesh query nodes", "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.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.mTrianglesPerChunk = static_cast<std::size_t>(Settings::Manager::getInt("triangles per chunk", "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");
|
||||
if (Settings::Manager::getBool("enable log", "Navigator"))
|
||||
DetourNavigator::Log::instance().setSink(std::unique_ptr<DetourNavigator::FileSink>(
|
||||
new DetourNavigator::FileSink(Settings::Manager::getString("log path", "Navigator"))));
|
||||
mNavigator.reset(new DetourNavigator::Navigator(navigatorSettings));
|
||||
|
||||
mRendering.reset(new MWRender::RenderingManager(viewer, rootNode, resourceSystem, workQueue, &mFallback, resourcePath, *mNavigator));
|
||||
mProjectileManager.reset(new ProjectileManager(mRendering->getLightRoot(), resourceSystem, mRendering.get(), mPhysics.get()));
|
||||
mRendering->preloadCommonAssets();
|
||||
|
||||
mWeatherManager.reset(new MWWorld::WeatherManager(*mRendering, mFallback, mStore));
|
||||
|
||||
mWorldScene.reset(new Scene(*mRendering.get(), mPhysics.get()));
|
||||
|
|
|
@ -48,6 +48,7 @@ namespace
|
|||
mSettings.mMaxSimplificationError = 1.3f;
|
||||
mSettings.mMaxSlope = 49;
|
||||
mSettings.mRecastScaleFactor = 0.017647058823529415f;
|
||||
mSettings.mSwimHeightScale = 0.89999997615814208984375f;
|
||||
mSettings.mMaxEdgeLen = 12;
|
||||
mSettings.mMaxNavMeshQueryNodes = 2048;
|
||||
mSettings.mMaxVertsPerPoly = 6;
|
||||
|
@ -415,4 +416,142 @@ namespace
|
|||
osg::Vec3f(215, -215, 1.93937528133392333984375),
|
||||
})) << mPath;
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorNavigatorTest, path_should_be_over_water_ground_lower_than_water)
|
||||
{
|
||||
std::array<btScalar, 5 * 5> heightfieldData {{
|
||||
-50, -50, -50, -50, 0,
|
||||
-50, -100, -150, -100, -50,
|
||||
-50, -150, -200, -150, -100,
|
||||
-50, -100, -150, -100, -100,
|
||||
0, -50, -100, -100, -100,
|
||||
}};
|
||||
btHeightfieldTerrainShape shape(5, 5, heightfieldData.data(), 1, 0, 0, 2, PHY_FLOAT, false);
|
||||
shape.setLocalScaling(btVector3(128, 128, 1));
|
||||
|
||||
mNavigator->addAgent(mAgentHalfExtents);
|
||||
mNavigator->addWater(osg::Vec2i(0, 0), 128 * 4, 300, btTransform::getIdentity());
|
||||
mNavigator->addObject(1, shape, btTransform::getIdentity());
|
||||
mNavigator->update(mPlayerPosition);
|
||||
mNavigator->wait();
|
||||
|
||||
mStart.x() = 0;
|
||||
mStart.z() = 300;
|
||||
mEnd.x() = 0;
|
||||
mEnd.z() = 300;
|
||||
|
||||
mNavigator->findPath(mAgentHalfExtents, mStart, mEnd, mOut);
|
||||
|
||||
EXPECT_EQ(mPath, std::deque<osg::Vec3f>({
|
||||
osg::Vec3f(0, 215, 185.33331298828125),
|
||||
osg::Vec3f(0, 186.6666717529296875, 185.33331298828125),
|
||||
osg::Vec3f(0, 158.333343505859375, 185.33331298828125),
|
||||
osg::Vec3f(0, 130.0000152587890625, 185.33331298828125),
|
||||
osg::Vec3f(0, 101.66667938232421875, 185.33331298828125),
|
||||
osg::Vec3f(0, 73.333343505859375, 185.33331298828125),
|
||||
osg::Vec3f(0, 45.0000152587890625, 185.33331298828125),
|
||||
osg::Vec3f(0, 16.6666812896728515625, 185.33331298828125),
|
||||
osg::Vec3f(0, -11.66664981842041015625, 185.33331298828125),
|
||||
osg::Vec3f(0, -39.999980926513671875, 185.33331298828125),
|
||||
osg::Vec3f(0, -68.33331298828125, 185.33331298828125),
|
||||
osg::Vec3f(0, -96.66664886474609375, 185.33331298828125),
|
||||
osg::Vec3f(0, -124.99997711181640625, 185.33331298828125),
|
||||
osg::Vec3f(0, -153.33331298828125, 185.33331298828125),
|
||||
osg::Vec3f(0, -181.6666412353515625, 185.33331298828125),
|
||||
osg::Vec3f(0, -209.999969482421875, 185.33331298828125),
|
||||
osg::Vec3f(0, -215, 185.33331298828125),
|
||||
})) << mPath;
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorNavigatorTest, path_should_be_over_water_when_ground_cross_water)
|
||||
{
|
||||
std::array<btScalar, 7 * 7> heightfieldData {{
|
||||
0, 0, 0, 0, 0, 0, 0,
|
||||
0, -100, -100, -100, -100, -100, 0,
|
||||
0, -100, -150, -150, -150, -100, 0,
|
||||
0, -100, -150, -200, -150, -100, 0,
|
||||
0, -100, -150, -150, -150, -100, 0,
|
||||
0, -100, -100, -100, -100, -100, 0,
|
||||
0, 0, 0, 0, 0, 0, 0,
|
||||
}};
|
||||
btHeightfieldTerrainShape shape(7, 7, heightfieldData.data(), 1, 0, 0, 2, PHY_FLOAT, false);
|
||||
shape.setLocalScaling(btVector3(128, 128, 1));
|
||||
|
||||
mNavigator->addAgent(mAgentHalfExtents);
|
||||
mNavigator->addWater(osg::Vec2i(0, 0), 128 * 4, -25, btTransform::getIdentity());
|
||||
mNavigator->addObject(1, shape, btTransform::getIdentity());
|
||||
mNavigator->update(mPlayerPosition);
|
||||
mNavigator->wait();
|
||||
|
||||
mStart.x() = 0;
|
||||
mEnd.x() = 0;
|
||||
|
||||
mNavigator->findPath(mAgentHalfExtents, mStart, mEnd, mOut);
|
||||
|
||||
EXPECT_EQ(mPath, std::deque<osg::Vec3f>({
|
||||
osg::Vec3f(0, 215, -94.75363922119140625),
|
||||
osg::Vec3f(0, 186.6666717529296875, -106.0000152587890625),
|
||||
osg::Vec3f(0, 158.333343505859375, -115.85507965087890625),
|
||||
osg::Vec3f(0, 130.0000152587890625, -125.71016693115234375),
|
||||
osg::Vec3f(0, 101.66667938232421875, -135.5652313232421875),
|
||||
osg::Vec3f(0, 73.333343505859375, -143.3333587646484375),
|
||||
osg::Vec3f(0, 45.0000152587890625, -143.3333587646484375),
|
||||
osg::Vec3f(0, 16.6666812896728515625, -143.3333587646484375),
|
||||
osg::Vec3f(0, -11.66664981842041015625, -143.3333587646484375),
|
||||
osg::Vec3f(0, -39.999980926513671875, -143.3333587646484375),
|
||||
osg::Vec3f(0, -68.33331298828125, -143.3333587646484375),
|
||||
osg::Vec3f(0, -96.66664886474609375, -137.3043670654296875),
|
||||
osg::Vec3f(0, -124.99997711181640625, -127.44930267333984375),
|
||||
osg::Vec3f(0, -153.33331298828125, -117.5942230224609375),
|
||||
osg::Vec3f(0, -181.6666412353515625, -107.7391510009765625),
|
||||
osg::Vec3f(0, -209.999969482421875, -97.79712677001953125),
|
||||
osg::Vec3f(0, -215, -94.753631591796875),
|
||||
})) << mPath;
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorNavigatorTest, path_should_be_over_water_when_ground_cross_water_with_max_int_cells_size)
|
||||
{
|
||||
std::array<btScalar, 7 * 7> heightfieldData {{
|
||||
0, 0, 0, 0, 0, 0, 0,
|
||||
0, -100, -100, -100, -100, -100, 0,
|
||||
0, -100, -150, -150, -150, -100, 0,
|
||||
0, -100, -150, -200, -150, -100, 0,
|
||||
0, -100, -150, -150, -150, -100, 0,
|
||||
0, -100, -100, -100, -100, -100, 0,
|
||||
0, 0, 0, 0, 0, 0, 0,
|
||||
}};
|
||||
btHeightfieldTerrainShape shape(7, 7, heightfieldData.data(), 1, 0, 0, 2, PHY_FLOAT, false);
|
||||
shape.setLocalScaling(btVector3(128, 128, 1));
|
||||
|
||||
mNavigator->addAgent(mAgentHalfExtents);
|
||||
mNavigator->addObject(1, shape, btTransform::getIdentity());
|
||||
mNavigator->addWater(osg::Vec2i(0, 0), std::numeric_limits<int>::max(), -25, btTransform::getIdentity());
|
||||
mNavigator->update(mPlayerPosition);
|
||||
mNavigator->wait();
|
||||
|
||||
mStart.x() = 0;
|
||||
mEnd.x() = 0;
|
||||
|
||||
mNavigator->findPath(mAgentHalfExtents, mStart, mEnd, mOut);
|
||||
|
||||
EXPECT_EQ(mPath, std::deque<osg::Vec3f>({
|
||||
osg::Vec3f(0, 215, -94.75363922119140625),
|
||||
osg::Vec3f(0, 186.6666717529296875, -106.0000152587890625),
|
||||
osg::Vec3f(0, 158.333343505859375, -115.85507965087890625),
|
||||
osg::Vec3f(0, 130.0000152587890625, -125.71016693115234375),
|
||||
osg::Vec3f(0, 101.66667938232421875, -135.5652313232421875),
|
||||
osg::Vec3f(0, 73.333343505859375, -143.3333587646484375),
|
||||
osg::Vec3f(0, 45.0000152587890625, -143.3333587646484375),
|
||||
osg::Vec3f(0, 16.6666812896728515625, -143.3333587646484375),
|
||||
osg::Vec3f(0, -11.66664981842041015625, -143.3333587646484375),
|
||||
osg::Vec3f(0, -39.999980926513671875, -143.3333587646484375),
|
||||
osg::Vec3f(0, -68.33331298828125, -143.3333587646484375),
|
||||
osg::Vec3f(0, -96.66664886474609375, -137.3043670654296875),
|
||||
osg::Vec3f(0, -124.99997711181640625, -127.44930267333984375),
|
||||
osg::Vec3f(0, -153.33331298828125, -117.5942230224609375),
|
||||
osg::Vec3f(0, -181.6666412353515625, -107.7391510009765625),
|
||||
osg::Vec3f(0, -209.999969482421875, -97.79712677001953125),
|
||||
osg::Vec3f(0, -215, -94.753631591796875),
|
||||
})) << mPath;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,6 +13,14 @@
|
|||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
namespace DetourNavigator
|
||||
{
|
||||
static inline bool operator ==(const RecastMesh::Water& lhs, const RecastMesh::Water& rhs)
|
||||
{
|
||||
return lhs.mCellSize == rhs.mCellSize && lhs.mTransform == rhs.mTransform;
|
||||
}
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
using namespace testing;
|
||||
|
@ -391,4 +399,14 @@ namespace
|
|||
EXPECT_EQ(recastMesh->getIndices(), std::vector<int>({0, 1, 2, 3, 4, 5}));
|
||||
EXPECT_EQ(recastMesh->getAreaTypes(), std::vector<AreaType>({AreaType_ground, AreaType_null}));
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorRecastMeshBuilderTest, add_water_then_get_water_should_return_it)
|
||||
{
|
||||
RecastMeshBuilder builder(mSettings, mBounds);
|
||||
builder.addWater(1000, btTransform(btMatrix3x3::getIdentity(), btVector3(100, 200, 300)));
|
||||
const auto recastMesh = builder.create();
|
||||
EXPECT_EQ(recastMesh->getWater(), std::vector<RecastMesh::Water>({
|
||||
RecastMesh::Water {1000, btTransform(btMatrix3x3::getIdentity(), btVector3(100, 200, 300))}
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ namespace DetourNavigator
|
|||
enum AreaType : unsigned char
|
||||
{
|
||||
AreaType_null = RC_NULL_AREA,
|
||||
AreaType_water,
|
||||
AreaType_ground = RC_WALKABLE_AREA,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -32,6 +32,23 @@ namespace DetourNavigator
|
|||
return object;
|
||||
}
|
||||
|
||||
bool CachedRecastMeshManager::addWater(const osg::Vec2i& cellPosition, const int cellSize,
|
||||
const btTransform& transform)
|
||||
{
|
||||
if (!mImpl.addWater(cellPosition, cellSize, transform))
|
||||
return false;
|
||||
mCached.reset();
|
||||
return true;
|
||||
}
|
||||
|
||||
boost::optional<RecastMeshManager::Water> CachedRecastMeshManager::removeWater(const osg::Vec2i& cellPosition)
|
||||
{
|
||||
const auto water = mImpl.removeWater(cellPosition);
|
||||
if (water)
|
||||
mCached.reset();
|
||||
return water;
|
||||
}
|
||||
|
||||
std::shared_ptr<RecastMesh> CachedRecastMeshManager::getMesh()
|
||||
{
|
||||
if (!mCached)
|
||||
|
|
|
@ -17,6 +17,10 @@ namespace DetourNavigator
|
|||
|
||||
bool updateObject(std::size_t id, const btTransform& transform, const AreaType areaType);
|
||||
|
||||
bool addWater(const osg::Vec2i& cellPosition, const int cellSize, const btTransform& transform);
|
||||
|
||||
boost::optional<RecastMeshManager::Water> removeWater(const osg::Vec2i& cellPosition);
|
||||
|
||||
boost::optional<RemovedRecastMeshObject> removeObject(std::size_t id);
|
||||
|
||||
std::shared_ptr<RecastMesh> getMesh();
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include "dtstatus.hpp"
|
||||
#include "exceptions.hpp"
|
||||
#include "flags.hpp"
|
||||
#include "settings.hpp"
|
||||
#include "settingsutils.hpp"
|
||||
|
||||
|
@ -10,6 +11,8 @@
|
|||
#include <DetourNavMesh.h>
|
||||
#include <DetourNavMeshQuery.h>
|
||||
|
||||
#include <LinearMath/btVector3.h>
|
||||
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
#include <osg/Vec3f>
|
||||
|
@ -27,6 +30,11 @@ namespace DetourNavigator
|
|||
return osg::Vec3f(values[0], values[1], values[2]);
|
||||
}
|
||||
|
||||
inline osg::Vec3f makeOsgVec3f(const btVector3& value)
|
||||
{
|
||||
return osg::Vec3f(value.x(), value.y(), value.z());
|
||||
}
|
||||
|
||||
inline bool inRange(const osg::Vec3f& v1, const osg::Vec3f& v2, const float r, const float h)
|
||||
{
|
||||
const auto d = v2 - v1;
|
||||
|
@ -217,6 +225,7 @@ namespace DetourNavigator
|
|||
OPENMW_CHECK_DT_STATUS(navMeshQuery.init(&navMesh, settings.mMaxNavMeshQueryNodes));
|
||||
|
||||
dtQueryFilter queryFilter;
|
||||
queryFilter.setIncludeFlags(Flag_swim | Flag_walk);
|
||||
|
||||
dtPolyRef startRef = 0;
|
||||
osg::Vec3f startPolygonPosition;
|
||||
|
|
|
@ -9,6 +9,7 @@ namespace DetourNavigator
|
|||
{
|
||||
Flag_none = 0,
|
||||
Flag_walk = 1 << 0,
|
||||
Flag_swim = 1 << 1,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -51,6 +51,23 @@ namespace DetourNavigator
|
|||
|
||||
getTilesPositions(makeOsgVec3f(aabbMin), makeOsgVec3f(aabbMax), settings, std::forward<Callback>(callback));
|
||||
}
|
||||
|
||||
template <class Callback>
|
||||
void getTilesPositions(const int cellSize, const btTransform& transform,
|
||||
const Settings& settings, Callback&& callback)
|
||||
{
|
||||
const auto halfCellSize = cellSize / 2;
|
||||
auto aabbMin = transform(btVector3(-halfCellSize, -halfCellSize, 0));
|
||||
auto aabbMax = transform(btVector3(halfCellSize, halfCellSize, 0));
|
||||
|
||||
aabbMin.setX(std::min(aabbMin.x(), aabbMax.x()));
|
||||
aabbMin.setY(std::min(aabbMin.y(), aabbMax.y()));
|
||||
|
||||
aabbMax.setX(std::max(aabbMin.x(), aabbMax.x()));
|
||||
aabbMax.setY(std::max(aabbMin.y(), aabbMax.y()));
|
||||
|
||||
getTilesPositions(makeOsgVec3f(aabbMin), makeOsgVec3f(aabbMax), settings, std::forward<Callback>(callback));
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <Recast.h>
|
||||
#include <RecastAlloc.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <iomanip>
|
||||
#include <limits>
|
||||
|
||||
|
@ -64,6 +65,41 @@ namespace
|
|||
{}
|
||||
};
|
||||
|
||||
osg::Vec3f makeOsgVec3f(const btVector3& value)
|
||||
{
|
||||
return osg::Vec3f(value.x(), value.y(), value.z());
|
||||
}
|
||||
|
||||
struct WaterBounds
|
||||
{
|
||||
osg::Vec3f mMin;
|
||||
osg::Vec3f mMax;
|
||||
};
|
||||
|
||||
WaterBounds getWaterBounds(const RecastMesh::Water& water, const Settings& settings,
|
||||
const osg::Vec3f& agentHalfExtents)
|
||||
{
|
||||
if (water.mCellSize == std::numeric_limits<int>::max())
|
||||
{
|
||||
const auto transform = getSwimLevelTransform(settings, water.mTransform, agentHalfExtents.z());
|
||||
const auto min = toNavMeshCoordinates(settings, makeOsgVec3f(transform(btVector3(-1, -1, 0))));
|
||||
const auto max = toNavMeshCoordinates(settings, makeOsgVec3f(transform(btVector3(1, 1, 0))));
|
||||
return WaterBounds {
|
||||
osg::Vec3f(-std::numeric_limits<float>::max(), min.y(), -std::numeric_limits<float>::max()),
|
||||
osg::Vec3f(std::numeric_limits<float>::max(), max.y(), std::numeric_limits<float>::max())
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto transform = getSwimLevelTransform(settings, water.mTransform, agentHalfExtents.z());
|
||||
const auto halfCellSize = water.mCellSize / 2.0f;
|
||||
return WaterBounds {
|
||||
toNavMeshCoordinates(settings, makeOsgVec3f(transform(btVector3(-halfCellSize, -halfCellSize, 0)))),
|
||||
toNavMeshCoordinates(settings, makeOsgVec3f(transform(btVector3(halfCellSize, halfCellSize, 0))))
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
NavMeshData makeNavMeshTileData(const osg::Vec3f& agentHalfExtents, const RecastMesh& recastMesh,
|
||||
const int tileX, const int tileY, const osg::Vec3f& boundsMin, const osg::Vec3f& boundsMax,
|
||||
const Settings& settings)
|
||||
|
@ -156,6 +192,56 @@ namespace
|
|||
}
|
||||
}
|
||||
|
||||
{
|
||||
const std::array<unsigned char, 2> areas {{AreaType_water, AreaType_water}};
|
||||
|
||||
for (const auto& water : recastMesh.getWater())
|
||||
{
|
||||
const auto bounds = getWaterBounds(water, settings, agentHalfExtents);
|
||||
|
||||
const osg::Vec2f tileBoundsMin(
|
||||
std::min(config.bmax[0], std::max(config.bmin[0], bounds.mMin.x())),
|
||||
std::min(config.bmax[2], std::max(config.bmin[2], bounds.mMin.z()))
|
||||
);
|
||||
const osg::Vec2f tileBoundsMax(
|
||||
std::min(config.bmax[0], std::max(config.bmin[0], bounds.mMax.x())),
|
||||
std::min(config.bmax[2], std::max(config.bmin[2], bounds.mMax.z()))
|
||||
);
|
||||
|
||||
if (tileBoundsMax == tileBoundsMin)
|
||||
continue;
|
||||
|
||||
const std::array<osg::Vec3f, 4> vertices {{
|
||||
osg::Vec3f(tileBoundsMin.x(), bounds.mMin.y(), tileBoundsMin.y()),
|
||||
osg::Vec3f(tileBoundsMin.x(), bounds.mMin.y(), tileBoundsMax.y()),
|
||||
osg::Vec3f(tileBoundsMax.x(), bounds.mMin.y(), tileBoundsMax.y()),
|
||||
osg::Vec3f(tileBoundsMax.x(), bounds.mMin.y(), tileBoundsMin.y()),
|
||||
}};
|
||||
|
||||
std::array<float, 4 * 3> convertedVertices;
|
||||
auto convertedVerticesIt = convertedVertices.begin();
|
||||
|
||||
for (const auto& vertex : vertices)
|
||||
convertedVerticesIt = std::copy(vertex.ptr(), vertex.ptr() + 3, convertedVerticesIt);
|
||||
|
||||
const std::array<int, 6> indices {{
|
||||
0, 1, 2,
|
||||
0, 2, 3,
|
||||
}};
|
||||
|
||||
OPENMW_CHECK_DT_RESULT(rcRasterizeTriangles(
|
||||
&context,
|
||||
convertedVertices.data(),
|
||||
static_cast<int>(convertedVertices.size() / 3),
|
||||
indices.data(),
|
||||
areas.data(),
|
||||
static_cast<int>(areas.size()),
|
||||
solid,
|
||||
config.walkableClimb
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
rcFilterLowHangingWalkableObstacles(&context, config.walkableClimb, solid);
|
||||
rcFilterLedgeSpans(&context, config.walkableHeight, config.walkableClimb, solid);
|
||||
rcFilterWalkableLowHeightSpans(&context, config.walkableHeight, solid);
|
||||
|
@ -187,8 +273,12 @@ namespace
|
|||
}
|
||||
|
||||
for (int i = 0; i < polyMesh.npolys; ++i)
|
||||
{
|
||||
if (polyMesh.areas[i] == AreaType_ground)
|
||||
polyMesh.flags[i] = Flag_walk;
|
||||
else if (polyMesh.areas[i] == AreaType_water)
|
||||
polyMesh.flags[i] = Flag_swim;
|
||||
}
|
||||
|
||||
dtNavMeshCreateParams params;
|
||||
params.verts = polyMesh.verts;
|
||||
|
@ -302,8 +392,15 @@ namespace DetourNavigator
|
|||
return removeTile();
|
||||
}
|
||||
|
||||
const auto& boundsMin = recastMesh->getBoundsMin();
|
||||
const auto& boundsMax = recastMesh->getBoundsMax();
|
||||
auto boundsMin = recastMesh->getBoundsMin();
|
||||
auto boundsMax = recastMesh->getBoundsMax();
|
||||
|
||||
for (const auto& water : recastMesh->getWater())
|
||||
{
|
||||
const auto bounds = getWaterBounds(water, settings, agentHalfExtents);
|
||||
boundsMin.y() = std::min(boundsMin.y(), bounds.mMin.y());
|
||||
boundsMax.y() = std::max(boundsMax.y(), bounds.mMax.y());
|
||||
}
|
||||
|
||||
if (boundsMin == boundsMax)
|
||||
{
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
#include <osg/Vec3f>
|
||||
|
||||
#include <memory>
|
||||
#include <set>
|
||||
|
||||
class dtNavMesh;
|
||||
|
||||
|
|
|
@ -71,9 +71,24 @@ namespace DetourNavigator
|
|||
{
|
||||
bool result = mNavMeshManager.removeObject(id);
|
||||
const auto avoid = mAvoidIds.find(id);
|
||||
if (avoid == mAvoidIds.end())
|
||||
return result;
|
||||
return mNavMeshManager.removeObject(avoid->second) || result;
|
||||
if (avoid != mAvoidIds.end())
|
||||
result = mNavMeshManager.removeObject(avoid->second) || result;
|
||||
const auto water = mWaterIds.find(id);
|
||||
if (water != mWaterIds.end())
|
||||
result = mNavMeshManager.removeObject(water->second) || result;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool Navigator::addWater(const osg::Vec2i& cellPosition, const int cellSize, const btScalar level,
|
||||
const btTransform& transform)
|
||||
{
|
||||
return mNavMeshManager.addWater(cellPosition, cellSize,
|
||||
btTransform(transform.getBasis(), btVector3(transform.getOrigin().x(), transform.getOrigin().y(), level)));
|
||||
}
|
||||
|
||||
bool Navigator::removeWater(const osg::Vec2i& cellPosition)
|
||||
{
|
||||
return mNavMeshManager.removeWater(cellPosition);
|
||||
}
|
||||
|
||||
void Navigator::update(const osg::Vec3f& playerPosition)
|
||||
|
@ -97,13 +112,23 @@ namespace DetourNavigator
|
|||
return mSettings;
|
||||
}
|
||||
|
||||
void Navigator::updateAvoidShapeId(std::size_t id, std::size_t avoidId)
|
||||
void Navigator::updateAvoidShapeId(const std::size_t id, const std::size_t avoidId)
|
||||
{
|
||||
auto inserted = mAvoidIds.insert(std::make_pair(id, avoidId));
|
||||
updateId(id, avoidId, mWaterIds);
|
||||
}
|
||||
|
||||
void Navigator::updateWaterShapeId(const std::size_t id, const std::size_t waterId)
|
||||
{
|
||||
updateId(id, waterId, mWaterIds);
|
||||
}
|
||||
|
||||
void Navigator::updateId(const std::size_t id, const std::size_t updateId, std::unordered_map<std::size_t, std::size_t>& ids)
|
||||
{
|
||||
auto inserted = ids.insert(std::make_pair(id, updateId));
|
||||
if (!inserted.second)
|
||||
{
|
||||
mNavMeshManager.removeObject(inserted.first->second);
|
||||
inserted.second = avoidId;
|
||||
inserted.second = updateId;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,6 +37,11 @@ namespace DetourNavigator
|
|||
|
||||
bool removeObject(std::size_t id);
|
||||
|
||||
bool addWater(const osg::Vec2i& cellPosition, const int cellSize, const btScalar level,
|
||||
const btTransform& transform);
|
||||
|
||||
bool removeWater(const osg::Vec2i& cellPosition);
|
||||
|
||||
void update(const osg::Vec3f& playerPosition);
|
||||
|
||||
void wait();
|
||||
|
@ -59,8 +64,11 @@ namespace DetourNavigator
|
|||
NavMeshManager mNavMeshManager;
|
||||
std::map<osg::Vec3f, std::size_t> mAgents;
|
||||
std::unordered_map<std::size_t, std::size_t> mAvoidIds;
|
||||
std::unordered_map<std::size_t, std::size_t> mWaterIds;
|
||||
|
||||
void updateAvoidShapeId(std::size_t id, std::size_t avoidId);
|
||||
void updateAvoidShapeId(const std::size_t id, const std::size_t avoidId);
|
||||
void updateWaterShapeId(const std::size_t id, const std::size_t waterId);
|
||||
void updateId(const std::size_t id, const std::size_t waterId, std::unordered_map<std::size_t, std::size_t>& ids);
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -58,6 +58,23 @@ namespace DetourNavigator
|
|||
return true;
|
||||
}
|
||||
|
||||
bool NavMeshManager::addWater(const osg::Vec2i& cellPosition, const int cellSize, const btTransform& transform)
|
||||
{
|
||||
if (!mRecastMeshManager.addWater(cellPosition, cellSize, transform))
|
||||
return false;
|
||||
addChangedTiles(cellSize, transform, ChangeType::add);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NavMeshManager::removeWater(const osg::Vec2i& cellPosition)
|
||||
{
|
||||
const auto water = mRecastMeshManager.removeWater(cellPosition);
|
||||
if (!water)
|
||||
return false;
|
||||
addChangedTiles(water->mCellSize, water->mTransform, ChangeType::remove);
|
||||
return true;
|
||||
}
|
||||
|
||||
void NavMeshManager::addAgent(const osg::Vec3f& agentHalfExtents)
|
||||
{
|
||||
auto cached = mCache.find(agentHalfExtents);
|
||||
|
@ -75,9 +92,7 @@ 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);
|
||||
const auto playerTile = getTilePosition(mSettings, toNavMeshCoordinates(mSettings, playerPosition));
|
||||
if (mLastRecastMeshManagerRevision >= mRecastMeshManager.getRevision() && mPlayerTile
|
||||
&& *mPlayerTile == playerTile)
|
||||
return;
|
||||
|
@ -140,20 +155,36 @@ namespace DetourNavigator
|
|||
}
|
||||
|
||||
void NavMeshManager::addChangedTiles(const btCollisionShape& shape, const btTransform& transform,
|
||||
const ChangeType changeType)
|
||||
const ChangeType changeType)
|
||||
{
|
||||
getTilesPositions(shape, transform, mSettings, [&] (const TilePosition& v) {
|
||||
for (const auto& cached : mCache)
|
||||
if (cached.second)
|
||||
{
|
||||
auto& tiles = mChangedTiles[cached.first];
|
||||
auto tile = tiles.find(v);
|
||||
if (tile == tiles.end())
|
||||
tiles.insert(std::make_pair(v, changeType));
|
||||
else
|
||||
tile->second = addChangeType(tile->second, changeType);
|
||||
}
|
||||
});
|
||||
getTilesPositions(shape, transform, mSettings,
|
||||
[&] (const TilePosition& v) { addChangedTile(v, changeType); });
|
||||
}
|
||||
|
||||
void NavMeshManager::addChangedTiles(const int cellSize, const btTransform& transform,
|
||||
const ChangeType changeType)
|
||||
{
|
||||
if (cellSize == std::numeric_limits<int>::max())
|
||||
return;
|
||||
|
||||
getTilesPositions(cellSize, transform, mSettings,
|
||||
[&] (const TilePosition& v) { addChangedTile(v, changeType); });
|
||||
}
|
||||
|
||||
void NavMeshManager::addChangedTile(const TilePosition& tilePosition, const ChangeType changeType)
|
||||
{
|
||||
for (const auto& cached : mCache)
|
||||
{
|
||||
if (cached.second)
|
||||
{
|
||||
auto& tiles = mChangedTiles[cached.first];
|
||||
auto tile = tiles.find(tilePosition);
|
||||
if (tile == tiles.end())
|
||||
tiles.insert(std::make_pair(tilePosition, changeType));
|
||||
else
|
||||
tile->second = addChangeType(tile->second, changeType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const std::shared_ptr<NavMeshCacheItem>& NavMeshManager::getCached(const osg::Vec3f& agentHalfExtents) const
|
||||
|
|
|
@ -7,8 +7,6 @@
|
|||
|
||||
#include <BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h>
|
||||
|
||||
#include <BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h>
|
||||
|
||||
#include <osg/Vec3f>
|
||||
|
||||
#include <map>
|
||||
|
@ -33,6 +31,10 @@ namespace DetourNavigator
|
|||
|
||||
void addAgent(const osg::Vec3f& agentHalfExtents);
|
||||
|
||||
bool addWater(const osg::Vec2i& cellPosition, const int cellSize, const btTransform& transform);
|
||||
|
||||
bool removeWater(const osg::Vec2i& cellPosition);
|
||||
|
||||
void reset(const osg::Vec3f& agentHalfExtents);
|
||||
|
||||
void update(osg::Vec3f playerPosition, const osg::Vec3f& agentHalfExtents);
|
||||
|
@ -55,6 +57,10 @@ namespace DetourNavigator
|
|||
|
||||
void addChangedTiles(const btCollisionShape& shape, const btTransform& transform, const ChangeType changeType);
|
||||
|
||||
void addChangedTiles(const int cellSize, const btTransform& transform, const ChangeType changeType);
|
||||
|
||||
void addChangedTile(const TilePosition& tilePosition, const ChangeType changeType);
|
||||
|
||||
const std::shared_ptr<NavMeshCacheItem>& getCached(const osg::Vec3f& agentHalfExtents) const;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -7,10 +7,11 @@
|
|||
namespace DetourNavigator
|
||||
{
|
||||
RecastMesh::RecastMesh(std::vector<int> indices, std::vector<float> vertices,
|
||||
std::vector<AreaType> areaTypes, const Settings& settings)
|
||||
std::vector<AreaType> areaTypes, std::vector<Water> water, const Settings& settings)
|
||||
: mIndices(std::move(indices))
|
||||
, mVertices(std::move(vertices))
|
||||
, mAreaTypes(std::move(areaTypes))
|
||||
, mWater(std::move(water))
|
||||
, mChunkyTriMesh(mVertices, mIndices, mAreaTypes, settings.mTrianglesPerChunk)
|
||||
{
|
||||
if (getTrianglesCount() != mAreaTypes.size())
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
|
||||
#include <osg/Vec3f>
|
||||
|
||||
#include <LinearMath/btTransform.h>
|
||||
|
||||
namespace DetourNavigator
|
||||
{
|
||||
struct Settings;
|
||||
|
@ -16,8 +18,14 @@ namespace DetourNavigator
|
|||
class RecastMesh
|
||||
{
|
||||
public:
|
||||
struct Water
|
||||
{
|
||||
int mCellSize;
|
||||
btTransform mTransform;
|
||||
};
|
||||
|
||||
RecastMesh(std::vector<int> indices, std::vector<float> vertices,
|
||||
std::vector<AreaType> areaTypes, const Settings& settings);
|
||||
std::vector<AreaType> areaTypes, std::vector<Water> water, const Settings& settings);
|
||||
|
||||
const std::vector<int>& getIndices() const
|
||||
{
|
||||
|
@ -34,6 +42,11 @@ namespace DetourNavigator
|
|||
return mAreaTypes;
|
||||
}
|
||||
|
||||
const std::vector<Water>& getWater() const
|
||||
{
|
||||
return mWater;
|
||||
}
|
||||
|
||||
std::size_t getVerticesCount() const
|
||||
{
|
||||
return mVertices.size() / 3;
|
||||
|
@ -63,6 +76,7 @@ namespace DetourNavigator
|
|||
std::vector<int> mIndices;
|
||||
std::vector<float> mVertices;
|
||||
std::vector<AreaType> mAreaTypes;
|
||||
std::vector<Water> mWater;
|
||||
ChunkyTriMesh mChunkyTriMesh;
|
||||
osg::Vec3f mBoundsMin;
|
||||
osg::Vec3f mBoundsMax;
|
||||
|
|
|
@ -82,19 +82,16 @@ namespace DetourNavigator
|
|||
|
||||
void RecastMeshBuilder::addObject(const btBoxShape& shape, const btTransform& transform, const AreaType areaType)
|
||||
{
|
||||
const auto indexOffset = int(mVertices.size() / 3);
|
||||
const auto indexOffset = static_cast<int>(mVertices.size() / 3);
|
||||
|
||||
for (int vertex = 0; vertex < shape.getNumVertices(); ++vertex)
|
||||
for (int vertex = 0, count = shape.getNumVertices(); vertex < count; ++vertex)
|
||||
{
|
||||
btVector3 position;
|
||||
shape.getVertex(vertex, position);
|
||||
addVertex(transform(position));
|
||||
}
|
||||
|
||||
for (int vertex = 0; vertex < 12; ++vertex)
|
||||
mAreaTypes.push_back(areaType);
|
||||
|
||||
static const std::array<int, 36> indices {{
|
||||
const std::array<int, 36> indices {{
|
||||
0, 2, 3,
|
||||
3, 1, 0,
|
||||
0, 4, 6,
|
||||
|
@ -111,11 +108,18 @@ namespace DetourNavigator
|
|||
|
||||
std::transform(indices.begin(), indices.end(), std::back_inserter(mIndices),
|
||||
[&] (int index) { return index + indexOffset; });
|
||||
|
||||
std::generate_n(std::back_inserter(mAreaTypes), 12, [=] { return areaType; });
|
||||
}
|
||||
|
||||
void RecastMeshBuilder::addWater(const int cellSize, const btTransform& transform)
|
||||
{
|
||||
mWater.push_back(RecastMesh::Water {cellSize, transform});
|
||||
}
|
||||
|
||||
std::shared_ptr<RecastMesh> RecastMeshBuilder::create() const
|
||||
{
|
||||
return std::make_shared<RecastMesh>(mIndices, mVertices, mAreaTypes, mSettings);
|
||||
return std::make_shared<RecastMesh>(mIndices, mVertices, mAreaTypes, mWater, mSettings);
|
||||
}
|
||||
|
||||
void RecastMeshBuilder::reset()
|
||||
|
@ -123,6 +127,7 @@ namespace DetourNavigator
|
|||
mIndices.clear();
|
||||
mVertices.clear();
|
||||
mAreaTypes.clear();
|
||||
mWater.clear();
|
||||
}
|
||||
|
||||
void RecastMeshBuilder::addObject(const btConcaveShape& shape, const btTransform& transform,
|
||||
|
|
|
@ -4,14 +4,17 @@
|
|||
#include "recastmesh.hpp"
|
||||
#include "tilebounds.hpp"
|
||||
|
||||
#include <LinearMath/btTransform.h>
|
||||
|
||||
#include <osg/Vec2f>
|
||||
#include <osg/Vec2i>
|
||||
|
||||
class btBoxShape;
|
||||
class btCollisionShape;
|
||||
class btCompoundShape;
|
||||
class btConcaveShape;
|
||||
class btHeightfieldTerrainShape;
|
||||
class btTransform;
|
||||
class btTriangleCallback;
|
||||
class btVector3;
|
||||
|
||||
namespace DetourNavigator
|
||||
{
|
||||
|
@ -30,6 +33,8 @@ namespace DetourNavigator
|
|||
|
||||
void addObject(const btBoxShape& shape, const btTransform& transform, const AreaType areaType);
|
||||
|
||||
void addWater(const int mCellSize, const btTransform& transform);
|
||||
|
||||
std::shared_ptr<RecastMesh> create() const;
|
||||
|
||||
void reset();
|
||||
|
@ -40,6 +45,7 @@ namespace DetourNavigator
|
|||
std::vector<int> mIndices;
|
||||
std::vector<float> mVertices;
|
||||
std::vector<AreaType> mAreaTypes;
|
||||
std::vector<RecastMesh::Water> mWater;
|
||||
|
||||
void addObject(const btConcaveShape& shape, const btTransform& transform, btTriangleCallback&& callback);
|
||||
|
||||
|
|
|
@ -42,6 +42,26 @@ namespace DetourNavigator
|
|||
return result;
|
||||
}
|
||||
|
||||
bool RecastMeshManager::addWater(const osg::Vec2i& cellPosition, const int cellSize,
|
||||
const btTransform& transform)
|
||||
{
|
||||
if (!mWater.insert(std::make_pair(cellPosition, Water {cellSize, transform})).second)
|
||||
return false;
|
||||
mShouldRebuild = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
boost::optional<RecastMeshManager::Water> RecastMeshManager::removeWater(const osg::Vec2i& cellPosition)
|
||||
{
|
||||
const auto water = mWater.find(cellPosition);
|
||||
if (water == mWater.end())
|
||||
return boost::none;
|
||||
mShouldRebuild = true;
|
||||
const auto result = water->second;
|
||||
mWater.erase(water);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::shared_ptr<RecastMesh> RecastMeshManager::getMesh()
|
||||
{
|
||||
rebuild();
|
||||
|
@ -58,6 +78,8 @@ namespace DetourNavigator
|
|||
if (!mShouldRebuild)
|
||||
return;
|
||||
mMeshBuilder.reset();
|
||||
for (const auto& v : mWater)
|
||||
mMeshBuilder.addWater(v.second.mCellSize, v.second.mTransform);
|
||||
for (const auto& v : mObjects)
|
||||
mMeshBuilder.addObject(v.second.getShape(), v.second.getTransform(), v.second.getAreaType());
|
||||
mShouldRebuild = false;
|
||||
|
|
|
@ -6,8 +6,11 @@
|
|||
|
||||
#include <LinearMath/btTransform.h>
|
||||
|
||||
#include <osg/Vec2i>
|
||||
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
|
||||
class btCollisionShape;
|
||||
|
@ -23,6 +26,12 @@ namespace DetourNavigator
|
|||
class RecastMeshManager
|
||||
{
|
||||
public:
|
||||
struct Water
|
||||
{
|
||||
int mCellSize;
|
||||
btTransform mTransform;
|
||||
};
|
||||
|
||||
RecastMeshManager(const Settings& settings, const TileBounds& bounds);
|
||||
|
||||
bool addObject(std::size_t id, const btCollisionShape& shape, const btTransform& transform,
|
||||
|
@ -30,6 +39,10 @@ namespace DetourNavigator
|
|||
|
||||
bool updateObject(std::size_t id, const btTransform& transform, const AreaType areaType);
|
||||
|
||||
bool addWater(const osg::Vec2i& cellPosition, const int cellSize, const btTransform& transform);
|
||||
|
||||
boost::optional<Water> removeWater(const osg::Vec2i& cellPosition);
|
||||
|
||||
boost::optional<RemovedRecastMeshObject> removeObject(std::size_t id);
|
||||
|
||||
std::shared_ptr<RecastMesh> getMesh();
|
||||
|
@ -40,6 +53,7 @@ namespace DetourNavigator
|
|||
bool mShouldRebuild;
|
||||
RecastMeshBuilder mMeshBuilder;
|
||||
std::unordered_map<std::size_t, RecastMeshObject> mObjects;
|
||||
std::map<osg::Vec2i, Water> mWater;
|
||||
|
||||
void rebuild();
|
||||
};
|
||||
|
|
|
@ -19,6 +19,7 @@ namespace DetourNavigator
|
|||
float mMaxSimplificationError;
|
||||
float mMaxSlope;
|
||||
float mRecastScaleFactor;
|
||||
float mSwimHeightScale;
|
||||
int mBorderSize;
|
||||
int mMaxEdgeLen;
|
||||
int mMaxNavMeshQueryNodes;
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
#include "tileposition.hpp"
|
||||
#include "tilebounds.hpp"
|
||||
|
||||
#include <LinearMath/btTransform.h>
|
||||
|
||||
#include <osg/Vec2f>
|
||||
#include <osg/Vec2i>
|
||||
#include <osg/Vec3f>
|
||||
|
@ -68,6 +70,20 @@ namespace DetourNavigator
|
|||
{
|
||||
return settings.mBorderSize * settings.mCellSize;
|
||||
}
|
||||
|
||||
inline float getSwimLevel(const Settings& settings, const float agentHalfExtentsZ)
|
||||
{
|
||||
return - settings.mSwimHeightScale * agentHalfExtentsZ;
|
||||
}
|
||||
|
||||
inline btTransform getSwimLevelTransform(const Settings& settings, const btTransform& transform,
|
||||
const float agentHalfExtentsZ)
|
||||
{
|
||||
return btTransform(
|
||||
transform.getBasis(),
|
||||
transform.getOrigin() + btVector3(0, 0, getSwimLevel(settings, agentHalfExtentsZ) - agentHalfExtentsZ)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -83,6 +83,80 @@ namespace DetourNavigator
|
|||
return result;
|
||||
}
|
||||
|
||||
bool TileCachedRecastMeshManager::addWater(const osg::Vec2i& cellPosition, const int cellSize,
|
||||
const btTransform& transform)
|
||||
{
|
||||
const auto border = getBorderSize(mSettings);
|
||||
|
||||
auto& tilesPositions = mWaterTilesPositions[cellPosition];
|
||||
|
||||
bool result = false;
|
||||
|
||||
if (cellSize == std::numeric_limits<int>::max())
|
||||
{
|
||||
const std::lock_guard<std::mutex> lock(mTilesMutex);
|
||||
for (auto& tile : mTiles)
|
||||
{
|
||||
if (tile.second.addWater(cellPosition, cellSize, transform))
|
||||
{
|
||||
tilesPositions.push_back(tile.first);
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
getTilesPositions(cellSize, 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.addWater(cellPosition, cellSize, transform))
|
||||
{
|
||||
lock.unlock();
|
||||
tilesPositions.push_back(tilePosition);
|
||||
result = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (result)
|
||||
++mRevision;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
boost::optional<RecastMeshManager::Water> TileCachedRecastMeshManager::removeWater(const osg::Vec2i& cellPosition)
|
||||
{
|
||||
const auto object = mWaterTilesPositions.find(cellPosition);
|
||||
if (object == mWaterTilesPositions.end())
|
||||
return boost::none;
|
||||
boost::optional<RecastMeshManager::Water> 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.removeWater(cellPosition);
|
||||
if (tile->second.isEmpty())
|
||||
mTiles.erase(tile);
|
||||
lock.unlock();
|
||||
if (tileResult && !result)
|
||||
result = tileResult;
|
||||
}
|
||||
if (result)
|
||||
++mRevision;
|
||||
return result;
|
||||
}
|
||||
|
||||
std::shared_ptr<RecastMesh> TileCachedRecastMeshManager::getMesh(const TilePosition& tilePosition)
|
||||
{
|
||||
const std::lock_guard<std::mutex> lock(mTilesMutex);
|
||||
|
|
|
@ -21,6 +21,10 @@ namespace DetourNavigator
|
|||
|
||||
boost::optional<RemovedRecastMeshObject> removeObject(std::size_t id);
|
||||
|
||||
bool addWater(const osg::Vec2i& cellPosition, const int cellSize, const btTransform& transform);
|
||||
|
||||
boost::optional<RecastMeshManager::Water> removeWater(const osg::Vec2i& cellPosition);
|
||||
|
||||
std::shared_ptr<RecastMesh> getMesh(const TilePosition& tilePosition);
|
||||
|
||||
bool hasTile(const TilePosition& tilePosition);
|
||||
|
@ -40,6 +44,7 @@ namespace DetourNavigator
|
|||
std::mutex mTilesMutex;
|
||||
std::map<TilePosition, CachedRecastMeshManager> mTiles;
|
||||
std::unordered_map<std::size_t, std::vector<TilePosition>> mObjectsTilesPositions;
|
||||
std::map<osg::Vec2i, std::vector<TilePosition>> mWaterTilesPositions;
|
||||
std::size_t mRevision = 0;
|
||||
};
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue