mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-20 07:53:51 +00:00
Merge pull request #2619 from elsid/togglerecastmesh
Support recast mesh rendering
This commit is contained in:
commit
1fadf259a9
36 changed files with 420 additions and 69 deletions
|
@ -21,7 +21,7 @@ add_openmw_dir (mwrender
|
|||
actors objects renderingmanager animation rotatecontroller sky npcanimation
|
||||
creatureanimation effectmanager util renderinginterface pathgrid rendermode weaponanimation
|
||||
bulletdebugdraw globalmap characterpreview camera localmap water terrainstorage ripplesimulation
|
||||
renderbin actoranimation landmanager navmesh actorspaths
|
||||
renderbin actoranimation landmanager navmesh actorspaths recastmesh
|
||||
)
|
||||
|
||||
add_openmw_dir (mwinput
|
||||
|
|
|
@ -34,7 +34,7 @@ namespace MWRender
|
|||
void NavMesh::update(const dtNavMesh& navMesh, const std::size_t id,
|
||||
const std::size_t generation, const std::size_t revision, const DetourNavigator::Settings& settings)
|
||||
{
|
||||
if (!mEnabled || (mGroup && mId == id && mGeneration >= generation && mRevision >= revision))
|
||||
if (!mEnabled || (mGroup && mId == id && mGeneration == generation && mRevision == revision))
|
||||
return;
|
||||
|
||||
mId = id;
|
||||
|
|
92
apps/openmw/mwrender/recastmesh.cpp
Normal file
92
apps/openmw/mwrender/recastmesh.cpp
Normal file
|
@ -0,0 +1,92 @@
|
|||
#include "recastmesh.hpp"
|
||||
|
||||
#include <components/sceneutil/vismask.hpp>
|
||||
#include <components/sceneutil/recastmesh.hpp>
|
||||
#include <components/debug/debuglog.hpp>
|
||||
|
||||
#include <osg/PositionAttitudeTransform>
|
||||
|
||||
namespace MWRender
|
||||
{
|
||||
RecastMesh::RecastMesh(const osg::ref_ptr<osg::Group>& root, bool enabled)
|
||||
: mRootNode(root)
|
||||
, mEnabled(enabled)
|
||||
{
|
||||
}
|
||||
|
||||
RecastMesh::~RecastMesh()
|
||||
{
|
||||
if (mEnabled)
|
||||
disable();
|
||||
}
|
||||
|
||||
bool RecastMesh::toggle()
|
||||
{
|
||||
if (mEnabled)
|
||||
disable();
|
||||
else
|
||||
enable();
|
||||
|
||||
return mEnabled;
|
||||
}
|
||||
|
||||
void RecastMesh::update(const DetourNavigator::RecastMeshTiles& tiles, const DetourNavigator::Settings& settings)
|
||||
{
|
||||
if (!mEnabled)
|
||||
return;
|
||||
|
||||
for (auto it = mGroups.begin(); it != mGroups.end();)
|
||||
{
|
||||
const auto tile = tiles.find(it->first);
|
||||
if (tile == tiles.end())
|
||||
{
|
||||
mRootNode->removeChild(it->second.mValue);
|
||||
it = mGroups.erase(it);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (it->second.mGeneration != tile->second->getGeneration()
|
||||
|| it->second.mRevision != tile->second->getRevision())
|
||||
{
|
||||
const auto group = SceneUtil::createRecastMeshGroup(*tile->second, settings);
|
||||
group->setNodeMask(SceneUtil::Mask_Debug);
|
||||
mRootNode->removeChild(it->second.mValue);
|
||||
mRootNode->addChild(group);
|
||||
it->second.mValue = group;
|
||||
it->second.mGeneration = tile->second->getGeneration();
|
||||
it->second.mRevision = tile->second->getRevision();
|
||||
continue;
|
||||
}
|
||||
|
||||
++it;
|
||||
}
|
||||
|
||||
for (const auto& tile : tiles)
|
||||
{
|
||||
if (mGroups.count(tile.first))
|
||||
continue;
|
||||
const auto group = SceneUtil::createRecastMeshGroup(*tile.second, settings);
|
||||
group->setNodeMask(SceneUtil::Mask_Debug);
|
||||
mGroups.emplace(tile.first, Group {tile.second->getGeneration(), tile.second->getRevision(), group});
|
||||
mRootNode->addChild(group);
|
||||
}
|
||||
}
|
||||
|
||||
void RecastMesh::reset()
|
||||
{
|
||||
std::for_each(mGroups.begin(), mGroups.end(), [&] (const auto& v) { mRootNode->removeChild(v.second.mValue); });
|
||||
mGroups.clear();
|
||||
}
|
||||
|
||||
void RecastMesh::enable()
|
||||
{
|
||||
std::for_each(mGroups.begin(), mGroups.end(), [&] (const auto& v) { mRootNode->addChild(v.second.mValue); });
|
||||
mEnabled = true;
|
||||
}
|
||||
|
||||
void RecastMesh::disable()
|
||||
{
|
||||
std::for_each(mGroups.begin(), mGroups.end(), [&] (const auto& v) { mRootNode->removeChild(v.second.mValue); });
|
||||
mEnabled = false;
|
||||
}
|
||||
}
|
53
apps/openmw/mwrender/recastmesh.hpp
Normal file
53
apps/openmw/mwrender/recastmesh.hpp
Normal file
|
@ -0,0 +1,53 @@
|
|||
#ifndef OPENMW_MWRENDER_RECASTMESH_H
|
||||
#define OPENMW_MWRENDER_RECASTMESH_H
|
||||
|
||||
#include <components/detournavigator/navigator.hpp>
|
||||
|
||||
#include <osg/ref_ptr>
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace osg
|
||||
{
|
||||
class Group;
|
||||
class Geometry;
|
||||
}
|
||||
|
||||
namespace MWRender
|
||||
{
|
||||
class RecastMesh
|
||||
{
|
||||
public:
|
||||
RecastMesh(const osg::ref_ptr<osg::Group>& root, bool enabled);
|
||||
~RecastMesh();
|
||||
|
||||
bool toggle();
|
||||
|
||||
void update(const DetourNavigator::RecastMeshTiles& recastMeshTiles, const DetourNavigator::Settings& settings);
|
||||
|
||||
void reset();
|
||||
|
||||
void enable();
|
||||
|
||||
void disable();
|
||||
|
||||
bool isEnabled() const
|
||||
{
|
||||
return mEnabled;
|
||||
}
|
||||
|
||||
private:
|
||||
struct Group
|
||||
{
|
||||
std::size_t mGeneration;
|
||||
std::size_t mRevision;
|
||||
osg::ref_ptr<osg::Group> mValue;
|
||||
};
|
||||
|
||||
osg::ref_ptr<osg::Group> mRootNode;
|
||||
bool mEnabled;
|
||||
std::map<DetourNavigator::TilePosition, Group> mGroups;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -66,6 +66,7 @@
|
|||
#include "util.hpp"
|
||||
#include "navmesh.hpp"
|
||||
#include "actorspaths.hpp"
|
||||
#include "recastmesh.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
|
@ -260,6 +261,7 @@ namespace MWRender
|
|||
|
||||
mNavMesh.reset(new NavMesh(mRootNode, Settings::Manager::getBool("enable nav mesh render", "Navigator")));
|
||||
mActorsPaths.reset(new ActorsPaths(mRootNode, Settings::Manager::getBool("enable agents paths render", "Navigator")));
|
||||
mRecastMesh.reset(new RecastMesh(mRootNode, Settings::Manager::getBool("enable recast mesh render", "Navigator")));
|
||||
mPathgrid.reset(new Pathgrid(mRootNode));
|
||||
|
||||
mObjects.reset(new Objects(mResourceSystem, sceneRoot, mUnrefQueue.get()));
|
||||
|
@ -585,6 +587,10 @@ namespace MWRender
|
|||
{
|
||||
return mActorsPaths->toggle();
|
||||
}
|
||||
else if (mode == Render_RecastMesh)
|
||||
{
|
||||
return mRecastMesh->toggle();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -651,6 +657,7 @@ namespace MWRender
|
|||
}
|
||||
|
||||
updateNavMesh();
|
||||
updateRecastMesh();
|
||||
|
||||
mCamera->update(dt, paused);
|
||||
|
||||
|
@ -1463,4 +1470,12 @@ namespace MWRender
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RenderingManager::updateRecastMesh()
|
||||
{
|
||||
if (!mRecastMesh->isEnabled())
|
||||
return;
|
||||
|
||||
mRecastMesh->update(mNavigator.getRecastMeshTiles(), mNavigator.getSettings());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -82,6 +82,7 @@ namespace MWRender
|
|||
class LandManager;
|
||||
class NavMesh;
|
||||
class ActorsPaths;
|
||||
class RecastMesh;
|
||||
|
||||
class RenderingManager : public MWRender::RenderingInterface
|
||||
{
|
||||
|
@ -246,6 +247,8 @@ namespace MWRender
|
|||
|
||||
void updateNavMesh();
|
||||
|
||||
void updateRecastMesh();
|
||||
|
||||
osg::ref_ptr<osgUtil::IntersectionVisitor> getIntersectionVisitor(osgUtil::Intersector* intersector, bool ignorePlayer, bool ignoreActors);
|
||||
|
||||
osg::ref_ptr<osgUtil::IntersectionVisitor> mIntersectionVisitor;
|
||||
|
@ -264,6 +267,7 @@ namespace MWRender
|
|||
std::unique_ptr<NavMesh> mNavMesh;
|
||||
std::size_t mNavMeshNumber = 0;
|
||||
std::unique_ptr<ActorsPaths> mActorsPaths;
|
||||
std::unique_ptr<RecastMesh> mRecastMesh;
|
||||
std::unique_ptr<Pathgrid> mPathgrid;
|
||||
std::unique_ptr<Objects> mObjects;
|
||||
std::unique_ptr<Water> mWater;
|
||||
|
|
|
@ -13,6 +13,7 @@ namespace MWRender
|
|||
Render_Scene,
|
||||
Render_NavMesh,
|
||||
Render_ActorsPaths,
|
||||
Render_RecastMesh,
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -463,5 +463,6 @@ op 0x200030c: RepairedOnMe
|
|||
op 0x200030d: RepairedOnMe, explicit
|
||||
op 0x200030e: TestCells
|
||||
op 0x200030f: TestInteriorCells
|
||||
op 0x2000310: ToggleRecastMesh
|
||||
|
||||
opcodes 0x2000310-0x3ffffff unused
|
||||
opcodes 0x2000311-0x3ffffff unused
|
||||
|
|
|
@ -1440,6 +1440,20 @@ namespace MWScript
|
|||
}
|
||||
};
|
||||
|
||||
class OpToggleRecastMesh : public Interpreter::Opcode0
|
||||
{
|
||||
public:
|
||||
|
||||
virtual void execute (Interpreter::Runtime& runtime)
|
||||
{
|
||||
bool enabled =
|
||||
MWBase::Environment::get().getWorld()->toggleRenderMode (MWRender::Render_RecastMesh);
|
||||
|
||||
runtime.getContext().report (enabled ?
|
||||
"Recast Mesh Rendering -> On" : "Recast Mesh Rendering -> Off");
|
||||
}
|
||||
};
|
||||
|
||||
void installOpcodes (Interpreter::Interpreter& interpreter)
|
||||
{
|
||||
interpreter.installSegment5 (Compiler::Misc::opcodeXBox, new OpXBox);
|
||||
|
@ -1545,6 +1559,7 @@ namespace MWScript
|
|||
interpreter.installSegment5 (Compiler::Misc::opcodeSetNavMeshNumberToRender, new OpSetNavMeshNumberToRender);
|
||||
interpreter.installSegment5 (Compiler::Misc::opcodeRepairedOnMe, new OpRepairedOnMe<ImplicitRef>);
|
||||
interpreter.installSegment5 (Compiler::Misc::opcodeRepairedOnMeExplicit, new OpRepairedOnMe<ExplicitRef>);
|
||||
interpreter.installSegment5 (Compiler::Misc::opcodeToggleRecastMesh, new OpToggleRecastMesh);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,12 +25,15 @@ namespace
|
|||
{
|
||||
const osg::Vec3f mAgentHalfExtents {1, 2, 3};
|
||||
const TilePosition mTilePosition {0, 0};
|
||||
const std::size_t mGeneration = 0;
|
||||
const std::size_t mRevision = 0;
|
||||
const std::vector<int> mIndices {{0, 1, 2}};
|
||||
const std::vector<float> mVertices {{0, 0, 0, 1, 0, 0, 1, 1, 0}};
|
||||
const std::vector<AreaType> mAreaTypes {1, AreaType_ground};
|
||||
const std::vector<RecastMesh::Water> mWater {};
|
||||
const std::size_t mTrianglesPerChunk {1};
|
||||
const RecastMesh mRecastMesh {mIndices, mVertices, mAreaTypes, mWater, mTrianglesPerChunk};
|
||||
const RecastMesh mRecastMesh {mGeneration, mRevision, mIndices, mVertices,
|
||||
mAreaTypes, mWater, mTrianglesPerChunk};
|
||||
const std::vector<OffMeshConnection> mOffMeshConnections {};
|
||||
unsigned char* const mData = reinterpret_cast<unsigned char*>(dtAlloc(1, DT_ALLOC_PERM));
|
||||
NavMeshData mNavMeshData {mData, 1};
|
||||
|
@ -128,7 +131,8 @@ namespace
|
|||
const std::size_t maxSize = 1;
|
||||
NavMeshTilesCache cache(maxSize);
|
||||
const std::vector<RecastMesh::Water> water {1, RecastMesh::Water {1, btTransform::getIdentity()}};
|
||||
const RecastMesh unexistentRecastMesh {mIndices, mVertices, mAreaTypes, water, mTrianglesPerChunk};
|
||||
const RecastMesh unexistentRecastMesh {mGeneration, mRevision, mIndices, mVertices,
|
||||
mAreaTypes, water, mTrianglesPerChunk};
|
||||
|
||||
cache.set(mAgentHalfExtents, mTilePosition, mRecastMesh, mOffMeshConnections, std::move(mNavMeshData));
|
||||
EXPECT_FALSE(cache.get(mAgentHalfExtents, mTilePosition, unexistentRecastMesh, mOffMeshConnections));
|
||||
|
@ -142,7 +146,8 @@ namespace
|
|||
NavMeshTilesCache cache(maxSize);
|
||||
|
||||
const std::vector<RecastMesh::Water> water {1, RecastMesh::Water {1, btTransform::getIdentity()}};
|
||||
const RecastMesh anotherRecastMesh {mIndices, mVertices, mAreaTypes, water, mTrianglesPerChunk};
|
||||
const RecastMesh anotherRecastMesh {mGeneration, mRevision, mIndices, mVertices,
|
||||
mAreaTypes, water, mTrianglesPerChunk};
|
||||
const auto anotherData = reinterpret_cast<unsigned char*>(dtAlloc(1, DT_ALLOC_PERM));
|
||||
NavMeshData anotherNavMeshData {anotherData, 1};
|
||||
|
||||
|
@ -162,7 +167,8 @@ namespace
|
|||
NavMeshTilesCache cache(maxSize);
|
||||
|
||||
const std::vector<RecastMesh::Water> water {1, RecastMesh::Water {1, btTransform::getIdentity()}};
|
||||
const RecastMesh anotherRecastMesh {mIndices, mVertices, mAreaTypes, water, mTrianglesPerChunk};
|
||||
const RecastMesh anotherRecastMesh {mGeneration, mRevision, mIndices, mVertices,
|
||||
mAreaTypes, water, mTrianglesPerChunk};
|
||||
const auto anotherData = reinterpret_cast<unsigned char*>(dtAlloc(1, DT_ALLOC_PERM));
|
||||
NavMeshData anotherNavMeshData {anotherData, 1};
|
||||
|
||||
|
@ -180,14 +186,14 @@ namespace
|
|||
NavMeshTilesCache cache(maxSize);
|
||||
|
||||
const std::vector<RecastMesh::Water> leastRecentlySetWater {1, RecastMesh::Water {1, btTransform::getIdentity()}};
|
||||
const RecastMesh leastRecentlySetRecastMesh {mIndices, mVertices, mAreaTypes, leastRecentlySetWater,
|
||||
mTrianglesPerChunk};
|
||||
const RecastMesh leastRecentlySetRecastMesh {mGeneration, mRevision, mIndices, mVertices,
|
||||
mAreaTypes, leastRecentlySetWater, mTrianglesPerChunk};
|
||||
const auto leastRecentlySetData = reinterpret_cast<unsigned char*>(dtAlloc(1, DT_ALLOC_PERM));
|
||||
NavMeshData leastRecentlySetNavMeshData {leastRecentlySetData, 1};
|
||||
|
||||
const std::vector<RecastMesh::Water> mostRecentlySetWater {1, RecastMesh::Water {2, btTransform::getIdentity()}};
|
||||
const RecastMesh mostRecentlySetRecastMesh {mIndices, mVertices, mAreaTypes, mostRecentlySetWater,
|
||||
mTrianglesPerChunk};
|
||||
const RecastMesh mostRecentlySetRecastMesh {mGeneration, mRevision, mIndices, mVertices,
|
||||
mAreaTypes, mostRecentlySetWater, mTrianglesPerChunk};
|
||||
const auto mostRecentlySetData = reinterpret_cast<unsigned char*>(dtAlloc(1, DT_ALLOC_PERM));
|
||||
NavMeshData mostRecentlySetNavMeshData {mostRecentlySetData, 1};
|
||||
|
||||
|
@ -212,14 +218,14 @@ namespace
|
|||
NavMeshTilesCache cache(maxSize);
|
||||
|
||||
const std::vector<RecastMesh::Water> leastRecentlyUsedWater {1, RecastMesh::Water {1, btTransform::getIdentity()}};
|
||||
const RecastMesh leastRecentlyUsedRecastMesh {mIndices, mVertices, mAreaTypes, leastRecentlyUsedWater,
|
||||
mTrianglesPerChunk};
|
||||
const RecastMesh leastRecentlyUsedRecastMesh {mGeneration, mRevision, mIndices, mVertices,
|
||||
mAreaTypes, leastRecentlyUsedWater, mTrianglesPerChunk};
|
||||
const auto leastRecentlyUsedData = reinterpret_cast<unsigned char*>(dtAlloc(1, DT_ALLOC_PERM));
|
||||
NavMeshData leastRecentlyUsedNavMeshData {leastRecentlyUsedData, 1};
|
||||
|
||||
const std::vector<RecastMesh::Water> mostRecentlyUsedWater {1, RecastMesh::Water {2, btTransform::getIdentity()}};
|
||||
const RecastMesh mostRecentlyUsedRecastMesh {mIndices, mVertices, mAreaTypes, mostRecentlyUsedWater,
|
||||
mTrianglesPerChunk};
|
||||
const RecastMesh mostRecentlyUsedRecastMesh {mGeneration, mRevision, mIndices, mVertices,
|
||||
mAreaTypes, mostRecentlyUsedWater, mTrianglesPerChunk};
|
||||
const auto mostRecentlyUsedData = reinterpret_cast<unsigned char*>(dtAlloc(1, DT_ALLOC_PERM));
|
||||
NavMeshData mostRecentlyUsedNavMeshData {mostRecentlyUsedData, 1};
|
||||
|
||||
|
@ -256,7 +262,7 @@ namespace
|
|||
NavMeshTilesCache cache(maxSize);
|
||||
|
||||
const std::vector<RecastMesh::Water> water {1, RecastMesh::Water {1, btTransform::getIdentity()}};
|
||||
const RecastMesh tooLargeRecastMesh {mIndices, mVertices, mAreaTypes, water, mTrianglesPerChunk};
|
||||
const RecastMesh tooLargeRecastMesh {mGeneration, mRevision, mIndices, mVertices, mAreaTypes, water, mTrianglesPerChunk};
|
||||
const auto tooLargeData = reinterpret_cast<unsigned char*>(dtAlloc(2, DT_ALLOC_PERM));
|
||||
NavMeshData tooLargeNavMeshData {tooLargeData, 2};
|
||||
|
||||
|
@ -275,12 +281,13 @@ namespace
|
|||
NavMeshTilesCache cache(maxSize);
|
||||
|
||||
const std::vector<RecastMesh::Water> anotherWater {1, RecastMesh::Water {1, btTransform::getIdentity()}};
|
||||
const RecastMesh anotherRecastMesh {mIndices, mVertices, mAreaTypes, anotherWater, mTrianglesPerChunk};
|
||||
const RecastMesh anotherRecastMesh {mGeneration, mRevision, mIndices, mVertices, mAreaTypes, anotherWater, mTrianglesPerChunk};
|
||||
const auto anotherData = reinterpret_cast<unsigned char*>(dtAlloc(1, DT_ALLOC_PERM));
|
||||
NavMeshData anotherNavMeshData {anotherData, 1};
|
||||
|
||||
const std::vector<RecastMesh::Water> tooLargeWater {1, RecastMesh::Water {2, btTransform::getIdentity()}};
|
||||
const RecastMesh tooLargeRecastMesh {mIndices, mVertices, mAreaTypes, tooLargeWater, mTrianglesPerChunk};
|
||||
const RecastMesh tooLargeRecastMesh {mGeneration, mRevision, mIndices, mVertices,
|
||||
mAreaTypes, tooLargeWater, mTrianglesPerChunk};
|
||||
const auto tooLargeData = reinterpret_cast<unsigned char*>(dtAlloc(2, DT_ALLOC_PERM));
|
||||
NavMeshData tooLargeNavMeshData {tooLargeData, 2};
|
||||
|
||||
|
@ -303,7 +310,8 @@ namespace
|
|||
NavMeshTilesCache cache(maxSize);
|
||||
|
||||
const std::vector<RecastMesh::Water> water {1, RecastMesh::Water {1, btTransform::getIdentity()}};
|
||||
const RecastMesh anotherRecastMesh {mIndices, mVertices, mAreaTypes, water, mTrianglesPerChunk};
|
||||
const RecastMesh anotherRecastMesh {mGeneration, mRevision, mIndices, mVertices,
|
||||
mAreaTypes, water, mTrianglesPerChunk};
|
||||
const auto anotherData = reinterpret_cast<unsigned char*>(dtAlloc(1, DT_ALLOC_PERM));
|
||||
NavMeshData anotherNavMeshData {anotherData, 1};
|
||||
|
||||
|
@ -326,7 +334,7 @@ namespace
|
|||
NavMeshTilesCache cache(maxSize);
|
||||
|
||||
const std::vector<RecastMesh::Water> water {1, RecastMesh::Water {1, btTransform::getIdentity()}};
|
||||
const RecastMesh anotherRecastMesh {mIndices, mVertices, mAreaTypes, water, mTrianglesPerChunk};
|
||||
const RecastMesh anotherRecastMesh {mGeneration, mRevision, mIndices, mVertices, mAreaTypes, water, mTrianglesPerChunk};
|
||||
const auto anotherData = reinterpret_cast<unsigned char*>(dtAlloc(1, DT_ALLOC_PERM));
|
||||
NavMeshData anotherNavMeshData {anotherData, 1};
|
||||
|
||||
|
|
|
@ -30,6 +30,8 @@ namespace
|
|||
{
|
||||
Settings mSettings;
|
||||
TileBounds mBounds;
|
||||
const std::size_t mGeneration = 0;
|
||||
const std::size_t mRevision = 0;
|
||||
|
||||
DetourNavigatorRecastMeshBuilderTest()
|
||||
{
|
||||
|
@ -45,7 +47,7 @@ namespace
|
|||
TEST_F(DetourNavigatorRecastMeshBuilderTest, create_for_empty_should_return_empty)
|
||||
{
|
||||
RecastMeshBuilder builder(mSettings, mBounds);
|
||||
const auto recastMesh = builder.create();
|
||||
const auto recastMesh = builder.create(mGeneration, mRevision);
|
||||
EXPECT_EQ(recastMesh->getVertices(), std::vector<float>());
|
||||
EXPECT_EQ(recastMesh->getIndices(), std::vector<int>());
|
||||
EXPECT_EQ(recastMesh->getAreaTypes(), std::vector<AreaType>());
|
||||
|
@ -59,7 +61,7 @@ namespace
|
|||
|
||||
RecastMeshBuilder builder(mSettings, mBounds);
|
||||
builder.addObject(static_cast<const btCollisionShape&>(shape), btTransform::getIdentity(), AreaType_ground);
|
||||
const auto recastMesh = builder.create();
|
||||
const auto recastMesh = builder.create(mGeneration, mRevision);
|
||||
EXPECT_EQ(recastMesh->getVertices(), std::vector<float>({
|
||||
1, 0, -1,
|
||||
-1, 0, 1,
|
||||
|
@ -80,7 +82,7 @@ namespace
|
|||
btTransform(btMatrix3x3::getIdentity().scaled(btVector3(1, 2, 3)), btVector3(1, 2, 3)),
|
||||
AreaType_ground
|
||||
);
|
||||
const auto recastMesh = builder.create();
|
||||
const auto recastMesh = builder.create(mGeneration, mRevision);
|
||||
EXPECT_EQ(recastMesh->getVertices(), std::vector<float>({
|
||||
2, 3, 0,
|
||||
0, 3, 4,
|
||||
|
@ -96,7 +98,7 @@ namespace
|
|||
btHeightfieldTerrainShape shape(2, 2, heightfieldData.data(), 1, 0, 0, 2, PHY_FLOAT, false);
|
||||
RecastMeshBuilder builder(mSettings, mBounds);
|
||||
builder.addObject(static_cast<const btCollisionShape&>(shape), btTransform::getIdentity(), AreaType_ground);
|
||||
const auto recastMesh = builder.create();
|
||||
const auto recastMesh = builder.create(mGeneration, mRevision);
|
||||
EXPECT_EQ(recastMesh->getVertices(), std::vector<float>({
|
||||
-0.5, 0, -0.5,
|
||||
-0.5, 0, 0.5,
|
||||
|
@ -114,7 +116,7 @@ namespace
|
|||
btBoxShape shape(btVector3(1, 1, 2));
|
||||
RecastMeshBuilder builder(mSettings, mBounds);
|
||||
builder.addObject(static_cast<const btCollisionShape&>(shape), btTransform::getIdentity(), AreaType_ground);
|
||||
const auto recastMesh = builder.create();
|
||||
const auto recastMesh = builder.create(mGeneration, mRevision);
|
||||
EXPECT_EQ(recastMesh->getVertices(), std::vector<float>({
|
||||
1, 2, 1,
|
||||
-1, 2, 1,
|
||||
|
@ -161,7 +163,7 @@ namespace
|
|||
btTransform::getIdentity(),
|
||||
AreaType_ground
|
||||
);
|
||||
const auto recastMesh = builder.create();
|
||||
const auto recastMesh = builder.create(mGeneration, mRevision);
|
||||
EXPECT_EQ(recastMesh->getVertices(), std::vector<float>({
|
||||
1, 0, -1,
|
||||
-1, 0, 1,
|
||||
|
@ -210,7 +212,7 @@ namespace
|
|||
btTransform(btMatrix3x3::getIdentity().scaled(btVector3(1, 2, 3)), btVector3(1, 2, 3)),
|
||||
AreaType_ground
|
||||
);
|
||||
const auto recastMesh = builder.create();
|
||||
const auto recastMesh = builder.create(mGeneration, mRevision);
|
||||
EXPECT_EQ(recastMesh->getVertices(), std::vector<float>({
|
||||
2, 3, 0,
|
||||
0, 3, 4,
|
||||
|
@ -234,7 +236,7 @@ namespace
|
|||
btTransform(btMatrix3x3::getIdentity().scaled(btVector3(1, 2, 3)), btVector3(1, 2, 3)),
|
||||
AreaType_ground
|
||||
);
|
||||
const auto recastMesh = builder.create();
|
||||
const auto recastMesh = builder.create(mGeneration, mRevision);
|
||||
EXPECT_EQ(recastMesh->getVertices(), std::vector<float>({
|
||||
3, 12, 2,
|
||||
1, 12, 10,
|
||||
|
@ -256,7 +258,7 @@ namespace
|
|||
btTransform::getIdentity(),
|
||||
AreaType_ground
|
||||
);
|
||||
const auto recastMesh = builder.create();
|
||||
const auto recastMesh = builder.create(mGeneration, mRevision);
|
||||
EXPECT_EQ(recastMesh->getVertices(), std::vector<float>({
|
||||
1, 0, -1,
|
||||
-1, 0, 1,
|
||||
|
@ -284,7 +286,7 @@ namespace
|
|||
btTransform::getIdentity(),
|
||||
AreaType_ground
|
||||
);
|
||||
const auto recastMesh = builder.create();
|
||||
const auto recastMesh = builder.create(mGeneration, mRevision);
|
||||
EXPECT_EQ(recastMesh->getVertices(), std::vector<float>({
|
||||
-0.2f, 0, -0.3f,
|
||||
-0.3f, 0, -0.2f,
|
||||
|
@ -309,7 +311,7 @@ namespace
|
|||
static_cast<btScalar>(-osg::PI_4))),
|
||||
AreaType_ground
|
||||
);
|
||||
const auto recastMesh = builder.create();
|
||||
const auto recastMesh = builder.create(mGeneration, mRevision);
|
||||
EXPECT_EQ(recastMesh->getVertices(), std::vector<float>({
|
||||
0, -0.70710659027099609375, -3.535533905029296875,
|
||||
0, 0.707107067108154296875, -3.535533905029296875,
|
||||
|
@ -334,7 +336,7 @@ namespace
|
|||
static_cast<btScalar>(osg::PI_4))),
|
||||
AreaType_ground
|
||||
);
|
||||
const auto recastMesh = builder.create();
|
||||
const auto recastMesh = builder.create(mGeneration, mRevision);
|
||||
EXPECT_EQ(recastMesh->getVertices(), std::vector<float>({
|
||||
-3.535533905029296875, -0.70710659027099609375, 0,
|
||||
-3.535533905029296875, 0.707107067108154296875, 0,
|
||||
|
@ -359,7 +361,7 @@ namespace
|
|||
static_cast<btScalar>(osg::PI_4))),
|
||||
AreaType_ground
|
||||
);
|
||||
const auto recastMesh = builder.create();
|
||||
const auto recastMesh = builder.create(mGeneration, mRevision);
|
||||
EXPECT_EQ(recastMesh->getVertices(), std::vector<float>({
|
||||
1.41421353816986083984375, 0, 1.1920928955078125e-07,
|
||||
-1.41421353816986083984375, 0, -1.1920928955078125e-07,
|
||||
|
@ -388,7 +390,7 @@ namespace
|
|||
btTransform::getIdentity(),
|
||||
AreaType_null
|
||||
);
|
||||
const auto recastMesh = builder.create();
|
||||
const auto recastMesh = builder.create(mGeneration, mRevision);
|
||||
EXPECT_EQ(recastMesh->getVertices(), std::vector<float>({
|
||||
1, 0, -1,
|
||||
-1, 0, 1,
|
||||
|
@ -405,7 +407,7 @@ namespace
|
|||
{
|
||||
RecastMeshBuilder builder(mSettings, mBounds);
|
||||
builder.addWater(1000, btTransform(btMatrix3x3::getIdentity(), btVector3(100, 200, 300)));
|
||||
const auto recastMesh = builder.create();
|
||||
const auto recastMesh = builder.create(mGeneration, mRevision);
|
||||
EXPECT_EQ(recastMesh->getWater(), std::vector<RecastMesh::Water>({
|
||||
RecastMesh::Water {1000, btTransform(btMatrix3x3::getIdentity(), btVector3(100, 200, 300))}
|
||||
}));
|
||||
|
|
|
@ -51,7 +51,7 @@ add_component_dir (shader
|
|||
add_component_dir (sceneutil
|
||||
clone attach visitor util statesetupdater controller skeleton riggeometry morphgeometry lightcontroller
|
||||
lightmanager lightutil positionattitudetransform workqueue unrefqueue pathgridutil waterutil writescene serialize optimizer
|
||||
actorutil detourdebugdraw navmesh agentpath shadow mwshadowtechnique vismask
|
||||
actorutil detourdebugdraw navmesh agentpath shadow mwshadowtechnique vismask recastmesh
|
||||
)
|
||||
|
||||
add_component_dir (nif
|
||||
|
|
|
@ -327,6 +327,7 @@ namespace Compiler
|
|||
extensions.registerInstruction ("toggleactorspaths", "", opcodeToggleActorsPaths);
|
||||
extensions.registerInstruction ("setnavmeshnumber", "l", opcodeSetNavMeshNumberToRender);
|
||||
extensions.registerFunction ("repairedonme", 'l', "S", opcodeRepairedOnMe, opcodeRepairedOnMeExplicit);
|
||||
extensions.registerInstruction ("togglerecastmesh", "", opcodeToggleRecastMesh);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -304,6 +304,7 @@ namespace Compiler
|
|||
const int opcodeSetNavMeshNumberToRender = 0x200030a;
|
||||
const int opcodeRepairedOnMe = 0x200030c;
|
||||
const int opcodeRepairedOnMeExplicit = 0x200030d;
|
||||
const int opcodeToggleRecastMesh = 0x2000310;
|
||||
}
|
||||
|
||||
namespace Sky
|
||||
|
|
|
@ -3,8 +3,9 @@
|
|||
|
||||
namespace DetourNavigator
|
||||
{
|
||||
CachedRecastMeshManager::CachedRecastMeshManager(const Settings& settings, const TileBounds& bounds)
|
||||
: mImpl(settings, bounds)
|
||||
CachedRecastMeshManager::CachedRecastMeshManager(const Settings& settings, const TileBounds& bounds,
|
||||
std::size_t generation)
|
||||
: mImpl(settings, bounds, generation)
|
||||
{}
|
||||
|
||||
bool CachedRecastMeshManager::addObject(const ObjectId id, const btCollisionShape& shape,
|
||||
|
|
|
@ -10,7 +10,7 @@ namespace DetourNavigator
|
|||
class CachedRecastMeshManager
|
||||
{
|
||||
public:
|
||||
CachedRecastMeshManager(const Settings& settings, const TileBounds& bounds);
|
||||
CachedRecastMeshManager(const Settings& settings, const TileBounds& bounds, std::size_t generation);
|
||||
|
||||
bool addObject(const ObjectId id, const btCollisionShape& shape, const btTransform& transform,
|
||||
const AreaType areaType);
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
#include "settings.hpp"
|
||||
#include "objectid.hpp"
|
||||
#include "navmeshcacheitem.hpp"
|
||||
#include "recastmesh.hpp"
|
||||
#include "recastmeshtiles.hpp"
|
||||
|
||||
namespace DetourNavigator
|
||||
{
|
||||
|
@ -204,6 +206,8 @@ namespace DetourNavigator
|
|||
*/
|
||||
boost::optional<osg::Vec3f> findRandomPointAroundCircle(const osg::Vec3f& agentHalfExtents,
|
||||
const osg::Vec3f& start, const float maxRadius, const Flags includeFlags) const;
|
||||
|
||||
virtual RecastMeshTiles getRecastMeshTiles() = 0;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -143,6 +143,11 @@ namespace DetourNavigator
|
|||
mNavMeshManager.reportStats(frameNumber, stats);
|
||||
}
|
||||
|
||||
RecastMeshTiles NavigatorImpl::getRecastMeshTiles()
|
||||
{
|
||||
return mNavMeshManager.getRecastMeshTiles();
|
||||
}
|
||||
|
||||
void NavigatorImpl::updateAvoidShapeId(const ObjectId id, const ObjectId avoidId)
|
||||
{
|
||||
updateId(id, avoidId, mWaterIds);
|
||||
|
|
|
@ -50,6 +50,8 @@ namespace DetourNavigator
|
|||
|
||||
void reportStats(unsigned int frameNumber, osg::Stats& stats) const override;
|
||||
|
||||
RecastMeshTiles getRecastMeshTiles() override;
|
||||
|
||||
private:
|
||||
Settings mSettings;
|
||||
NavMeshManager mNavMeshManager;
|
||||
|
|
|
@ -81,6 +81,11 @@ namespace DetourNavigator
|
|||
|
||||
void reportStats(unsigned int /*frameNumber*/, osg::Stats& /*stats*/) const override {}
|
||||
|
||||
RecastMeshTiles getRecastMeshTiles() override
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
private:
|
||||
Settings mDefaultSettings {};
|
||||
SharedNavMeshCacheItem mEmptyNavMeshCacheItem;
|
||||
|
|
|
@ -147,7 +147,7 @@ namespace DetourNavigator
|
|||
const auto playerTile = getTilePosition(mSettings, toNavMeshCoordinates(mSettings, playerPosition));
|
||||
auto& lastRevision = mLastRecastMeshManagerRevision[agentHalfExtents];
|
||||
auto lastPlayerTile = mPlayerTile.find(agentHalfExtents);
|
||||
if (lastRevision >= mRecastMeshManager.getRevision() && lastPlayerTile != mPlayerTile.end()
|
||||
if (lastRevision == mRecastMeshManager.getRevision() && lastPlayerTile != mPlayerTile.end()
|
||||
&& lastPlayerTile->second == playerTile)
|
||||
return;
|
||||
lastRevision = mRecastMeshManager.getRevision();
|
||||
|
@ -220,6 +220,17 @@ namespace DetourNavigator
|
|||
mAsyncNavMeshUpdater.reportStats(frameNumber, stats);
|
||||
}
|
||||
|
||||
RecastMeshTiles NavMeshManager::getRecastMeshTiles()
|
||||
{
|
||||
std::vector<TilePosition> tiles;
|
||||
mRecastMeshManager.forEachTilePosition(
|
||||
[&tiles] (const TilePosition& tile) { tiles.push_back(tile); });
|
||||
RecastMeshTiles result;
|
||||
std::transform(tiles.begin(), tiles.end(), std::inserter(result, result.end()),
|
||||
[this] (const TilePosition& tile) { return std::make_pair(tile, mRecastMeshManager.getMesh(tile)); });
|
||||
return result;
|
||||
}
|
||||
|
||||
void NavMeshManager::addChangedTiles(const btCollisionShape& shape, const btTransform& transform,
|
||||
const ChangeType changeType)
|
||||
{
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include "cachedrecastmeshmanager.hpp"
|
||||
#include "offmeshconnectionsmanager.hpp"
|
||||
#include "sharednavmesh.hpp"
|
||||
#include "recastmeshtiles.hpp"
|
||||
|
||||
#include <BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h>
|
||||
|
||||
|
@ -52,6 +53,8 @@ namespace DetourNavigator
|
|||
|
||||
void reportStats(unsigned int frameNumber, osg::Stats& stats) const;
|
||||
|
||||
RecastMeshTiles getRecastMeshTiles();
|
||||
|
||||
private:
|
||||
const Settings& mSettings;
|
||||
TileCachedRecastMeshManager mRecastMeshManager;
|
||||
|
|
|
@ -5,9 +5,11 @@
|
|||
|
||||
namespace DetourNavigator
|
||||
{
|
||||
RecastMesh::RecastMesh(std::vector<int> indices, std::vector<float> vertices, std::vector<AreaType> areaTypes,
|
||||
std::vector<Water> water, const std::size_t trianglesPerChunk)
|
||||
: mIndices(std::move(indices))
|
||||
RecastMesh::RecastMesh(std::size_t generation, std::size_t revision, std::vector<int> indices, std::vector<float> vertices,
|
||||
std::vector<AreaType> areaTypes, std::vector<Water> water, const std::size_t trianglesPerChunk)
|
||||
: mGeneration(generation)
|
||||
, mRevision(revision)
|
||||
, mIndices(std::move(indices))
|
||||
, mVertices(std::move(vertices))
|
||||
, mAreaTypes(std::move(areaTypes))
|
||||
, mWater(std::move(water))
|
||||
|
|
|
@ -24,8 +24,18 @@ namespace DetourNavigator
|
|||
btTransform mTransform;
|
||||
};
|
||||
|
||||
RecastMesh(std::vector<int> indices, std::vector<float> vertices, std::vector<AreaType> areaTypes,
|
||||
std::vector<Water> water, const std::size_t trianglesPerChunk);
|
||||
RecastMesh(std::size_t generation, std::size_t revision, std::vector<int> indices, std::vector<float> vertices,
|
||||
std::vector<AreaType> areaTypes, std::vector<Water> water, const std::size_t trianglesPerChunk);
|
||||
|
||||
std::size_t getGeneration() const
|
||||
{
|
||||
return mGeneration;
|
||||
}
|
||||
|
||||
std::size_t getRevision() const
|
||||
{
|
||||
return mRevision;
|
||||
}
|
||||
|
||||
const std::vector<int>& getIndices() const
|
||||
{
|
||||
|
@ -68,6 +78,8 @@ namespace DetourNavigator
|
|||
}
|
||||
|
||||
private:
|
||||
std::size_t mGeneration;
|
||||
std::size_t mRevision;
|
||||
std::vector<int> mIndices;
|
||||
std::vector<float> mVertices;
|
||||
std::vector<AreaType> mAreaTypes;
|
||||
|
|
|
@ -112,9 +112,10 @@ namespace DetourNavigator
|
|||
mWater.push_back(RecastMesh::Water {cellSize, transform});
|
||||
}
|
||||
|
||||
std::shared_ptr<RecastMesh> RecastMeshBuilder::create() const
|
||||
std::shared_ptr<RecastMesh> RecastMeshBuilder::create(std::size_t generation, std::size_t revision) const
|
||||
{
|
||||
return std::make_shared<RecastMesh>(mIndices, mVertices, mAreaTypes, mWater, mSettings.get().mTrianglesPerChunk);
|
||||
return std::make_shared<RecastMesh>(generation, revision, mIndices, mVertices, mAreaTypes,
|
||||
mWater, mSettings.get().mTrianglesPerChunk);
|
||||
}
|
||||
|
||||
void RecastMeshBuilder::reset()
|
||||
|
|
|
@ -34,7 +34,7 @@ namespace DetourNavigator
|
|||
|
||||
void addWater(const int mCellSize, const btTransform& transform);
|
||||
|
||||
std::shared_ptr<RecastMesh> create() const;
|
||||
std::shared_ptr<RecastMesh> create(std::size_t generation, std::size_t revision) const;
|
||||
|
||||
void reset();
|
||||
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
|
||||
namespace DetourNavigator
|
||||
{
|
||||
RecastMeshManager::RecastMeshManager(const Settings& settings, const TileBounds& bounds)
|
||||
: mShouldRebuild(false)
|
||||
RecastMeshManager::RecastMeshManager(const Settings& settings, const TileBounds& bounds, std::size_t generation)
|
||||
: mGeneration(generation)
|
||||
, mMeshBuilder(settings, bounds)
|
||||
{
|
||||
}
|
||||
|
@ -19,8 +19,8 @@ namespace DetourNavigator
|
|||
mObjectsOrder.erase(iterator);
|
||||
return false;
|
||||
}
|
||||
mShouldRebuild = true;
|
||||
return mShouldRebuild;
|
||||
++mRevision;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RecastMeshManager::updateObject(const ObjectId id, const btTransform& transform, const AreaType areaType)
|
||||
|
@ -30,8 +30,8 @@ namespace DetourNavigator
|
|||
return false;
|
||||
if (!object->second->update(transform, areaType))
|
||||
return false;
|
||||
mShouldRebuild = true;
|
||||
return mShouldRebuild;
|
||||
++mRevision;
|
||||
return true;
|
||||
}
|
||||
|
||||
boost::optional<RemovedRecastMeshObject> RecastMeshManager::removeObject(const ObjectId id)
|
||||
|
@ -42,7 +42,7 @@ namespace DetourNavigator
|
|||
const RemovedRecastMeshObject result {object->second->getShape(), object->second->getTransform()};
|
||||
mObjectsOrder.erase(object->second);
|
||||
mObjects.erase(object);
|
||||
mShouldRebuild = true;
|
||||
++mRevision;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -55,7 +55,7 @@ namespace DetourNavigator
|
|||
mWaterOrder.erase(iterator);
|
||||
return false;
|
||||
}
|
||||
mShouldRebuild = true;
|
||||
++mRevision;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -64,7 +64,7 @@ namespace DetourNavigator
|
|||
const auto water = mWater.find(cellPosition);
|
||||
if (water == mWater.end())
|
||||
return boost::none;
|
||||
mShouldRebuild = true;
|
||||
++mRevision;
|
||||
const auto result = *water->second;
|
||||
mWaterOrder.erase(water->second);
|
||||
mWater.erase(water);
|
||||
|
@ -74,7 +74,7 @@ namespace DetourNavigator
|
|||
std::shared_ptr<RecastMesh> RecastMeshManager::getMesh()
|
||||
{
|
||||
rebuild();
|
||||
return mMeshBuilder.create();
|
||||
return mMeshBuilder.create(mGeneration, mLastBuildRevision);
|
||||
}
|
||||
|
||||
bool RecastMeshManager::isEmpty() const
|
||||
|
@ -84,13 +84,13 @@ namespace DetourNavigator
|
|||
|
||||
void RecastMeshManager::rebuild()
|
||||
{
|
||||
if (!mShouldRebuild)
|
||||
if (mLastBuildRevision == mRevision)
|
||||
return;
|
||||
mMeshBuilder.reset();
|
||||
for (const auto& v : mWaterOrder)
|
||||
mMeshBuilder.addWater(v.mCellSize, v.mTransform);
|
||||
for (const auto& v : mObjectsOrder)
|
||||
mMeshBuilder.addObject(v.getShape(), v.getTransform(), v.getAreaType());
|
||||
mShouldRebuild = false;
|
||||
mLastBuildRevision = mRevision;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ namespace DetourNavigator
|
|||
btTransform mTransform;
|
||||
};
|
||||
|
||||
RecastMeshManager(const Settings& settings, const TileBounds& bounds);
|
||||
RecastMeshManager(const Settings& settings, const TileBounds& bounds, std::size_t generation);
|
||||
|
||||
bool addObject(const ObjectId id, const btCollisionShape& shape, const btTransform& transform,
|
||||
const AreaType areaType);
|
||||
|
@ -52,7 +52,9 @@ namespace DetourNavigator
|
|||
bool isEmpty() const;
|
||||
|
||||
private:
|
||||
bool mShouldRebuild;
|
||||
std::size_t mRevision = 0;
|
||||
std::size_t mLastBuildRevision = 0;
|
||||
std::size_t mGeneration;
|
||||
RecastMeshBuilder mMeshBuilder;
|
||||
std::list<RecastMeshObject> mObjectsOrder;
|
||||
std::unordered_map<ObjectId, std::list<RecastMeshObject>::iterator> mObjects;
|
||||
|
|
15
components/detournavigator/recastmeshtiles.hpp
Normal file
15
components/detournavigator/recastmeshtiles.hpp
Normal file
|
@ -0,0 +1,15 @@
|
|||
#ifndef OPENMW_COMPONENTS_DETOURNAVIGATOR_RECASTMESHTILE_H
|
||||
#define OPENMW_COMPONENTS_DETOURNAVIGATOR_RECASTMESHTILE_H
|
||||
|
||||
#include "tileposition.hpp"
|
||||
#include "recastmesh.hpp"
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
|
||||
namespace DetourNavigator
|
||||
{
|
||||
using RecastMeshTiles = std::map<TilePosition, std::shared_ptr<RecastMesh>>;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -121,7 +121,7 @@ namespace DetourNavigator
|
|||
tileBounds.mMin -= osg::Vec2f(border, border);
|
||||
tileBounds.mMax += osg::Vec2f(border, border);
|
||||
tile = tiles->insert(std::make_pair(tilePosition,
|
||||
CachedRecastMeshManager(mSettings, tileBounds))).first;
|
||||
CachedRecastMeshManager(mSettings, tileBounds, mTilesGeneration))).first;
|
||||
}
|
||||
if (tile->second.addWater(cellPosition, cellSize, transform))
|
||||
{
|
||||
|
@ -151,7 +151,10 @@ namespace DetourNavigator
|
|||
continue;
|
||||
const auto tileResult = tile->second.removeWater(cellPosition);
|
||||
if (tile->second.isEmpty())
|
||||
{
|
||||
tiles->erase(tile);
|
||||
++mTilesGeneration;
|
||||
}
|
||||
if (tileResult && !result)
|
||||
result = tileResult;
|
||||
}
|
||||
|
@ -189,7 +192,8 @@ namespace DetourNavigator
|
|||
auto tileBounds = makeTileBounds(mSettings, tilePosition);
|
||||
tileBounds.mMin -= osg::Vec2f(border, border);
|
||||
tileBounds.mMax += osg::Vec2f(border, border);
|
||||
tile = tiles.insert(std::make_pair(tilePosition, CachedRecastMeshManager(mSettings, tileBounds))).first;
|
||||
tile = tiles.insert(std::make_pair(
|
||||
tilePosition, CachedRecastMeshManager(mSettings, tileBounds, mTilesGeneration))).first;
|
||||
}
|
||||
return tile->second.addObject(id, shape, transform, areaType);
|
||||
}
|
||||
|
@ -209,7 +213,10 @@ namespace DetourNavigator
|
|||
return boost::optional<RemovedRecastMeshObject>();
|
||||
const auto tileResult = tile->second.removeObject(id);
|
||||
if (tile->second.isEmpty())
|
||||
{
|
||||
tiles.erase(tile);
|
||||
++mTilesGeneration;
|
||||
}
|
||||
return tileResult;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,6 +48,7 @@ namespace DetourNavigator
|
|||
std::unordered_map<ObjectId, std::set<TilePosition>> mObjectsTilesPositions;
|
||||
std::map<osg::Vec2i, std::vector<TilePosition>> mWaterTilesPositions;
|
||||
std::size_t mRevision = 0;
|
||||
std::size_t mTilesGeneration = 0;
|
||||
|
||||
bool addTile(const ObjectId id, const btCollisionShape& shape, const btTransform& transform,
|
||||
const AreaType areaType, const TilePosition& tilePosition, float border,
|
||||
|
|
|
@ -50,10 +50,8 @@ namespace SceneUtil
|
|||
mDepthMask = state;
|
||||
}
|
||||
|
||||
void DebugDraw::texture(bool state)
|
||||
void DebugDraw::texture(bool)
|
||||
{
|
||||
if (state)
|
||||
throw std::logic_error("DebugDraw does not support textures (at " __FILE__ ":" OPENMW_LINE_STRING ")");
|
||||
}
|
||||
|
||||
void DebugDraw::begin(osg::PrimitiveSet::Mode mode, float size)
|
||||
|
@ -85,9 +83,10 @@ namespace SceneUtil
|
|||
vertex(pos[0], pos[1], pos[2], color, uv[0], uv[1]);
|
||||
}
|
||||
|
||||
void DebugDraw::vertex(const float, const float, const float, unsigned, const float, const float)
|
||||
void DebugDraw::vertex(const float x, const float y, const float z, unsigned color, const float, const float)
|
||||
{
|
||||
throw std::logic_error("Not implemented (at " __FILE__ ":" OPENMW_LINE_STRING ")");
|
||||
addVertex(osg::Vec3f(x, y, z));
|
||||
addColor(SceneUtil::colourFromRGBA(color));
|
||||
}
|
||||
|
||||
void DebugDraw::end()
|
||||
|
|
48
components/sceneutil/recastmesh.cpp
Normal file
48
components/sceneutil/recastmesh.cpp
Normal file
|
@ -0,0 +1,48 @@
|
|||
#include "navmesh.hpp"
|
||||
#include "detourdebugdraw.hpp"
|
||||
|
||||
#include <components/detournavigator/settings.hpp>
|
||||
#include <components/detournavigator/recastmesh.hpp>
|
||||
|
||||
#include <RecastDebugDraw.h>
|
||||
|
||||
#include <osg/Group>
|
||||
|
||||
namespace
|
||||
{
|
||||
std::vector<float> calculateNormals(const std::vector<float>& vertices, const std::vector<int>& indices)
|
||||
{
|
||||
std::vector<float> result(indices.size());
|
||||
for (std::size_t i = 0, n = indices.size(); i < n; i += 3)
|
||||
{
|
||||
const float* v0_ptr = &vertices[indices[i] * 3];
|
||||
const float* v1_ptr = &vertices[indices[i + 1] * 3];
|
||||
const float* v2_ptr = &vertices[indices[i + 2] * 3];
|
||||
const osg::Vec3f v0(v0_ptr[0], v0_ptr[1], v0_ptr[2]);
|
||||
const osg::Vec3f v1(v1_ptr[0], v1_ptr[1], v1_ptr[2]);
|
||||
const osg::Vec3f v2(v2_ptr[0], v2_ptr[1], v2_ptr[2]);
|
||||
const osg::Vec3f e0 = v1 - v0;
|
||||
const osg::Vec3f e1 = v2 - v0;
|
||||
osg::Vec3f normal = e0 ^ e1;
|
||||
normal.normalize();
|
||||
for (std::size_t j = 0; j < 3; ++j)
|
||||
result[i + j] = normal[j];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
namespace SceneUtil
|
||||
{
|
||||
osg::ref_ptr<osg::Group> createRecastMeshGroup(const DetourNavigator::RecastMesh& recastMesh,
|
||||
const DetourNavigator::Settings& settings)
|
||||
{
|
||||
const osg::ref_ptr<osg::Group> group(new osg::Group);
|
||||
DebugDraw debugDraw(*group, osg::Vec3f(0, 0, 0), 1.0f / settings.mRecastScaleFactor);
|
||||
const auto normals = calculateNormals(recastMesh.getVertices(), recastMesh.getIndices());
|
||||
const auto texScale = 1.0f / (settings.mCellSize * 10.0f);
|
||||
duDebugDrawTriMesh(&debugDraw, recastMesh.getVertices().data(), recastMesh.getVerticesCount(),
|
||||
recastMesh.getIndices().data(), normals.data(), recastMesh.getTrianglesCount(), nullptr, texScale);
|
||||
return group;
|
||||
}
|
||||
}
|
23
components/sceneutil/recastmesh.hpp
Normal file
23
components/sceneutil/recastmesh.hpp
Normal file
|
@ -0,0 +1,23 @@
|
|||
#ifndef OPENMW_COMPONENTS_SCENEUTIL_RECASTMESH_H
|
||||
#define OPENMW_COMPONENTS_SCENEUTIL_RECASTMESH_H
|
||||
|
||||
#include <osg/ref_ptr>
|
||||
|
||||
namespace osg
|
||||
{
|
||||
class Group;
|
||||
}
|
||||
|
||||
namespace DetourNavigator
|
||||
{
|
||||
class RecastMesh;
|
||||
struct Settings;
|
||||
}
|
||||
|
||||
namespace SceneUtil
|
||||
{
|
||||
osg::ref_ptr<osg::Group> createRecastMeshGroup(const DetourNavigator::RecastMesh& recastMesh,
|
||||
const DetourNavigator::Settings& settings);
|
||||
}
|
||||
|
||||
#endif
|
|
@ -166,6 +166,20 @@ Make visible all NPC's and creaure's plans where they are going.
|
|||
Works even if Navigator is disabled.
|
||||
Potentially decreases performance.
|
||||
|
||||
enable recast mesh render
|
||||
----------------------
|
||||
|
||||
:Type: boolean
|
||||
:Range: True/False
|
||||
:Default: False
|
||||
|
||||
Render recast mesh that is built as set of culled tiles from physical mesh.
|
||||
Should show similar mesh to physical one.
|
||||
Little difference can be a result of floating point error.
|
||||
Absent pieces usually mean a bug in recast mesh tiles building.
|
||||
Allows to do in-game debug.
|
||||
Potentially decreases performance.
|
||||
|
||||
Expert settings
|
||||
***************
|
||||
|
||||
|
|
|
@ -748,6 +748,9 @@ enable nav mesh render = false
|
|||
# Render agents paths (true, false)
|
||||
enable agents paths render = false
|
||||
|
||||
# Render recast mesh (true, false)
|
||||
enable recast mesh render = false
|
||||
|
||||
# Max number of navmesh tiles (value >= 0)
|
||||
max tiles number = 512
|
||||
|
||||
|
|
Loading…
Reference in a new issue