1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-02-19 15:09:43 +00:00

Merge branch 'navmesh_render' into 'master'

Rework navmesh render (#6187)

See merge request OpenMW/openmw!1338
This commit is contained in:
psi29a 2021-12-02 10:34:41 +00:00
commit 7256654f29
14 changed files with 432 additions and 101 deletions

View file

@ -4,8 +4,11 @@
#include <components/sceneutil/navmesh.hpp>
#include <components/resource/resourcesystem.hpp>
#include <components/resource/scenemanager.hpp>
#include <components/detournavigator/navmeshcacheitem.hpp>
#include <components/sceneutil/detourdebugdraw.hpp>
#include <osg/PositionAttitudeTransform>
#include <osg/StateSet>
#include "../mwbase/world.hpp"
#include "../mwbase/environment.hpp"
@ -16,10 +19,10 @@ namespace MWRender
{
NavMesh::NavMesh(const osg::ref_ptr<osg::Group>& root, bool enabled)
: mRootNode(root)
, mGroupStateSet(SceneUtil::makeNavMeshTileStateSet())
, mDebugDrawStateSet(SceneUtil::DebugDraw::makeStateSet())
, mEnabled(enabled)
, mId(std::numeric_limits<std::size_t>::max())
, mGeneration(0)
, mRevision(0)
{
}
@ -39,46 +42,71 @@ namespace MWRender
return mEnabled;
}
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)
void NavMesh::update(const DetourNavigator::NavMeshCacheItem& navMesh, std::size_t id,
const DetourNavigator::Settings& settings)
{
if (!mEnabled || (mGroup && mId == id && mGeneration == generation && mRevision == revision))
using DetourNavigator::TilePosition;
using DetourNavigator::Version;
if (!mEnabled || (!mTiles.empty() && mId == id && mVersion == navMesh.getVersion()))
return;
mId = id;
mGeneration = generation;
mRevision = revision;
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,
mGroupStateSet, mDebugDrawStateSet);
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;
}
}

View file

@ -1,9 +1,13 @@
#ifndef OPENMW_MWRENDER_NAVMESH_H
#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;
@ -11,10 +15,12 @@ namespace osg
{
class Group;
class Geometry;
class StateSet;
}
namespace DetourNavigator
{
class NavMeshCacheItem;
struct Settings;
}
@ -28,8 +34,8 @@ namespace MWRender
bool toggle();
void update(const dtNavMesh& navMesh, const std::size_t number, const std::size_t generation,
const std::size_t revision, const DetourNavigator::Settings& settings);
void update(const DetourNavigator::NavMeshCacheItem& navMesh, std::size_t id,
const DetourNavigator::Settings& settings);
void reset();
@ -43,12 +49,19 @@ namespace MWRender
}
private:
struct Tile
{
DetourNavigator::Version mVersion;
osg::ref_ptr<osg::Group> mGroup;
};
osg::ref_ptr<osg::Group> mRootNode;
osg::ref_ptr<osg::StateSet> mGroupStateSet;
osg::ref_ptr<osg::StateSet> mDebugDrawStateSet;
bool mEnabled;
std::size_t mId;
std::size_t mGeneration;
std::size_t mRevision;
osg::ref_ptr<osg::Group> mGroup;
DetourNavigator::Version mVersion;
std::map<DetourNavigator::TilePosition, Tile> mTiles;
};
}

View file

