From 7ec5a20c64ae7ff10a8cd95ffa23619026931323 Mon Sep 17 00:00:00 2001 From: elsid Date: Fri, 29 Nov 2019 21:17:52 +0100 Subject: [PATCH] Filter recast mesh triangles by global bounding box Except heightfields to reduce slow down. --- .../detournavigator/recastmeshbuilder.cpp | 6 +- .../bullethelpers/transformboundingbox.hpp | 38 +++++++++++++ .../detournavigator/recastmeshbuilder.cpp | 57 +++++++++++++------ .../detournavigator/recastmeshbuilder.hpp | 2 + 4 files changed, 84 insertions(+), 19 deletions(-) create mode 100644 components/bullethelpers/transformboundingbox.hpp diff --git a/apps/openmw_test_suite/detournavigator/recastmeshbuilder.cpp b/apps/openmw_test_suite/detournavigator/recastmeshbuilder.cpp index 38b1ab3614..60b7549151 100644 --- a/apps/openmw_test_suite/detournavigator/recastmeshbuilder.cpp +++ b/apps/openmw_test_suite/detournavigator/recastmeshbuilder.cpp @@ -361,9 +361,9 @@ namespace ); const auto recastMesh = builder.create(); EXPECT_EQ(recastMesh->getVertices(), std::vector({ - 0.707107067108154296875, 0, -3.535533905029296875, - -0.70710659027099609375, 0, -3.535533905029296875, - 2.384185791015625e-07, 0, -4.24264049530029296875, + 1.41421353816986083984375, 0, 1.1920928955078125e-07, + -1.41421353816986083984375, 0, -1.1920928955078125e-07, + 1.1920928955078125e-07, 0, -1.41421353816986083984375, })); EXPECT_EQ(recastMesh->getIndices(), std::vector({0, 1, 2})); EXPECT_EQ(recastMesh->getAreaTypes(), std::vector({AreaType_ground})); diff --git a/components/bullethelpers/transformboundingbox.hpp b/components/bullethelpers/transformboundingbox.hpp new file mode 100644 index 0000000000..05632eec72 --- /dev/null +++ b/components/bullethelpers/transformboundingbox.hpp @@ -0,0 +1,38 @@ +#ifndef OPENMW_COMPONENTS_BULLETHELPERS_TRANSFORMBOUNDINGBOX_H +#define OPENMW_COMPONENTS_BULLETHELPERS_TRANSFORMBOUNDINGBOX_H + +#include +#include + +#include + +namespace BulletHelpers +{ + inline btVector3 min(const btVector3& a, const btVector3& b) + { + return btVector3(std::min(a.x(), b.x()), std::min(a.y(), b.y()), std::min(a.z(), b.z())); + } + + inline btVector3 max(const btVector3& a, const btVector3& b) + { + return btVector3(std::max(a.x(), b.x()), std::max(a.y(), b.y()), std::max(a.z(), b.z())); + } + + // http://dev.theomader.com/transform-bounding-boxes/ + inline void transformBoundingBox(const btTransform& transform, btVector3& aabbMin, btVector3& aabbMax) + { + const btVector3 xa(transform.getBasis().getColumn(0) * aabbMin.x()); + const btVector3 xb(transform.getBasis().getColumn(0) * aabbMax.x()); + + const btVector3 ya(transform.getBasis().getColumn(1) * aabbMin.y()); + const btVector3 yb(transform.getBasis().getColumn(1) * aabbMax.y()); + + const btVector3 za(transform.getBasis().getColumn(2) * aabbMin.z()); + const btVector3 zb(transform.getBasis().getColumn(2) * aabbMax.z()); + + aabbMin = min(xa, xb) + min(ya, yb) + min(za, zb) + transform.getOrigin(); + aabbMax = max(xa, xb) + max(ya, yb) + max(za, zb) + transform.getOrigin(); + } +} + +#endif diff --git a/components/detournavigator/recastmeshbuilder.cpp b/components/detournavigator/recastmeshbuilder.cpp index 71c4f04051..5d8a07055f 100644 --- a/components/detournavigator/recastmeshbuilder.cpp +++ b/components/detournavigator/recastmeshbuilder.cpp @@ -5,6 +5,7 @@ #include "settingsutils.hpp" #include "exceptions.hpp" +#include #include #include @@ -13,6 +14,7 @@ #include #include #include +#include #include @@ -57,7 +59,7 @@ namespace DetourNavigator return addObject(shape, transform, makeProcessTriangleCallback([&] (btVector3* triangle, int, int) { for (std::size_t i = 3; i > 0; --i) - addTriangleVertex(transform(triangle[i - 1])); + addTriangleVertex(triangle[i - 1]); mAreaTypes.push_back(areaType); })); } @@ -68,7 +70,7 @@ namespace DetourNavigator return addObject(shape, transform, makeProcessTriangleCallback([&] (btVector3* triangle, int, int) { for (std::size_t i = 0; i < 3; ++i) - addTriangleVertex(transform(triangle[i])); + addTriangleVertex(triangle[i]); mAreaTypes.push_back(areaType); })); } @@ -131,8 +133,34 @@ namespace DetourNavigator shape.getAabb(btTransform::getIdentity(), aabbMin, aabbMax); - aabbMin = transform(aabbMin); - aabbMax = transform(aabbMax); + const btVector3 boundsMin(mBounds.mMin.x(), mBounds.mMin.y(), + -std::numeric_limits::max() * std::numeric_limits::epsilon()); + const btVector3 boundsMax(mBounds.mMax.x(), mBounds.mMax.y(), + std::numeric_limits::max() * std::numeric_limits::epsilon()); + + auto wrapper = makeProcessTriangleCallback([&] (btVector3* triangle, int partId, int triangleIndex) + { + std::array transformed; + for (std::size_t i = 0; i < 3; ++i) + transformed[i] = transform(triangle[i]); + if (TestTriangleAgainstAabb2(transformed.data(), boundsMin, boundsMax)) + callback.processTriangle(transformed.data(), partId, triangleIndex); + }); + + shape.processAllTriangles(&wrapper, aabbMin, aabbMax); + } + + void RecastMeshBuilder::addObject(const btHeightfieldTerrainShape& shape, const btTransform& transform, + btTriangleCallback&& callback) + { + using BulletHelpers::transformBoundingBox; + + btVector3 aabbMin; + btVector3 aabbMax; + + shape.getAabb(btTransform::getIdentity(), aabbMin, aabbMax); + + transformBoundingBox(transform, aabbMin, aabbMax); aabbMin.setX(std::max(mBounds.mMin.x(), aabbMin.x())); aabbMin.setX(std::min(mBounds.mMax.x(), aabbMin.x())); @@ -144,20 +172,17 @@ namespace DetourNavigator aabbMax.setY(std::max(mBounds.mMin.y(), aabbMax.y())); aabbMax.setY(std::min(mBounds.mMax.y(), aabbMax.y())); - const auto inversedTransform = transform.inverse(); + transformBoundingBox(transform.inverse(), aabbMin, aabbMax); - aabbMin = inversedTransform(aabbMin); - aabbMax = inversedTransform(aabbMax); + auto wrapper = makeProcessTriangleCallback([&] (btVector3* triangle, int partId, int triangleIndex) + { + std::array transformed; + for (std::size_t i = 0; i < 3; ++i) + transformed[i] = transform(triangle[i]); + callback.processTriangle(transformed.data(), partId, triangleIndex); + }); - aabbMin.setX(std::min(aabbMin.x(), aabbMax.x())); - aabbMin.setY(std::min(aabbMin.y(), aabbMax.y())); - aabbMin.setZ(std::min(aabbMin.z(), aabbMax.z())); - - aabbMax.setX(std::max(aabbMin.x(), aabbMax.x())); - aabbMax.setY(std::max(aabbMin.y(), aabbMax.y())); - aabbMax.setZ(std::max(aabbMin.z(), aabbMax.z())); - - shape.processAllTriangles(&callback, aabbMin, aabbMax); + shape.processAllTriangles(&wrapper, aabbMin, aabbMax); } void RecastMeshBuilder::addTriangleVertex(const btVector3& worldPosition) diff --git a/components/detournavigator/recastmeshbuilder.hpp b/components/detournavigator/recastmeshbuilder.hpp index 2f9d0373db..070b9c67d1 100644 --- a/components/detournavigator/recastmeshbuilder.hpp +++ b/components/detournavigator/recastmeshbuilder.hpp @@ -48,6 +48,8 @@ namespace DetourNavigator void addObject(const btConcaveShape& shape, const btTransform& transform, btTriangleCallback&& callback); + void addObject(const btHeightfieldTerrainShape& shape, const btTransform& transform, btTriangleCallback&& callback); + void addTriangleVertex(const btVector3& worldPosition); void addVertex(const btVector3& worldPosition);