1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-02-28 16:09:43 +00:00

Simplify adding water to recast mesh

Remove redundant computations and conversions.
This commit is contained in:
elsid 2021-07-16 00:09:05 +02:00
parent 5d6c93566d
commit 24b802b3d8
No known key found for this signature in database
GPG key ID: B845CB9FEE18AB40
2 changed files with 46 additions and 53 deletions

View file

@ -28,32 +28,35 @@ namespace
{ {
using namespace DetourNavigator; using namespace DetourNavigator;
struct WaterBounds struct Rectangle
{ {
osg::Vec3f mMin; TileBounds mBounds;
osg::Vec3f mMax; float mHeight;
}; };
WaterBounds getWaterBounds(const Cell& water, const Settings& settings, Rectangle getSwimRectangle(const Cell& water, const Settings& settings,
const osg::Vec3f& agentHalfExtents) const osg::Vec3f& agentHalfExtents)
{ {
if (water.mSize == std::numeric_limits<int>::max()) if (water.mSize == std::numeric_limits<int>::max())
{ {
const auto transform = getSwimLevelTransform(settings, water.mShift, agentHalfExtents.z()); return Rectangle {
const auto min = toNavMeshCoordinates(settings, Misc::Convert::makeOsgVec3f(transform(btVector3(-1, -1, 0)))); TileBounds {
const auto max = toNavMeshCoordinates(settings, Misc::Convert::makeOsgVec3f(transform(btVector3(1, 1, 0)))); osg::Vec2f(-std::numeric_limits<float>::max(), -std::numeric_limits<float>::max()),
return WaterBounds { osg::Vec2f(std::numeric_limits<float>::max(), std::numeric_limits<float>::max())
osg::Vec3f(-std::numeric_limits<float>::max(), min.y(), -std::numeric_limits<float>::max()), },
osg::Vec3f(std::numeric_limits<float>::max(), max.y(), std::numeric_limits<float>::max()) toNavMeshCoordinates(settings, getSwimLevel(settings, water.mShift.z(), agentHalfExtents.z()))
}; };
} }
else else
{ {
const auto transform = getSwimLevelTransform(settings, water.mShift, agentHalfExtents.z()); const osg::Vec2f shift(water.mShift.x(), water.mShift.y());
const auto halfCellSize = water.mSize / 2.0f; const float halfCellSize = water.mSize / 2.0f;
return WaterBounds { return Rectangle {
toNavMeshCoordinates(settings, Misc::Convert::makeOsgVec3f(transform(btVector3(-halfCellSize, -halfCellSize, 0)))), TileBounds{
toNavMeshCoordinates(settings, Misc::Convert::makeOsgVec3f(transform(btVector3(halfCellSize, halfCellSize, 0)))) toNavMeshCoordinates(settings, shift + osg::Vec2f(-halfCellSize, -halfCellSize)),
toNavMeshCoordinates(settings, shift + osg::Vec2f(halfCellSize, halfCellSize))
},
toNavMeshCoordinates(settings, getSwimLevel(settings, water.mShift.z(), agentHalfExtents.z()))
}; };
} }
} }
@ -192,49 +195,43 @@ namespace
); );
} }
void rasterizeWaterTriangles(rcContext& context, const osg::Vec3f& agentHalfExtents, const RecastMesh& recastMesh, void rasterizeWaterTriangles(rcContext& context, const osg::Vec3f& agentHalfExtents, const std::vector<Cell>& cells,
const Settings& settings, const rcConfig& config, rcHeightfield& solid) const Settings& settings, const rcConfig& config, rcHeightfield& solid)
{ {
const std::array<unsigned char, 2> areas {{AreaType_water, AreaType_water}}; const std::array<unsigned char, 2> areas {{AreaType_water, AreaType_water}};
for (const auto& water : recastMesh.getWater()) for (const Cell& cell : cells)
{ {
const auto bounds = getWaterBounds(water, settings, agentHalfExtents); const auto rectangle = getSwimRectangle(cell, settings, agentHalfExtents);
const osg::Vec2f tileBoundsMin( const osg::Vec2f tileBoundsMin(
std::min(config.bmax[0], std::max(config.bmin[0], bounds.mMin.x())), std::min(config.bmax[0], std::max(config.bmin[0], rectangle.mBounds.mMin.x())),
std::min(config.bmax[2], std::max(config.bmin[2], bounds.mMin.z())) std::min(config.bmax[2], std::max(config.bmin[2], rectangle.mBounds.mMin.y()))
); );
const osg::Vec2f tileBoundsMax( const osg::Vec2f tileBoundsMax(
std::min(config.bmax[0], std::max(config.bmin[0], bounds.mMax.x())), std::min(config.bmax[0], std::max(config.bmin[0], rectangle.mBounds.mMax.x())),
std::min(config.bmax[2], std::max(config.bmin[2], bounds.mMax.z())) std::min(config.bmax[2], std::max(config.bmin[2], rectangle.mBounds.mMax.y()))
); );
if (tileBoundsMax == tileBoundsMin) if (tileBoundsMax == tileBoundsMin)
continue; continue;
const std::array<osg::Vec3f, 4> vertices {{ const std::array vertices {
osg::Vec3f(tileBoundsMin.x(), bounds.mMin.y(), tileBoundsMin.y()), tileBoundsMin.x(), rectangle.mHeight, tileBoundsMin.y(),
osg::Vec3f(tileBoundsMin.x(), bounds.mMin.y(), tileBoundsMax.y()), tileBoundsMin.x(), rectangle.mHeight, tileBoundsMax.y(),
osg::Vec3f(tileBoundsMax.x(), bounds.mMin.y(), tileBoundsMax.y()), tileBoundsMax.x(), rectangle.mHeight, tileBoundsMax.y(),
osg::Vec3f(tileBoundsMax.x(), bounds.mMin.y(), tileBoundsMin.y()), tileBoundsMax.x(), rectangle.mHeight, tileBoundsMin.y(),
}}; };
std::array<float, 4 * 3> convertedVertices; const std::array indices {
auto convertedVerticesIt = convertedVertices.begin();
for (const auto& vertex : vertices)
convertedVerticesIt = std::copy(vertex.ptr(), vertex.ptr() + 3, convertedVerticesIt);
const std::array<int, 6> indices {{
0, 1, 2, 0, 1, 2,
0, 2, 3, 0, 2, 3,
}}; };
const auto trianglesRasterized = rcRasterizeTriangles( const auto trianglesRasterized = rcRasterizeTriangles(
&context, &context,
convertedVertices.data(), vertices.data(),
static_cast<int>(convertedVertices.size() / 3), static_cast<int>(vertices.size() / 3),
indices.data(), indices.data(),
areas.data(), areas.data(),
static_cast<int>(areas.size()), static_cast<int>(areas.size()),
@ -253,7 +250,7 @@ namespace
if (!rasterizeTriangles(context, recastMesh.getMesh(), settings, 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.getWater(), settings, config, solid);
return true; return true;
} }
@ -504,9 +501,9 @@ namespace DetourNavigator
for (const auto& water : recastMesh->getWater()) for (const auto& water : recastMesh->getWater())
{ {
const auto waterBounds = getWaterBounds(water, settings, agentHalfExtents); const float height = toNavMeshCoordinates(settings, getSwimLevel(settings, water.mShift.z(), agentHalfExtents.z()));
recastMeshBounds.mMin.y() = std::min(recastMeshBounds.mMin.y(), waterBounds.mMin.y()); recastMeshBounds.mMin.y() = std::min(recastMeshBounds.mMin.y(), height);
recastMeshBounds.mMax.y() = std::max(recastMeshBounds.mMax.y(), waterBounds.mMax.y()); recastMeshBounds.mMax.y() = std::max(recastMeshBounds.mMax.y(), height);
} }
if (isEmpty(recastMeshBounds)) if (isEmpty(recastMeshBounds))

View file

@ -37,6 +37,11 @@ namespace DetourNavigator
return value * settings.mRecastScaleFactor; return value * settings.mRecastScaleFactor;
} }
inline osg::Vec2f toNavMeshCoordinates(const Settings& settings, osg::Vec2f position)
{
return position * settings.mRecastScaleFactor;
}
inline osg::Vec3f toNavMeshCoordinates(const Settings& settings, osg::Vec3f position) inline osg::Vec3f toNavMeshCoordinates(const Settings& settings, osg::Vec3f position)
{ {
std::swap(position.y(), position.z()); std::swap(position.y(), position.z());
@ -77,18 +82,9 @@ namespace DetourNavigator
return static_cast<float>(settings.mBorderSize) * settings.mCellSize; return static_cast<float>(settings.mBorderSize) * settings.mCellSize;
} }
inline float getSwimLevel(const Settings& settings, const float agentHalfExtentsZ) inline float getSwimLevel(const Settings& settings, const float waterLevel, const float agentHalfExtentsZ)
{ {
return - settings.mSwimHeightScale * agentHalfExtentsZ; return waterLevel - settings.mSwimHeightScale * agentHalfExtentsZ - agentHalfExtentsZ;;
}
inline btTransform getSwimLevelTransform(const Settings& settings, const osg::Vec3f& shift,
const float agentHalfExtentsZ)
{
return btTransform(
btMatrix3x3::getIdentity(),
btVector3(shift.x(), shift.y(), shift.z() + getSwimLevel(settings, agentHalfExtentsZ) - agentHalfExtentsZ)
);
} }
inline float getRealTileSize(const Settings& settings) inline float getRealTileSize(const Settings& settings)