@ -1378,9 +1378,7 @@ namespace MWRender
{
try
{
const auto locked = it->second->lockConst();
mNavMesh->update(locked->getImpl(), mNavMeshNumber, locked->getGeneration(),
locked->getNavMeshRevision(), mNavigator.getSettings());
mNavMesh->update(*it->second->lockConst(), mNavMeshNumber, mNavigator.getSettings());
}
catch (const std::exception& e)
{

View file

@ -990,8 +990,7 @@ namespace
ASSERT_EQ(navMeshes.size(), 1);
{
const auto navMesh = navMeshes.begin()->second->lockConst();
ASSERT_EQ(navMesh->getGeneration(), 1);
ASSERT_EQ(navMesh->getNavMeshRevision(), 4);
ASSERT_EQ(navMesh->getVersion(), (Version {1, 4}));
}
for (int n = 0; n < 10; ++n)
@ -1006,8 +1005,7 @@ namespace
ASSERT_EQ(navMeshes.size(), 1);
{
const auto navMesh = navMeshes.begin()->second->lockConst();
ASSERT_EQ(navMesh->getGeneration(), 1);
ASSERT_EQ(navMesh->getNavMeshRevision(), 4);
ASSERT_EQ(navMesh->getVersion(), (Version {1, 4}));
}
}

View file

@ -311,12 +311,7 @@ namespace DetourNavigator
if (recastMesh != nullptr)
{
Version navMeshVersion;
{
const auto locked = navMeshCacheItem->lockConst();
navMeshVersion.mGeneration = locked->getGeneration();
navMeshVersion.mRevision = locked->getNavMeshRevision();
}
const Version navMeshVersion = navMeshCacheItem->lockConst()->getVersion();
mRecastMeshManager.get().reportNavMeshChange(job.mChangedTile,
Version {recastMesh->getGeneration(), recastMesh->getRevision()},
navMeshVersion);
@ -339,13 +334,13 @@ namespace DetourNavigator
using FloatMs = std::chrono::duration<float, std::milli>;
const auto locked = navMeshCacheItem->lockConst();
const Version version = navMeshCacheItem->lockConst()->getVersion();
Log(Debug::Debug) << std::fixed << std::setprecision(2) <<
"Cache updated for agent=(" << job.mAgentHalfExtents << ")" <<
" tile=" << job.mChangedTile <<
" status=" << status <<
" generation=" << locked->getGeneration() <<
" revision=" << locked->getNavMeshRevision() <<
" generation=" << version.mGeneration <<
" revision=" << version.mRevision <<
" time=" << std::chrono::duration_cast<FloatMs>(finish - start).count() << "ms" <<
" thread=" << std::this_thread::get_id();

View file

@ -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,8 +54,19 @@ 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));
++mNavMeshRevision;
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();
}
else
@ -63,7 +74,7 @@ namespace DetourNavigator
if (removed)
{
mUsedTiles.erase(position);
++mNavMeshRevision;
++mVersion.mRevision;
}
return UpdateNavMeshStatusBuilder().removed(removed).failed((addStatus & DT_OUT_OF_MEMORY) != 0).getResult();
}
@ -75,7 +86,7 @@ namespace DetourNavigator
if (removed)
{
mUsedTiles.erase(position);
++mNavMeshRevision;
++mVersion.mRevision;
}
return UpdateNavMeshStatusBuilder().removed(removed).getResult();
}

View file

@ -6,6 +6,7 @@
#include "navmeshtilescache.hpp"
#include "dtstatus.hpp"
#include "navmeshdata.hpp"
#include "version.hpp"
#include <components/misc/guarded.hpp>
@ -123,11 +124,14 @@ namespace DetourNavigator
}
};
const dtMeshTile* getTile(const dtNavMesh& navMesh, const TilePosition& position);
class NavMeshCacheItem
{
public:
NavMeshCacheItem(const NavMeshPtr& impl, std::size_t generation)
: mImpl(impl), mGeneration(generation), mNavMeshRevision(0)
: mImpl(impl)
, mVersion {generation, 0}
{
}
@ -136,26 +140,32 @@ namespace DetourNavigator
return *mImpl;
}
std::size_t getGeneration() const
{
return mGeneration;
}
std::size_t getNavMeshRevision() const
{
return mNavMeshRevision;
}
const Version& getVersion() const { return mVersion; }
UpdateNavMeshStatus updateTile(const TilePosition& position, NavMeshTilesCache::Value&& cached,
NavMeshData&& navMeshData);
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;
std::size_t mGeneration;
std::size_t mNavMeshRevision;
std::map<TilePosition, std::pair<NavMeshTilesCache::Value, NavMeshData>> mUsedTiles;
Version mVersion;
std::map<TilePosition, Tile> mUsedTiles;
};
using GuardedNavMeshCacheItem = Misc::ScopeGuarded<NavMeshCacheItem>;

View file

@ -8,12 +8,32 @@ namespace DetourNavigator
{
struct Version
{
std::size_t mGeneration;
std::size_t mRevision;
std::size_t mGeneration = 0;
std::size_t mRevision = 0;
friend inline auto tie(const Version& value)
{
return std::tie(value.mGeneration, value.mRevision);
}
friend inline bool operator<(const Version& lhs, const Version& rhs)
{
return std::tie(lhs.mGeneration, lhs.mRevision) < std::tie(rhs.mGeneration, rhs.mRevision);
return tie(lhs) < tie(rhs);
}
friend inline bool operator<=(const Version& lhs, const Version& rhs)
{
return tie(lhs) <= tie(rhs);
}
friend inline bool operator==(const Version& lhs, const Version& rhs)
{
return tie(lhs) == tie(rhs);
}
friend inline bool operator!=(const Version& lhs, const Version& rhs)
{
return !(lhs == rhs);
}
};
}

View file

