1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-11-08 21:46:43 +00:00

Make RecastMesh independent from recast scale factor

To avoid scaling until it's required by delaying coordinates conversion until
navmesh generation.
This commit is contained in:
elsid 2021-07-16 20:19:11 +02:00
parent af7059373c
commit d60edb36aa
No known key found for this signature in database
GPG key ID: B845CB9FEE18AB40
6 changed files with 153 additions and 140 deletions

View file

@ -1,7 +1,6 @@
#include "operators.hpp" #include "operators.hpp"
#include <components/detournavigator/recastmeshbuilder.hpp> #include <components/detournavigator/recastmeshbuilder.hpp>
#include <components/detournavigator/settings.hpp>
#include <components/detournavigator/recastmesh.hpp> #include <components/detournavigator/recastmesh.hpp>
#include <components/detournavigator/exceptions.hpp> #include <components/detournavigator/exceptions.hpp>
@ -33,14 +32,12 @@ namespace
struct DetourNavigatorRecastMeshBuilderTest : Test struct DetourNavigatorRecastMeshBuilderTest : Test
{ {
Settings mSettings;
TileBounds mBounds; TileBounds mBounds;
const std::size_t mGeneration = 0; const std::size_t mGeneration = 0;
const std::size_t mRevision = 0; const std::size_t mRevision = 0;
DetourNavigatorRecastMeshBuilderTest() DetourNavigatorRecastMeshBuilderTest()
{ {
mSettings.mRecastScaleFactor = 1.0f;
mBounds.mMin = osg::Vec2f(-std::numeric_limits<float>::max() * std::numeric_limits<float>::epsilon(), mBounds.mMin = osg::Vec2f(-std::numeric_limits<float>::max() * std::numeric_limits<float>::epsilon(),
-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(), mBounds.mMax = osg::Vec2f(std::numeric_limits<float>::max() * std::numeric_limits<float>::epsilon(),
@ -50,7 +47,7 @@ namespace
TEST_F(DetourNavigatorRecastMeshBuilderTest, create_for_empty_should_return_empty) TEST_F(DetourNavigatorRecastMeshBuilderTest, create_for_empty_should_return_empty)
{ {
RecastMeshBuilder builder(mSettings, mBounds); RecastMeshBuilder builder(mBounds);
const auto recastMesh = std::move(builder).create(mGeneration, mRevision); const auto recastMesh = std::move(builder).create(mGeneration, mRevision);
EXPECT_EQ(recastMesh->getMesh().getVertices(), std::vector<float>()); EXPECT_EQ(recastMesh->getMesh().getVertices(), std::vector<float>());
EXPECT_EQ(recastMesh->getMesh().getIndices(), std::vector<int>()); EXPECT_EQ(recastMesh->getMesh().getIndices(), std::vector<int>());
@ -63,13 +60,13 @@ namespace
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); btBvhTriangleMeshShape shape(&mesh, true);
RecastMeshBuilder builder(mSettings, mBounds); RecastMeshBuilder builder(mBounds);
builder.addObject(static_cast<const btCollisionShape&>(shape), btTransform::getIdentity(), AreaType_ground); builder.addObject(static_cast<const btCollisionShape&>(shape), btTransform::getIdentity(), AreaType_ground);
const auto recastMesh = std::move(builder).create(mGeneration, mRevision); const auto recastMesh = std::move(builder).create(mGeneration, mRevision);
EXPECT_EQ(recastMesh->getMesh().getVertices(), std::vector<float>({ EXPECT_EQ(recastMesh->getMesh().getVertices(), std::vector<float>({
-1, 0, -1, -1, -1, 0,
-1, 0, 1, -1, 1, 0,
1, 0, -1, 1, -1, 0,
})) << recastMesh->getMesh().getVertices(); })) << recastMesh->getMesh().getVertices();
EXPECT_EQ(recastMesh->getMesh().getIndices(), std::vector<int>({2, 1, 0})); EXPECT_EQ(recastMesh->getMesh().getIndices(), std::vector<int>({2, 1, 0}));
EXPECT_EQ(recastMesh->getMesh().getAreaTypes(), std::vector<AreaType>({AreaType_ground})); EXPECT_EQ(recastMesh->getMesh().getAreaTypes(), std::vector<AreaType>({AreaType_ground}));
@ -80,7 +77,7 @@ namespace
btTriangleMesh mesh; 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); btBvhTriangleMeshShape shape(&mesh, true);
RecastMeshBuilder builder(mSettings, mBounds); RecastMeshBuilder builder(mBounds);
builder.addObject( builder.addObject(
static_cast<const btCollisionShape&>(shape), static_cast<const btCollisionShape&>(shape),
btTransform(btMatrix3x3::getIdentity().scaled(btVector3(1, 2, 3)), btVector3(1, 2, 3)), btTransform(btMatrix3x3::getIdentity().scaled(btVector3(1, 2, 3)), btVector3(1, 2, 3)),
@ -88,9 +85,9 @@ namespace
); );
const auto recastMesh = std::move(builder).create(mGeneration, mRevision); const auto recastMesh = std::move(builder).create(mGeneration, mRevision);
EXPECT_EQ(recastMesh->getMesh().getVertices(), std::vector<float>({ EXPECT_EQ(recastMesh->getMesh().getVertices(), std::vector<float>({
0, 3, 0, 0, 0, 3,
0, 3, 4, 0, 4, 3,
2, 3, 0, 2, 0, 3,
})) << recastMesh->getMesh().getVertices(); })) << recastMesh->getMesh().getVertices();
EXPECT_EQ(recastMesh->getMesh().getIndices(), std::vector<int>({2, 1, 0})); EXPECT_EQ(recastMesh->getMesh().getIndices(), std::vector<int>({2, 1, 0}));
EXPECT_EQ(recastMesh->getMesh().getAreaTypes(), std::vector<AreaType>({AreaType_ground})); EXPECT_EQ(recastMesh->getMesh().getAreaTypes(), std::vector<AreaType>({AreaType_ground}));
@ -100,15 +97,15 @@ namespace
{ {
const std::array<btScalar, 4> heightfieldData {{0, 0, 0, 0}}; const std::array<btScalar, 4> heightfieldData {{0, 0, 0, 0}};
btHeightfieldTerrainShape shape(2, 2, heightfieldData.data(), 1, 0, 0, 2, PHY_FLOAT, false); btHeightfieldTerrainShape shape(2, 2, heightfieldData.data(), 1, 0, 0, 2, PHY_FLOAT, false);
RecastMeshBuilder builder(mSettings, mBounds); RecastMeshBuilder builder(mBounds);
builder.addObject(static_cast<const btCollisionShape&>(shape), btTransform::getIdentity(), AreaType_ground); builder.addObject(static_cast<const btCollisionShape&>(shape), btTransform::getIdentity(), AreaType_ground);
const auto recastMesh = std::move(builder).create(mGeneration, mRevision); const auto recastMesh = std::move(builder).create(mGeneration, mRevision);
EXPECT_EQ(recastMesh->getMesh().getVertices(), std::vector<float>({ EXPECT_EQ(recastMesh->getMesh().getVertices(), std::vector<float>({
-0.5, 0, -0.5, -0.5, -0.5, 0,
-0.5, 0, 0.5, -0.5, 0.5, 0,
0.5, 0, -0.5, 0.5, -0.5, 0,
0.5, 0, 0.5, 0.5, 0.5, 0,
})); })) << recastMesh->getMesh().getVertices();
EXPECT_EQ(recastMesh->getMesh().getIndices(), std::vector<int>({0, 1, 2, 2, 1, 3})); EXPECT_EQ(recastMesh->getMesh().getIndices(), std::vector<int>({0, 1, 2, 2, 1, 3}));
EXPECT_EQ(recastMesh->getMesh().getAreaTypes(), std::vector<AreaType>({AreaType_ground, AreaType_ground})); EXPECT_EQ(recastMesh->getMesh().getAreaTypes(), std::vector<AreaType>({AreaType_ground, AreaType_ground}));
} }
@ -116,32 +113,32 @@ namespace
TEST_F(DetourNavigatorRecastMeshBuilderTest, add_box_shape_should_produce_12_triangles) TEST_F(DetourNavigatorRecastMeshBuilderTest, add_box_shape_should_produce_12_triangles)
{ {
btBoxShape shape(btVector3(1, 1, 2)); btBoxShape shape(btVector3(1, 1, 2));
RecastMeshBuilder builder(mSettings, mBounds); RecastMeshBuilder builder(mBounds);
builder.addObject(static_cast<const btCollisionShape&>(shape), btTransform::getIdentity(), AreaType_ground); builder.addObject(static_cast<const btCollisionShape&>(shape), btTransform::getIdentity(), AreaType_ground);
const auto recastMesh = std::move(builder).create(mGeneration, mRevision); const auto recastMesh = std::move(builder).create(mGeneration, mRevision);
EXPECT_EQ(recastMesh->getMesh().getVertices(), std::vector<float>({ EXPECT_EQ(recastMesh->getMesh().getVertices(), std::vector<float>({
-1, -2, -1, -1, -1, -2,
-1, -2, 1, -1, -1, 2,
-1, 2, -1, -1, 1, -2,
-1, 2, 1, -1, 1, 2,
1, -2, -1, 1, -1, -2,
1, -2, 1, 1, -1, 2,
1, 2, -1, 1, 1, -2,
1, 2, 1, 1, 1, 2,
})) << recastMesh->getMesh().getVertices(); })) << recastMesh->getMesh().getVertices();
EXPECT_EQ(recastMesh->getMesh().getIndices(), std::vector<int>({ EXPECT_EQ(recastMesh->getMesh().getIndices(), std::vector<int>({
0, 1, 3, 0, 1, 5,
0, 2, 6, 0, 2, 3,
0, 4, 5, 0, 4, 6,
1, 5, 7, 1, 3, 7,
2, 3, 7, 2, 6, 7,
3, 2, 0, 3, 1, 0,
4, 6, 7, 4, 5, 7,
5, 1, 0, 5, 4, 0,
6, 4, 0, 6, 2, 0,
7, 3, 1, 7, 3, 2,
7, 5, 4, 7, 5, 1,
7, 6, 2, 7, 6, 4,
})) << recastMesh->getMesh().getIndices(); })) << recastMesh->getMesh().getIndices();
EXPECT_EQ(recastMesh->getMesh().getAreaTypes(), std::vector<AreaType>(12, AreaType_ground)); EXPECT_EQ(recastMesh->getMesh().getAreaTypes(), std::vector<AreaType>(12, AreaType_ground));
} }
@ -159,7 +156,7 @@ namespace
shape.addChildShape(btTransform::getIdentity(), &triangle1); shape.addChildShape(btTransform::getIdentity(), &triangle1);
shape.addChildShape(btTransform::getIdentity(), &box); shape.addChildShape(btTransform::getIdentity(), &box);
shape.addChildShape(btTransform::getIdentity(), &triangle2); shape.addChildShape(btTransform::getIdentity(), &triangle2);
RecastMeshBuilder builder(mSettings, mBounds); RecastMeshBuilder builder(mBounds);
builder.addObject( builder.addObject(
static_cast<const btCollisionShape&>(shape), static_cast<const btCollisionShape&>(shape),
btTransform::getIdentity(), btTransform::getIdentity(),
@ -167,34 +164,34 @@ namespace
); );
const auto recastMesh = std::move(builder).create(mGeneration, mRevision); const auto recastMesh = std::move(builder).create(mGeneration, mRevision);
EXPECT_EQ(recastMesh->getMesh().getVertices(), std::vector<float>({ EXPECT_EQ(recastMesh->getMesh().getVertices(), std::vector<float>({
-1, -2, -1, -1, -1, -2,
-1, -2, 1, -1, -1, 0,
-1, 0, -1, -1, -1, 2,
-1, 0, 1, -1, 1, -2,
-1, 2, -1, -1, 1, 0,
-1, 2, 1, -1, 1, 2,
1, -2, -1, 1, -1, -2,
1, -2, 1, 1, -1, 0,
1, 0, -1, 1, -1, 2,
1, 0, 1, 1, 1, -2,
1, 2, -1, 1, 1, 0,
1, 2, 1, 1, 1, 2,
})) << recastMesh->getMesh().getVertices(); })) << recastMesh->getMesh().getVertices();
EXPECT_EQ(recastMesh->getMesh().getIndices(), std::vector<int>({ EXPECT_EQ(recastMesh->getMesh().getIndices(), std::vector<int>({
0, 1, 5, 0, 2, 8,
0, 4, 10, 0, 3, 5,
0, 6, 7, 0, 6, 9,
1, 7, 11, 2, 5, 11,
4, 5, 11, 3, 9, 11,
5, 4, 0, 5, 2, 0,
6, 10, 11, 6, 8, 11,
7, 1, 0, 7, 4, 1,
8, 3, 2, 7, 4, 10,
8, 3, 9, 8, 6, 0,
10, 6, 0, 9, 3, 0,
11, 5, 1, 11, 5, 3,
11, 7, 6, 11, 8, 2,
11, 10, 4, 11, 9, 6,
})) << recastMesh->getMesh().getIndices(); })) << recastMesh->getMesh().getIndices();
EXPECT_EQ(recastMesh->getMesh().getAreaTypes(), std::vector<AreaType>(14, AreaType_ground)); EXPECT_EQ(recastMesh->getMesh().getAreaTypes(), std::vector<AreaType>(14, AreaType_ground));
} }
@ -206,7 +203,7 @@ namespace
btBvhTriangleMeshShape triangle(&mesh, true); btBvhTriangleMeshShape triangle(&mesh, true);
btCompoundShape shape; btCompoundShape shape;
shape.addChildShape(btTransform::getIdentity(), &triangle); shape.addChildShape(btTransform::getIdentity(), &triangle);
RecastMeshBuilder builder(mSettings, mBounds); RecastMeshBuilder builder(mBounds);
builder.addObject( builder.addObject(
static_cast<const btCollisionShape&>(shape), static_cast<const btCollisionShape&>(shape),
btTransform(btMatrix3x3::getIdentity().scaled(btVector3(1, 2, 3)), btVector3(1, 2, 3)), btTransform(btMatrix3x3::getIdentity().scaled(btVector3(1, 2, 3)), btVector3(1, 2, 3)),
@ -214,9 +211,9 @@ namespace
); );
const auto recastMesh = std::move(builder).create(mGeneration, mRevision); const auto recastMesh = std::move(builder).create(mGeneration, mRevision);
EXPECT_EQ(recastMesh->getMesh().getVertices(), std::vector<float>({ EXPECT_EQ(recastMesh->getMesh().getVertices(), std::vector<float>({
0, 3, 0, 0, 0, 3,
0, 3, 4, 0, 4, 3,
2, 3, 0, 2, 0, 3,
})) << recastMesh->getMesh().getVertices(); })) << recastMesh->getMesh().getVertices();
EXPECT_EQ(recastMesh->getMesh().getIndices(), std::vector<int>({2, 1, 0})); EXPECT_EQ(recastMesh->getMesh().getIndices(), std::vector<int>({2, 1, 0}));
EXPECT_EQ(recastMesh->getMesh().getAreaTypes(), std::vector<AreaType>({AreaType_ground})); EXPECT_EQ(recastMesh->getMesh().getAreaTypes(), std::vector<AreaType>({AreaType_ground}));
@ -230,7 +227,7 @@ namespace
btCompoundShape shape; btCompoundShape shape;
shape.addChildShape(btTransform(btMatrix3x3::getIdentity().scaled(btVector3(1, 2, 3)), btVector3(1, 2, 3)), shape.addChildShape(btTransform(btMatrix3x3::getIdentity().scaled(btVector3(1, 2, 3)), btVector3(1, 2, 3)),
&triangle); &triangle);
RecastMeshBuilder builder(mSettings, mBounds); RecastMeshBuilder builder(mBounds);
builder.addObject( builder.addObject(
static_cast<const btCollisionShape&>(shape), static_cast<const btCollisionShape&>(shape),
btTransform(btMatrix3x3::getIdentity().scaled(btVector3(1, 2, 3)), btVector3(1, 2, 3)), btTransform(btMatrix3x3::getIdentity().scaled(btVector3(1, 2, 3)), btVector3(1, 2, 3)),
@ -238,9 +235,9 @@ namespace
); );
const auto recastMesh = std::move(builder).create(mGeneration, mRevision); const auto recastMesh = std::move(builder).create(mGeneration, mRevision);
EXPECT_EQ(recastMesh->getMesh().getVertices(), std::vector<float>({ EXPECT_EQ(recastMesh->getMesh().getVertices(), std::vector<float>({
1, 12, 2, 1, 2, 12,
1, 12, 10, 1, 10, 12,
3, 12, 2, 3, 2, 12,
})) << recastMesh->getMesh().getVertices(); })) << recastMesh->getMesh().getVertices();
EXPECT_EQ(recastMesh->getMesh().getIndices(), std::vector<int>({2, 1, 0})); EXPECT_EQ(recastMesh->getMesh().getIndices(), std::vector<int>({2, 1, 0}));
EXPECT_EQ(recastMesh->getMesh().getAreaTypes(), std::vector<AreaType>({AreaType_ground})); EXPECT_EQ(recastMesh->getMesh().getAreaTypes(), std::vector<AreaType>({AreaType_ground}));
@ -252,7 +249,7 @@ namespace
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));
mesh.addTriangle(btVector3(-3, -3, 0), btVector3(-3, -2, 0), btVector3(-2, -3, 0)); mesh.addTriangle(btVector3(-3, -3, 0), btVector3(-3, -2, 0), btVector3(-2, -3, 0));
btBvhTriangleMeshShape shape(&mesh, true); btBvhTriangleMeshShape shape(&mesh, true);
RecastMeshBuilder builder(mSettings, mBounds); RecastMeshBuilder builder(mBounds);
builder.addObject( builder.addObject(
static_cast<const btCollisionShape&>(shape), static_cast<const btCollisionShape&>(shape),
btTransform::getIdentity(), btTransform::getIdentity(),
@ -260,12 +257,12 @@ namespace
); );
const auto recastMesh = std::move(builder).create(mGeneration, mRevision); const auto recastMesh = std::move(builder).create(mGeneration, mRevision);
EXPECT_EQ(recastMesh->getMesh().getVertices(), std::vector<float>({ EXPECT_EQ(recastMesh->getMesh().getVertices(), std::vector<float>({
-3, 0, -3, -3, -3, 0,
-3, 0, -2, -3, -2, 0,
-2, 0, -3, -2, -3, 0,
-1, 0, -1, -1, -1, 0,
-1, 0, 1, -1, 1, 0,
1, 0, -1, 1, -1, 0,
})) << recastMesh->getMesh().getVertices(); })) << recastMesh->getMesh().getVertices();
EXPECT_EQ(recastMesh->getMesh().getIndices(), std::vector<int>({2, 1, 0, 5, 4, 3})); EXPECT_EQ(recastMesh->getMesh().getIndices(), std::vector<int>({2, 1, 0, 5, 4, 3}));
EXPECT_EQ(recastMesh->getMesh().getAreaTypes(), std::vector<AreaType>(2, AreaType_ground)); EXPECT_EQ(recastMesh->getMesh().getAreaTypes(), std::vector<AreaType>(2, AreaType_ground));
@ -273,14 +270,13 @@ namespace
TEST_F(DetourNavigatorRecastMeshBuilderTest, with_bounds_add_bhv_triangle_shape_should_filter_by_bounds) TEST_F(DetourNavigatorRecastMeshBuilderTest, with_bounds_add_bhv_triangle_shape_should_filter_by_bounds)
{ {
mSettings.mRecastScaleFactor = 0.1f; mBounds.mMin = osg::Vec2f(-3, -3);
mBounds.mMin = osg::Vec2f(-3, -3) * mSettings.mRecastScaleFactor; mBounds.mMax = osg::Vec2f(-2, -2);
mBounds.mMax = osg::Vec2f(-2, -2) * mSettings.mRecastScaleFactor;
btTriangleMesh mesh; 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));
mesh.addTriangle(btVector3(-3, -3, 0), btVector3(-3, -2, 0), btVector3(-2, -3, 0)); mesh.addTriangle(btVector3(-3, -3, 0), btVector3(-3, -2, 0), btVector3(-2, -3, 0));
btBvhTriangleMeshShape shape(&mesh, true); btBvhTriangleMeshShape shape(&mesh, true);
RecastMeshBuilder builder(mSettings, mBounds); RecastMeshBuilder builder(mBounds);
builder.addObject( builder.addObject(
static_cast<const btCollisionShape&>(shape), static_cast<const btCollisionShape&>(shape),
btTransform::getIdentity(), btTransform::getIdentity(),
@ -288,9 +284,9 @@ namespace
); );
const auto recastMesh = std::move(builder).create(mGeneration, mRevision); const auto recastMesh = std::move(builder).create(mGeneration, mRevision);
EXPECT_EQ(recastMesh->getMesh().getVertices(), std::vector<float>({ EXPECT_EQ(recastMesh->getMesh().getVertices(), std::vector<float>({
-0.3f, 0, -0.3f, -3, -3, 0,
-0.3f, 0, -0.2f, -3, -2, 0,
-0.2f, 0, -0.3f, -2, -3, 0,
})) << recastMesh->getMesh().getVertices(); })) << recastMesh->getMesh().getVertices();
EXPECT_EQ(recastMesh->getMesh().getIndices(), std::vector<int>({2, 1, 0})); EXPECT_EQ(recastMesh->getMesh().getIndices(), std::vector<int>({2, 1, 0}));
EXPECT_EQ(recastMesh->getMesh().getAreaTypes(), std::vector<AreaType>({AreaType_ground})); EXPECT_EQ(recastMesh->getMesh().getAreaTypes(), std::vector<AreaType>({AreaType_ground}));
@ -304,7 +300,7 @@ namespace
mesh.addTriangle(btVector3(0, -1, -1), btVector3(0, -1, -1), btVector3(0, 1, -1)); mesh.addTriangle(btVector3(0, -1, -1), btVector3(0, -1, -1), btVector3(0, 1, -1));
mesh.addTriangle(btVector3(0, -3, -3), btVector3(0, -3, -2), btVector3(0, -2, -3)); mesh.addTriangle(btVector3(0, -3, -3), btVector3(0, -3, -2), btVector3(0, -2, -3));
btBvhTriangleMeshShape shape(&mesh, true); btBvhTriangleMeshShape shape(&mesh, true);
RecastMeshBuilder builder(mSettings, mBounds); RecastMeshBuilder builder(mBounds);
builder.addObject( builder.addObject(
static_cast<const btCollisionShape&>(shape), static_cast<const btCollisionShape&>(shape),
btTransform(btQuaternion(btVector3(1, 0, 0), btTransform(btQuaternion(btVector3(1, 0, 0),
@ -313,11 +309,11 @@ namespace
); );
const auto recastMesh = std::move(builder).create(mGeneration, mRevision); const auto recastMesh = std::move(builder).create(mGeneration, mRevision);
EXPECT_THAT(recastMesh->getMesh().getVertices(), Pointwise(FloatNear(1e-5), std::vector<float>({ EXPECT_THAT(recastMesh->getMesh().getVertices(), Pointwise(FloatNear(1e-5), std::vector<float>({
0, -0.707106769084930419921875, -3.535533905029296875, 0, -4.24264049530029296875, 4.44089209850062616169452667236328125e-16,
0, 4.44089209850062616169452667236328125e-16, -4.24264049530029296875, 0, -3.535533905029296875, -0.707106769084930419921875,
0, 0.707106769084930419921875, -3.535533905029296875, 0, -3.535533905029296875, 0.707106769084930419921875,
}))) << recastMesh->getMesh().getVertices(); }))) << recastMesh->getMesh().getVertices();
EXPECT_EQ(recastMesh->getMesh().getIndices(), std::vector<int>({0, 2, 1})); EXPECT_EQ(recastMesh->getMesh().getIndices(), std::vector<int>({1, 2, 0}));
EXPECT_EQ(recastMesh->getMesh().getAreaTypes(), std::vector<AreaType>({AreaType_ground})); EXPECT_EQ(recastMesh->getMesh().getAreaTypes(), std::vector<AreaType>({AreaType_ground}));
} }
@ -329,7 +325,7 @@ namespace
mesh.addTriangle(btVector3(-1, 0, -1), btVector3(-1, 0, 1), btVector3(1, 0, -1)); mesh.addTriangle(btVector3(-1, 0, -1), btVector3(-1, 0, 1), btVector3(1, 0, -1));
mesh.addTriangle(btVector3(-3, 0, -3), btVector3(-3, 0, -2), btVector3(-2, 0, -3)); mesh.addTriangle(btVector3(-3, 0, -3), btVector3(-3, 0, -2), btVector3(-2, 0, -3));
btBvhTriangleMeshShape shape(&mesh, true); btBvhTriangleMeshShape shape(&mesh, true);
RecastMeshBuilder builder(mSettings, mBounds); RecastMeshBuilder builder(mBounds);
builder.addObject( builder.addObject(
static_cast<const btCollisionShape&>(shape), static_cast<const btCollisionShape&>(shape),
btTransform(btQuaternion(btVector3(0, 1, 0), btTransform(btQuaternion(btVector3(0, 1, 0),
@ -338,9 +334,9 @@ namespace
); );
const auto recastMesh = std::move(builder).create(mGeneration, mRevision); const auto recastMesh = std::move(builder).create(mGeneration, mRevision);
EXPECT_THAT(recastMesh->getMesh().getVertices(), Pointwise(FloatNear(1e-5), std::vector<float>({ EXPECT_THAT(recastMesh->getMesh().getVertices(), Pointwise(FloatNear(1e-5), std::vector<float>({
-4.24264049530029296875, 4.44089209850062616169452667236328125e-16, 0, -4.24264049530029296875, 0, 4.44089209850062616169452667236328125e-16,
-3.535533905029296875, -0.707106769084930419921875, 0, -3.535533905029296875, 0, -0.707106769084930419921875,
-3.535533905029296875, 0.707106769084930419921875, 0, -3.535533905029296875, 0, 0.707106769084930419921875,
}))) << recastMesh->getMesh().getVertices(); }))) << recastMesh->getMesh().getVertices();
EXPECT_EQ(recastMesh->getMesh().getIndices(), std::vector<int>({1, 2, 0})); EXPECT_EQ(recastMesh->getMesh().getIndices(), std::vector<int>({1, 2, 0}));
EXPECT_EQ(recastMesh->getMesh().getAreaTypes(), std::vector<AreaType>({AreaType_ground})); EXPECT_EQ(recastMesh->getMesh().getAreaTypes(), std::vector<AreaType>({AreaType_ground}));
@ -354,7 +350,7 @@ namespace
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));
mesh.addTriangle(btVector3(-3, -3, 0), btVector3(-3, -2, 0), btVector3(-2, -3, 0)); mesh.addTriangle(btVector3(-3, -3, 0), btVector3(-3, -2, 0), btVector3(-2, -3, 0));
btBvhTriangleMeshShape shape(&mesh, true); btBvhTriangleMeshShape shape(&mesh, true);
RecastMeshBuilder builder(mSettings, mBounds); RecastMeshBuilder builder(mBounds);
builder.addObject( builder.addObject(
static_cast<const btCollisionShape&>(shape), static_cast<const btCollisionShape&>(shape),
btTransform(btQuaternion(btVector3(0, 0, 1), btTransform(btQuaternion(btVector3(0, 0, 1),
@ -363,9 +359,9 @@ namespace
); );
const auto recastMesh = std::move(builder).create(mGeneration, mRevision); const auto recastMesh = std::move(builder).create(mGeneration, mRevision);
EXPECT_THAT(recastMesh->getMesh().getVertices(), Pointwise(FloatNear(1e-5), std::vector<float>({ EXPECT_THAT(recastMesh->getMesh().getVertices(), Pointwise(FloatNear(1e-5), std::vector<float>({
-1.41421353816986083984375, 0, -1.1102230246251565404236316680908203125e-16, -1.41421353816986083984375, -1.1102230246251565404236316680908203125e-16, 0,
1.1102230246251565404236316680908203125e-16, 0, -1.41421353816986083984375, 1.1102230246251565404236316680908203125e-16, -1.41421353816986083984375, 0,
1.41421353816986083984375, 0, 1.1102230246251565404236316680908203125e-16, 1.41421353816986083984375, 1.1102230246251565404236316680908203125e-16, 0,
}))) << recastMesh->getMesh().getVertices(); }))) << recastMesh->getMesh().getVertices();
EXPECT_EQ(recastMesh->getMesh().getIndices(), std::vector<int>({2, 0, 1})); EXPECT_EQ(recastMesh->getMesh().getIndices(), std::vector<int>({2, 0, 1}));
EXPECT_EQ(recastMesh->getMesh().getAreaTypes(), std::vector<AreaType>({AreaType_ground})); EXPECT_EQ(recastMesh->getMesh().getAreaTypes(), std::vector<AreaType>({AreaType_ground}));
@ -379,7 +375,7 @@ namespace
btTriangleMesh mesh2; btTriangleMesh mesh2;
mesh2.addTriangle(btVector3(-3, -3, 0), btVector3(-3, -2, 0), btVector3(-2, -3, 0)); mesh2.addTriangle(btVector3(-3, -3, 0), btVector3(-3, -2, 0), btVector3(-2, -3, 0));
btBvhTriangleMeshShape shape2(&mesh2, true); btBvhTriangleMeshShape shape2(&mesh2, true);
RecastMeshBuilder builder(mSettings, mBounds); RecastMeshBuilder builder(mBounds);
builder.addObject( builder.addObject(
static_cast<const btCollisionShape&>(shape1), static_cast<const btCollisionShape&>(shape1),
btTransform::getIdentity(), btTransform::getIdentity(),
@ -392,12 +388,12 @@ namespace
); );
const auto recastMesh = std::move(builder).create(mGeneration, mRevision); const auto recastMesh = std::move(builder).create(mGeneration, mRevision);
EXPECT_EQ(recastMesh->getMesh().getVertices(), std::vector<float>({ EXPECT_EQ(recastMesh->getMesh().getVertices(), std::vector<float>({
-3, 0, -3, -3, -3, 0,
-3, 0, -2, -3, -2, 0,
-2, 0, -3, -2, -3, 0,
-1, 0, -1, -1, -1, 0,
-1, 0, 1, -1, 1, 0,
1, 0, -1, 1, -1, 0,
})) << recastMesh->getMesh().getVertices(); })) << recastMesh->getMesh().getVertices();
EXPECT_EQ(recastMesh->getMesh().getIndices(), std::vector<int>({2, 1, 0, 5, 4, 3})); EXPECT_EQ(recastMesh->getMesh().getIndices(), std::vector<int>({2, 1, 0, 5, 4, 3}));
EXPECT_EQ(recastMesh->getMesh().getAreaTypes(), std::vector<AreaType>({AreaType_null, AreaType_ground})); EXPECT_EQ(recastMesh->getMesh().getAreaTypes(), std::vector<AreaType>({AreaType_null, AreaType_ground}));
@ -405,7 +401,7 @@ namespace
TEST_F(DetourNavigatorRecastMeshBuilderTest, add_water_then_get_water_should_return_it) TEST_F(DetourNavigatorRecastMeshBuilderTest, add_water_then_get_water_should_return_it)
{ {
RecastMeshBuilder builder(mSettings, mBounds); RecastMeshBuilder builder(mBounds);
builder.addWater(1000, btTransform(btMatrix3x3::getIdentity(), btVector3(100, 200, 300))); builder.addWater(1000, btTransform(btMatrix3x3::getIdentity(), btVector3(100, 200, 300)));
const auto recastMesh = std::move(builder).create(mGeneration, mRevision); const auto recastMesh = std::move(builder).create(mGeneration, mRevision);
EXPECT_EQ(recastMesh->getWater(), std::vector<RecastMesh::Water>({ EXPECT_EQ(recastMesh->getWater(), std::vector<RecastMesh::Water>({
@ -420,14 +416,14 @@ namespace
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); btBvhTriangleMeshShape shape(&mesh, true);
RecastMeshBuilder builder(mSettings, mBounds); RecastMeshBuilder builder(mBounds);
builder.addObject(static_cast<const btCollisionShape&>(shape), btTransform::getIdentity(), AreaType_ground); builder.addObject(static_cast<const btCollisionShape&>(shape), btTransform::getIdentity(), AreaType_ground);
const auto recastMesh = std::move(builder).create(mGeneration, mRevision); const auto recastMesh = std::move(builder).create(mGeneration, mRevision);
EXPECT_EQ(recastMesh->getMesh().getVertices(), std::vector<float>({ EXPECT_EQ(recastMesh->getMesh().getVertices(), std::vector<float>({
-1, 0, -1, -1, -1, 0,
-1, 0, 1, -1, 1, 0,
1, 0, -1, 1, -1, 0,
1, 0, 1, 1, 1, 0,
})) << recastMesh->getMesh().getVertices(); })) << recastMesh->getMesh().getVertices();
EXPECT_EQ(recastMesh->getMesh().getIndices(), std::vector<int>({2, 1, 0, 2, 1, 3})); EXPECT_EQ(recastMesh->getMesh().getIndices(), std::vector<int>({2, 1, 0, 2, 1, 3}));
EXPECT_EQ(recastMesh->getMesh().getAreaTypes(), std::vector<AreaType>({AreaType_ground, AreaType_ground})); EXPECT_EQ(recastMesh->getMesh().getAreaTypes(), std::vector<AreaType>({AreaType_ground, AreaType_ground}));

View file

@ -157,15 +157,23 @@ namespace
throw NavigatorException("Failed to create heightfield for navmesh"); throw NavigatorException("Failed to create heightfield for navmesh");
} }
bool rasterizeTriangles(rcContext& context, const Mesh& mesh, const rcConfig& config, bool rasterizeTriangles(rcContext& context, const Mesh& mesh, const Settings& settings, const rcConfig& config,
rcHeightfield& solid) rcHeightfield& solid)
{ {
std::vector<unsigned char> areas(mesh.getAreaTypes().begin(), mesh.getAreaTypes().end()); std::vector<unsigned char> areas(mesh.getAreaTypes().begin(), mesh.getAreaTypes().end());
std::vector<float> vertices = mesh.getVertices();
for (std::size_t i = 0; i < vertices.size(); i += 3)
{
for (std::size_t j = 0; j < 3; ++j)
vertices[i + j] = toNavMeshCoordinates(settings, vertices[i + j]);
std::swap(vertices[i + 1], vertices[i + 2]);
}
rcClearUnwalkableTriangles( rcClearUnwalkableTriangles(
&context, &context,
config.walkableSlopeAngle, config.walkableSlopeAngle,
mesh.getVertices().data(), vertices.data(),
static_cast<int>(mesh.getVerticesCount()), static_cast<int>(mesh.getVerticesCount()),
mesh.getIndices().data(), mesh.getIndices().data(),
static_cast<int>(areas.size()), static_cast<int>(areas.size()),
@ -174,7 +182,7 @@ namespace
return rcRasterizeTriangles( return rcRasterizeTriangles(
&context, &context,
mesh.getVertices().data(), vertices.data(),
static_cast<int>(mesh.getVerticesCount()), static_cast<int>(mesh.getVerticesCount()),
mesh.getIndices().data(), mesh.getIndices().data(),
areas.data(), areas.data(),
@ -242,7 +250,7 @@ namespace
bool rasterizeTriangles(rcContext& context, const osg::Vec3f& agentHalfExtents, const RecastMesh& recastMesh, bool rasterizeTriangles(rcContext& context, const osg::Vec3f& agentHalfExtents, const RecastMesh& recastMesh,
const rcConfig& config, const Settings& settings, rcHeightfield& solid) const rcConfig& config, const Settings& settings, rcHeightfield& solid)
{ {
if (!rasterizeTriangles(context, recastMesh.getMesh(), config, solid)) if (!rasterizeTriangles(context, recastMesh.getMesh(), settings, config, solid))
return false; return false;
rasterizeWaterTriangles(context, agentHalfExtents, recastMesh, settings, config, solid); rasterizeWaterTriangles(context, agentHalfExtents, recastMesh, settings, config, solid);
@ -491,6 +499,8 @@ namespace DetourNavigator
} }
auto recastMeshBounds = recastMesh->getBounds(); auto recastMeshBounds = recastMesh->getBounds();
recastMeshBounds.mMin = toNavMeshCoordinates(settings, recastMeshBounds.mMin);
recastMeshBounds.mMax = toNavMeshCoordinates(settings, recastMeshBounds.mMax);
for (const auto& water : recastMesh->getWater()) for (const auto& water : recastMesh->getWater())
{ {

View file

@ -1,12 +1,11 @@
#include "recastmeshbuilder.hpp" #include "recastmeshbuilder.hpp"
#include "debug.hpp" #include "debug.hpp"
#include "settings.hpp"
#include "settingsutils.hpp"
#include "exceptions.hpp" #include "exceptions.hpp"
#include <components/bullethelpers/transformboundingbox.hpp> #include <components/bullethelpers/transformboundingbox.hpp>
#include <components/bullethelpers/processtrianglecallback.hpp> #include <components/bullethelpers/processtrianglecallback.hpp>
#include <components/misc/convert.hpp> #include <components/misc/convert.hpp>
#include <components/debug/debuglog.hpp>
#include <BulletCollision/CollisionShapes/btBoxShape.h> #include <BulletCollision/CollisionShapes/btBoxShape.h>
#include <BulletCollision/CollisionShapes/btCompoundShape.h> #include <BulletCollision/CollisionShapes/btCompoundShape.h>
@ -26,12 +25,12 @@ namespace DetourNavigator
namespace namespace
{ {
RecastMeshTriangle makeRecastMeshTriangle(const btVector3* vertices, const AreaType areaType, const Settings& settings) RecastMeshTriangle makeRecastMeshTriangle(const btVector3* vertices, const AreaType areaType)
{ {
RecastMeshTriangle result; RecastMeshTriangle result;
result.mAreaType = areaType; result.mAreaType = areaType;
for (std::size_t i = 0; i < 3; ++i) for (std::size_t i = 0; i < 3; ++i)
result.mVertices[i] = toNavMeshCoordinates(settings, Misc::Convert::makeOsgVec3f(vertices[i])); result.mVertices[i] = Misc::Convert::makeOsgVec3f(vertices[i]);
return result; return result;
} }
} }
@ -81,12 +80,9 @@ namespace DetourNavigator
return Mesh(std::move(indices), std::move(vertices), std::move(areaTypes)); return Mesh(std::move(indices), std::move(vertices), std::move(areaTypes));
} }
RecastMeshBuilder::RecastMeshBuilder(const Settings& settings, const TileBounds& bounds) RecastMeshBuilder::RecastMeshBuilder(const TileBounds& bounds) noexcept
: mSettings(settings) : mBounds(bounds)
, mBounds(bounds)
{ {
mBounds.mMin /= mSettings.get().mRecastScaleFactor;
mBounds.mMax /= mSettings.get().mRecastScaleFactor;
} }
void RecastMeshBuilder::addObject(const btCollisionShape& shape, const btTransform& transform, void RecastMeshBuilder::addObject(const btCollisionShape& shape, const btTransform& transform,
@ -117,7 +113,7 @@ namespace DetourNavigator
{ {
return addObject(shape, transform, makeProcessTriangleCallback([&] (btVector3* vertices, int, int) return addObject(shape, transform, makeProcessTriangleCallback([&] (btVector3* vertices, int, int)
{ {
RecastMeshTriangle triangle = makeRecastMeshTriangle(vertices, areaType, mSettings); RecastMeshTriangle triangle = makeRecastMeshTriangle(vertices, areaType);
std::reverse(triangle.mVertices.begin(), triangle.mVertices.end()); std::reverse(triangle.mVertices.begin(), triangle.mVertices.end());
mTriangles.emplace_back(triangle); mTriangles.emplace_back(triangle);
})); }));
@ -128,7 +124,7 @@ namespace DetourNavigator
{ {
return addObject(shape, transform, makeProcessTriangleCallback([&] (btVector3* vertices, int, int) return addObject(shape, transform, makeProcessTriangleCallback([&] (btVector3* vertices, int, int)
{ {
mTriangles.emplace_back(makeRecastMeshTriangle(vertices, areaType, mSettings)); mTriangles.emplace_back(makeRecastMeshTriangle(vertices, areaType));
})); }));
} }
@ -158,7 +154,7 @@ namespace DetourNavigator
shape.getVertex(indices[i + j], position); shape.getVertex(indices[i + j], position);
vertices[j] = transform(position); vertices[j] = transform(position);
} }
mTriangles.emplace_back(makeRecastMeshTriangle(vertices.data(), areaType, mSettings)); mTriangles.emplace_back(makeRecastMeshTriangle(vertices.data(), areaType));
} }
} }

View file

@ -23,8 +23,6 @@ class btTriangleCallback;
namespace DetourNavigator namespace DetourNavigator
{ {
struct Settings;
struct RecastMeshTriangle struct RecastMeshTriangle
{ {
AreaType mAreaType; AreaType mAreaType;
@ -39,7 +37,7 @@ namespace DetourNavigator
class RecastMeshBuilder class RecastMeshBuilder
{ {
public: public:
RecastMeshBuilder(const Settings& settings, const TileBounds& bounds); explicit RecastMeshBuilder(const TileBounds& bounds) noexcept;
void addObject(const btCollisionShape& shape, const btTransform& transform, const AreaType areaType); void addObject(const btCollisionShape& shape, const btTransform& transform, const AreaType areaType);
@ -56,8 +54,7 @@ namespace DetourNavigator
std::shared_ptr<RecastMesh> create(std::size_t generation, std::size_t revision) &&; std::shared_ptr<RecastMesh> create(std::size_t generation, std::size_t revision) &&;
private: private:
std::reference_wrapper<const Settings> mSettings; const TileBounds mBounds;
TileBounds mBounds;
std::vector<RecastMeshTriangle> mTriangles; std::vector<RecastMeshTriangle> mTriangles;
std::vector<RecastMesh::Water> mWater; std::vector<RecastMesh::Water> mWater;

View file

@ -1,5 +1,6 @@
#include "recastmeshmanager.hpp" #include "recastmeshmanager.hpp"
#include "recastmeshbuilder.hpp" #include "recastmeshbuilder.hpp"
#include "settings.hpp"
namespace DetourNavigator namespace DetourNavigator
{ {
@ -68,7 +69,10 @@ namespace DetourNavigator
std::shared_ptr<RecastMesh> RecastMeshManager::getMesh() std::shared_ptr<RecastMesh> RecastMeshManager::getMesh()
{ {
RecastMeshBuilder builder(mSettings, mTileBounds); TileBounds tileBounds = mTileBounds;
tileBounds.mMin /= mSettings.mRecastScaleFactor;
tileBounds.mMax /= mSettings.mRecastScaleFactor;
RecastMeshBuilder builder(tileBounds);
for (const auto& [k, v] : mWater) for (const auto& [k, v] : mWater)
builder.addWater(v.mCellSize, v.mTransform); builder.addWater(v.mCellSize, v.mTransform);
for (const auto& [k, object] : mObjects) for (const auto& [k, object] : mObjects)

View file

@ -8,6 +8,9 @@
#include <osg/Group> #include <osg/Group>
#include <algorithm>
#include <vector>
namespace namespace
{ {
std::vector<float> calculateNormals(const std::vector<float>& vertices, const std::vector<int>& indices) std::vector<float> calculateNormals(const std::vector<float>& vertices, const std::vector<int>& indices)
@ -37,13 +40,20 @@ namespace SceneUtil
osg::ref_ptr<osg::Group> createRecastMeshGroup(const DetourNavigator::RecastMesh& recastMesh, osg::ref_ptr<osg::Group> createRecastMeshGroup(const DetourNavigator::RecastMesh& recastMesh,
const DetourNavigator::Settings& settings) const DetourNavigator::Settings& settings)
{ {
using namespace DetourNavigator;
const osg::ref_ptr<osg::Group> group(new osg::Group); const osg::ref_ptr<osg::Group> group(new osg::Group);
DebugDraw debugDraw(*group, osg::Vec3f(0, 0, 0), 1.0f / settings.mRecastScaleFactor); DebugDraw debugDraw(*group, osg::Vec3f(0, 0, 0), 1.0f);
const DetourNavigator::Mesh& mesh = recastMesh.getMesh(); const DetourNavigator::Mesh& mesh = recastMesh.getMesh();
const auto normals = calculateNormals(mesh.getVertices(), mesh.getIndices()); std::vector<float> vertices = mesh.getVertices();
for (std::size_t i = 0; i < vertices.size(); i += 3)
std::swap(vertices[i + 1], vertices[i + 2]);
const auto normals = calculateNormals(vertices, mesh.getIndices());
const auto texScale = 1.0f / (settings.mCellSize * 10.0f); const auto texScale = 1.0f / (settings.mCellSize * 10.0f);
duDebugDrawTriMesh(&debugDraw, mesh.getVertices().data(), mesh.getVerticesCount(), duDebugDrawTriMesh(&debugDraw, vertices.data(), static_cast<int>(vertices.size() / 3),
mesh.getIndices().data(), normals.data(), mesh.getTrianglesCount(), nullptr, texScale); mesh.getIndices().data(), normals.data(), static_cast<int>(mesh.getIndices().size() / 3), nullptr, texScale);
return group; return group;
} }
} }