mirror of
https://github.com/OpenMW/openmw.git
synced 2025-01-16 15:29:55 +00:00
Add raw heightfield data to navigator
This commit is contained in:
parent
8571c317d8
commit
7dcb219ecf
23 changed files with 266 additions and 210 deletions
|
@ -25,18 +25,10 @@ namespace
|
|||
};
|
||||
|
||||
template <typename Random>
|
||||
TilePosition generateTilePosition(int max, Random& random)
|
||||
osg::Vec2i generateVec2i(int max, Random& random)
|
||||
{
|
||||
std::uniform_int_distribution<int> distribution(0, max);
|
||||
return TilePosition(distribution(random), distribution(random));
|
||||
}
|
||||
|
||||
template <typename Random>
|
||||
TileBounds generateTileBounds(Random& random)
|
||||
{
|
||||
std::uniform_real_distribution<float> distribution(0.0, 1.0);
|
||||
const osg::Vec2f min(distribution(random), distribution(random));
|
||||
return TileBounds {min, min + osg::Vec2f(1.0, 1.0)};
|
||||
return osg::Vec2i(distribution(random), distribution(random));
|
||||
}
|
||||
|
||||
template <typename Random>
|
||||
|
@ -89,11 +81,9 @@ namespace
|
|||
template <typename OutputIterator, typename Random>
|
||||
void generateWater(OutputIterator out, std::size_t count, Random& random)
|
||||
{
|
||||
std::uniform_real_distribution<float> floatDistribution(0.0, 1.0);
|
||||
std::uniform_int_distribution<int> intDistribution(-10, 10);
|
||||
std::uniform_real_distribution<float> distribution(0.0, 1.0);
|
||||
std::generate_n(out, count, [&] {
|
||||
const osg::Vec2i cellPosition(intDistribution(random), intDistribution(random));
|
||||
return CellWater {cellPosition, Water {8196, floatDistribution(random)}};
|
||||
return CellWater {generateVec2i(1000, random), Water {ESM::Land::REAL_SIZE, distribution(random)}};
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -118,16 +108,18 @@ namespace
|
|||
{
|
||||
std::uniform_real_distribution<float> distribution(0.0, 1.0);
|
||||
Heightfield result;
|
||||
result.mBounds = generateTileBounds(random);
|
||||
result.mCellPosition = generateVec2i(1000, random);
|
||||
result.mCellSize = ESM::Land::REAL_SIZE;
|
||||
result.mMinHeight = distribution(random);
|
||||
result.mMaxHeight = result.mMinHeight + 1.0;
|
||||
result.mShift = osg::Vec3f(distribution(random), distribution(random), distribution(random));
|
||||
result.mScale = distribution(random);
|
||||
result.mLength = static_cast<std::uint8_t>(ESM::Land::LAND_SIZE);
|
||||
std::generate_n(std::back_inserter(result.mHeights), ESM::Land::LAND_NUM_VERTS, [&]
|
||||
{
|
||||
return distribution(random);
|
||||
});
|
||||
result.mOriginalSize = ESM::Land::LAND_SIZE;
|
||||
result.mMinX = 0;
|
||||
result.mMinY = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -136,7 +128,8 @@ namespace
|
|||
{
|
||||
std::uniform_real_distribution<float> distribution(0.0, 1.0);
|
||||
FlatHeightfield result;
|
||||
result.mBounds = generateTileBounds(random);
|
||||
result.mCellPosition = generateVec2i(1000, random);
|
||||
result.mCellSize = ESM::Land::REAL_SIZE;
|
||||
result.mHeight = distribution(random);
|
||||
return result;
|
||||
}
|
||||
|
@ -145,7 +138,7 @@ namespace
|
|||
Key generateKey(std::size_t triangles, Random& random)
|
||||
{
|
||||
const osg::Vec3f agentHalfExtents = generateAgentHalfExtents(0.5, 1.5, random);
|
||||
const TilePosition tilePosition = generateTilePosition(10000, random);
|
||||
const TilePosition tilePosition = generateVec2i(10000, random);
|
||||
const std::size_t generation = std::uniform_int_distribution<std::size_t>(0, 100)(random);
|
||||
const std::size_t revision = std::uniform_int_distribution<std::size_t>(0, 10000)(random);
|
||||
Mesh mesh = generateMesh(triangles, random);
|
||||
|
|
|
@ -404,7 +404,7 @@ namespace MWWorld
|
|||
return heights;
|
||||
}
|
||||
} ();
|
||||
mNavigator.addHeightfield(cellPosition, ESM::Land::REAL_SIZE, shift, shape);
|
||||
mNavigator.addHeightfield(cellPosition, ESM::Land::REAL_SIZE, shape);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -47,7 +47,6 @@ namespace
|
|||
Loading::Listener mListener;
|
||||
const osg::Vec2i mCellPosition {0, 0};
|
||||
const int mHeightfieldTileSize = ESM::Land::REAL_SIZE / (ESM::Land::LAND_SIZE - 1);
|
||||
const osg::Vec3f mShift {0, 0, 0};
|
||||
const float mEndTolerance = 0;
|
||||
const btTransform mTransform {btMatrix3x3::getIdentity(), btVector3(256, 256, 0)};
|
||||
|
||||
|
@ -137,9 +136,9 @@ namespace
|
|||
osg::ref_ptr<const Resource::BulletShapeInstance> mInstance;
|
||||
};
|
||||
|
||||
osg::Vec3f getHeightfieldShift(const osg::Vec2i& cellPosition, int cellSize, float minHeight, float maxHeight)
|
||||
btVector3 getHeightfieldShift(const osg::Vec2i& cellPosition, int cellSize, float minHeight, float maxHeight)
|
||||
{
|
||||
return Misc::Convert::toOsg(BulletHelpers::getHeightfieldShift(cellPosition.x(), cellPosition.x(), cellSize, minHeight, maxHeight));
|
||||
return BulletHelpers::getHeightfieldShift(cellPosition.x(), cellPosition.x(), cellSize, minHeight, maxHeight);
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorNavigatorTest, find_path_for_empty_should_return_empty)
|
||||
|
@ -176,10 +175,9 @@ namespace
|
|||
}};
|
||||
const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData);
|
||||
const int cellSize = mHeightfieldTileSize * (surface.mSize - 1);
|
||||
const osg::Vec3f shift = getHeightfieldShift(mCellPosition, cellSize, surface.mMinHeight, surface.mMaxHeight);
|
||||
|
||||
mNavigator->addAgent(mAgentHalfExtents);
|
||||
mNavigator->addHeightfield(mCellPosition, cellSize, shift, surface);
|
||||
mNavigator->addHeightfield(mCellPosition, cellSize, surface);
|
||||
mNavigator->update(mPlayerPosition);
|
||||
mNavigator->wait(mListener, WaitConditionType::requiredTilesPresent);
|
||||
|
||||
|
@ -223,13 +221,12 @@ namespace
|
|||
}};
|
||||
const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData);
|
||||
const int cellSize = mHeightfieldTileSize * (surface.mSize - 1);
|
||||
const osg::Vec3f shift = getHeightfieldShift(mCellPosition, cellSize, surface.mMinHeight, surface.mMaxHeight);
|
||||
|
||||
CollisionShapeInstance compound(std::make_unique<btCompoundShape>());
|
||||
compound.shape().addChildShape(btTransform(btMatrix3x3::getIdentity(), btVector3(0, 0, 0)), new btBoxShape(btVector3(20, 20, 100)));
|
||||
|
||||
mNavigator->addAgent(mAgentHalfExtents);
|
||||
mNavigator->addHeightfield(mCellPosition, cellSize, shift, surface);
|
||||
mNavigator->addHeightfield(mCellPosition, cellSize, surface);
|
||||
mNavigator->update(mPlayerPosition);
|
||||
mNavigator->wait(mListener, WaitConditionType::allJobsDone);
|
||||
|
||||
|
@ -308,13 +305,12 @@ namespace
|
|||
}};
|
||||
const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData);
|
||||
const int cellSize = mHeightfieldTileSize * (surface.mSize - 1);
|
||||
const osg::Vec3f shift = getHeightfieldShift(mCellPosition, cellSize, surface.mMinHeight, surface.mMaxHeight);
|
||||
|
||||
CollisionShapeInstance compound(std::make_unique<btCompoundShape>());
|
||||
compound.shape().addChildShape(btTransform(btMatrix3x3::getIdentity(), btVector3(0, 0, 0)), new btBoxShape(btVector3(20, 20, 100)));
|
||||
|
||||
mNavigator->addAgent(mAgentHalfExtents);
|
||||
mNavigator->addHeightfield(mCellPosition, cellSize, shift, surface);
|
||||
mNavigator->addHeightfield(mCellPosition, cellSize, surface);
|
||||
mNavigator->addObject(ObjectId(&compound.shape()), ObjectShapes(compound.instance()), mTransform);
|
||||
mNavigator->update(mPlayerPosition);
|
||||
mNavigator->wait(mListener, WaitConditionType::allJobsDone);
|
||||
|
@ -453,7 +449,6 @@ namespace
|
|||
}};
|
||||
const HeightfieldSurface surface1 = makeSquareHeightfieldSurface(heightfieldData1);
|
||||
const int cellSize1 = mHeightfieldTileSize * (surface1.mSize - 1);
|
||||
const osg::Vec3f shift1 = getHeightfieldShift(mCellPosition, cellSize1, surface1.mMinHeight, surface1.mMaxHeight);
|
||||
|
||||
const std::array<float, 5 * 5> heightfieldData2 {{
|
||||
-25, -25, -25, -25, -25,
|
||||
|
@ -464,11 +459,10 @@ namespace
|
|||
}};
|
||||
const HeightfieldSurface surface2 = makeSquareHeightfieldSurface(heightfieldData2);
|
||||
const int cellSize2 = mHeightfieldTileSize * (surface2.mSize - 1);
|
||||
const osg::Vec3f shift2 = getHeightfieldShift(mCellPosition, cellSize2, surface2.mMinHeight, surface2.mMaxHeight);
|
||||
|
||||
mNavigator->addAgent(mAgentHalfExtents);
|
||||
EXPECT_TRUE(mNavigator->addHeightfield(mCellPosition, cellSize1, shift1, surface1));
|
||||
EXPECT_FALSE(mNavigator->addHeightfield(mCellPosition, cellSize2, shift2, surface2));
|
||||
EXPECT_TRUE(mNavigator->addHeightfield(mCellPosition, cellSize1, surface1));
|
||||
EXPECT_FALSE(mNavigator->addHeightfield(mCellPosition, cellSize2, surface2));
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorNavigatorTest, path_should_be_around_avoid_shape)
|
||||
|
@ -545,11 +539,10 @@ namespace
|
|||
}};
|
||||
const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData);
|
||||
const int cellSize = mHeightfieldTileSize * (surface.mSize - 1);
|
||||
const osg::Vec3f shift = getHeightfieldShift(mCellPosition, cellSize, surface.mMinHeight, surface.mMaxHeight);
|
||||
|
||||
mNavigator->addAgent(mAgentHalfExtents);
|
||||
mNavigator->addWater(mCellPosition, cellSize, 300);
|
||||
mNavigator->addHeightfield(mCellPosition, cellSize, shift, surface);
|
||||
mNavigator->addHeightfield(mCellPosition, cellSize, surface);
|
||||
mNavigator->update(mPlayerPosition);
|
||||
mNavigator->wait(mListener, WaitConditionType::allJobsDone);
|
||||
|
||||
|
@ -594,11 +587,10 @@ namespace
|
|||
}};
|
||||
const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData);
|
||||
const int cellSize = mHeightfieldTileSize * (surface.mSize - 1);
|
||||
const osg::Vec3f shift = getHeightfieldShift(mCellPosition, cellSize, surface.mMinHeight, surface.mMaxHeight);
|
||||
|
||||
mNavigator->addAgent(mAgentHalfExtents);
|
||||
mNavigator->addWater(mCellPosition, cellSize, -25);
|
||||
mNavigator->addHeightfield(mCellPosition, cellSize, shift, surface);
|
||||
mNavigator->addHeightfield(mCellPosition, cellSize, surface);
|
||||
mNavigator->update(mPlayerPosition);
|
||||
mNavigator->wait(mListener, WaitConditionType::allJobsDone);
|
||||
|
||||
|
@ -641,10 +633,9 @@ namespace
|
|||
}};
|
||||
const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData);
|
||||
const int cellSize = mHeightfieldTileSize * (surface.mSize - 1);
|
||||
const osg::Vec3f shift = getHeightfieldShift(mCellPosition, cellSize, surface.mMinHeight, surface.mMaxHeight);
|
||||
|
||||
mNavigator->addAgent(mAgentHalfExtents);
|
||||
mNavigator->addHeightfield(mCellPosition, cellSize, shift, surface);
|
||||
mNavigator->addHeightfield(mCellPosition, cellSize, surface);
|
||||
mNavigator->addWater(mCellPosition, std::numeric_limits<int>::max(), -25);
|
||||
mNavigator->update(mPlayerPosition);
|
||||
mNavigator->wait(mListener, WaitConditionType::allJobsDone);
|
||||
|
@ -688,11 +679,10 @@ namespace
|
|||
}};
|
||||
const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData);
|
||||
const int cellSize = mHeightfieldTileSize * (surface.mSize - 1);
|
||||
const osg::Vec3f shift = getHeightfieldShift(mCellPosition, cellSize, surface.mMinHeight, surface.mMaxHeight);
|
||||
|
||||
mNavigator->addAgent(mAgentHalfExtents);
|
||||
mNavigator->addWater(mCellPosition, cellSize, -25);
|
||||
mNavigator->addHeightfield(mCellPosition, cellSize, shift, surface);
|
||||
mNavigator->addHeightfield(mCellPosition, cellSize, surface);
|
||||
mNavigator->update(mPlayerPosition);
|
||||
mNavigator->wait(mListener, WaitConditionType::allJobsDone);
|
||||
|
||||
|
@ -787,10 +777,9 @@ namespace
|
|||
}};
|
||||
const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData);
|
||||
const int cellSize = mHeightfieldTileSize * (surface.mSize - 1);
|
||||
const osg::Vec3f shift = getHeightfieldShift(mCellPosition, cellSize, surface.mMinHeight, surface.mMaxHeight);
|
||||
|
||||
mNavigator->addAgent(mAgentHalfExtents);
|
||||
mNavigator->addHeightfield(mCellPosition, cellSize, shift, surface);
|
||||
mNavigator->addHeightfield(mCellPosition, cellSize, surface);
|
||||
mNavigator->update(mPlayerPosition);
|
||||
mNavigator->wait(mListener, WaitConditionType::allJobsDone);
|
||||
|
||||
|
@ -798,7 +787,7 @@ namespace
|
|||
mNavigator->update(mPlayerPosition);
|
||||
mNavigator->wait(mListener, WaitConditionType::allJobsDone);
|
||||
|
||||
mNavigator->addHeightfield(mCellPosition, cellSize, shift, surface);
|
||||
mNavigator->addHeightfield(mCellPosition, cellSize, surface);
|
||||
mNavigator->update(mPlayerPosition);
|
||||
mNavigator->wait(mListener, WaitConditionType::allJobsDone);
|
||||
|
||||
|
@ -843,10 +832,9 @@ namespace
|
|||
}};
|
||||
const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData);
|
||||
const int cellSize = mHeightfieldTileSize * (surface.mSize - 1);
|
||||
const osg::Vec3f shift = getHeightfieldShift(mCellPosition, cellSize, surface.mMinHeight, surface.mMaxHeight);
|
||||
|
||||
mNavigator->addAgent(mAgentHalfExtents);
|
||||
mNavigator->addHeightfield(mCellPosition, cellSize, shift, surface);
|
||||
mNavigator->addHeightfield(mCellPosition, cellSize, surface);
|
||||
mNavigator->update(mPlayerPosition);
|
||||
mNavigator->wait(mListener, WaitConditionType::allJobsDone);
|
||||
|
||||
|
@ -876,14 +864,14 @@ namespace
|
|||
}};
|
||||
const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData);
|
||||
const int cellSize = mHeightfieldTileSize * (surface.mSize - 1);
|
||||
const osg::Vec3f shift = getHeightfieldShift(mCellPosition, cellSize, surface.mMinHeight, surface.mMaxHeight);
|
||||
const btVector3 shift = getHeightfieldShift(mCellPosition, cellSize, surface.mMinHeight, surface.mMaxHeight);
|
||||
|
||||
std::vector<CollisionShapeInstance<btBoxShape>> boxes;
|
||||
std::generate_n(std::back_inserter(boxes), 100, [] { return std::make_unique<btBoxShape>(btVector3(20, 20, 100)); });
|
||||
|
||||
mNavigator->addAgent(mAgentHalfExtents);
|
||||
|
||||
mNavigator->addHeightfield(mCellPosition, cellSize, shift, surface);
|
||||
mNavigator->addHeightfield(mCellPosition, cellSize, surface);
|
||||
|
||||
for (std::size_t i = 0; i < boxes.size(); ++i)
|
||||
{
|
||||
|
@ -981,10 +969,9 @@ namespace
|
|||
}};
|
||||
const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData);
|
||||
const int cellSize = mHeightfieldTileSize * (surface.mSize - 1);
|
||||
const osg::Vec3f shift = getHeightfieldShift(mCellPosition, cellSize, surface.mMinHeight, surface.mMaxHeight);
|
||||
|
||||
mNavigator->addAgent(mAgentHalfExtents);
|
||||
mNavigator->addHeightfield(mCellPosition, cellSize, shift, surface);
|
||||
mNavigator->addHeightfield(mCellPosition, cellSize, surface);
|
||||
mNavigator->update(mPlayerPosition);
|
||||
mNavigator->wait(mListener, WaitConditionType::allJobsDone);
|
||||
|
||||
|
@ -1007,14 +994,13 @@ namespace
|
|||
}};
|
||||
const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData);
|
||||
const int cellSize = mHeightfieldTileSize * (surface.mSize - 1);
|
||||
const osg::Vec3f shift = getHeightfieldShift(mCellPosition, cellSize, surface.mMinHeight, surface.mMaxHeight);
|
||||
|
||||
CollisionShapeInstance oscillatingBox(std::make_unique<btBoxShape>(btVector3(20, 20, 20)));
|
||||
const btVector3 oscillatingBoxShapePosition(288, 288, 400);
|
||||
CollisionShapeInstance borderBox(std::make_unique<btBoxShape>(btVector3(50, 50, 50)));
|
||||
|
||||
mNavigator->addAgent(mAgentHalfExtents);
|
||||
mNavigator->addHeightfield(mCellPosition, cellSize, shift, surface);
|
||||
mNavigator->addHeightfield(mCellPosition, cellSize, surface);
|
||||
mNavigator->addObject(ObjectId(&oscillatingBox.shape()), ObjectShapes(oscillatingBox.instance()),
|
||||
btTransform(btMatrix3x3::getIdentity(), oscillatingBoxShapePosition));
|
||||
// add this box to make navmesh bound box independent from oscillatingBoxShape rotations
|
||||
|
@ -1046,10 +1032,9 @@ namespace
|
|||
{
|
||||
const HeightfieldPlane plane {100};
|
||||
const int cellSize = mHeightfieldTileSize * 4;
|
||||
const osg::Vec3f shift = getHeightfieldShift(mCellPosition, cellSize, plane.mHeight, plane.mHeight);
|
||||
|
||||
mNavigator->addAgent(mAgentHalfExtents);
|
||||
mNavigator->addHeightfield(mCellPosition, cellSize, shift, plane);
|
||||
mNavigator->addHeightfield(mCellPosition, cellSize, plane);
|
||||
mNavigator->update(mPlayerPosition);
|
||||
mNavigator->wait(mListener, WaitConditionType::requiredTilesPresent);
|
||||
|
||||
|
@ -1057,28 +1042,28 @@ namespace
|
|||
Status::Success);
|
||||
|
||||
EXPECT_THAT(mPath, ElementsAre(
|
||||
Vec3fEq(56.66666412353515625, 460, 203.9999847412109375),
|
||||
Vec3fEq(76.70135498046875, 439.965301513671875, 203.9999847412109375),
|
||||
Vec3fEq(96.73604583740234375, 419.93060302734375, 203.9999847412109375),
|
||||
Vec3fEq(116.770751953125, 399.89593505859375, 203.9999847412109375),
|
||||
Vec3fEq(136.8054351806640625, 379.861236572265625, 203.9999847412109375),
|
||||
Vec3fEq(156.840118408203125, 359.826568603515625, 203.9999847412109375),
|
||||
Vec3fEq(176.8748016357421875, 339.7918701171875, 203.9999847412109375),
|
||||
Vec3fEq(196.90948486328125, 319.757171630859375, 203.9999847412109375),
|
||||
Vec3fEq(216.944183349609375, 299.722503662109375, 203.9999847412109375),
|
||||
Vec3fEq(236.9788665771484375, 279.68780517578125, 203.9999847412109375),
|
||||
Vec3fEq(257.0135498046875, 259.65313720703125, 203.9999847412109375),
|
||||
Vec3fEq(277.048248291015625, 239.618438720703125, 203.9999847412109375),
|
||||
Vec3fEq(297.082916259765625, 219.583740234375, 203.9999847412109375),
|
||||
Vec3fEq(317.11761474609375, 199.549041748046875, 203.9999847412109375),
|
||||
Vec3fEq(337.15228271484375, 179.5143585205078125, 203.9999847412109375),
|
||||
Vec3fEq(357.186981201171875, 159.47967529296875, 203.9999847412109375),
|
||||
Vec3fEq(377.221649169921875, 139.4449920654296875, 203.9999847412109375),
|
||||
Vec3fEq(397.25634765625, 119.41030120849609375, 203.9999847412109375),
|
||||
Vec3fEq(417.291046142578125, 99.3756103515625, 203.9999847412109375),
|
||||
Vec3fEq(437.325714111328125, 79.340911865234375, 203.9999847412109375),
|
||||
Vec3fEq(457.360443115234375, 59.3062286376953125, 203.9999847412109375),
|
||||
Vec3fEq(460, 56.66666412353515625, 203.9999847412109375)
|
||||
Vec3fEq(56.66666412353515625, 460, 101.99999237060546875),
|
||||
Vec3fEq(76.70135498046875, 439.965301513671875, 101.99999237060546875),
|
||||
Vec3fEq(96.73604583740234375, 419.93060302734375, 101.99999237060546875),
|
||||
Vec3fEq(116.770751953125, 399.89593505859375, 101.99999237060546875),
|
||||
Vec3fEq(136.8054351806640625, 379.861236572265625, 101.99999237060546875),
|
||||
Vec3fEq(156.840118408203125, 359.826568603515625, 101.99999237060546875),
|
||||
Vec3fEq(176.8748016357421875, 339.7918701171875, 101.99999237060546875),
|
||||
Vec3fEq(196.90948486328125, 319.757171630859375, 101.99999237060546875),
|
||||
Vec3fEq(216.944183349609375, 299.722503662109375, 101.99999237060546875),
|
||||
Vec3fEq(236.9788665771484375, 279.68780517578125, 101.99999237060546875),
|
||||
Vec3fEq(257.0135498046875, 259.65313720703125, 101.99999237060546875),
|
||||
Vec3fEq(277.048248291015625, 239.618438720703125, 101.99999237060546875),
|
||||
Vec3fEq(297.082916259765625, 219.583740234375, 101.99999237060546875),
|
||||
Vec3fEq(317.11761474609375, 199.549041748046875, 101.99999237060546875),
|
||||
Vec3fEq(337.15228271484375, 179.5143585205078125, 101.99999237060546875),
|
||||
Vec3fEq(357.186981201171875, 159.47967529296875, 101.99999237060546875),
|
||||
Vec3fEq(377.221649169921875, 139.4449920654296875, 101.99999237060546875),
|
||||
Vec3fEq(397.25634765625, 119.41030120849609375, 101.99999237060546875),
|
||||
Vec3fEq(417.291046142578125, 99.3756103515625, 101.99999237060546875),
|
||||
Vec3fEq(437.325714111328125, 79.340911865234375, 101.99999237060546875),
|
||||
Vec3fEq(457.360443115234375, 59.3062286376953125, 101.99999237060546875),
|
||||
Vec3fEq(460, 56.66666412353515625, 101.99999237060546875)
|
||||
)) << mPath;
|
||||
}
|
||||
|
||||
|
@ -1093,14 +1078,13 @@ namespace
|
|||
}};
|
||||
const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData);
|
||||
const int cellSize = mHeightfieldTileSize * (surface.mSize - 1);
|
||||
const osg::Vec3f shift = getHeightfieldShift(mCellPosition, cellSize, surface.mMinHeight, surface.mMaxHeight);
|
||||
|
||||
CollisionShapeInstance compound(std::make_unique<btCompoundShape>());
|
||||
compound.shape().addChildShape(btTransform(btMatrix3x3::getIdentity(), btVector3(204, -204, 0)),
|
||||
new btBoxShape(btVector3(200, 200, 1000)));
|
||||
|
||||
mNavigator->addAgent(mAgentHalfExtents);
|
||||
mNavigator->addHeightfield(mCellPosition, cellSize, shift, surface);
|
||||
mNavigator->addHeightfield(mCellPosition, cellSize, surface);
|
||||
mNavigator->addObject(ObjectId(&compound.shape()), ObjectShapes(compound.instance()), mTransform);
|
||||
mNavigator->update(mPlayerPosition);
|
||||
mNavigator->wait(mListener, WaitConditionType::allJobsDone);
|
||||
|
@ -1133,14 +1117,13 @@ namespace
|
|||
}};
|
||||
const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData);
|
||||
const int cellSize = mHeightfieldTileSize * (surface.mSize - 1);
|
||||
const osg::Vec3f shift = getHeightfieldShift(mCellPosition, cellSize, surface.mMinHeight, surface.mMaxHeight);
|
||||
|
||||
CollisionShapeInstance compound(std::make_unique<btCompoundShape>());
|
||||
compound.shape().addChildShape(btTransform(btMatrix3x3::getIdentity(), btVector3(204, -204, 0)),
|
||||
new btBoxShape(btVector3(100, 100, 1000)));
|
||||
|
||||
mNavigator->addAgent(mAgentHalfExtents);
|
||||
mNavigator->addHeightfield(mCellPosition, cellSize, shift, surface);
|
||||
mNavigator->addHeightfield(mCellPosition, cellSize, surface);
|
||||
mNavigator->addObject(ObjectId(&compound.shape()), ObjectShapes(compound.instance()), mTransform);
|
||||
mNavigator->update(mPlayerPosition);
|
||||
mNavigator->wait(mListener, WaitConditionType::allJobsDone);
|
||||
|
|
|
@ -23,11 +23,6 @@
|
|||
|
||||
namespace DetourNavigator
|
||||
{
|
||||
static inline bool operator ==(const Cell& lhs, const Cell& rhs)
|
||||
{
|
||||
return lhs.mSize == rhs.mSize && lhs.mShift == rhs.mShift;
|
||||
}
|
||||
|
||||
static inline bool operator ==(const Water& lhs, const Water& rhs)
|
||||
{
|
||||
const auto tie = [] (const Water& v) { return std::tie(v.mCellSize, v.mLevel); };
|
||||
|
@ -47,7 +42,11 @@ namespace DetourNavigator
|
|||
|
||||
static inline bool operator==(const FlatHeightfield& lhs, const FlatHeightfield& rhs)
|
||||
{
|
||||
return std::tie(lhs.mBounds, lhs.mHeight) == std::tie(rhs.mBounds, rhs.mHeight);
|
||||
const auto tie = [] (const FlatHeightfield& v)
|
||||
{
|
||||
return std::tie(v.mCellPosition, v.mCellSize, v.mHeight);
|
||||
};
|
||||
return tie(lhs) == tie(rhs);
|
||||
}
|
||||
|
||||
static inline std::ostream& operator<<(std::ostream& s, const Water& v)
|
||||
|
@ -62,21 +61,21 @@ namespace DetourNavigator
|
|||
|
||||
static inline std::ostream& operator<<(std::ostream& s, const FlatHeightfield& v)
|
||||
{
|
||||
return s << "FlatHeightfield {" << v.mBounds << ", " << v.mHeight << "}";
|
||||
return s << "FlatHeightfield {" << v.mCellPosition << ", " << v.mCellSize << ", " << v.mHeight << "}";
|
||||
}
|
||||
|
||||
static inline std::ostream& operator<<(std::ostream& s, const Heightfield& v)
|
||||
{
|
||||
s << "Heightfield {.mBounds=" << v.mBounds
|
||||
<< ", .mLength=" << int(v.mLength)
|
||||
s << "Heightfield {.mCellPosition=" << v.mCellPosition
|
||||
<< ", .mCellSize=" << v.mCellSize
|
||||
<< ", .mLength=" << static_cast<int>(v.mLength)
|
||||
<< ", .mMinHeight=" << v.mMinHeight
|
||||
<< ", .mMaxHeight=" << v.mMaxHeight
|
||||
<< ", .mShift=" << v.mShift
|
||||
<< ", .mScale=" << v.mScale
|
||||
<< ", .mHeights={";
|
||||
for (float h : v.mHeights)
|
||||
s << h << ", ";
|
||||
return s << "}}";
|
||||
s << "}";
|
||||
return s << ", .mOriginalSize=" << v.mOriginalSize << "}";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -486,62 +485,111 @@ namespace
|
|||
|
||||
TEST_F(DetourNavigatorRecastMeshBuilderTest, add_flat_heightfield_should_add_intersection)
|
||||
{
|
||||
mBounds.mMin = osg::Vec2f(0, 0);
|
||||
const osg::Vec2i cellPosition(0, 0);
|
||||
const int cellSize = 1000;
|
||||
const float height = 10;
|
||||
mBounds.mMin = osg::Vec2f(100, 100);
|
||||
RecastMeshBuilder builder(mBounds);
|
||||
builder.addHeightfield(1000, osg::Vec3f(1, 2, 3), 10);
|
||||
builder.addHeightfield(cellPosition, cellSize, height);
|
||||
const auto recastMesh = std::move(builder).create(mGeneration, mRevision);
|
||||
EXPECT_EQ(recastMesh->getFlatHeightfields(), std::vector<FlatHeightfield>({
|
||||
FlatHeightfield {TileBounds {osg::Vec2f(0, 0), osg::Vec2f(501, 502)}, 13},
|
||||
FlatHeightfield {cellPosition, cellSize, height},
|
||||
}));
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorRecastMeshBuilderTest, add_heightfield_inside_tile)
|
||||
{
|
||||
constexpr std::array<float, 9> heights {{
|
||||
constexpr std::size_t size = 3;
|
||||
constexpr std::array<float, size * size> heights {{
|
||||
0, 1, 2,
|
||||
3, 4, 5,
|
||||
6, 7, 8,
|
||||
}};
|
||||
const osg::Vec2i cellPosition(0, 0);
|
||||
const int cellSize = 1000;
|
||||
const float minHeight = 0;
|
||||
const float maxHeight = 8;
|
||||
RecastMeshBuilder builder(mBounds);
|
||||
builder.addHeightfield(1000, osg::Vec3f(1, 2, 3), heights.data(), 3, 0, 8);
|
||||
builder.addHeightfield(cellPosition, cellSize, heights.data(), size, minHeight, maxHeight);
|
||||
const auto recastMesh = std::move(builder).create(mGeneration, mRevision);
|
||||
Heightfield expected;
|
||||
expected.mBounds = TileBounds {osg::Vec2f(-499, -498), osg::Vec2f(501, 502)};
|
||||
expected.mLength = 3;
|
||||
expected.mMinHeight = 0;
|
||||
expected.mMaxHeight = 8;
|
||||
expected.mShift = osg::Vec3f(-499, -498, 3);
|
||||
expected.mScale = 500;
|
||||
expected.mCellPosition = cellPosition;
|
||||
expected.mCellSize = cellSize;
|
||||
expected.mLength = size;
|
||||
expected.mMinHeight = minHeight;
|
||||
expected.mMaxHeight = maxHeight;
|
||||
expected.mHeights = {
|
||||
0, 1, 2,
|
||||
3, 4, 5,
|
||||
6, 7, 8,
|
||||
};
|
||||
expected.mOriginalSize = 3;
|
||||
expected.mMinX = 0;
|
||||
expected.mMinY = 0;
|
||||
EXPECT_EQ(recastMesh->getHeightfields(), std::vector<Heightfield>({expected}));
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorRecastMeshBuilderTest, add_heightfield_to_shifted_cell_inside_tile)
|
||||
{
|
||||
constexpr std::size_t size = 3;
|
||||
constexpr std::array<float, size * size> heights {{
|
||||
0, 1, 2,
|
||||
3, 4, 5,
|
||||
6, 7, 8,
|
||||
}};
|
||||
const osg::Vec2i cellPosition(1, 2);
|
||||
const int cellSize = 1000;
|
||||
const float minHeight = 0;
|
||||
const float maxHeight = 8;
|
||||
RecastMeshBuilder builder(maxCellTileBounds(cellPosition, cellSize));
|
||||
builder.addHeightfield(cellPosition, cellSize, heights.data(), size, minHeight, maxHeight);
|
||||
const auto recastMesh = std::move(builder).create(mGeneration, mRevision);
|
||||
Heightfield expected;
|
||||
expected.mCellPosition = cellPosition;
|
||||
expected.mCellSize = cellSize;
|
||||
expected.mLength = size;
|
||||
expected.mMinHeight = minHeight;
|
||||
expected.mMaxHeight = maxHeight;
|
||||
expected.mHeights = {
|
||||
0, 1, 2,
|
||||
3, 4, 5,
|
||||
6, 7, 8,
|
||||
};
|
||||
expected.mOriginalSize = 3;
|
||||
expected.mMinX = 0;
|
||||
expected.mMinY = 0;
|
||||
EXPECT_EQ(recastMesh->getHeightfields(), std::vector<Heightfield>({expected}));
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorRecastMeshBuilderTest, add_heightfield_should_add_intersection)
|
||||
{
|
||||
constexpr std::array<float, 9> heights {{
|
||||
constexpr std::size_t size = 3;
|
||||
constexpr std::array<float, 3 * 3> heights {{
|
||||
0, 1, 2,
|
||||
3, 4, 5,
|
||||
6, 7, 8,
|
||||
}};
|
||||
mBounds.mMin = osg::Vec2f(250, 250);
|
||||
const osg::Vec2i cellPosition(0, 0);
|
||||
const int cellSize = 1000;
|
||||
const float minHeight = 0;
|
||||
const float maxHeight = 8;
|
||||
mBounds.mMin = osg::Vec2f(750, 750);
|
||||
RecastMeshBuilder builder(mBounds);
|
||||
builder.addHeightfield(1000, osg::Vec3f(-1, -2, 3), heights.data(), 3, 0, 8);
|
||||
builder.addHeightfield(cellPosition, cellSize, heights.data(), size, minHeight, maxHeight);
|
||||
const auto recastMesh = std::move(builder).create(mGeneration, mRevision);
|
||||
Heightfield expected;
|
||||
expected.mBounds = TileBounds {osg::Vec2f(250, 250), osg::Vec2f(499, 498)};
|
||||
expected.mCellPosition = cellPosition;
|
||||
expected.mCellSize = cellSize;
|
||||
expected.mLength = 2;
|
||||
expected.mMinHeight = 0;
|
||||
expected.mMaxHeight = 8;
|
||||
expected.mShift = osg::Vec3f(-1, -2, 3);
|
||||
expected.mScale = 500;
|
||||
expected.mHeights = {
|
||||
4, 5,
|
||||
7, 8,
|
||||
};
|
||||
expected.mOriginalSize = 3;
|
||||
expected.mMinX = 1;
|
||||
expected.mMinY = 1;
|
||||
EXPECT_EQ(recastMesh->getHeightfields(), std::vector<Heightfield>({expected}));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -49,20 +49,20 @@ namespace DetourNavigator
|
|||
}
|
||||
|
||||
bool CachedRecastMeshManager::addHeightfield(const osg::Vec2i& cellPosition, int cellSize,
|
||||
const osg::Vec3f& shift, const HeightfieldShape& shape)
|
||||
const HeightfieldShape& shape)
|
||||
{
|
||||
if (!mImpl.addHeightfield(cellPosition, cellSize, shift, shape))
|
||||
if (!mImpl.addHeightfield(cellPosition, cellSize, shape))
|
||||
return false;
|
||||
mOutdatedCache = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
std::optional<Cell> CachedRecastMeshManager::removeHeightfield(const osg::Vec2i& cellPosition)
|
||||
std::optional<SizedHeightfieldShape> CachedRecastMeshManager::removeHeightfield(const osg::Vec2i& cellPosition)
|
||||
{
|
||||
const auto cell = mImpl.removeHeightfield(cellPosition);
|
||||
if (cell)
|
||||
const auto heightfield = mImpl.removeHeightfield(cellPosition);
|
||||
if (heightfield)
|
||||
mOutdatedCache = true;
|
||||
return cell;
|
||||
return heightfield;
|
||||
}
|
||||
|
||||
std::shared_ptr<RecastMesh> CachedRecastMeshManager::getMesh()
|
||||
|
|
|
@ -27,10 +27,9 @@ namespace DetourNavigator
|
|||
|
||||
std::optional<Water> removeWater(const osg::Vec2i& cellPosition);
|
||||
|
||||
bool addHeightfield(const osg::Vec2i& cellPosition, int cellSize, const osg::Vec3f& shift,
|
||||
const HeightfieldShape& shape);
|
||||
bool addHeightfield(const osg::Vec2i& cellPosition, int cellSize, const HeightfieldShape& shape);
|
||||
|
||||
std::optional<Cell> removeHeightfield(const osg::Vec2i& cellPosition);
|
||||
std::optional<SizedHeightfieldShape> removeHeightfield(const osg::Vec2i& cellPosition);
|
||||
|
||||
std::shared_ptr<RecastMesh> getMesh();
|
||||
|
||||
|
|
|
@ -50,13 +50,13 @@ namespace DetourNavigator
|
|||
}
|
||||
|
||||
template <class Callback>
|
||||
void getTilesPositions(const int cellSize, const osg::Vec3f& shift,
|
||||
void getTilesPositions(const int cellSize, const btVector3& shift,
|
||||
const Settings& settings, Callback&& callback)
|
||||
{
|
||||
using Misc::Convert::toOsg;
|
||||
|
||||
const auto halfCellSize = cellSize / 2;
|
||||
const btTransform transform(btMatrix3x3::getIdentity(), Misc::Convert::toBullet(shift));
|
||||
const btTransform transform(btMatrix3x3::getIdentity(), shift);
|
||||
auto aabbMin = transform(btVector3(-halfCellSize, -halfCellSize, 0));
|
||||
auto aabbMax = transform(btVector3(halfCellSize, halfCellSize, 0));
|
||||
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
#ifndef OPENMW_COMPONENTS_DETOURNAVIGATOR_HEIGHFIELDSHAPE_H
|
||||
#define OPENMW_COMPONENTS_DETOURNAVIGATOR_HEIGHFIELDSHAPE_H
|
||||
|
||||
#include <components/bullethelpers/heightfield.hpp>
|
||||
|
||||
#include <osg/Vec2i>
|
||||
|
||||
#include <cstddef>
|
||||
#include <variant>
|
||||
|
||||
|
@ -20,6 +24,21 @@ namespace DetourNavigator
|
|||
};
|
||||
|
||||
using HeightfieldShape = std::variant<HeightfieldPlane, HeightfieldSurface>;
|
||||
|
||||
inline btVector3 getHeightfieldShift(const HeightfieldPlane& v, const osg::Vec2i& cellPosition, int cellSize)
|
||||
{
|
||||
return BulletHelpers::getHeightfieldShift(cellPosition.x(), cellPosition.y(), cellSize, v.mHeight, v.mHeight);
|
||||
}
|
||||
|
||||
inline btVector3 getHeightfieldShift(const HeightfieldSurface& v, const osg::Vec2i& cellPosition, int cellSize)
|
||||
{
|
||||
return BulletHelpers::getHeightfieldShift(cellPosition.x(), cellPosition.y(), cellSize, v.mMinHeight, v.mMaxHeight);
|
||||
}
|
||||
|
||||
inline btVector3 getHeightfieldShift(const HeightfieldShape& v, const osg::Vec2i& cellPosition, int cellSize)
|
||||
{
|
||||
return std::visit([&] (const auto& w) { return getHeightfieldShift(w, cellPosition, cellSize); }, v);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -252,14 +252,17 @@ namespace
|
|||
return true;
|
||||
}
|
||||
|
||||
bool rasterizeTriangles(rcContext& context, const std::vector<FlatHeightfield>& heightfields,
|
||||
bool rasterizeTriangles(rcContext& context, const TileBounds& tileBounds, const std::vector<FlatHeightfield>& heightfields,
|
||||
const Settings& settings, const rcConfig& config, rcHeightfield& solid)
|
||||
{
|
||||
for (const FlatHeightfield& heightfield : heightfields)
|
||||
{
|
||||
const Rectangle rectangle {heightfield.mBounds, toNavMeshCoordinates(settings, heightfield.mHeight)};
|
||||
if (!rasterizeTriangles(context, rectangle, config, AreaType_ground, solid))
|
||||
return false;
|
||||
if (auto intersection = getIntersection(tileBounds, maxCellTileBounds(heightfield.mCellPosition, heightfield.mCellSize)))
|
||||
{
|
||||
const Rectangle rectangle {*intersection, toNavMeshCoordinates(settings, heightfield.mHeight)};
|
||||
if (!rasterizeTriangles(context, rectangle, config, AreaType_ground, solid))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -278,13 +281,14 @@ namespace
|
|||
return true;
|
||||
}
|
||||
|
||||
bool rasterizeTriangles(rcContext& context, const osg::Vec3f& agentHalfExtents, const RecastMesh& recastMesh,
|
||||
const rcConfig& config, const Settings& settings, rcHeightfield& solid)
|
||||
bool rasterizeTriangles(rcContext& context, const TilePosition& tilePosition, const osg::Vec3f& agentHalfExtents,
|
||||
const RecastMesh& recastMesh, const rcConfig& config, const Settings& settings, rcHeightfield& solid)
|
||||
{
|
||||
return rasterizeTriangles(context, recastMesh.getMesh(), settings, config, solid)
|
||||
&& rasterizeTriangles(context, agentHalfExtents, recastMesh.getWater(), settings, config, solid)
|
||||
&& rasterizeTriangles(context, recastMesh.getHeightfields(), settings, config, solid)
|
||||
&& rasterizeTriangles(context, recastMesh.getFlatHeightfields(), settings, config, solid);
|
||||
&& rasterizeTriangles(context, makeRealTileBoundsWithBorder(settings, tilePosition),
|
||||
recastMesh.getFlatHeightfields(), settings, config, solid);
|
||||
}
|
||||
|
||||
void buildCompactHeightfield(rcContext& context, const int walkableHeight, const int walkableClimb,
|
||||
|
@ -444,7 +448,7 @@ namespace DetourNavigator
|
|||
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))
|
||||
if (!rasterizeTriangles(context, tilePosition, agentHalfExtents, recastMesh, config, settings, solid))
|
||||
return nullptr;
|
||||
|
||||
rcFilterLowHangingWalkableObstacles(&context, config.walkableClimb, solid);
|
||||
|
|
|
@ -131,8 +131,7 @@ namespace DetourNavigator
|
|||
*/
|
||||
virtual bool removeWater(const osg::Vec2i& cellPosition) = 0;
|
||||
|
||||
virtual bool addHeightfield(const osg::Vec2i& cellPosition, int cellSize, const osg::Vec3f& shift,
|
||||
const HeightfieldShape& shape) = 0;
|
||||
virtual bool addHeightfield(const osg::Vec2i& cellPosition, int cellSize, const HeightfieldShape& shape) = 0;
|
||||
|
||||
virtual bool removeHeightfield(const osg::Vec2i& cellPosition) = 0;
|
||||
|
||||
|
|
|
@ -107,10 +107,9 @@ namespace DetourNavigator
|
|||
return mNavMeshManager.removeWater(cellPosition);
|
||||
}
|
||||
|
||||
bool NavigatorImpl::addHeightfield(const osg::Vec2i& cellPosition, int cellSize, const osg::Vec3f& shift,
|
||||
const HeightfieldShape& shape)
|
||||
bool NavigatorImpl::addHeightfield(const osg::Vec2i& cellPosition, int cellSize, const HeightfieldShape& shape)
|
||||
{
|
||||
return mNavMeshManager.addHeightfield(cellPosition, cellSize, shift, shape);
|
||||
return mNavMeshManager.addHeightfield(cellPosition, cellSize, shape);
|
||||
}
|
||||
|
||||
bool NavigatorImpl::removeHeightfield(const osg::Vec2i& cellPosition)
|
||||
|
|
|
@ -35,8 +35,7 @@ namespace DetourNavigator
|
|||
|
||||
bool removeWater(const osg::Vec2i& cellPosition) override;
|
||||
|
||||
bool addHeightfield(const osg::Vec2i& cellPosition, int cellSize, const osg::Vec3f& shift,
|
||||
const HeightfieldShape& shape) override;
|
||||
bool addHeightfield(const osg::Vec2i& cellPosition, int cellSize, const HeightfieldShape& shape) override;
|
||||
|
||||
bool removeHeightfield(const osg::Vec2i& cellPosition) override;
|
||||
|
||||
|
|
|
@ -54,8 +54,7 @@ namespace DetourNavigator
|
|||
return false;
|
||||
}
|
||||
|
||||
bool addHeightfield(const osg::Vec2i& /*cellPosition*/, int /*cellSize*/, const osg::Vec3f& /*shift*/,
|
||||
const HeightfieldShape& /*height*/) override
|
||||
bool addHeightfield(const osg::Vec2i& /*cellPosition*/, int /*cellSize*/, const HeightfieldShape& /*height*/) override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "waitconditiontype.hpp"
|
||||
|
||||
#include <components/debug/debuglog.hpp>
|
||||
#include <components/bullethelpers/heightfield.hpp>
|
||||
|
||||
#include <DetourNavMesh.h>
|
||||
|
||||
|
@ -77,7 +78,7 @@ namespace DetourNavigator
|
|||
{
|
||||
if (!mRecastMeshManager.addWater(cellPosition, cellSize, level))
|
||||
return false;
|
||||
const osg::Vec3f shift = getWaterShift3d(cellPosition, cellSize, level);
|
||||
const btVector3 shift = Misc::Convert::toBullet(getWaterShift3d(cellPosition, cellSize, level));
|
||||
addChangedTiles(cellSize, shift, ChangeType::add);
|
||||
return true;
|
||||
}
|
||||
|
@ -87,16 +88,16 @@ namespace DetourNavigator
|
|||
const auto water = mRecastMeshManager.removeWater(cellPosition);
|
||||
if (!water)
|
||||
return false;
|
||||
const osg::Vec3f shift = getWaterShift3d(cellPosition, water->mCellSize, water->mLevel);
|
||||
const btVector3 shift = Misc::Convert::toBullet(getWaterShift3d(cellPosition, water->mCellSize, water->mLevel));
|
||||
addChangedTiles(water->mCellSize, shift, ChangeType::remove);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NavMeshManager::addHeightfield(const osg::Vec2i& cellPosition, int cellSize, const osg::Vec3f& shift,
|
||||
const HeightfieldShape& shape)
|
||||
bool NavMeshManager::addHeightfield(const osg::Vec2i& cellPosition, int cellSize, const HeightfieldShape& shape)
|
||||
{
|
||||
if (!mRecastMeshManager.addHeightfield(cellPosition, cellSize, shift, shape))
|
||||
if (!mRecastMeshManager.addHeightfield(cellPosition, cellSize, shape))
|
||||
return false;
|
||||
const btVector3 shift = getHeightfieldShift(shape, cellPosition, cellSize);
|
||||
addChangedTiles(cellSize, shift, ChangeType::add);
|
||||
return true;
|
||||
}
|
||||
|
@ -106,7 +107,8 @@ namespace DetourNavigator
|
|||
const auto heightfield = mRecastMeshManager.removeHeightfield(cellPosition);
|
||||
if (!heightfield)
|
||||
return false;
|
||||
addChangedTiles(heightfield->mSize, heightfield->mShift, ChangeType::remove);
|
||||
const btVector3 shift = getHeightfieldShift(heightfield->mShape, cellPosition, heightfield->mCellSize);
|
||||
addChangedTiles(heightfield->mCellSize, shift, ChangeType::remove);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -253,7 +255,7 @@ namespace DetourNavigator
|
|||
[&] (const TilePosition& v) { addChangedTile(v, changeType); });
|
||||
}
|
||||
|
||||
void NavMeshManager::addChangedTiles(const int cellSize, const osg::Vec3f& shift,
|
||||
void NavMeshManager::addChangedTiles(const int cellSize, const btVector3& shift,
|
||||
const ChangeType changeType)
|
||||
{
|
||||
if (cellSize == std::numeric_limits<int>::max())
|
||||
|
|
|
@ -38,8 +38,7 @@ namespace DetourNavigator
|
|||
|
||||
bool removeWater(const osg::Vec2i& cellPosition);
|
||||
|
||||
bool addHeightfield(const osg::Vec2i& cellPosition, int cellSize, const osg::Vec3f& shift,
|
||||
const HeightfieldShape& shape);
|
||||
bool addHeightfield(const osg::Vec2i& cellPosition, int cellSize, const HeightfieldShape& shape);
|
||||
|
||||
bool removeHeightfield(const osg::Vec2i& cellPosition);
|
||||
|
||||
|
@ -74,7 +73,7 @@ namespace DetourNavigator
|
|||
|
||||
void addChangedTiles(const btCollisionShape& shape, const btTransform& transform, const ChangeType changeType);
|
||||
|
||||
void addChangedTiles(const int cellSize, const osg::Vec3f& shift, const ChangeType changeType);
|
||||
void addChangedTiles(const int cellSize, const btVector3& shift, const ChangeType changeType);
|
||||
|
||||
void addChangedTile(const TilePosition& tilePosition, const ChangeType changeType);
|
||||
|
||||
|
|
|
@ -48,12 +48,6 @@ namespace DetourNavigator
|
|||
}
|
||||
};
|
||||
|
||||
struct Cell
|
||||
{
|
||||
int mSize;
|
||||
osg::Vec3f mShift;
|
||||
};
|
||||
|
||||
struct Water
|
||||
{
|
||||
int mCellSize;
|
||||
|
@ -90,18 +84,21 @@ namespace DetourNavigator
|
|||
|
||||
struct Heightfield
|
||||
{
|
||||
TileBounds mBounds;
|
||||
osg::Vec2i mCellPosition;
|
||||
int mCellSize;
|
||||
std::uint8_t mLength;
|
||||
float mMinHeight;
|
||||
float mMaxHeight;
|
||||
osg::Vec3f mShift;
|
||||
float mScale;
|
||||
std::vector<float> mHeights;
|
||||
std::size_t mOriginalSize;
|
||||
std::uint8_t mMinX;
|
||||
std::uint8_t mMinY;
|
||||
};
|
||||
|
||||
inline auto makeTuple(const Heightfield& v) noexcept
|
||||
{
|
||||
return std::tie(v.mBounds, v.mLength, v.mMinHeight, v.mMaxHeight, v.mShift, v.mScale, v.mHeights);
|
||||
return std::tie(v.mCellPosition, v.mCellSize, v.mLength, v.mMinHeight, v.mMaxHeight,
|
||||
v.mHeights, v.mOriginalSize, v.mMinX, v.mMinY);
|
||||
}
|
||||
|
||||
inline bool operator<(const Heightfield& lhs, const Heightfield& rhs) noexcept
|
||||
|
@ -111,13 +108,15 @@ namespace DetourNavigator
|
|||
|
||||
struct FlatHeightfield
|
||||
{
|
||||
TileBounds mBounds;
|
||||
osg::Vec2i mCellPosition;
|
||||
int mCellSize;
|
||||
float mHeight;
|
||||
};
|
||||
|
||||
inline bool operator<(const FlatHeightfield& lhs, const FlatHeightfield& rhs) noexcept
|
||||
{
|
||||
return std::tie(lhs.mBounds, lhs.mHeight) < std::tie(rhs.mBounds, rhs.mHeight);
|
||||
const auto tie = [] (const FlatHeightfield& v) { return std::tie(v.mCellPosition, v.mCellSize, v.mHeight); };
|
||||
return tie(lhs) < tie(rhs);
|
||||
}
|
||||
|
||||
class RecastMesh
|
||||
|
@ -170,11 +169,6 @@ namespace DetourNavigator
|
|||
+ value.mFlatHeightfields.size() * sizeof(FlatHeightfield);
|
||||
}
|
||||
};
|
||||
|
||||
inline bool operator<(const Cell& lhs, const Cell& rhs) noexcept
|
||||
{
|
||||
return std::tie(lhs.mSize, lhs.mShift) < std::tie(rhs.mSize, rhs.mShift);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include <components/bullethelpers/processtrianglecallback.hpp>
|
||||
#include <components/misc/convert.hpp>
|
||||
#include <components/debug/debuglog.hpp>
|
||||
#include <components/bullethelpers/heightfield.hpp>
|
||||
|
||||
#include <BulletCollision/CollisionShapes/btBoxShape.h>
|
||||
#include <BulletCollision/CollisionShapes/btCompoundShape.h>
|
||||
|
@ -35,13 +36,9 @@ namespace DetourNavigator
|
|||
return result;
|
||||
}
|
||||
|
||||
TileBounds maxCellTileBounds(int size, const osg::Vec3f& shift)
|
||||
float getHeightfieldScale(int cellSize, std::size_t dataSize)
|
||||
{
|
||||
const float halfCellSize = static_cast<float>(size) / 2;
|
||||
return TileBounds {
|
||||
osg::Vec2f(shift.x() - halfCellSize, shift.y() - halfCellSize),
|
||||
osg::Vec2f(shift.x() + halfCellSize, shift.y() + halfCellSize)
|
||||
};
|
||||
return static_cast<float>(cellSize) / (dataSize - 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -108,7 +105,8 @@ namespace DetourNavigator
|
|||
static_cast<int>(heightfield.mLength), heightfield.mHeights.data(),
|
||||
heightfield.mMinHeight, heightfield.mMaxHeight, upAxis, flipQuadEdges);
|
||||
#endif
|
||||
shape.setLocalScaling(btVector3(heightfield.mScale, heightfield.mScale, 1));
|
||||
const float scale = getHeightfieldScale(heightfield.mCellSize, heightfield.mOriginalSize);
|
||||
shape.setLocalScaling(btVector3(scale, scale, 1));
|
||||
btVector3 aabbMin;
|
||||
btVector3 aabbMax;
|
||||
shape.getAabb(btTransform::getIdentity(), aabbMin, aabbMax);
|
||||
|
@ -118,8 +116,16 @@ namespace DetourNavigator
|
|||
triangles.emplace_back(makeRecastMeshTriangle(vertices, AreaType_ground));
|
||||
});
|
||||
shape.processAllTriangles(&callback, aabbMin, aabbMax);
|
||||
const osg::Vec2f shift = (osg::Vec2f(aabbMax.x(), aabbMax.y()) - osg::Vec2f(aabbMin.x(), aabbMin.y())) * 0.5;
|
||||
return makeMesh(std::move(triangles), heightfield.mShift + osg::Vec3f(shift.x(), shift.y(), 0));
|
||||
const osg::Vec2f aabbShift = (osg::Vec2f(aabbMax.x(), aabbMax.y()) - osg::Vec2f(aabbMin.x(), aabbMin.y())) * 0.5;
|
||||
const osg::Vec2f tileShift = osg::Vec2f(heightfield.mMinX, heightfield.mMinY) * scale;
|
||||
const osg::Vec2f localShift = aabbShift + tileShift;
|
||||
const float cellSize = static_cast<float>(heightfield.mCellSize);
|
||||
const osg::Vec3f cellShift(
|
||||
heightfield.mCellPosition.x() * cellSize,
|
||||
heightfield.mCellPosition.y() * cellSize,
|
||||
(heightfield.mMinHeight + heightfield.mMaxHeight) * 0.5f
|
||||
);
|
||||
return makeMesh(std::move(triangles), cellShift + osg::Vec3f(localShift.x(), localShift.y(), 0));
|
||||
}
|
||||
|
||||
RecastMeshBuilder::RecastMeshBuilder(const TileBounds& bounds) noexcept
|
||||
|
@ -205,19 +211,20 @@ namespace DetourNavigator
|
|||
mWater.push_back(CellWater {cellPosition, water});
|
||||
}
|
||||
|
||||
void RecastMeshBuilder::addHeightfield(int cellSize, const osg::Vec3f& shift, float height)
|
||||
void RecastMeshBuilder::addHeightfield(const osg::Vec2i& cellPosition, int cellSize, float height)
|
||||
{
|
||||
if (const auto intersection = getIntersection(mBounds, maxCellTileBounds(cellSize, shift)))
|
||||
mFlatHeightfields.emplace_back(FlatHeightfield {*intersection, height + shift.z()});
|
||||
if (const auto intersection = getIntersection(mBounds, maxCellTileBounds(cellPosition, cellSize)))
|
||||
mFlatHeightfields.emplace_back(FlatHeightfield {cellPosition, cellSize, height});
|
||||
}
|
||||
|
||||
void RecastMeshBuilder::addHeightfield(int cellSize, const osg::Vec3f& shift, const float* heights,
|
||||
void RecastMeshBuilder::addHeightfield(const osg::Vec2i& cellPosition, int cellSize, const float* heights,
|
||||
std::size_t size, float minHeight, float maxHeight)
|
||||
{
|
||||
const auto intersection = getIntersection(mBounds, maxCellTileBounds(cellSize, shift));
|
||||
const auto intersection = getIntersection(mBounds, maxCellTileBounds(cellPosition, cellSize));
|
||||
if (!intersection.has_value())
|
||||
return;
|
||||
const float stepSize = static_cast<float>(cellSize) / (size - 1);
|
||||
const osg::Vec3f shift = Misc::Convert::toOsg(BulletHelpers::getHeightfieldShift(cellPosition.x(), cellPosition.y(), cellSize, minHeight, maxHeight));
|
||||
const float stepSize = getHeightfieldScale(cellSize, size);
|
||||
const int halfCellSize = cellSize / 2;
|
||||
const auto local = [&] (float v, float shift) { return (v - shift + halfCellSize) / stepSize; };
|
||||
const auto index = [&] (float v, int add) { return std::clamp<int>(static_cast<int>(v) + add, 0, size); };
|
||||
|
@ -236,13 +243,15 @@ namespace DetourNavigator
|
|||
for (std::size_t x = minX; x < endX; ++x)
|
||||
tileHeights.push_back(heights[x + y * size]);
|
||||
Heightfield heightfield;
|
||||
heightfield.mBounds = *intersection;
|
||||
heightfield.mCellPosition = cellPosition;
|
||||
heightfield.mCellSize = cellSize;
|
||||
heightfield.mLength = static_cast<std::uint8_t>(endY - minY);
|
||||
heightfield.mMinHeight = minHeight;
|
||||
heightfield.mMaxHeight = maxHeight;
|
||||
heightfield.mShift = shift + osg::Vec3f(minX, minY, 0) * stepSize - osg::Vec3f(halfCellSize, halfCellSize, 0);
|
||||
heightfield.mScale = stepSize;
|
||||
heightfield.mHeights = std::move(tileHeights);
|
||||
heightfield.mOriginalSize = size;
|
||||
heightfield.mMinX = static_cast<std::uint8_t>(minX);
|
||||
heightfield.mMinY = static_cast<std::uint8_t>(minY);
|
||||
mHeightfields.push_back(std::move(heightfield));
|
||||
}
|
||||
|
||||
|
|
|
@ -50,9 +50,9 @@ namespace DetourNavigator
|
|||
|
||||
void addWater(const osg::Vec2i& cellPosition, const Water& water);
|
||||
|
||||
void addHeightfield(int cellSize, const osg::Vec3f& shift, float height);
|
||||
void addHeightfield(const osg::Vec2i& cellPosition, int cellSize, float height);
|
||||
|
||||
void addHeightfield(int cellSize, const osg::Vec3f& shift, const float* heights, std::size_t size,
|
||||
void addHeightfield(const osg::Vec2i& cellPosition, int cellSize, const float* heights, std::size_t size,
|
||||
float minHeight, float maxHeight);
|
||||
|
||||
std::shared_ptr<RecastMesh> create(std::size_t generation, std::size_t revision) &&;
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include "heightfieldshape.hpp"
|
||||
|
||||
#include <components/debug/debuglog.hpp>
|
||||
#include <components/misc/convert.hpp>
|
||||
|
||||
#include <utility>
|
||||
|
||||
|
@ -11,17 +12,18 @@ namespace
|
|||
{
|
||||
struct AddHeightfield
|
||||
{
|
||||
const DetourNavigator::Cell& mCell;
|
||||
osg::Vec2i mCellPosition;
|
||||
int mCellSize;
|
||||
DetourNavigator::RecastMeshBuilder& mBuilder;
|
||||
|
||||
void operator()(const DetourNavigator::HeightfieldSurface& v)
|
||||
{
|
||||
mBuilder.addHeightfield(mCell.mSize, mCell.mShift, v.mHeights, v.mSize, v.mMinHeight, v.mMaxHeight);
|
||||
mBuilder.addHeightfield(mCellPosition, mCellSize, v.mHeights, v.mSize, v.mMinHeight, v.mMaxHeight);
|
||||
}
|
||||
|
||||
void operator()(DetourNavigator::HeightfieldPlane v)
|
||||
{
|
||||
mBuilder.addHeightfield(mCell.mSize, mCell.mShift, v.mHeight);
|
||||
mBuilder.addHeightfield(mCellPosition, mCellSize, v.mHeight);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -94,24 +96,24 @@ namespace DetourNavigator
|
|||
return result;
|
||||
}
|
||||
|
||||
bool RecastMeshManager::addHeightfield(const osg::Vec2i& cellPosition, int cellSize, const osg::Vec3f& shift,
|
||||
bool RecastMeshManager::addHeightfield(const osg::Vec2i& cellPosition, int cellSize,
|
||||
const HeightfieldShape& shape)
|
||||
{
|
||||
const std::lock_guard lock(mMutex);
|
||||
if (!mHeightfields.emplace(cellPosition, Heightfield {Cell {cellSize, shift}, shape}).second)
|
||||
if (!mHeightfields.emplace(cellPosition, SizedHeightfieldShape {cellSize, shape}).second)
|
||||
return false;
|
||||
++mRevision;
|
||||
return true;
|
||||
}
|
||||
|
||||
std::optional<Cell> RecastMeshManager::removeHeightfield(const osg::Vec2i& cellPosition)
|
||||
std::optional<SizedHeightfieldShape> RecastMeshManager::removeHeightfield(const osg::Vec2i& cellPosition)
|
||||
{
|
||||
const std::lock_guard lock(mMutex);
|
||||
const auto it = mHeightfields.find(cellPosition);
|
||||
if (it == mHeightfields.end())
|
||||
return std::nullopt;
|
||||
++mRevision;
|
||||
const auto result = std::make_optional(it->second.mCell);
|
||||
auto result = std::make_optional(it->second);
|
||||
mHeightfields.erase(it);
|
||||
return result;
|
||||
}
|
||||
|
@ -132,7 +134,7 @@ namespace DetourNavigator
|
|||
for (const auto& [k, v] : mWater)
|
||||
builder.addWater(k, v);
|
||||
for (const auto& [cellPosition, v] : mHeightfields)
|
||||
std::visit(AddHeightfield {v.mCell, builder}, v.mShape);
|
||||
std::visit(AddHeightfield {cellPosition, v.mCellSize, builder}, v.mShape);
|
||||
objects.reserve(mObjects.size());
|
||||
for (const auto& [k, object] : mObjects)
|
||||
{
|
||||
|
|
|
@ -29,6 +29,12 @@ namespace DetourNavigator
|
|||
btTransform mTransform;
|
||||
};
|
||||
|
||||
struct SizedHeightfieldShape
|
||||
{
|
||||
int mCellSize;
|
||||
HeightfieldShape mShape;
|
||||
};
|
||||
|
||||
class RecastMeshManager
|
||||
{
|
||||
public:
|
||||
|
@ -45,10 +51,9 @@ namespace DetourNavigator
|
|||
|
||||
std::optional<Water> removeWater(const osg::Vec2i& cellPosition);
|
||||
|
||||
bool addHeightfield(const osg::Vec2i& cellPosition, int cellSize, const osg::Vec3f& shift,
|
||||
const HeightfieldShape& shape);
|
||||
bool addHeightfield(const osg::Vec2i& cellPosition, int cellSize, const HeightfieldShape& shape);
|
||||
|
||||
std::optional<Cell> removeHeightfield(const osg::Vec2i& cellPosition);
|
||||
std::optional<SizedHeightfieldShape> removeHeightfield(const osg::Vec2i& cellPosition);
|
||||
|
||||
std::shared_ptr<RecastMesh> getMesh() const;
|
||||
|
||||
|
@ -65,19 +70,13 @@ namespace DetourNavigator
|
|||
Version mNavMeshVersion;
|
||||
};
|
||||
|
||||
struct Heightfield
|
||||
{
|
||||
Cell mCell;
|
||||
HeightfieldShape mShape;
|
||||
};
|
||||
|
||||
const std::size_t mGeneration;
|
||||
const TileBounds mTileBounds;
|
||||
mutable std::mutex mMutex;
|
||||
std::size_t mRevision = 0;
|
||||
std::map<ObjectId, OscillatingRecastMeshObject> mObjects;
|
||||
std::map<osg::Vec2i, Water> mWater;
|
||||
std::map<osg::Vec2i, Heightfield> mHeightfields;
|
||||
std::map<osg::Vec2i, SizedHeightfieldShape> mHeightfields;
|
||||
std::optional<Report> mLastNavMeshReportedChange;
|
||||
std::optional<Report> mLastNavMeshReport;
|
||||
};
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#define OPENMW_COMPONENTS_DETOURNAVIGATOR_TILEBOUNDS_H
|
||||
|
||||
#include <osg/Vec2f>
|
||||
#include <osg/Vec2i>
|
||||
|
||||
#include <algorithm>
|
||||
#include <optional>
|
||||
|
@ -32,6 +33,14 @@ namespace DetourNavigator
|
|||
return std::nullopt;
|
||||
return TileBounds {osg::Vec2f(minX, minY), osg::Vec2f(maxX, maxY)};
|
||||
}
|
||||
|
||||
inline TileBounds maxCellTileBounds(const osg::Vec2i& position, int size)
|
||||
{
|
||||
return TileBounds {
|
||||
osg::Vec2f(position.x(), position.y()) * size,
|
||||
osg::Vec2f(position.x() + 1, position.y() + 1) * size
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -74,7 +74,7 @@ namespace DetourNavigator
|
|||
}
|
||||
else
|
||||
{
|
||||
const osg::Vec3f shift = getWaterShift3d(cellPosition, cellSize, level);
|
||||
const btVector3 shift = Misc::Convert::toBullet(getWaterShift3d(cellPosition, cellSize, level));
|
||||
getTilesPositions(cellSize, shift, mSettings, [&] (const TilePosition& tilePosition)
|
||||
{
|
||||
const auto tiles = mTiles.lock();
|
||||
|
@ -126,8 +126,9 @@ namespace DetourNavigator
|
|||
}
|
||||
|
||||
bool TileCachedRecastMeshManager::addHeightfield(const osg::Vec2i& cellPosition, int cellSize,
|
||||
const osg::Vec3f& shift, const HeightfieldShape& shape)
|
||||
const HeightfieldShape& shape)
|
||||
{
|
||||
const btVector3 shift = getHeightfieldShift(shape, cellPosition, cellSize);
|
||||
auto& tilesPositions = mHeightfieldTilesPositions[cellPosition];
|
||||
|
||||
bool result = false;
|
||||
|
@ -142,7 +143,7 @@ namespace DetourNavigator
|
|||
tile = tiles->emplace(tilePosition,
|
||||
std::make_shared<CachedRecastMeshManager>(tileBounds, mTilesGeneration)).first;
|
||||
}
|
||||
if (tile->second->addHeightfield(cellPosition, cellSize, shift, shape))
|
||||
if (tile->second->addHeightfield(cellPosition, cellSize, shape))
|
||||
{
|
||||
tilesPositions.push_back(tilePosition);
|
||||
result = true;
|
||||
|
@ -155,12 +156,12 @@ namespace DetourNavigator
|
|||
return result;
|
||||
}
|
||||
|
||||
std::optional<Cell> TileCachedRecastMeshManager::removeHeightfield(const osg::Vec2i& cellPosition)
|
||||
std::optional<SizedHeightfieldShape> TileCachedRecastMeshManager::removeHeightfield(const osg::Vec2i& cellPosition)
|
||||
{
|
||||
const auto object = mHeightfieldTilesPositions.find(cellPosition);
|
||||
if (object == mHeightfieldTilesPositions.end())
|
||||
return std::nullopt;
|
||||
std::optional<Cell> result;
|
||||
std::optional<SizedHeightfieldShape> result;
|
||||
for (const auto& tilePosition : object->second)
|
||||
{
|
||||
const auto tiles = mTiles.lock();
|
||||
|
|
|
@ -80,10 +80,9 @@ namespace DetourNavigator
|
|||
|
||||
std::optional<Water> removeWater(const osg::Vec2i& cellPosition);
|
||||
|
||||
bool addHeightfield(const osg::Vec2i& cellPosition, int cellSize, const osg::Vec3f& shift,
|
||||
const HeightfieldShape& shape);
|
||||
bool addHeightfield(const osg::Vec2i& cellPosition, int cellSize, const HeightfieldShape& shape);
|
||||
|
||||
std::optional<Cell> removeHeightfield(const osg::Vec2i& cellPosition);
|
||||
std::optional<SizedHeightfieldShape> removeHeightfield(const osg::Vec2i& cellPosition);
|
||||
|
||||
std::shared_ptr<RecastMesh> getMesh(const TilePosition& tilePosition) const;
|
||||
|
||||
|
|
Loading…
Reference in a new issue