mirror of
https://github.com/OpenMW/openmw.git
synced 2025-01-16 15:29:55 +00:00
Split makeNavMeshTileData
This commit is contained in:
parent
fb655cb04f
commit
0f6a64ad54
4 changed files with 240 additions and 186 deletions
20
components/detournavigator/bounds.hpp
Normal file
20
components/detournavigator/bounds.hpp
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
#ifndef OPENMW_COMPONENTS_DETOURNAVIGATOR_BOUNDS_H
|
||||||
|
#define OPENMW_COMPONENTS_DETOURNAVIGATOR_BOUNDS_H
|
||||||
|
|
||||||
|
#include <osg/Vec3f>
|
||||||
|
|
||||||
|
namespace DetourNavigator
|
||||||
|
{
|
||||||
|
struct Bounds
|
||||||
|
{
|
||||||
|
osg::Vec3f mMin;
|
||||||
|
osg::Vec3f mMax;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline bool isEmpty(const Bounds& value)
|
||||||
|
{
|
||||||
|
return value.mMin == value.mMax;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -102,6 +102,37 @@ namespace
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rcConfig makeConfig(const osg::Vec3f& agentHalfExtents, const osg::Vec3f& boundsMin, const osg::Vec3f& boundsMax,
|
||||||
|
const Settings& settings)
|
||||||
|
{
|
||||||
|
rcConfig config;
|
||||||
|
|
||||||
|
config.cs = settings.mCellSize;
|
||||||
|
config.ch = settings.mCellHeight;
|
||||||
|
config.walkableSlopeAngle = settings.mMaxSlope;
|
||||||
|
config.walkableHeight = static_cast<int>(std::ceil(getHeight(settings, agentHalfExtents) / config.ch));
|
||||||
|
config.walkableClimb = static_cast<int>(std::floor(getMaxClimb(settings) / config.ch));
|
||||||
|
config.walkableRadius = static_cast<int>(std::ceil(getRadius(settings, agentHalfExtents) / config.cs));
|
||||||
|
config.maxEdgeLen = static_cast<int>(std::round(settings.mMaxEdgeLen / config.cs));
|
||||||
|
config.maxSimplificationError = settings.mMaxSimplificationError;
|
||||||
|
config.minRegionArea = settings.mRegionMinSize * settings.mRegionMinSize;
|
||||||
|
config.mergeRegionArea = settings.mRegionMergeSize * settings.mRegionMergeSize;
|
||||||
|
config.maxVertsPerPoly = settings.mMaxVertsPerPoly;
|
||||||
|
config.detailSampleDist = settings.mDetailSampleDist < 0.9f ? 0 : config.cs * settings.mDetailSampleDist;
|
||||||
|
config.detailSampleMaxError = config.ch * settings.mDetailSampleMaxError;
|
||||||
|
config.borderSize = settings.mBorderSize;
|
||||||
|
config.width = settings.mTileSize + config.borderSize * 2;
|
||||||
|
config.height = settings.mTileSize + config.borderSize * 2;
|
||||||
|
rcVcopy(config.bmin, boundsMin.ptr());
|
||||||
|
rcVcopy(config.bmax, boundsMax.ptr());
|
||||||
|
config.bmin[0] -= getBorderSize(settings);
|
||||||
|
config.bmin[2] -= getBorderSize(settings);
|
||||||
|
config.bmax[0] += getBorderSize(settings);
|
||||||
|
config.bmax[2] += getBorderSize(settings);
|
||||||
|
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
void createHeightfield(rcContext& context, rcHeightfield& solid, int width, int height, const float* bmin,
|
void createHeightfield(rcContext& context, rcHeightfield& solid, int width, int height, const float* bmin,
|
||||||
const float* bmax, const float cs, const float ch)
|
const float* bmax, const float cs, const float ch)
|
||||||
{
|
{
|
||||||
|
@ -111,6 +142,137 @@ namespace
|
||||||
throw NavigatorException("Failed to create heightfield for navmesh");
|
throw NavigatorException("Failed to create heightfield for navmesh");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool rasterizeSolidObjectsTriangles(rcContext& context, const RecastMesh& recastMesh, const rcConfig& config,
|
||||||
|
rcHeightfield& solid)
|
||||||
|
{
|
||||||
|
const auto& chunkyMesh = recastMesh.getChunkyTriMesh();
|
||||||
|
std::vector<unsigned char> areas(chunkyMesh.getMaxTrisPerChunk(), AreaType_null);
|
||||||
|
const osg::Vec2f tileBoundsMin(config.bmin[0], config.bmin[2]);
|
||||||
|
const osg::Vec2f tileBoundsMax(config.bmax[0], config.bmax[2]);
|
||||||
|
std::vector<std::size_t> cids;
|
||||||
|
chunkyMesh.getChunksOverlappingRect(Rect {tileBoundsMin, tileBoundsMax}, std::back_inserter(cids));
|
||||||
|
|
||||||
|
if (cids.empty())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (const auto cid : cids)
|
||||||
|
{
|
||||||
|
const auto chunk = chunkyMesh.getChunk(cid);
|
||||||
|
|
||||||
|
std::fill(
|
||||||
|
areas.begin(),
|
||||||
|
std::min(areas.begin() + static_cast<std::ptrdiff_t>(chunk.mSize),
|
||||||
|
areas.end()),
|
||||||
|
AreaType_null
|
||||||
|
);
|
||||||
|
|
||||||
|
rcMarkWalkableTriangles(
|
||||||
|
&context,
|
||||||
|
config.walkableSlopeAngle,
|
||||||
|
recastMesh.getVertices().data(),
|
||||||
|
static_cast<int>(recastMesh.getVerticesCount()),
|
||||||
|
chunk.mIndices,
|
||||||
|
static_cast<int>(chunk.mSize),
|
||||||
|
areas.data()
|
||||||
|
);
|
||||||
|
|
||||||
|
for (std::size_t i = 0; i < chunk.mSize; ++i)
|
||||||
|
areas[i] = chunk.mAreaTypes[i];
|
||||||
|
|
||||||
|
rcClearUnwalkableTriangles(
|
||||||
|
&context,
|
||||||
|
config.walkableSlopeAngle,
|
||||||
|
recastMesh.getVertices().data(),
|
||||||
|
static_cast<int>(recastMesh.getVerticesCount()),
|
||||||
|
chunk.mIndices,
|
||||||
|
static_cast<int>(chunk.mSize),
|
||||||
|
areas.data()
|
||||||
|
);
|
||||||
|
|
||||||
|
const auto trianglesRasterized = rcRasterizeTriangles(
|
||||||
|
&context,
|
||||||
|
recastMesh.getVertices().data(),
|
||||||
|
static_cast<int>(recastMesh.getVerticesCount()),
|
||||||
|
chunk.mIndices,
|
||||||
|
areas.data(),
|
||||||
|
static_cast<int>(chunk.mSize),
|
||||||
|
solid,
|
||||||
|
config.walkableClimb
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!trianglesRasterized)
|
||||||
|
throw NavigatorException("Failed to create rasterize triangles from recast mesh for navmesh");
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rasterizeWaterTriangles(rcContext& context, const osg::Vec3f& agentHalfExtents, const RecastMesh& recastMesh,
|
||||||
|
const Settings& settings, const rcConfig& config, rcHeightfield& solid)
|
||||||
|
{
|
||||||
|
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,
|
||||||
|
}};
|
||||||
|
|
||||||
|
const auto trianglesRasterized = rcRasterizeTriangles(
|
||||||
|
&context,
|
||||||
|
convertedVertices.data(),
|
||||||
|
static_cast<int>(convertedVertices.size() / 3),
|
||||||
|
indices.data(),
|
||||||
|
areas.data(),
|
||||||
|
static_cast<int>(areas.size()),
|
||||||
|
solid,
|
||||||
|
config.walkableClimb
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!trianglesRasterized)
|
||||||
|
throw NavigatorException("Failed to create rasterize water triangles for navmesh");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool rasterizeTriangles(rcContext& context, const osg::Vec3f& agentHalfExtents, const RecastMesh& recastMesh,
|
||||||
|
const rcConfig& config, const Settings& settings, rcHeightfield& solid)
|
||||||
|
{
|
||||||
|
if (!rasterizeSolidObjectsTriangles(context, recastMesh, config, solid))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
rasterizeWaterTriangles(context, agentHalfExtents, recastMesh, settings, config, solid);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void buildCompactHeightfield(rcContext& context, const int walkableHeight, const int walkableClimb,
|
void buildCompactHeightfield(rcContext& context, const int walkableHeight, const int walkableClimb,
|
||||||
rcHeightfield& solid, rcCompactHeightfield& compact)
|
rcHeightfield& solid, rcCompactHeightfield& compact)
|
||||||
{
|
{
|
||||||
|
@ -173,161 +335,19 @@ namespace
|
||||||
throw NavigatorException("Failed to build detail poly mesh for navmesh");
|
throw NavigatorException("Failed to build detail poly mesh for navmesh");
|
||||||
}
|
}
|
||||||
|
|
||||||
NavMeshData makeNavMeshTileData(const osg::Vec3f& agentHalfExtents, const RecastMesh& recastMesh,
|
void setPolyMeshFlags(rcPolyMesh& polyMesh)
|
||||||
const std::vector<OffMeshConnection>& offMeshConnections, const int tileX, const int tileY,
|
|
||||||
const osg::Vec3f& boundsMin, const osg::Vec3f& boundsMax, const Settings& settings)
|
|
||||||
{
|
{
|
||||||
rcContext context;
|
for (int i = 0; i < polyMesh.npolys; ++i)
|
||||||
rcConfig config;
|
|
||||||
|
|
||||||
config.cs = settings.mCellSize;
|
|
||||||
config.ch = settings.mCellHeight;
|
|
||||||
config.walkableSlopeAngle = settings.mMaxSlope;
|
|
||||||
config.walkableHeight = static_cast<int>(std::ceil(getHeight(settings, agentHalfExtents) / config.ch));
|
|
||||||
config.walkableClimb = static_cast<int>(std::floor(getMaxClimb(settings) / config.ch));
|
|
||||||
config.walkableRadius = static_cast<int>(std::ceil(getRadius(settings, agentHalfExtents) / config.cs));
|
|
||||||
config.maxEdgeLen = static_cast<int>(std::round(settings.mMaxEdgeLen / config.cs));
|
|
||||||
config.maxSimplificationError = settings.mMaxSimplificationError;
|
|
||||||
config.minRegionArea = settings.mRegionMinSize * settings.mRegionMinSize;
|
|
||||||
config.mergeRegionArea = settings.mRegionMergeSize * settings.mRegionMergeSize;
|
|
||||||
config.maxVertsPerPoly = settings.mMaxVertsPerPoly;
|
|
||||||
config.detailSampleDist = settings.mDetailSampleDist < 0.9f ? 0 : config.cs * settings.mDetailSampleDist;
|
|
||||||
config.detailSampleMaxError = config.ch * settings.mDetailSampleMaxError;
|
|
||||||
config.borderSize = settings.mBorderSize;
|
|
||||||
config.width = settings.mTileSize + config.borderSize * 2;
|
|
||||||
config.height = settings.mTileSize + config.borderSize * 2;
|
|
||||||
rcVcopy(config.bmin, boundsMin.ptr());
|
|
||||||
rcVcopy(config.bmax, boundsMax.ptr());
|
|
||||||
config.bmin[0] -= getBorderSize(settings);
|
|
||||||
config.bmin[2] -= getBorderSize(settings);
|
|
||||||
config.bmax[0] += getBorderSize(settings);
|
|
||||||
config.bmax[2] += getBorderSize(settings);
|
|
||||||
|
|
||||||
rcHeightfield solid;
|
|
||||||
createHeightfield(context, solid, config.width, config.height, config.bmin, config.bmax, config.cs, config.ch);
|
|
||||||
|
|
||||||
{
|
{
|
||||||
const auto& chunkyMesh = recastMesh.getChunkyTriMesh();
|
if (polyMesh.areas[i] == AreaType_ground)
|
||||||
std::vector<unsigned char> areas(chunkyMesh.getMaxTrisPerChunk(), AreaType_null);
|
polyMesh.flags[i] = Flag_walk;
|
||||||
const osg::Vec2f tileBoundsMin(config.bmin[0], config.bmin[2]);
|
else if (polyMesh.areas[i] == AreaType_water)
|
||||||
const osg::Vec2f tileBoundsMax(config.bmax[0], config.bmax[2]);
|
polyMesh.flags[i] = Flag_swim;
|
||||||
std::vector<std::size_t> cids;
|
|
||||||
chunkyMesh.getChunksOverlappingRect(Rect {tileBoundsMin, tileBoundsMax}, std::back_inserter(cids));
|
|
||||||
|
|
||||||
if (cids.empty())
|
|
||||||
return NavMeshData();
|
|
||||||
|
|
||||||
for (const auto cid : cids)
|
|
||||||
{
|
|
||||||
const auto chunk = chunkyMesh.getChunk(cid);
|
|
||||||
|
|
||||||
std::fill(
|
|
||||||
areas.begin(),
|
|
||||||
std::min(areas.begin() + static_cast<std::ptrdiff_t>(chunk.mSize),
|
|
||||||
areas.end()),
|
|
||||||
AreaType_null
|
|
||||||
);
|
|
||||||
|
|
||||||
rcMarkWalkableTriangles(
|
|
||||||
&context,
|
|
||||||
config.walkableSlopeAngle,
|
|
||||||
recastMesh.getVertices().data(),
|
|
||||||
static_cast<int>(recastMesh.getVerticesCount()),
|
|
||||||
chunk.mIndices,
|
|
||||||
static_cast<int>(chunk.mSize),
|
|
||||||
areas.data()
|
|
||||||
);
|
|
||||||
|
|
||||||
for (std::size_t i = 0; i < chunk.mSize; ++i)
|
|
||||||
areas[i] = chunk.mAreaTypes[i];
|
|
||||||
|
|
||||||
rcClearUnwalkableTriangles(
|
|
||||||
&context,
|
|
||||||
config.walkableSlopeAngle,
|
|
||||||
recastMesh.getVertices().data(),
|
|
||||||
static_cast<int>(recastMesh.getVerticesCount()),
|
|
||||||
chunk.mIndices,
|
|
||||||
static_cast<int>(chunk.mSize),
|
|
||||||
areas.data()
|
|
||||||
);
|
|
||||||
|
|
||||||
const auto trianglesRasterized = rcRasterizeTriangles(
|
|
||||||
&context,
|
|
||||||
recastMesh.getVertices().data(),
|
|
||||||
static_cast<int>(recastMesh.getVerticesCount()),
|
|
||||||
chunk.mIndices,
|
|
||||||
areas.data(),
|
|
||||||
static_cast<int>(chunk.mSize),
|
|
||||||
solid,
|
|
||||||
config.walkableClimb
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!trianglesRasterized)
|
|
||||||
throw NavigatorException("Failed to create rasterize triangles from recast mesh for navmesh");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
bool fillPolyMesh(rcContext& context, const rcConfig& config, rcHeightfield& solid, rcPolyMesh& polyMesh,
|
||||||
const std::array<unsigned char, 2> areas {{AreaType_water, AreaType_water}};
|
rcPolyMeshDetail& polyMeshDetail)
|
||||||
|
|
||||||
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,
|
|
||||||
}};
|
|
||||||
|
|
||||||
const auto trianglesRasterized = rcRasterizeTriangles(
|
|
||||||
&context,
|
|
||||||
convertedVertices.data(),
|
|
||||||
static_cast<int>(convertedVertices.size() / 3),
|
|
||||||
indices.data(),
|
|
||||||
areas.data(),
|
|
||||||
static_cast<int>(areas.size()),
|
|
||||||
solid,
|
|
||||||
config.walkableClimb
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!trianglesRasterized)
|
|
||||||
throw NavigatorException("Failed to create rasterize water triangles for navmesh");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rcFilterLowHangingWalkableObstacles(&context, config.walkableClimb, solid);
|
|
||||||
rcFilterLedgeSpans(&context, config.walkableHeight, config.walkableClimb, solid);
|
|
||||||
rcFilterWalkableLowHeightSpans(&context, config.walkableHeight, solid);
|
|
||||||
|
|
||||||
rcPolyMesh polyMesh;
|
|
||||||
rcPolyMeshDetail polyMeshDetail;
|
|
||||||
initPolyMeshDetail(polyMeshDetail);
|
|
||||||
const PolyMeshDetailStackPtr polyMeshDetailPtr(&polyMeshDetail);
|
|
||||||
{
|
{
|
||||||
rcCompactHeightfield compact;
|
rcCompactHeightfield compact;
|
||||||
buildCompactHeightfield(context, config.walkableHeight, config.walkableClimb, solid, compact);
|
buildCompactHeightfield(context, config.walkableHeight, config.walkableClimb, solid, compact);
|
||||||
|
@ -340,21 +360,41 @@ namespace
|
||||||
buildContours(context, compact, config.maxSimplificationError, config.maxEdgeLen, contourSet);
|
buildContours(context, compact, config.maxSimplificationError, config.maxEdgeLen, contourSet);
|
||||||
|
|
||||||
if (contourSet.nconts == 0)
|
if (contourSet.nconts == 0)
|
||||||
return NavMeshData();
|
return false;
|
||||||
|
|
||||||
buildPolyMesh(context, contourSet, config.maxVertsPerPoly, polyMesh);
|
buildPolyMesh(context, contourSet, config.maxVertsPerPoly, polyMesh);
|
||||||
|
|
||||||
buildPolyMeshDetail(context, polyMesh, compact, config.detailSampleDist, config.detailSampleMaxError,
|
buildPolyMeshDetail(context, polyMesh, compact, config.detailSampleDist, config.detailSampleMaxError,
|
||||||
polyMeshDetail);
|
polyMeshDetail);
|
||||||
|
|
||||||
|
setPolyMeshFlags(polyMesh);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < polyMesh.npolys; ++i)
|
NavMeshData makeNavMeshTileData(const osg::Vec3f& agentHalfExtents, const RecastMesh& recastMesh,
|
||||||
|
const std::vector<OffMeshConnection>& offMeshConnections, const TilePosition& tile,
|
||||||
|
const osg::Vec3f& boundsMin, const osg::Vec3f& boundsMax, const Settings& settings)
|
||||||
{
|
{
|
||||||
if (polyMesh.areas[i] == AreaType_ground)
|
rcContext context;
|
||||||
polyMesh.flags[i] = Flag_walk;
|
const auto config = makeConfig(agentHalfExtents, boundsMin, boundsMax, settings);
|
||||||
else if (polyMesh.areas[i] == AreaType_water)
|
|
||||||
polyMesh.flags[i] = Flag_swim;
|
rcHeightfield solid;
|
||||||
}
|
createHeightfield(context, solid, config.width, config.height, config.bmin, config.bmax, config.cs, config.ch);
|
||||||
|
|
||||||
|
if (!rasterizeTriangles(context, agentHalfExtents, recastMesh, config, settings, solid))
|
||||||
|
return NavMeshData();
|
||||||
|
|
||||||
|
rcFilterLowHangingWalkableObstacles(&context, config.walkableClimb, solid);
|
||||||
|
rcFilterLedgeSpans(&context, config.walkableHeight, config.walkableClimb, solid);
|
||||||
|
rcFilterWalkableLowHeightSpans(&context, config.walkableHeight, solid);
|
||||||
|
|
||||||
|
rcPolyMesh polyMesh;
|
||||||
|
rcPolyMeshDetail polyMeshDetail;
|
||||||
|
initPolyMeshDetail(polyMeshDetail);
|
||||||
|
const PolyMeshDetailStackPtr polyMeshDetailPtr(&polyMeshDetail);
|
||||||
|
if (!fillPolyMesh(context, config, solid, polyMesh, polyMeshDetail))
|
||||||
|
return NavMeshData();
|
||||||
|
|
||||||
const auto offMeshConVerts = getOffMeshVerts(offMeshConnections);
|
const auto offMeshConVerts = getOffMeshVerts(offMeshConnections);
|
||||||
const std::vector<float> offMeshConRad(offMeshConnections.size(), getRadius(settings, agentHalfExtents));
|
const std::vector<float> offMeshConRad(offMeshConnections.size(), getRadius(settings, agentHalfExtents));
|
||||||
|
@ -391,8 +431,8 @@ namespace
|
||||||
params.ch = config.ch;
|
params.ch = config.ch;
|
||||||
params.buildBvTree = true;
|
params.buildBvTree = true;
|
||||||
params.userId = 0;
|
params.userId = 0;
|
||||||
params.tileX = tileX;
|
params.tileX = tile.x();
|
||||||
params.tileY = tileY;
|
params.tileY = tile.y();
|
||||||
params.tileLayer = 0;
|
params.tileLayer = 0;
|
||||||
|
|
||||||
unsigned char* navMeshData;
|
unsigned char* navMeshData;
|
||||||
|
@ -483,17 +523,16 @@ namespace DetourNavigator
|
||||||
return removeTile();
|
return removeTile();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto boundsMin = recastMesh->getBoundsMin();
|
auto recastMeshBounds = recastMesh->getBounds();
|
||||||
auto boundsMax = recastMesh->getBoundsMax();
|
|
||||||
|
|
||||||
for (const auto& water : recastMesh->getWater())
|
for (const auto& water : recastMesh->getWater())
|
||||||
{
|
{
|
||||||
const auto bounds = getWaterBounds(water, settings, agentHalfExtents);
|
const auto waterBounds = getWaterBounds(water, settings, agentHalfExtents);
|
||||||
boundsMin.y() = std::min(boundsMin.y(), bounds.mMin.y());
|
recastMeshBounds.mMin.y() = std::min(recastMeshBounds.mMin.y(), waterBounds.mMin.y());
|
||||||
boundsMax.y() = std::max(boundsMax.y(), bounds.mMax.y());
|
recastMeshBounds.mMax.y() = std::max(recastMeshBounds.mMax.y(), waterBounds.mMax.y());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (boundsMin == boundsMax)
|
if (isEmpty(recastMeshBounds))
|
||||||
{
|
{
|
||||||
log("ignore add tile: recastMesh is empty");
|
log("ignore add tile: recastMesh is empty");
|
||||||
return removeTile();
|
return removeTile();
|
||||||
|
@ -510,10 +549,10 @@ namespace DetourNavigator
|
||||||
if (!cachedNavMeshData)
|
if (!cachedNavMeshData)
|
||||||
{
|
{
|
||||||
const auto tileBounds = makeTileBounds(settings, changedTile);
|
const auto tileBounds = makeTileBounds(settings, changedTile);
|
||||||
const osg::Vec3f tileBorderMin(tileBounds.mMin.x(), boundsMin.y() - 1, tileBounds.mMin.y());
|
const osg::Vec3f tileBorderMin(tileBounds.mMin.x(), recastMeshBounds.mMin.y() - 1, tileBounds.mMin.y());
|
||||||
const osg::Vec3f tileBorderMax(tileBounds.mMax.x(), boundsMax.y() + 1, tileBounds.mMax.y());
|
const osg::Vec3f tileBorderMax(tileBounds.mMax.x(), recastMeshBounds.mMax.y() + 1, tileBounds.mMax.y());
|
||||||
|
|
||||||
auto navMeshData = makeNavMeshTileData(agentHalfExtents, *recastMesh, offMeshConnections, x, y,
|
auto navMeshData = makeNavMeshTileData(agentHalfExtents, *recastMesh, offMeshConnections, changedTile,
|
||||||
tileBorderMin, tileBorderMax, settings);
|
tileBorderMin, tileBorderMax, settings);
|
||||||
|
|
||||||
if (!navMeshData.mValue)
|
if (!navMeshData.mValue)
|
||||||
|
|
|
@ -17,6 +17,6 @@ namespace DetourNavigator
|
||||||
throw InvalidArgument("Number of flags doesn't match number of triangles: triangles="
|
throw InvalidArgument("Number of flags doesn't match number of triangles: triangles="
|
||||||
+ std::to_string(getTrianglesCount()) + ", areaTypes=" + std::to_string(mAreaTypes.size()));
|
+ std::to_string(getTrianglesCount()) + ", areaTypes=" + std::to_string(mAreaTypes.size()));
|
||||||
if (getVerticesCount())
|
if (getVerticesCount())
|
||||||
rcCalcBounds(mVertices.data(), static_cast<int>(getVerticesCount()), mBoundsMin.ptr(), mBoundsMax.ptr());
|
rcCalcBounds(mVertices.data(), static_cast<int>(getVerticesCount()), mBounds.mMin.ptr(), mBounds.mMax.ptr());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
#include "areatype.hpp"
|
#include "areatype.hpp"
|
||||||
#include "chunkytrimesh.hpp"
|
#include "chunkytrimesh.hpp"
|
||||||
|
#include "bounds.hpp"
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
@ -61,14 +62,9 @@ namespace DetourNavigator
|
||||||
return mChunkyTriMesh;
|
return mChunkyTriMesh;
|
||||||
}
|
}
|
||||||
|
|
||||||
const osg::Vec3f& getBoundsMin() const
|
const Bounds& getBounds() const
|
||||||
{
|
{
|
||||||
return mBoundsMin;
|
return mBounds;
|
||||||
}
|
|
||||||
|
|
||||||
const osg::Vec3f& getBoundsMax() const
|
|
||||||
{
|
|
||||||
return mBoundsMax;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -77,8 +73,7 @@ namespace DetourNavigator
|
||||||
std::vector<AreaType> mAreaTypes;
|
std::vector<AreaType> mAreaTypes;
|
||||||
std::vector<Water> mWater;
|
std::vector<Water> mWater;
|
||||||
ChunkyTriMesh mChunkyTriMesh;
|
ChunkyTriMesh mChunkyTriMesh;
|
||||||
osg::Vec3f mBoundsMin;
|
Bounds mBounds;
|
||||||
osg::Vec3f mBoundsMax;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue