mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-19 22:23:51 +00:00
Merge pull request #2910 from elsid/optimize_recast_mesh
Reduce navmesh size
This commit is contained in:
commit
ecc125cdba
4 changed files with 116 additions and 42 deletions
|
@ -23,17 +23,23 @@ namespace DetourNavigator
|
|||
namespace
|
||||
{
|
||||
template <class T>
|
||||
struct Wrapper {
|
||||
struct Wrapper
|
||||
{
|
||||
const T& mValue;
|
||||
};
|
||||
|
||||
template <class Range>
|
||||
inline testing::Message& writeRange(testing::Message& message, const Range& range)
|
||||
inline testing::Message& writeRange(testing::Message& message, const Range& range, std::size_t newLine)
|
||||
{
|
||||
message << "{\n";
|
||||
message << "{";
|
||||
std::size_t i = 0;
|
||||
for (const auto& v : range)
|
||||
message << Wrapper<typename std::decay<decltype(v)>::type> {v} << ",\n";
|
||||
return message << "}";
|
||||
{
|
||||
if (i++ % newLine == 0)
|
||||
message << "\n";
|
||||
message << Wrapper<typename std::decay<decltype(v)>::type> {v} << ", ";
|
||||
}
|
||||
return message << "\n}";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -60,22 +66,34 @@ namespace testing
|
|||
return (*this) << std::setprecision(std::numeric_limits<float>::max_exponent10) << value.mValue;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline testing::Message& Message::operator <<(const Wrapper<int>& value)
|
||||
{
|
||||
return (*this) << value.mValue;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline testing::Message& Message::operator <<(const std::deque<osg::Vec3f>& value)
|
||||
{
|
||||
return writeRange(*this, value);
|
||||
return writeRange(*this, value, 1);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline testing::Message& Message::operator <<(const std::vector<osg::Vec3f>& value)
|
||||
{
|
||||
return writeRange(*this, value);
|
||||
return writeRange(*this, value, 1);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline testing::Message& Message::operator <<(const std::vector<float>& value)
|
||||
{
|
||||
return writeRange(*this, value);
|
||||
return writeRange(*this, value, 3);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline testing::Message& Message::operator <<(const std::vector<int>& value)
|
||||
{
|
||||
return writeRange(*this, value, 3);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -104,11 +104,9 @@ namespace
|
|||
-0.5, 0, -0.5,
|
||||
-0.5, 0, 0.5,
|
||||
0.5, 0, -0.5,
|
||||
0.5, 0, -0.5,
|
||||
-0.5, 0, 0.5,
|
||||
0.5, 0, 0.5,
|
||||
}));
|
||||
EXPECT_EQ(recastMesh->getIndices(), std::vector<int>({0, 1, 2, 3, 4, 5}));
|
||||
EXPECT_EQ(recastMesh->getIndices(), std::vector<int>({0, 1, 2, 2, 1, 3}));
|
||||
EXPECT_EQ(recastMesh->getAreaTypes(), std::vector<AreaType>({AreaType_ground, AreaType_ground}));
|
||||
}
|
||||
|
||||
|
@ -127,7 +125,7 @@ namespace
|
|||
-1, -2, 1,
|
||||
1, -2, -1,
|
||||
-1, -2, -1,
|
||||
}));
|
||||
})) << recastMesh->getVertices();
|
||||
EXPECT_EQ(recastMesh->getIndices(), std::vector<int>({
|
||||
0, 2, 3,
|
||||
3, 1, 0,
|
||||
|
@ -141,7 +139,7 @@ namespace
|
|||
2, 6, 7,
|
||||
7, 6, 4,
|
||||
4, 5, 7,
|
||||
}));
|
||||
})) << recastMesh->getIndices();
|
||||
EXPECT_EQ(recastMesh->getAreaTypes(), std::vector<AreaType>(12, AreaType_ground));
|
||||
}
|
||||
|
||||
|
@ -166,37 +164,35 @@ namespace
|
|||
);
|
||||
const auto recastMesh = builder.create(mGeneration, mRevision);
|
||||
EXPECT_EQ(recastMesh->getVertices(), std::vector<float>({
|
||||
1, 0, -1,
|
||||
-1, 0, 1,
|
||||
-1, 0, -1,
|
||||
1, 2, 1,
|
||||
-1, 2, 1,
|
||||
1, 2, -1,
|
||||
-1, 2, -1,
|
||||
1, -2, 1,
|
||||
-1, -2, 1,
|
||||
1, -2, -1,
|
||||
-1, -2, -1,
|
||||
1, 0, -1,
|
||||
-1, -2, 1,
|
||||
-1, 0, -1,
|
||||
-1, 0, 1,
|
||||
-1, 2, -1,
|
||||
-1, 2, 1,
|
||||
1, -2, -1,
|
||||
1, -2, 1,
|
||||
1, 0, -1,
|
||||
1, 0, 1,
|
||||
}));
|
||||
1, 2, -1,
|
||||
1, 2, 1,
|
||||
})) << recastMesh->getVertices();
|
||||
EXPECT_EQ(recastMesh->getIndices(), std::vector<int>({
|
||||
0, 1, 2,
|
||||
3, 5, 6,
|
||||
6, 4, 3,
|
||||
3, 7, 9,
|
||||
9, 5, 3,
|
||||
3, 4, 8,
|
||||
8, 7, 3,
|
||||
10, 8, 4,
|
||||
4, 6, 10,
|
||||
10, 6, 5,
|
||||
5, 9, 10,
|
||||
10, 9, 7,
|
||||
7, 8, 10,
|
||||
11, 12, 13,
|
||||
}));
|
||||
8, 3, 2,
|
||||
11, 10, 4,
|
||||
4, 5, 11,
|
||||
11, 7, 6,
|
||||
6, 10, 11,
|
||||
11, 5, 1,
|
||||
1, 7, 11,
|
||||
0, 1, 5,
|
||||
5, 4, 0,
|
||||
0, 4, 10,
|
||||
10, 6, 0,
|
||||
0, 6, 7,
|
||||
7, 1, 0,
|
||||
8, 3, 9,
|
||||
})) << recastMesh->getIndices();
|
||||
EXPECT_EQ(recastMesh->getAreaTypes(), std::vector<AreaType>(14, AreaType_ground));
|
||||
}
|
||||
|
||||
|
@ -413,4 +409,24 @@ namespace
|
|||
RecastMesh::Water {1000, btTransform(btMatrix3x3::getIdentity(), btVector3(100, 200, 300))}
|
||||
}));
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorRecastMeshBuilderTest, add_bhv_triangle_mesh_shape_with_duplicated_vertices)
|
||||
{
|
||||
btTriangleMesh mesh;
|
||||
mesh.addTriangle(btVector3(-1, -1, 0), btVector3(-1, 1, 0), btVector3(1, -1, 0));
|
||||
mesh.addTriangle(btVector3(1, 1, 0), btVector3(-1, 1, 0), btVector3(1, -1, 0));
|
||||
btBvhTriangleMeshShape shape(&mesh, true);
|
||||
|
||||
RecastMeshBuilder builder(mSettings, mBounds);
|
||||
builder.addObject(static_cast<const btCollisionShape&>(shape), btTransform::getIdentity(), AreaType_ground);
|
||||
const auto recastMesh = builder.create(mGeneration, mRevision);
|
||||
EXPECT_EQ(recastMesh->getVertices(), std::vector<float>({
|
||||
-1, 0, -1,
|
||||
-1, 0, 1,
|
||||
1, 0, -1,
|
||||
1, 0, 1,
|
||||
})) << recastMesh->getVertices();
|
||||
EXPECT_EQ(recastMesh->getIndices(), std::vector<int>({2, 1, 0, 2, 1, 3}));
|
||||
EXPECT_EQ(recastMesh->getAreaTypes(), std::vector<AreaType>({AreaType_ground, AreaType_ground}));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,11 +17,50 @@
|
|||
#include <LinearMath/btAabbUtil2.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <tuple>
|
||||
|
||||
namespace DetourNavigator
|
||||
{
|
||||
using BulletHelpers::makeProcessTriangleCallback;
|
||||
|
||||
namespace
|
||||
{
|
||||
void optimizeRecastMesh(std::vector<int>& indices, std::vector<float>& vertices)
|
||||
{
|
||||
std::vector<std::tuple<float, float, float>> uniqueVertices;
|
||||
uniqueVertices.reserve(vertices.size() / 3);
|
||||
|
||||
for (std::size_t i = 0, n = vertices.size() / 3; i < n; ++i)
|
||||
uniqueVertices.emplace_back(vertices[i * 3], vertices[i * 3 + 1], vertices[i * 3 + 2]);
|
||||
|
||||
std::sort(uniqueVertices.begin(), uniqueVertices.end());
|
||||
const auto end = std::unique(uniqueVertices.begin(), uniqueVertices.end());
|
||||
uniqueVertices.erase(end, uniqueVertices.end());
|
||||
|
||||
if (uniqueVertices.size() == vertices.size() / 3)
|
||||
return;
|
||||
|
||||
for (std::size_t i = 0, n = indices.size(); i < n; ++i)
|
||||
{
|
||||
const auto index = indices[i];
|
||||
const auto vertex = std::make_tuple(vertices[index * 3], vertices[index * 3 + 1], vertices[index * 3 + 2]);
|
||||
const auto it = std::lower_bound(uniqueVertices.begin(), uniqueVertices.end(), vertex);
|
||||
assert(it != uniqueVertices.end());
|
||||
assert(*it == vertex);
|
||||
indices[i] = std::distance(uniqueVertices.begin(), it);
|
||||
}
|
||||
|
||||
vertices.resize(uniqueVertices.size() * 3);
|
||||
|
||||
for (std::size_t i = 0, n = uniqueVertices.size(); i < n; ++i)
|
||||
{
|
||||
vertices[i * 3] = std::get<0>(uniqueVertices[i]);
|
||||
vertices[i * 3 + 1] = std::get<1>(uniqueVertices[i]);
|
||||
vertices[i * 3 + 2] = std::get<2>(uniqueVertices[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RecastMeshBuilder::RecastMeshBuilder(const Settings& settings, const TileBounds& bounds)
|
||||
: mSettings(settings)
|
||||
, mBounds(bounds)
|
||||
|
@ -112,8 +151,9 @@ namespace DetourNavigator
|
|||
mWater.push_back(RecastMesh::Water {cellSize, transform});
|
||||
}
|
||||
|
||||
std::shared_ptr<RecastMesh> RecastMeshBuilder::create(std::size_t generation, std::size_t revision) const
|
||||
std::shared_ptr<RecastMesh> RecastMeshBuilder::create(std::size_t generation, std::size_t revision)
|
||||
{
|
||||
optimizeRecastMesh(mIndices, mVertices);
|
||||
return std::make_shared<RecastMesh>(generation, revision, mIndices, mVertices, mAreaTypes,
|
||||
mWater, mSettings.get().mTrianglesPerChunk);
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ namespace DetourNavigator
|
|||
|
||||
void addWater(const int mCellSize, const btTransform& transform);
|
||||
|
||||
std::shared_ptr<RecastMesh> create(std::size_t generation, std::size_t revision) const;
|
||||
std::shared_ptr<RecastMesh> create(std::size_t generation, std::size_t revision);
|
||||
|
||||
void reset();
|
||||
|
||||
|
|
Loading…
Reference in a new issue