@ -43,7 +43,7 @@ namespace SceneUtil
const osg::ref_ptr<osg::Group> group(new osg::Group);
DebugDraw debugDraw(*group, osg::Vec3f(0, 0, 0), 1);
DebugDraw debugDraw(*group, DebugDraw::makeStateSet(), osg::Vec3f(0, 0, 0), 1);
const auto agentRadius = halfExtents.x();
const auto agentHeight = 2.0f * halfExtents.z();

View file

@ -32,19 +32,19 @@ namespace
namespace SceneUtil
{
DebugDraw::DebugDraw(osg::Group& group, const osg::Vec3f& shift, float recastInvertedScaleFactor)
DebugDraw::DebugDraw(osg::Group& group, const osg::ref_ptr<osg::StateSet>& stateSet,
const osg::Vec3f& shift, float recastInvertedScaleFactor)
: mGroup(group)
, mStateSet(stateSet)
, mShift(shift)
, mRecastInvertedScaleFactor(recastInvertedScaleFactor)
, mDepthMask(false)
, mMode(osg::PrimitiveSet::POINTS)
, mSize(1.0f)
{
}
void DebugDraw::depthMask(bool state)
void DebugDraw::depthMask(bool)
{
mDepthMask = state;
}
void DebugDraw::texture(bool)
@ -56,7 +56,7 @@ namespace SceneUtil
mMode = mode;
mVertices = new osg::Vec3Array;
mColors = new osg::Vec4Array;
mSize = size * mRecastInvertedScaleFactor;
mSize = size;
}
void DebugDraw::begin(duDebugDrawPrimitives prim, float size)
@ -88,16 +88,8 @@ namespace SceneUtil
void DebugDraw::end()
{
osg::ref_ptr<osg::StateSet> stateSet(new osg::StateSet);
stateSet->setMode(GL_BLEND, osg::StateAttribute::ON);
stateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
stateSet->setMode(GL_DEPTH, (mDepthMask ? osg::StateAttribute::ON : osg::StateAttribute::OFF));
stateSet->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
stateSet->setAttributeAndModes(new osg::LineWidth(mSize));
stateSet->setAttributeAndModes(new osg::BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
osg::ref_ptr<osg::Geometry> geometry(new osg::Geometry);
geometry->setStateSet(stateSet);
geometry->setStateSet(mStateSet);
geometry->setVertexArray(mVertices);
geometry->setColorArray(mColors, osg::Array::BIND_PER_VERTEX);
geometry->addPrimitiveSet(new osg::DrawArrays(mMode, 0, static_cast<int>(mVertices->size())));
@ -117,4 +109,16 @@ namespace SceneUtil
{
mColors->push_back(value);
}
osg::ref_ptr<osg::StateSet> DebugDraw::makeStateSet()
{
osg::ref_ptr<osg::StateSet> stateSet = new osg::StateSet;
stateSet->setMode(GL_BLEND, osg::StateAttribute::ON);
stateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
stateSet->setMode(GL_DEPTH, osg::StateAttribute::OFF);
stateSet->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
stateSet->setAttributeAndModes(new osg::LineWidth());
stateSet->setAttributeAndModes(new osg::BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
return stateSet;
}
}

View file

@ -15,7 +15,10 @@ namespace SceneUtil
class DebugDraw : public duDebugDraw
{
public:
DebugDraw(osg::Group& group, const osg::Vec3f& shift, float recastInvertedScaleFactor);
explicit DebugDraw(osg::Group& group, const osg::ref_ptr<osg::StateSet>& stateSet,
const osg::Vec3f& shift, float recastInvertedScaleFactor);
static osg::ref_ptr<osg::StateSet> makeStateSet();
void depthMask(bool state) override;
@ -38,9 +41,9 @@ namespace SceneUtil
private:
osg::Group& mGroup;
osg::ref_ptr<osg::StateSet> mStateSet;
osg::Vec3f mShift;
float mRecastInvertedScaleFactor;
bool mDepthMask;
osg::PrimitiveSet::Mode mMode;
float mSize;
osg::ref_ptr<osg::Vec3Array> mVertices;

View file

@ -1,5 +1,6 @@
#include "navmesh.hpp"
#include "detourdebugdraw.hpp"
#include "depth.hpp"
#include <components/detournavigator/settings.hpp>
@ -7,21 +8,256 @@
#include <osg/Group>
#include <osg/Material>
#include <osg/PolygonOffset>
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();
}
// Based on 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 tileNumColor = duIntToCol(tileNum, 128);
const unsigned alpha = tile->header->userId == 0 ? 64 : 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, alpha);
else
{
if (flags & DU_DRAWNAVMESH_COLOR_TILES)
col = duTransCol(tileNumColor, alpha);
else
col = duTransCol(dd->areaToCol(p->getArea()), alpha);
}
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::StateSet> makeNavMeshTileStateSet()
{
const 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);
osg::ref_ptr<osg::Material> material = new osg::Material;
material->setColorMode(osg::Material::AMBIENT_AND_DIFFUSE);
group->getOrCreateStateSet()->setAttribute(material);
const float polygonOffsetFactor = SceneUtil::AutoDepth::isReversed() ? 1.0 : -1.0;
const float polygonOffsetUnits = SceneUtil::AutoDepth::isReversed() ? 1.0 : -1.0;
osg::ref_ptr<osg::PolygonOffset> polygonOffset = new osg::PolygonOffset(polygonOffsetFactor, polygonOffsetUnits);
osg::ref_ptr<osg::StateSet> stateSet = new osg::StateSet;
stateSet->setAttribute(material);
stateSet->setAttributeAndModes(polygonOffset);
return stateSet;
}
osg::ref_ptr<osg::Group> createNavMeshTileGroup(const dtNavMesh& navMesh, const dtMeshTile& meshTile,
const DetourNavigator::Settings& settings, const osg::ref_ptr<osg::StateSet>& groupStateSet,
const osg::ref_ptr<osg::StateSet>& debugDrawStateSet)
{
if (meshTile.header == nullptr)
return nullptr;
osg::ref_ptr<osg::Group> group(new osg::Group);
group->setStateSet(groupStateSet);
constexpr float shift = 10.0f;
DebugDraw debugDraw(*group, debugDrawStateSet, osg::Vec3f(0, 0, shift), 1.0f / settings.mRecastScaleFactor);
dtNavMeshQuery navMeshQuery;
navMeshQuery.init(&navMesh, settings.mMaxNavMeshQueryNodes);
drawMeshTile(&debugDraw, navMesh, &navMeshQuery, &meshTile, DU_DRAWNAVMESH_OFFMESHCONS | DU_DRAWNAVMESH_CLOSEDLIST);
return group;
}

