mirror of
https://github.com/OpenMW/openmw.git
synced 2025-01-29 21:45:33 +00:00
Remove redundant ChunkyTriMesh
This AABB tree required when need to filter out input mesh that has not influence navmesh tile output. This filtering is already done before. Each recast mesh corresponds to a single navmesh tile and has appropriate bounds.
This commit is contained in:
parent
bce06df254
commit
ec87b3f8f7
16 changed files with 37 additions and 371 deletions
|
@ -114,9 +114,8 @@ namespace
|
|||
generateAreaTypes(std::back_inserter(areaTypes), indices.size() / 3, random);
|
||||
std::vector<RecastMesh::Water> water;
|
||||
generateWater(std::back_inserter(water), 2, random);
|
||||
const std::size_t trianglesPerChunk = 256;
|
||||
RecastMesh recastMesh(generation, revision, std::move(indices), std::move(vertices),
|
||||
std::move(areaTypes), std::move(water), trianglesPerChunk);
|
||||
std::move(areaTypes), std::move(water));
|
||||
std::vector<OffMeshConnection> offMeshConnections;
|
||||
generateOffMeshConnection(std::back_inserter(offMeshConnections), 300, random);
|
||||
return Key {agentHalfExtents, tilePosition, std::move(recastMesh), std::move(offMeshConnections)};
|
||||
|
|
|
@ -68,7 +68,6 @@ namespace
|
|||
mSettings.mMaxNavMeshTilesCacheSize = 1024 * 1024;
|
||||
mSettings.mMaxPolygonPathSize = 1024;
|
||||
mSettings.mMaxSmoothPathSize = 1024;
|
||||
mSettings.mTrianglesPerChunk = 256;
|
||||
mSettings.mMaxPolys = 4096;
|
||||
mSettings.mMaxTilesNumber = 512;
|
||||
mSettings.mMinUpdateInterval = std::chrono::milliseconds(50);
|
||||
|
|
|
@ -31,9 +31,7 @@ namespace
|
|||
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 {mGeneration, mRevision, mIndices, mVertices,
|
||||
mAreaTypes, mWater, mTrianglesPerChunk};
|
||||
const RecastMesh mRecastMesh {mGeneration, mRevision, mIndices, mVertices, mAreaTypes, mWater};
|
||||
const std::vector<OffMeshConnection> mOffMeshConnections {};
|
||||
unsigned char* const mData = reinterpret_cast<unsigned char*>(dtAlloc(1, DT_ALLOC_PERM));
|
||||
NavMeshData mNavMeshData {mData, 1};
|
||||
|
@ -130,8 +128,7 @@ 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 {mGeneration, mRevision, mIndices, mVertices,
|
||||
mAreaTypes, water, mTrianglesPerChunk};
|
||||
const RecastMesh unexistentRecastMesh {mGeneration, mRevision, mIndices, mVertices, mAreaTypes, water};
|
||||
|
||||
cache.set(mAgentHalfExtents, mTilePosition, mRecastMesh, mOffMeshConnections, std::move(mNavMeshData));
|
||||
EXPECT_FALSE(cache.get(mAgentHalfExtents, mTilePosition, unexistentRecastMesh, mOffMeshConnections));
|
||||
|
@ -145,8 +142,7 @@ namespace
|
|||
NavMeshTilesCache cache(maxSize);
|
||||
|
||||
const std::vector<RecastMesh::Water> water {1, RecastMesh::Water {1, btTransform::getIdentity()}};
|
||||
const RecastMesh anotherRecastMesh {mGeneration, mRevision, mIndices, mVertices,
|
||||
mAreaTypes, water, mTrianglesPerChunk};
|
||||
const RecastMesh anotherRecastMesh {mGeneration, mRevision, mIndices, mVertices, mAreaTypes, water};
|
||||
const auto anotherData = reinterpret_cast<unsigned char*>(dtAlloc(1, DT_ALLOC_PERM));
|
||||
NavMeshData anotherNavMeshData {anotherData, 1};
|
||||
|
||||
|
@ -166,8 +162,7 @@ namespace
|
|||
NavMeshTilesCache cache(maxSize);
|
||||
|
||||
const std::vector<RecastMesh::Water> water {1, RecastMesh::Water {1, btTransform::getIdentity()}};
|
||||
const RecastMesh anotherRecastMesh {mGeneration, mRevision, mIndices, mVertices,
|
||||
mAreaTypes, water, mTrianglesPerChunk};
|
||||
const RecastMesh anotherRecastMesh {mGeneration, mRevision, mIndices, mVertices, mAreaTypes, water};
|
||||
const auto anotherData = reinterpret_cast<unsigned char*>(dtAlloc(1, DT_ALLOC_PERM));
|
||||
NavMeshData anotherNavMeshData {anotherData, 1};
|
||||
|
||||
|
@ -186,13 +181,13 @@ namespace
|
|||
|
||||
const std::vector<RecastMesh::Water> leastRecentlySetWater {1, RecastMesh::Water {1, btTransform::getIdentity()}};
|
||||
const RecastMesh leastRecentlySetRecastMesh {mGeneration, mRevision, mIndices, mVertices,
|
||||
mAreaTypes, leastRecentlySetWater, mTrianglesPerChunk};
|
||||
mAreaTypes, leastRecentlySetWater};
|
||||
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 {mGeneration, mRevision, mIndices, mVertices,
|
||||
mAreaTypes, mostRecentlySetWater, mTrianglesPerChunk};
|
||||
mAreaTypes, mostRecentlySetWater};
|
||||
const auto mostRecentlySetData = reinterpret_cast<unsigned char*>(dtAlloc(1, DT_ALLOC_PERM));
|
||||
NavMeshData mostRecentlySetNavMeshData {mostRecentlySetData, 1};
|
||||
|
||||
|
@ -218,13 +213,13 @@ namespace
|
|||
|
||||
const std::vector<RecastMesh::Water> leastRecentlyUsedWater {1, RecastMesh::Water {1, btTransform::getIdentity()}};
|
||||
const RecastMesh leastRecentlyUsedRecastMesh {mGeneration, mRevision, mIndices, mVertices,
|
||||
mAreaTypes, leastRecentlyUsedWater, mTrianglesPerChunk};
|
||||
mAreaTypes, leastRecentlyUsedWater};
|
||||
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 {mGeneration, mRevision, mIndices, mVertices,
|
||||
mAreaTypes, mostRecentlyUsedWater, mTrianglesPerChunk};
|
||||
mAreaTypes, mostRecentlyUsedWater};
|
||||
const auto mostRecentlyUsedData = reinterpret_cast<unsigned char*>(dtAlloc(1, DT_ALLOC_PERM));
|
||||
NavMeshData mostRecentlyUsedNavMeshData {mostRecentlyUsedData, 1};
|
||||
|
||||
|
@ -261,7 +256,7 @@ namespace
|
|||
NavMeshTilesCache cache(maxSize);
|
||||
|
||||
const std::vector<RecastMesh::Water> water {1, RecastMesh::Water {1, btTransform::getIdentity()}};
|
||||
const RecastMesh tooLargeRecastMesh {mGeneration, mRevision, mIndices, mVertices, mAreaTypes, water, mTrianglesPerChunk};
|
||||
const RecastMesh tooLargeRecastMesh {mGeneration, mRevision, mIndices, mVertices, mAreaTypes, water};
|
||||
const auto tooLargeData = reinterpret_cast<unsigned char*>(dtAlloc(2, DT_ALLOC_PERM));
|
||||
NavMeshData tooLargeNavMeshData {tooLargeData, 2};
|
||||
|
||||
|
@ -280,13 +275,13 @@ namespace
|
|||
NavMeshTilesCache cache(maxSize);
|
||||
|
||||
const std::vector<RecastMesh::Water> anotherWater {1, RecastMesh::Water {1, btTransform::getIdentity()}};
|
||||
const RecastMesh anotherRecastMesh {mGeneration, mRevision, mIndices, mVertices, mAreaTypes, anotherWater, mTrianglesPerChunk};
|
||||
const RecastMesh anotherRecastMesh {mGeneration, mRevision, mIndices, mVertices, mAreaTypes, anotherWater};
|
||||
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 {mGeneration, mRevision, mIndices, mVertices,
|
||||
mAreaTypes, tooLargeWater, mTrianglesPerChunk};
|
||||
mAreaTypes, tooLargeWater};
|
||||
const auto tooLargeData = reinterpret_cast<unsigned char*>(dtAlloc(2, DT_ALLOC_PERM));
|
||||
NavMeshData tooLargeNavMeshData {tooLargeData, 2};
|
||||
|
||||
|
@ -310,7 +305,7 @@ namespace
|
|||
|
||||
const std::vector<RecastMesh::Water> water {1, RecastMesh::Water {1, btTransform::getIdentity()}};
|
||||
const RecastMesh anotherRecastMesh {mGeneration, mRevision, mIndices, mVertices,
|
||||
mAreaTypes, water, mTrianglesPerChunk};
|
||||
mAreaTypes, water};
|
||||
const auto anotherData = reinterpret_cast<unsigned char*>(dtAlloc(1, DT_ALLOC_PERM));
|
||||
NavMeshData anotherNavMeshData {anotherData, 1};
|
||||
|
||||
|
@ -333,7 +328,7 @@ namespace
|
|||
NavMeshTilesCache cache(maxSize);
|
||||
|
||||
const std::vector<RecastMesh::Water> water {1, RecastMesh::Water {1, btTransform::getIdentity()}};
|
||||
const RecastMesh anotherRecastMesh {mGeneration, mRevision, mIndices, mVertices, mAreaTypes, water, mTrianglesPerChunk};
|
||||
const RecastMesh anotherRecastMesh {mGeneration, mRevision, mIndices, mVertices, mAreaTypes, water};
|
||||
const auto anotherData = reinterpret_cast<unsigned char*>(dtAlloc(1, DT_ALLOC_PERM));
|
||||
NavMeshData anotherNavMeshData {anotherData, 1};
|
||||
|
||||
|
|
|
@ -37,7 +37,6 @@ namespace
|
|||
DetourNavigatorRecastMeshBuilderTest()
|
||||
{
|
||||
mSettings.mRecastScaleFactor = 1.0f;
|
||||
mSettings.mTrianglesPerChunk = 256;
|
||||
mBounds.mMin = osg::Vec2f(-std::numeric_limits<float>::max() * std::numeric_limits<float>::epsilon(),
|
||||
-std::numeric_limits<float>::max() * std::numeric_limits<float>::epsilon());
|
||||
mBounds.mMax = osg::Vec2f(std::numeric_limits<float>::max() * std::numeric_limits<float>::epsilon(),
|
||||
|
|
|
@ -24,7 +24,6 @@ namespace
|
|||
mSettings.mCellSize = 0.2f;
|
||||
mSettings.mRecastScaleFactor = 0.017647058823529415f;
|
||||
mSettings.mTileSize = 64;
|
||||
mSettings.mTrianglesPerChunk = 256;
|
||||
}
|
||||
|
||||
void onChangedTile(const TilePosition& tilePosition)
|
||||
|
|
|
@ -173,7 +173,6 @@ add_component_dir(detournavigator
|
|||
navmeshmanager
|
||||
navigatorimpl
|
||||
asyncnavmeshupdater
|
||||
chunkytrimesh
|
||||
recastmesh
|
||||
tilecachedrecastmeshmanager
|
||||
recastmeshobject
|
||||
|
|
|
@ -1,179 +0,0 @@
|
|||
#include "chunkytrimesh.hpp"
|
||||
#include "exceptions.hpp"
|
||||
|
||||
#include <osg/Vec2f>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace DetourNavigator
|
||||
{
|
||||
namespace
|
||||
{
|
||||
struct BoundsItem
|
||||
{
|
||||
Rect mBounds;
|
||||
std::ptrdiff_t mOffset;
|
||||
unsigned char mAreaTypes;
|
||||
};
|
||||
|
||||
template <std::size_t axis>
|
||||
struct LessBoundsItem
|
||||
{
|
||||
bool operator ()(const BoundsItem& lhs, const BoundsItem& rhs) const
|
||||
{
|
||||
return lhs.mBounds.mMinBound[axis] < rhs.mBounds.mMinBound[axis];
|
||||
}
|
||||
};
|
||||
|
||||
void calcExtends(const std::vector<BoundsItem>& items, const std::size_t imin, const std::size_t imax,
|
||||
Rect& bounds)
|
||||
{
|
||||
bounds = items[imin].mBounds;
|
||||
|
||||
std::for_each(
|
||||
items.begin() + static_cast<std::ptrdiff_t>(imin) + 1,
|
||||
items.begin() + static_cast<std::ptrdiff_t>(imax),
|
||||
[&] (const BoundsItem& item)
|
||||
{
|
||||
for (int i = 0; i < 2; ++i)
|
||||
{
|
||||
bounds.mMinBound[i] = std::min(bounds.mMinBound[i], item.mBounds.mMinBound[i]);
|
||||
bounds.mMaxBound[i] = std::max(bounds.mMaxBound[i], item.mBounds.mMaxBound[i]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void subdivide(std::vector<BoundsItem>& items, const std::size_t imin, const std::size_t imax,
|
||||
const std::size_t trisPerChunk, const std::vector<int>& inIndices, const std::vector<AreaType>& inAreaTypes,
|
||||
std::size_t& curNode, std::vector<ChunkyTriMeshNode>& nodes, std::size_t& curTri,
|
||||
std::vector<int>& outIndices, std::vector<AreaType>& outAreaTypes)
|
||||
{
|
||||
const auto inum = imax - imin;
|
||||
const auto icur = curNode;
|
||||
|
||||
if (curNode >= nodes.size())
|
||||
return;
|
||||
|
||||
ChunkyTriMeshNode& node = nodes[curNode++];
|
||||
|
||||
if (inum <= trisPerChunk)
|
||||
{
|
||||
// Leaf
|
||||
calcExtends(items, imin, imax, node.mBounds);
|
||||
|
||||
// Copy triangles.
|
||||
node.mOffset = static_cast<std::ptrdiff_t>(curTri);
|
||||
node.mSize = inum;
|
||||
|
||||
for (std::size_t i = imin; i < imax; ++i)
|
||||
{
|
||||
std::copy(
|
||||
inIndices.begin() + items[i].mOffset * 3,
|
||||
inIndices.begin() + items[i].mOffset * 3 + 3,
|
||||
outIndices.begin() + static_cast<std::ptrdiff_t>(curTri) * 3
|
||||
);
|
||||
outAreaTypes[curTri] = inAreaTypes[static_cast<std::size_t>(items[i].mOffset)];
|
||||
curTri++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Split
|
||||
calcExtends(items, imin, imax, node.mBounds);
|
||||
|
||||
if (node.mBounds.mMaxBound.x() - node.mBounds.mMinBound.x()
|
||||
>= node.mBounds.mMaxBound.y() - node.mBounds.mMinBound.y())
|
||||
{
|
||||
// Sort along x-axis
|
||||
std::sort(
|
||||
items.begin() + static_cast<std::ptrdiff_t>(imin),
|
||||
items.begin() + static_cast<std::ptrdiff_t>(imax),
|
||||
LessBoundsItem<0> {}
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Sort along y-axis
|
||||
std::sort(
|
||||
items.begin() + static_cast<std::ptrdiff_t>(imin),
|
||||
items.begin() + static_cast<std::ptrdiff_t>(imax),
|
||||
LessBoundsItem<1> {}
|
||||
);
|
||||
}
|
||||
|
||||
const auto isplit = imin + inum / 2;
|
||||
|
||||
// Left
|
||||
subdivide(items, imin, isplit, trisPerChunk, inIndices, inAreaTypes, curNode, nodes, curTri, outIndices, outAreaTypes);
|
||||
// Right
|
||||
subdivide(items, isplit, imax, trisPerChunk, inIndices, inAreaTypes, curNode, nodes, curTri, outIndices, outAreaTypes);
|
||||
|
||||
const auto iescape = static_cast<std::ptrdiff_t>(curNode) - static_cast<std::ptrdiff_t>(icur);
|
||||
// Negative index means escape.
|
||||
node.mOffset = -iescape;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ChunkyTriMesh::ChunkyTriMesh(const std::vector<float>& verts, const std::vector<int>& indices,
|
||||
const std::vector<AreaType>& flags, const std::size_t trisPerChunk)
|
||||
: mMaxTrisPerChunk(0)
|
||||
{
|
||||
const auto trianglesCount = indices.size() / 3;
|
||||
|
||||
if (trianglesCount == 0)
|
||||
return;
|
||||
|
||||
const auto nchunks = (trianglesCount + trisPerChunk - 1) / trisPerChunk;
|
||||
|
||||
mNodes.resize(nchunks * 4);
|
||||
mIndices.resize(trianglesCount * 3);
|
||||
mAreaTypes.resize(trianglesCount);
|
||||
|
||||
// Build tree
|
||||
std::vector<BoundsItem> items(trianglesCount);
|
||||
|
||||
for (std::size_t i = 0; i < trianglesCount; i++)
|
||||
{
|
||||
auto& item = items[i];
|
||||
|
||||
item.mOffset = static_cast<std::ptrdiff_t>(i);
|
||||
item.mAreaTypes = flags[i];
|
||||
|
||||
// Calc triangle XZ bounds.
|
||||
const auto baseIndex = static_cast<std::size_t>(indices[i * 3]) * 3;
|
||||
|
||||
item.mBounds.mMinBound.x() = item.mBounds.mMaxBound.x() = verts[baseIndex + 0];
|
||||
item.mBounds.mMinBound.y() = item.mBounds.mMaxBound.y() = verts[baseIndex + 2];
|
||||
|
||||
for (std::size_t j = 1; j < 3; ++j)
|
||||
{
|
||||
const auto index = static_cast<std::size_t>(indices[i * 3 + j]) * 3;
|
||||
|
||||
item.mBounds.mMinBound.x() = std::min(item.mBounds.mMinBound.x(), verts[index + 0]);
|
||||
item.mBounds.mMinBound.y() = std::min(item.mBounds.mMinBound.y(), verts[index + 2]);
|
||||
|
||||
item.mBounds.mMaxBound.x() = std::max(item.mBounds.mMaxBound.x(), verts[index + 0]);
|
||||
item.mBounds.mMaxBound.y() = std::max(item.mBounds.mMaxBound.y(), verts[index + 2]);
|
||||
}
|
||||
}
|
||||
|
||||
std::size_t curTri = 0;
|
||||
std::size_t curNode = 0;
|
||||
subdivide(items, 0, trianglesCount, trisPerChunk, indices, flags, curNode, mNodes, curTri, mIndices, mAreaTypes);
|
||||
|
||||
items.clear();
|
||||
|
||||
mNodes.resize(curNode);
|
||||
|
||||
// Calc max tris per node.
|
||||
for (auto& node : mNodes)
|
||||
{
|
||||
const bool isLeaf = node.mOffset >= 0;
|
||||
if (!isLeaf)
|
||||
continue;
|
||||
if (node.mSize > mMaxTrisPerChunk)
|
||||
mMaxTrisPerChunk = node.mSize;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,102 +0,0 @@
|
|||
#ifndef OPENMW_COMPONENTS_DETOURNAVIGATOR_CHUNKYTRIMESH_H
|
||||
#define OPENMW_COMPONENTS_DETOURNAVIGATOR_CHUNKYTRIMESH_H
|
||||
|
||||
#include "areatype.hpp"
|
||||
|
||||
#include <osg/Vec2f>
|
||||
|
||||
#include <array>
|
||||
#include <vector>
|
||||
|
||||
namespace DetourNavigator
|
||||
{
|
||||
struct Rect
|
||||
{
|
||||
osg::Vec2f mMinBound;
|
||||
osg::Vec2f mMaxBound;
|
||||
};
|
||||
|
||||
struct ChunkyTriMeshNode
|
||||
{
|
||||
Rect mBounds;
|
||||
std::ptrdiff_t mOffset;
|
||||
std::size_t mSize;
|
||||
};
|
||||
|
||||
struct Chunk
|
||||
{
|
||||
const int* const mIndices;
|
||||
const AreaType* const mAreaTypes;
|
||||
const std::size_t mSize;
|
||||
};
|
||||
|
||||
inline bool checkOverlapRect(const Rect& lhs, const Rect& rhs)
|
||||
{
|
||||
bool overlap = true;
|
||||
overlap = (lhs.mMinBound.x() > rhs.mMaxBound.x() || lhs.mMaxBound.x() < rhs.mMinBound.x()) ? false : overlap;
|
||||
overlap = (lhs.mMinBound.y() > rhs.mMaxBound.y() || lhs.mMaxBound.y() < rhs.mMinBound.y()) ? false : overlap;
|
||||
return overlap;
|
||||
}
|
||||
|
||||
class ChunkyTriMesh
|
||||
{
|
||||
public:
|
||||
/// Creates partitioned triangle mesh (AABB tree),
|
||||
/// where each node contains at max trisPerChunk triangles.
|
||||
ChunkyTriMesh(const std::vector<float>& verts, const std::vector<int>& tris,
|
||||
const std::vector<AreaType>& flags, const std::size_t trisPerChunk);
|
||||
|
||||
ChunkyTriMesh(ChunkyTriMesh&&) = default;
|
||||
ChunkyTriMesh& operator=(ChunkyTriMesh&&) = default;
|
||||
|
||||
ChunkyTriMesh(const ChunkyTriMesh&) = delete;
|
||||
ChunkyTriMesh& operator=(const ChunkyTriMesh&) = delete;
|
||||
|
||||
/// Returns the chunk indices which overlap the input rectable.
|
||||
template <class Function>
|
||||
void forEachChunksOverlappingRect(const Rect& rect, Function&& function) const
|
||||
{
|
||||
// Traverse tree
|
||||
for (std::size_t i = 0; i < mNodes.size(); )
|
||||
{
|
||||
const ChunkyTriMeshNode* node = &mNodes[i];
|
||||
const bool overlap = checkOverlapRect(rect, node->mBounds);
|
||||
const bool isLeafNode = node->mOffset >= 0;
|
||||
|
||||
if (isLeafNode && overlap)
|
||||
function(i);
|
||||
|
||||
if (overlap || isLeafNode)
|
||||
i++;
|
||||
else
|
||||
{
|
||||
const auto escapeIndex = -node->mOffset;
|
||||
i += static_cast<std::size_t>(escapeIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Chunk getChunk(const std::size_t chunkId) const
|
||||
{
|
||||
const auto& node = mNodes[chunkId];
|
||||
return Chunk {
|
||||
mIndices.data() + node.mOffset * 3,
|
||||
mAreaTypes.data() + node.mOffset,
|
||||
node.mSize
|
||||
};
|
||||
}
|
||||
|
||||
std::size_t getMaxTrisPerChunk() const
|
||||
{
|
||||
return mMaxTrisPerChunk;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<ChunkyTriMeshNode> mNodes;
|
||||
std::vector<int> mIndices;
|
||||
std::vector<AreaType> mAreaTypes;
|
||||
std::size_t mMaxTrisPerChunk;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,5 +1,4 @@
|
|||
#include "makenavmesh.hpp"
|
||||
#include "chunkytrimesh.hpp"
|
||||
#include "debug.hpp"
|
||||
#include "dtstatus.hpp"
|
||||
#include "exceptions.hpp"
|
||||
|
@ -179,48 +178,30 @@ namespace
|
|||
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]);
|
||||
bool result = false;
|
||||
std::vector<unsigned char> areas(recastMesh.getAreaTypes().begin(), recastMesh.getAreaTypes().end());
|
||||
|
||||
chunkyMesh.forEachChunksOverlappingRect(Rect {tileBoundsMin, tileBoundsMax},
|
||||
[&] (const std::size_t cid)
|
||||
{
|
||||
const auto chunk = chunkyMesh.getChunk(cid);
|
||||
rcClearUnwalkableTriangles(
|
||||
&context,
|
||||
config.walkableSlopeAngle,
|
||||
recastMesh.getVertices().data(),
|
||||
static_cast<int>(recastMesh.getVerticesCount()),
|
||||
recastMesh.getIndices().data(),
|
||||
static_cast<int>(areas.size()),
|
||||
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");
|
||||
|
||||
result = true;
|
||||
});
|
||||
|
||||
return result;
|
||||
return rcRasterizeTriangles(
|
||||
&context,
|
||||
recastMesh.getVertices().data(),
|
||||
static_cast<int>(recastMesh.getVerticesCount()),
|
||||
recastMesh.getIndices().data(),
|
||||
areas.data(),
|
||||
static_cast<int>(areas.size()),
|
||||
solid,
|
||||
config.walkableClimb
|
||||
);
|
||||
}
|
||||
|
||||
void rasterizeWaterTriangles(rcContext& context, const osg::Vec3f& agentHalfExtents, const RecastMesh& recastMesh,
|
||||
|
|
|
@ -6,14 +6,13 @@
|
|||
namespace DetourNavigator
|
||||
{
|
||||
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)
|
||||
std::vector<AreaType> areaTypes, std::vector<Water> water)
|
||||
: mGeneration(generation)
|
||||
, mRevision(revision)
|
||||
, mIndices(std::move(indices))
|
||||
, mVertices(std::move(vertices))
|
||||
, mAreaTypes(std::move(areaTypes))
|
||||
, mWater(std::move(water))
|
||||
, mChunkyTriMesh(mVertices, mIndices, mAreaTypes, trianglesPerChunk)
|
||||
{
|
||||
if (getTrianglesCount() != mAreaTypes.size())
|
||||
throw InvalidArgument("Number of flags doesn't match number of triangles: triangles="
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
#define OPENMW_COMPONENTS_DETOURNAVIGATOR_RECASTMESH_H
|
||||
|
||||
#include "areatype.hpp"
|
||||
#include "chunkytrimesh.hpp"
|
||||
#include "bounds.hpp"
|
||||
|
||||
#include <components/bullethelpers/operators.hpp>
|
||||
|
@ -28,7 +27,7 @@ namespace DetourNavigator
|
|||
};
|
||||
|
||||
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::vector<AreaType> areaTypes, std::vector<Water> water);
|
||||
|
||||
std::size_t getGeneration() const
|
||||
{
|
||||
|
@ -70,11 +69,6 @@ namespace DetourNavigator
|
|||
return mIndices.size() / 3;
|
||||
}
|
||||
|
||||
const ChunkyTriMesh& getChunkyTriMesh() const
|
||||
{
|
||||
return mChunkyTriMesh;
|
||||
}
|
||||
|
||||
const Bounds& getBounds() const
|
||||
{
|
||||
return mBounds;
|
||||
|
@ -87,7 +81,6 @@ namespace DetourNavigator
|
|||
std::vector<float> mVertices;
|
||||
std::vector<AreaType> mAreaTypes;
|
||||
std::vector<Water> mWater;
|
||||
ChunkyTriMesh mChunkyTriMesh;
|
||||
Bounds mBounds;
|
||||
};
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
#include "recastmeshbuilder.hpp"
|
||||
#include "chunkytrimesh.hpp"
|
||||
#include "debug.hpp"
|
||||
#include "settings.hpp"
|
||||
#include "settingsutils.hpp"
|
||||
|
@ -157,8 +156,7 @@ namespace DetourNavigator
|
|||
{
|
||||
optimizeRecastMesh(mIndices, mVertices);
|
||||
std::sort(mWater.begin(), mWater.end());
|
||||
return std::make_shared<RecastMesh>(generation, revision, mIndices, mVertices, mAreaTypes,
|
||||
mWater, mSettings.get().mTrianglesPerChunk);
|
||||
return std::make_shared<RecastMesh>(generation, revision, mIndices, mVertices, mAreaTypes, mWater);
|
||||
}
|
||||
|
||||
void RecastMeshBuilder::reset()
|
||||
|
|
|
@ -33,7 +33,6 @@ namespace DetourNavigator
|
|||
navigatorSettings.mMaxNavMeshTilesCacheSize = static_cast<std::size_t>(::Settings::Manager::getInt("max nav mesh tiles cache size", "Navigator"));
|
||||
navigatorSettings.mMaxPolygonPathSize = static_cast<std::size_t>(::Settings::Manager::getInt("max polygon path size", "Navigator"));
|
||||
navigatorSettings.mMaxSmoothPathSize = static_cast<std::size_t>(::Settings::Manager::getInt("max smooth path size", "Navigator"));
|
||||
navigatorSettings.mTrianglesPerChunk = static_cast<std::size_t>(::Settings::Manager::getInt("triangles per chunk", "Navigator"));
|
||||
navigatorSettings.mEnableWriteRecastMeshToFile = ::Settings::Manager::getBool("enable write recast mesh to file", "Navigator");
|
||||
navigatorSettings.mEnableWriteNavMeshToFile = ::Settings::Manager::getBool("enable write nav mesh to file", "Navigator");
|
||||
navigatorSettings.mRecastMeshPathPrefix = ::Settings::Manager::getString("recast mesh path prefix", "Navigator");
|
||||
|
|
|
@ -35,7 +35,6 @@ namespace DetourNavigator
|
|||
std::size_t mMaxNavMeshTilesCacheSize = 0;
|
||||
std::size_t mMaxPolygonPathSize = 0;
|
||||
std::size_t mMaxSmoothPathSize = 0;
|
||||
std::size_t mTrianglesPerChunk = 0;
|
||||
std::string mRecastMeshPathPrefix;
|
||||
std::string mNavMeshPathPrefix;
|
||||
std::chrono::milliseconds mMinUpdateInterval;
|
||||
|
|
|
@ -231,15 +231,6 @@ max smooth path size
|
|||
|
||||
Maximum size of smoothed path.
|
||||
|
||||
triangles per chunk
|
||||
-------------------
|
||||
|
||||
:Type: integer
|
||||
:Range: > 0
|
||||
:Default: 256
|
||||
|
||||
Maximum number of triangles in each node of mesh AABB tree.
|
||||
|
||||
Expert Recastnavigation related settings
|
||||
****************************************
|
||||
|
||||
|
|
|
@ -875,9 +875,6 @@ max polygon path size = 1024
|
|||
# Maximum size of smoothed path (value > 0)
|
||||
max smooth path size = 1024
|
||||
|
||||
# Maximum number of triangles in each node of mesh AABB tree (value > 0)
|
||||
triangles per chunk = 256
|
||||
|
||||
# Write recast mesh to file in .obj format for each use to update nav mesh (true, false)
|
||||
enable write recast mesh to file = false
|
||||
|
||||
|
|
Loading…
Reference in a new issue