mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-03-27 23:37:20 +00:00
Render each navmesh tile independently
This commit is contained in:
parent
66390bd8a4
commit
3c41d0efc3
apps/openmw/mwrender
components
@ -4,6 +4,7 @@
|
||||
#include <components/sceneutil/navmesh.hpp>
|
||||
#include <components/resource/resourcesystem.hpp>
|
||||
#include <components/resource/scenemanager.hpp>
|
||||
#include <components/detournavigator/navmeshcacheitem.hpp>
|
||||
|
||||
#include <osg/PositionAttitudeTransform>
|
||||
|
||||
@ -37,45 +38,70 @@ namespace MWRender
|
||||
return mEnabled;
|
||||
}
|
||||
|
||||
void NavMesh::update(const dtNavMesh& navMesh, std::size_t id, const DetourNavigator::Version& version,
|
||||
void NavMesh::update(const DetourNavigator::NavMeshCacheItem& navMesh, std::size_t id,
|
||||
const DetourNavigator::Settings& settings)
|
||||
{
|
||||
if (!mEnabled || (mGroup && mId == id && mVersion == version))
|
||||
using DetourNavigator::TilePosition;
|
||||
using DetourNavigator::Version;
|
||||
|
||||
if (!mEnabled || (!mTiles.empty() && mId == id && mVersion == navMesh.getVersion()))
|
||||
return;
|
||||
|
||||
mId = id;
|
||||
mVersion = version;
|
||||
if (mGroup)
|
||||
mRootNode->removeChild(mGroup);
|
||||
mGroup = SceneUtil::createNavMeshGroup(navMesh, settings);
|
||||
if (mGroup)
|
||||
if (mId != id)
|
||||
{
|
||||
MWBase::Environment::get().getResourceSystem()->getSceneManager()->recreateShaders(mGroup, "debug");
|
||||
mGroup->setNodeMask(Mask_Debug);
|
||||
mRootNode->addChild(mGroup);
|
||||
reset();
|
||||
mId = id;
|
||||
}
|
||||
|
||||
mVersion = navMesh.getVersion();
|
||||
|
||||
std::vector<TilePosition> updated;
|
||||
navMesh.forEachUsedTile([&] (const TilePosition& position, const Version& version, const dtMeshTile& meshTile)
|
||||
{
|
||||
updated.push_back(position);
|
||||
Tile& tile = mTiles[position];
|
||||
if (tile.mGroup != nullptr && tile.mVersion == version)
|
||||
return;
|
||||
if (tile.mGroup != nullptr)
|
||||
mRootNode->removeChild(tile.mGroup);
|
||||
tile.mGroup = SceneUtil::createNavMeshTileGroup(navMesh.getImpl(), meshTile, settings);
|
||||
if (tile.mGroup == nullptr)
|
||||
return;
|
||||
MWBase::Environment::get().getResourceSystem()->getSceneManager()->recreateShaders(tile.mGroup, "debug");
|
||||
tile.mGroup->setNodeMask(Mask_Debug);
|
||||
mRootNode->addChild(tile.mGroup);
|
||||
});
|
||||
std::sort(updated.begin(), updated.end());
|
||||
for (auto it = mTiles.begin(); it != mTiles.end();)
|
||||
{
|
||||
if (!std::binary_search(updated.begin(), updated.end(), it->first))
|
||||
{
|
||||
mRootNode->removeChild(it->second.mGroup);
|
||||
it = mTiles.erase(it);
|
||||
}
|
||||
else
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
void NavMesh::reset()
|
||||
{
|
||||
if (mGroup)
|
||||
{
|
||||
mRootNode->removeChild(mGroup);
|
||||
mGroup = nullptr;
|
||||
}
|
||||
for (auto& [position, tile] : mTiles)
|
||||
mRootNode->removeChild(tile.mGroup);
|
||||
mTiles.clear();
|
||||
}
|
||||
|
||||
void NavMesh::enable()
|
||||
{
|
||||
if (mGroup)
|
||||
mRootNode->addChild(mGroup);
|
||||
for (const auto& [position, tile] : mTiles)
|
||||
mRootNode->addChild(tile.mGroup);
|
||||
mEnabled = true;
|
||||
}
|
||||
|
||||
void NavMesh::disable()
|
||||
{
|
||||
if (mGroup)
|
||||
mRootNode->removeChild(mGroup);
|
||||
for (const auto& [position, tile] : mTiles)
|
||||
mRootNode->removeChild(tile.mGroup);
|
||||
mEnabled = false;
|
||||
}
|
||||
}
|
||||
|
@ -2,10 +2,12 @@
|
||||
#define OPENMW_MWRENDER_NAVMESH_H
|
||||
|
||||
#include <components/detournavigator/version.hpp>
|
||||
#include <components/detournavigator/tileposition.hpp>
|
||||
|
||||
#include <osg/ref_ptr>
|
||||
|
||||
#include <cstddef>
|
||||
#include <map>
|
||||
|
||||
class dtNavMesh;
|
||||
|
||||
@ -17,6 +19,7 @@ namespace osg
|
||||
|
||||
namespace DetourNavigator
|
||||
{
|
||||
class NavMeshCacheItem;
|
||||
struct Settings;
|
||||
}
|
||||
|
||||
@ -30,7 +33,7 @@ namespace MWRender
|
||||
|
||||
bool toggle();
|
||||
|
||||
void update(const dtNavMesh& navMesh, std::size_t id, const DetourNavigator::Version& version,
|
||||
void update(const DetourNavigator::NavMeshCacheItem& navMesh, std::size_t id,
|
||||
const DetourNavigator::Settings& settings);
|
||||
|
||||
void reset();
|
||||
@ -45,11 +48,17 @@ namespace MWRender
|
||||
}
|
||||
|
||||
private:
|
||||
struct Tile
|
||||
{
|
||||
DetourNavigator::Version mVersion;
|
||||
osg::ref_ptr<osg::Group> mGroup;
|
||||
};
|
||||
|
||||
osg::ref_ptr<osg::Group> mRootNode;
|
||||
bool mEnabled;
|
||||
std::size_t mId;
|
||||
DetourNavigator::Version mVersion;
|
||||
osg::ref_ptr<osg::Group> mGroup;
|
||||
std::map<DetourNavigator::TilePosition, Tile> mTiles;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -1365,8 +1365,7 @@ namespace MWRender
|
||||
{
|
||||
try
|
||||
{
|
||||
const auto locked = it->second->lockConst();
|
||||
mNavMesh->update(locked->getImpl(), mNavMeshNumber, locked->getVersion(), mNavigator.getSettings());
|
||||
mNavMesh->update(*it->second->lockConst(), mNavMeshNumber, mNavigator.getSettings());
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
|
@ -13,12 +13,6 @@ namespace
|
||||
{
|
||||
using DetourNavigator::TilePosition;
|
||||
|
||||
const dtMeshTile* getTile(const dtNavMesh& navMesh, const TilePosition& position)
|
||||
{
|
||||
const int layer = 0;
|
||||
return navMesh.getTileAt(position.x(), position.y(), layer);
|
||||
}
|
||||
|
||||
bool removeTile(dtNavMesh& navMesh, const TilePosition& position)
|
||||
{
|
||||
const int layer = 0;
|
||||
@ -41,10 +35,16 @@ namespace
|
||||
|
||||
namespace DetourNavigator
|
||||
{
|
||||
const dtMeshTile* getTile(const dtNavMesh& navMesh, const TilePosition& position)
|
||||
{
|
||||
const int layer = 0;
|
||||
return navMesh.getTileAt(position.x(), position.y(), layer);
|
||||
}
|
||||
|
||||
UpdateNavMeshStatus NavMeshCacheItem::updateTile(const TilePosition& position, NavMeshTilesCache::Value&& cached,
|
||||
NavMeshData&& navMeshData)
|
||||
{
|
||||
const dtMeshTile* currentTile = ::getTile(*mImpl, position);
|
||||
const dtMeshTile* currentTile = getTile(*mImpl, position);
|
||||
if (currentTile != nullptr
|
||||
&& asNavMeshTileConstView(*currentTile) == asNavMeshTileConstView(navMeshData.mValue.get()))
|
||||
{
|
||||
@ -54,7 +54,18 @@ namespace DetourNavigator
|
||||
const auto addStatus = addTile(*mImpl, navMeshData.mValue.get(), navMeshData.mSize);
|
||||
if (dtStatusSucceed(addStatus))
|
||||
{
|
||||
mUsedTiles[position] = std::make_pair(std::move(cached), std::move(navMeshData));
|
||||
auto tile = mUsedTiles.find(position);
|
||||
if (tile == mUsedTiles.end())
|
||||
{
|
||||
mUsedTiles.emplace_hint(tile, position,
|
||||
Tile {Version {mVersion.mRevision, 1}, std::move(cached), std::move(navMeshData)});
|
||||
}
|
||||
else
|
||||
{
|
||||
++tile->second.mVersion.mRevision;
|
||||
tile->second.mCached = std::move(cached);
|
||||
tile->second.mData = std::move(navMeshData);
|
||||
}
|
||||
++mVersion.mRevision;
|
||||
return UpdateNavMeshStatusBuilder().added(true).removed(removed).getResult();
|
||||
}
|
||||
|
@ -124,6 +124,8 @@ namespace DetourNavigator
|
||||
}
|
||||
};
|
||||
|
||||
const dtMeshTile* getTile(const dtNavMesh& navMesh, const TilePosition& position);
|
||||
|
||||
class NavMeshCacheItem
|
||||
{
|
||||
public:
|
||||
@ -145,10 +147,25 @@ namespace DetourNavigator
|
||||
|
||||
UpdateNavMeshStatus removeTile(const TilePosition& position);
|
||||
|
||||
template <class Function>
|
||||
void forEachUsedTile(Function&& function) const
|
||||
{
|
||||
for (const auto& [position, tile] : mUsedTiles)
|
||||
if (const dtMeshTile* meshTile = getTile(*mImpl, position))
|
||||
function(position, tile.mVersion, *meshTile);
|
||||
}
|
||||
|
||||
private:
|
||||
struct Tile
|
||||
{
|
||||
Version mVersion;
|
||||
NavMeshTilesCache::Value mCached;
|
||||
NavMeshData mData;
|
||||
};
|
||||
|
||||
NavMeshPtr mImpl;
|
||||
Version mVersion;
|
||||
std::map<TilePosition, std::pair<NavMeshTilesCache::Value, NavMeshData>> mUsedTiles;
|
||||
std::map<TilePosition, Tile> mUsedTiles;
|
||||
};
|
||||
|
||||
using GuardedNavMeshCacheItem = Misc::ScopeGuarded<NavMeshCacheItem>;
|
||||
|
@ -8,16 +8,235 @@
|
||||
#include <osg/Group>
|
||||
#include <osg/Material>
|
||||
|
||||
namespace
|
||||
{
|
||||
// Copied from https://github.com/recastnavigation/recastnavigation/blob/c5cbd53024c8a9d8d097a4371215e3342d2fdc87/DebugUtils/Source/DetourDebugDraw.cpp#L26-L38
|
||||
float distancePtLine2d(const float* pt, const float* p, const float* q)
|
||||
{
|
||||
float pqx = q[0] - p[0];
|
||||
float pqz = q[2] - p[2];
|
||||
float dx = pt[0] - p[0];
|
||||
float dz = pt[2] - p[2];
|
||||
float d = pqx*pqx + pqz*pqz;
|
||||
float t = pqx*dx + pqz*dz;
|
||||
if (d != 0) t /= d;
|
||||
dx = p[0] + t*pqx - pt[0];
|
||||
dz = p[2] + t*pqz - pt[2];
|
||||
return dx*dx + dz*dz;
|
||||
}
|
||||
|
||||
// Copied from https://github.com/recastnavigation/recastnavigation/blob/c5cbd53024c8a9d8d097a4371215e3342d2fdc87/DebugUtils/Source/DetourDebugDraw.cpp#L40-L118
|
||||
void drawPolyBoundaries(duDebugDraw* dd, const dtMeshTile* tile, const unsigned int col,
|
||||
const float linew, bool inner)
|
||||
{
|
||||
static const float thr = 0.01f*0.01f;
|
||||
|
||||
dd->begin(DU_DRAW_LINES, linew);
|
||||
|
||||
for (int i = 0; i < tile->header->polyCount; ++i)
|
||||
{
|
||||
const dtPoly* p = &tile->polys[i];
|
||||
|
||||
if (p->getType() == DT_POLYTYPE_OFFMESH_CONNECTION) continue;
|
||||
|
||||
const dtPolyDetail* pd = &tile->detailMeshes[i];
|
||||
|
||||
for (int j = 0, nj = (int)p->vertCount; j < nj; ++j)
|
||||
{
|
||||
unsigned int c = col;
|
||||
if (inner)
|
||||
{
|
||||
if (p->neis[j] == 0) continue;
|
||||
if (p->neis[j] & DT_EXT_LINK)
|
||||
{
|
||||
bool con = false;
|
||||
for (unsigned int k = p->firstLink; k != DT_NULL_LINK; k = tile->links[k].next)
|
||||
{
|
||||
if (tile->links[k].edge == j)
|
||||
{
|
||||
con = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (con)
|
||||
c = duRGBA(255,255,255,48);
|
||||
else
|
||||
c = duRGBA(0,0,0,48);
|
||||
}
|
||||
else
|
||||
c = duRGBA(0,48,64,32);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (p->neis[j] != 0) continue;
|
||||
}
|
||||
|
||||
const float* v0 = &tile->verts[p->verts[j]*3];
|
||||
const float* v1 = &tile->verts[p->verts[(j+1) % nj]*3];
|
||||
|
||||
// Draw detail mesh edges which align with the actual poly edge.
|
||||
// This is really slow.
|
||||
for (int k = 0; k < pd->triCount; ++k)
|
||||
{
|
||||
const unsigned char* t = &tile->detailTris[(pd->triBase+k)*4];
|
||||
const float* tv[3];
|
||||
for (int m = 0; m < 3; ++m)
|
||||
{
|
||||
if (t[m] < p->vertCount)
|
||||
tv[m] = &tile->verts[p->verts[t[m]]*3];
|
||||
else
|
||||
tv[m] = &tile->detailVerts[(pd->vertBase+(t[m]-p->vertCount))*3];
|
||||
}
|
||||
for (int m = 0, n = 2; m < 3; n=m++)
|
||||
{
|
||||
if ((dtGetDetailTriEdgeFlags(t[3], n) & DT_DETAIL_EDGE_BOUNDARY) == 0)
|
||||
continue;
|
||||
|
||||
if (distancePtLine2d(tv[n],v0,v1) < thr &&
|
||||
distancePtLine2d(tv[m],v0,v1) < thr)
|
||||
{
|
||||
dd->vertex(tv[n], c);
|
||||
dd->vertex(tv[m], c);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
dd->end();
|
||||
}
|
||||
|
||||
// Copied from https://github.com/recastnavigation/recastnavigation/blob/c5cbd53024c8a9d8d097a4371215e3342d2fdc87/DebugUtils/Source/DetourDebugDraw.cpp#L120-L235
|
||||
void drawMeshTile(duDebugDraw* dd, const dtNavMesh& mesh, const dtNavMeshQuery* query,
|
||||
const dtMeshTile* tile, unsigned char flags)
|
||||
{
|
||||
dtPolyRef base = mesh.getPolyRefBase(tile);
|
||||
|
||||
int tileNum = mesh.decodePolyIdTile(base);
|
||||
const unsigned int tileColor = duIntToCol(tileNum, 128);
|
||||
|
||||
dd->depthMask(false);
|
||||
|
||||
dd->begin(DU_DRAW_TRIS);
|
||||
for (int i = 0; i < tile->header->polyCount; ++i)
|
||||
{
|
||||
const dtPoly* p = &tile->polys[i];
|
||||
if (p->getType() == DT_POLYTYPE_OFFMESH_CONNECTION) // Skip off-mesh links.
|
||||
continue;
|
||||
|
||||
const dtPolyDetail* pd = &tile->detailMeshes[i];
|
||||
|
||||
unsigned int col;
|
||||
if (query && query->isInClosedList(base | (dtPolyRef)i))
|
||||
col = duRGBA(255,196,0,64);
|
||||
else
|
||||
{
|
||||
if (flags & DU_DRAWNAVMESH_COLOR_TILES)
|
||||
col = tileColor;
|
||||
else
|
||||
col = duTransCol(dd->areaToCol(p->getArea()), 64);
|
||||
}
|
||||
|
||||
for (int j = 0; j < pd->triCount; ++j)
|
||||
{
|
||||
const unsigned char* t = &tile->detailTris[(pd->triBase+j)*4];
|
||||
for (int k = 0; k < 3; ++k)
|
||||
{
|
||||
if (t[k] < p->vertCount)
|
||||
dd->vertex(&tile->verts[p->verts[t[k]]*3], col);
|
||||
else
|
||||
dd->vertex(&tile->detailVerts[(pd->vertBase+t[k]-p->vertCount)*3], col);
|
||||
}
|
||||
}
|
||||
}
|
||||
dd->end();
|
||||
|
||||
// Draw inter poly boundaries
|
||||
drawPolyBoundaries(dd, tile, duRGBA(0,48,64,32), 1.5f, true);
|
||||
|
||||
// Draw outer poly boundaries
|
||||
drawPolyBoundaries(dd, tile, duRGBA(0,48,64,220), 2.5f, false);
|
||||
|
||||
if (flags & DU_DRAWNAVMESH_OFFMESHCONS)
|
||||
{
|
||||
dd->begin(DU_DRAW_LINES, 2.0f);
|
||||
for (int i = 0; i < tile->header->polyCount; ++i)
|
||||
{
|
||||
const dtPoly* p = &tile->polys[i];
|
||||
if (p->getType() != DT_POLYTYPE_OFFMESH_CONNECTION) // Skip regular polys.
|
||||
continue;
|
||||
|
||||
unsigned int col, col2;
|
||||
if (query && query->isInClosedList(base | (dtPolyRef)i))
|
||||
col = duRGBA(255,196,0,220);
|
||||
else
|
||||
col = duDarkenCol(duTransCol(dd->areaToCol(p->getArea()), 220));
|
||||
|
||||
const dtOffMeshConnection* con = &tile->offMeshCons[i - tile->header->offMeshBase];
|
||||
const float* va = &tile->verts[p->verts[0]*3];
|
||||
const float* vb = &tile->verts[p->verts[1]*3];
|
||||
|
||||
// Check to see if start and end end-points have links.
|
||||
bool startSet = false;
|
||||
bool endSet = false;
|
||||
for (unsigned int k = p->firstLink; k != DT_NULL_LINK; k = tile->links[k].next)
|
||||
{
|
||||
if (tile->links[k].edge == 0)
|
||||
startSet = true;
|
||||
if (tile->links[k].edge == 1)
|
||||
endSet = true;
|
||||
}
|
||||
|
||||
// End points and their on-mesh locations.
|
||||
dd->vertex(va[0],va[1],va[2], col);
|
||||
dd->vertex(con->pos[0],con->pos[1],con->pos[2], col);
|
||||
col2 = startSet ? col : duRGBA(220,32,16,196);
|
||||
duAppendCircle(dd, con->pos[0],con->pos[1]+0.1f,con->pos[2], con->rad, col2);
|
||||
|
||||
dd->vertex(vb[0],vb[1],vb[2], col);
|
||||
dd->vertex(con->pos[3],con->pos[4],con->pos[5], col);
|
||||
col2 = endSet ? col : duRGBA(220,32,16,196);
|
||||
duAppendCircle(dd, con->pos[3],con->pos[4]+0.1f,con->pos[5], con->rad, col2);
|
||||
|
||||
// End point vertices.
|
||||
dd->vertex(con->pos[0],con->pos[1],con->pos[2], duRGBA(0,48,64,196));
|
||||
dd->vertex(con->pos[0],con->pos[1]+0.2f,con->pos[2], duRGBA(0,48,64,196));
|
||||
|
||||
dd->vertex(con->pos[3],con->pos[4],con->pos[5], duRGBA(0,48,64,196));
|
||||
dd->vertex(con->pos[3],con->pos[4]+0.2f,con->pos[5], duRGBA(0,48,64,196));
|
||||
|
||||
// Connection arc.
|
||||
duAppendArc(dd, con->pos[0],con->pos[1],con->pos[2], con->pos[3],con->pos[4],con->pos[5], 0.25f,
|
||||
(con->flags & 1) ? 0.6f : 0, 0.6f, col);
|
||||
}
|
||||
dd->end();
|
||||
}
|
||||
|
||||
const unsigned int vcol = duRGBA(0,0,0,196);
|
||||
dd->begin(DU_DRAW_POINTS, 3.0f);
|
||||
for (int i = 0; i < tile->header->vertCount; ++i)
|
||||
{
|
||||
const float* v = &tile->verts[i*3];
|
||||
dd->vertex(v[0], v[1], v[2], vcol);
|
||||
}
|
||||
dd->end();
|
||||
|
||||
dd->depthMask(true);
|
||||
}
|
||||
}
|
||||
|
||||
namespace SceneUtil
|
||||
{
|
||||
osg::ref_ptr<osg::Group> createNavMeshGroup(const dtNavMesh& navMesh, const DetourNavigator::Settings& settings)
|
||||
osg::ref_ptr<osg::Group> createNavMeshTileGroup(const dtNavMesh& navMesh, const dtMeshTile& meshTile,
|
||||
const DetourNavigator::Settings& settings)
|
||||
{
|
||||
if (meshTile.header == nullptr)
|
||||
return nullptr;
|
||||
|
||||
osg::ref_ptr<osg::Group> group(new osg::Group);
|
||||
DebugDraw debugDraw(*group, osg::Vec3f(0, 0, 10), 1.0f / settings.mRecastScaleFactor);
|
||||
dtNavMeshQuery navMeshQuery;
|
||||
navMeshQuery.init(&navMesh, settings.mMaxNavMeshQueryNodes);
|
||||
duDebugDrawNavMeshWithClosedList(&debugDraw, navMesh, navMeshQuery,
|
||||
DU_DRAWNAVMESH_OFFMESHCONS | DU_DRAWNAVMESH_CLOSEDLIST);
|
||||
drawMeshTile(&debugDraw, navMesh, &navMeshQuery, &meshTile, DU_DRAWNAVMESH_OFFMESHCONS | DU_DRAWNAVMESH_CLOSEDLIST);
|
||||
|
||||
osg::ref_ptr<osg::Material> material = new osg::Material;
|
||||
material->setColorMode(osg::Material::AMBIENT_AND_DIFFUSE);
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include <osg/ref_ptr>
|
||||
|
||||
class dtNavMesh;
|
||||
struct dtMeshTile;
|
||||
|
||||
namespace osg
|
||||
{
|
||||
@ -17,7 +18,8 @@ namespace DetourNavigator
|
||||
|
||||
namespace SceneUtil
|
||||
{
|
||||
osg::ref_ptr<osg::Group> createNavMeshGroup(const dtNavMesh& navMesh, const DetourNavigator::Settings& settings);
|
||||
osg::ref_ptr<osg::Group> createNavMeshTileGroup(const dtNavMesh& navMesh, const dtMeshTile& meshTile,
|
||||
const DetourNavigator::Settings& settings);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
Loading…
x
Reference in New Issue
Block a user