View file

@ -4,10 +4,12 @@
#include <osg/ref_ptr>
class dtNavMesh;
struct dtMeshTile;
namespace osg
{
class Group;
class StateSet;
}
namespace DetourNavigator
@ -17,7 +19,11 @@ namespace DetourNavigator
namespace SceneUtil
{
osg::ref_ptr<osg::Group> createNavMeshGroup(const dtNavMesh& navMesh, const DetourNavigator::Settings& settings);
osg::ref_ptr<osg::StateSet> makeNavMeshTileStateSet();
osg::ref_ptr<osg::Group> createNavMeshTileGroup(const dtNavMesh& navMesh, const dtMeshTile& meshTile,
const DetourNavigator::Settings& settings, const osg::ref_ptr<osg::StateSet>& groupStateSet,
const osg::ref_ptr<osg::StateSet>& debugDrawStateSet);
}
#endif

View file

@ -1,5 +1,6 @@
#include "recastmesh.hpp"
#include "detourdebugdraw.hpp"
#include "depth.hpp"
#include <components/detournavigator/settings.hpp>
#include <components/detournavigator/recastmesh.hpp>
@ -9,6 +10,7 @@
#include <osg/Group>
#include <osg/Material>
#include <osg/PolygonOffset>
#include <algorithm>
#include <vector>
@ -45,7 +47,7 @@ namespace SceneUtil
using namespace DetourNavigator;
const osg::ref_ptr<osg::Group> group(new osg::Group);
DebugDraw debugDraw(*group, osg::Vec3f(0, 0, 0), 1.0f);
DebugDraw debugDraw(*group, DebugDraw::makeStateSet(), osg::Vec3f(0, 0, 0), 1.0f);
const DetourNavigator::Mesh& mesh = recastMesh.getMesh();
std::vector<int> indices = mesh.getIndices();
std::vector<float> vertices = mesh.getVertices();
@ -69,7 +71,14 @@ namespace SceneUtil
osg::ref_ptr<osg::Material> material = new osg::Material;
material->setColorMode(osg::Material::AMBIENT_AND_DIFFUSE);
group->getOrCreateStateSet()->setAttribute(material);
const float polygonOffsetFactor = SceneUtil::AutoDepth::isReversed() ? 1.0 : -1.0;
const float polygonOffsetUnits = SceneUtil::AutoDepth::isReversed() ? 1.0 : -1.0;
osg::ref_ptr<osg::PolygonOffset> polygonOffset = new osg::PolygonOffset(polygonOffsetFactor, polygonOffsetUnits);
osg::ref_ptr<osg::StateSet> stateSet = group->getOrCreateStateSet();
stateSet->setAttribute(material);
stateSet->setAttributeAndModes(polygonOffset);
return group;
}