2018-03-13 22:49:08 +00:00
|
|
|
#include "recastmeshbuilder.hpp"
|
2018-04-02 21:04:19 +00:00
|
|
|
#include "debug.hpp"
|
|
|
|
#include "exceptions.hpp"
|
2018-03-13 22:49:08 +00:00
|
|
|
|
2019-11-29 20:17:52 +00:00
|
|
|
#include <components/bullethelpers/transformboundingbox.hpp>
|
2018-03-13 22:49:08 +00:00
|
|
|
#include <components/bullethelpers/processtrianglecallback.hpp>
|
2019-02-28 20:03:42 +00:00
|
|
|
#include <components/misc/convert.hpp>
|
2021-07-16 18:19:11 +00:00
|
|
|
#include <components/debug/debuglog.hpp>
|
2018-03-13 22:49:08 +00:00
|
|
|
|
2018-04-07 20:09:42 +00:00
|
|
|
#include <BulletCollision/CollisionShapes/btBoxShape.h>
|
2018-04-02 21:04:19 +00:00
|
|
|
#include <BulletCollision/CollisionShapes/btCompoundShape.h>
|
2018-03-13 22:49:08 +00:00
|
|
|
#include <BulletCollision/CollisionShapes/btConcaveShape.h>
|
2018-04-02 21:04:19 +00:00
|
|
|
#include <BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h>
|
2018-04-07 20:09:42 +00:00
|
|
|
#include <LinearMath/btTransform.h>
|
2019-11-29 20:17:52 +00:00
|
|
|
#include <LinearMath/btAabbUtil2.h>
|
2018-04-07 20:09:42 +00:00
|
|
|
|
|
|
|
#include <algorithm>
|
2020-10-24 23:34:04 +00:00
|
|
|
#include <cassert>
|
2021-05-04 10:47:11 +00:00
|
|
|
#include <array>
|
2021-07-11 19:43:19 +00:00
|
|
|
#include <vector>
|
2018-03-13 22:49:08 +00:00
|
|
|
|
|
|
|
namespace DetourNavigator
|
|
|
|
{
|
|
|
|
using BulletHelpers::makeProcessTriangleCallback;
|
|
|
|
|
2020-06-15 21:53:22 +00:00
|
|
|
namespace
|
|
|
|
{
|
2021-07-16 18:19:11 +00:00
|
|
|
RecastMeshTriangle makeRecastMeshTriangle(const btVector3* vertices, const AreaType areaType)
|
2020-06-15 21:53:22 +00:00
|
|
|
{
|
2021-07-11 19:43:19 +00:00
|
|
|
RecastMeshTriangle result;
|
|
|
|
result.mAreaType = areaType;
|
|
|
|
for (std::size_t i = 0; i < 3; ++i)
|
2021-07-16 18:19:11 +00:00
|
|
|
result.mVertices[i] = Misc::Convert::makeOsgVec3f(vertices[i]);
|
2021-07-11 19:43:19 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Mesh makeMesh(std::vector<RecastMeshTriangle>&& triangles)
|
|
|
|
{
|
|
|
|
std::vector<osg::Vec3f> uniqueVertices;
|
|
|
|
uniqueVertices.reserve(3 * triangles.size());
|
|
|
|
|
|
|
|
for (const RecastMeshTriangle& v : triangles)
|
|
|
|
for (const osg::Vec3f& v : v.mVertices)
|
|
|
|
uniqueVertices.push_back(v);
|
2020-06-15 21:53:22 +00:00
|
|
|
|
2021-07-11 19:43:19 +00:00
|
|
|
std::sort(uniqueVertices.begin(), uniqueVertices.end());
|
|
|
|
uniqueVertices.erase(std::unique(uniqueVertices.begin(), uniqueVertices.end()), uniqueVertices.end());
|
2020-06-15 21:53:22 +00:00
|
|
|
|
2021-07-11 19:43:19 +00:00
|
|
|
std::vector<int> indices;
|
|
|
|
indices.reserve(3 * triangles.size());
|
|
|
|
std::vector<AreaType> areaTypes;
|
|
|
|
areaTypes.reserve(triangles.size());
|
2020-06-15 21:53:22 +00:00
|
|
|
|
2021-07-11 19:43:19 +00:00
|
|
|
for (const RecastMeshTriangle& v : triangles)
|
|
|
|
{
|
|
|
|
areaTypes.push_back(v.mAreaType);
|
2020-06-15 21:53:22 +00:00
|
|
|
|
2021-07-11 19:43:19 +00:00
|
|
|
for (const osg::Vec3f& v : v.mVertices)
|
2020-06-15 21:53:22 +00:00
|
|
|
{
|
2021-07-11 19:43:19 +00:00
|
|
|
const auto it = std::lower_bound(uniqueVertices.begin(), uniqueVertices.end(), v);
|
2020-06-15 21:53:22 +00:00
|
|
|
assert(it != uniqueVertices.end());
|
2021-07-11 19:43:19 +00:00
|
|
|
assert(*it == v);
|
|
|
|
indices.push_back(static_cast<int>(it - uniqueVertices.begin()));
|
2020-06-15 21:53:22 +00:00
|
|
|
}
|
2021-07-11 19:43:19 +00:00
|
|
|
}
|
2020-06-15 21:53:22 +00:00
|
|
|
|
2021-07-11 19:43:19 +00:00
|
|
|
triangles.clear();
|
2020-06-15 21:53:22 +00:00
|
|
|
|
2021-07-11 19:43:19 +00:00
|
|
|
std::vector<float> vertices;
|
|
|
|
vertices.reserve(3 * uniqueVertices.size());
|
|
|
|
|
|
|
|
for (const osg::Vec3f& v : uniqueVertices)
|
|
|
|
{
|
|
|
|
vertices.push_back(v.x());
|
|
|
|
vertices.push_back(v.y());
|
|
|
|
vertices.push_back(v.z());
|
2020-06-15 21:53:22 +00:00
|
|
|
}
|
2021-07-11 19:43:19 +00:00
|
|
|
|
|
|
|
return Mesh(std::move(indices), std::move(vertices), std::move(areaTypes));
|
2020-06-15 21:53:22 +00:00
|
|
|
}
|
|
|
|
|
2021-07-16 18:19:11 +00:00
|
|
|
RecastMeshBuilder::RecastMeshBuilder(const TileBounds& bounds) noexcept
|
|
|
|
: mBounds(bounds)
|
2018-04-15 22:07:18 +00:00
|
|
|
{
|
|
|
|
}
|
2018-04-02 21:04:19 +00:00
|
|
|
|
2018-07-12 08:44:11 +00:00
|
|
|
void RecastMeshBuilder::addObject(const btCollisionShape& shape, const btTransform& transform,
|
2018-07-18 19:09:50 +00:00
|
|
|
const AreaType areaType)
|
2018-04-02 21:04:19 +00:00
|
|
|
{
|
|
|
|
if (shape.isCompound())
|
2018-07-18 19:09:50 +00:00
|
|
|
return addObject(static_cast<const btCompoundShape&>(shape), transform, areaType);
|
2018-04-02 21:04:19 +00:00
|
|
|
else if (shape.getShapeType() == TERRAIN_SHAPE_PROXYTYPE)
|
2018-07-18 19:09:50 +00:00
|
|
|
return addObject(static_cast<const btHeightfieldTerrainShape&>(shape), transform, areaType);
|
2018-04-02 21:04:19 +00:00
|
|
|
else if (shape.isConcave())
|
2018-07-18 19:09:50 +00:00
|
|
|
return addObject(static_cast<const btConcaveShape&>(shape), transform, areaType);
|
2018-04-07 20:09:42 +00:00
|
|
|
else if (shape.getShapeType() == BOX_SHAPE_PROXYTYPE)
|
2018-07-18 19:09:50 +00:00
|
|
|
return addObject(static_cast<const btBoxShape&>(shape), transform, areaType);
|
2018-04-02 21:04:19 +00:00
|
|
|
std::ostringstream message;
|
|
|
|
message << "Unsupported shape type: " << BroadphaseNativeTypes(shape.getShapeType());
|
|
|
|
throw InvalidArgument(message.str());
|
|
|
|
}
|
|
|
|
|
2018-07-12 08:44:11 +00:00
|
|
|
void RecastMeshBuilder::addObject(const btCompoundShape& shape, const btTransform& transform,
|
2018-07-18 19:09:50 +00:00
|
|
|
const AreaType areaType)
|
2018-03-13 22:49:08 +00:00
|
|
|
{
|
2018-04-02 21:04:19 +00:00
|
|
|
for (int i = 0, num = shape.getNumChildShapes(); i < num; ++i)
|
2018-07-18 19:09:50 +00:00
|
|
|
addObject(*shape.getChildShape(i), transform * shape.getChildTransform(i), areaType);
|
2018-03-13 22:49:08 +00:00
|
|
|
}
|
|
|
|
|
2018-07-12 08:44:11 +00:00
|
|
|
void RecastMeshBuilder::addObject(const btConcaveShape& shape, const btTransform& transform,
|
2018-07-18 19:09:50 +00:00
|
|
|
const AreaType areaType)
|
2018-03-13 22:49:08 +00:00
|
|
|
{
|
2021-07-11 19:43:19 +00:00
|
|
|
return addObject(shape, transform, makeProcessTriangleCallback([&] (btVector3* vertices, int, int)
|
2018-03-13 22:49:08 +00:00
|
|
|
{
|
2021-07-16 18:19:11 +00:00
|
|
|
RecastMeshTriangle triangle = makeRecastMeshTriangle(vertices, areaType);
|
2021-07-11 19:43:19 +00:00
|
|
|
std::reverse(triangle.mVertices.begin(), triangle.mVertices.end());
|
|
|
|
mTriangles.emplace_back(triangle);
|
2018-03-13 22:49:08 +00:00
|
|
|
}));
|
|
|
|
}
|
|
|
|
|
2018-07-12 08:44:11 +00:00
|
|
|
void RecastMeshBuilder::addObject(const btHeightfieldTerrainShape& shape, const btTransform& transform,
|
2018-07-18 19:09:50 +00:00
|
|
|
const AreaType areaType)
|
2018-03-13 22:49:08 +00:00
|
|
|
{
|
2021-07-11 19:43:19 +00:00
|
|
|
return addObject(shape, transform, makeProcessTriangleCallback([&] (btVector3* vertices, int, int)
|
2018-03-13 22:49:08 +00:00
|
|
|
{
|
2021-07-16 18:19:11 +00:00
|
|
|
mTriangles.emplace_back(makeRecastMeshTriangle(vertices, areaType));
|
2018-03-13 22:49:08 +00:00
|
|
|
}));
|
|
|
|
}
|
|
|
|
|
2018-07-18 19:09:50 +00:00
|
|
|
void RecastMeshBuilder::addObject(const btBoxShape& shape, const btTransform& transform, const AreaType areaType)
|
2018-04-07 20:09:42 +00:00
|
|
|
{
|
2021-07-11 19:43:19 +00:00
|
|
|
constexpr std::array<int, 36> indices {{
|
2018-04-07 20:09:42 +00:00
|
|
|
0, 2, 3,
|
|
|
|
3, 1, 0,
|
|
|
|
0, 4, 6,
|
|
|
|
6, 2, 0,
|
|
|
|
0, 1, 5,
|
|
|
|
5, 4, 0,
|
|
|
|
7, 5, 1,
|
|
|
|
1, 3, 7,
|
|
|
|
7, 3, 2,
|
|
|
|
2, 6, 7,
|
|
|
|
7, 6, 4,
|
|
|
|
4, 5, 7,
|
|
|
|
}};
|
|
|
|
|
2021-07-11 19:43:19 +00:00
|
|
|
for (std::size_t i = 0; i < indices.size(); i += 3)
|
|
|
|
{
|
|
|
|
std::array<btVector3, 3> vertices;
|
|
|
|
for (std::size_t j = 0; j < 3; ++j)
|
|
|
|
{
|
|
|
|
btVector3 position;
|
|
|
|
shape.getVertex(indices[i + j], position);
|
|
|
|
vertices[j] = transform(position);
|
|
|
|
}
|
2021-07-16 18:19:11 +00:00
|
|
|
mTriangles.emplace_back(makeRecastMeshTriangle(vertices.data(), areaType));
|
2021-07-11 19:43:19 +00:00
|
|
|
}
|
2018-07-20 19:11:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void RecastMeshBuilder::addWater(const int cellSize, const btTransform& transform)
|
|
|
|
{
|
2021-07-14 15:30:47 +00:00
|
|
|
mWater.push_back(Water {cellSize, transform});
|
2018-04-07 20:09:42 +00:00
|
|
|
}
|
|
|
|
|
2021-07-03 00:59:07 +00:00
|
|
|
std::shared_ptr<RecastMesh> RecastMeshBuilder::create(std::size_t generation, std::size_t revision) &&
|
2018-03-13 22:49:08 +00:00
|
|
|
{
|
2021-07-11 19:43:19 +00:00
|
|
|
std::sort(mTriangles.begin(), mTriangles.end());
|
2021-02-03 23:14:29 +00:00
|
|
|
std::sort(mWater.begin(), mWater.end());
|
2021-07-11 19:43:19 +00:00
|
|
|
Mesh mesh = makeMesh(std::move(mTriangles));
|
|
|
|
return std::make_shared<RecastMesh>(generation, revision, std::move(mesh), std::move(mWater));
|
2018-03-13 22:49:08 +00:00
|
|
|
}
|
|
|
|
|
2018-04-15 22:07:18 +00:00
|
|
|
void RecastMeshBuilder::addObject(const btConcaveShape& shape, const btTransform& transform,
|
|
|
|
btTriangleCallback&& callback)
|
2018-03-13 22:49:08 +00:00
|
|
|
{
|
|
|
|
btVector3 aabbMin;
|
|
|
|
btVector3 aabbMax;
|
2018-10-28 13:54:47 +00:00
|
|
|
|
2018-03-13 22:49:08 +00:00
|
|
|
shape.getAabb(btTransform::getIdentity(), aabbMin, aabbMax);
|
2018-10-28 13:54:47 +00:00
|
|
|
|
2019-11-29 20:17:52 +00:00
|
|
|
const btVector3 boundsMin(mBounds.mMin.x(), mBounds.mMin.y(),
|
|
|
|
-std::numeric_limits<btScalar>::max() * std::numeric_limits<btScalar>::epsilon());
|
|
|
|
const btVector3 boundsMax(mBounds.mMax.x(), mBounds.mMax.y(),
|
|
|
|
std::numeric_limits<btScalar>::max() * std::numeric_limits<btScalar>::epsilon());
|
|
|
|
|
|
|
|
auto wrapper = makeProcessTriangleCallback([&] (btVector3* triangle, int partId, int triangleIndex)
|
|
|
|
{
|
|
|
|
std::array<btVector3, 3> 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);
|
2018-10-28 13:54:47 +00:00
|
|
|
|
2018-11-25 08:42:26 +00:00
|
|
|
aabbMin.setX(std::max(static_cast<btScalar>(mBounds.mMin.x()), aabbMin.x()));
|
|
|
|
aabbMin.setX(std::min(static_cast<btScalar>(mBounds.mMax.x()), aabbMin.x()));
|
|
|
|
aabbMin.setY(std::max(static_cast<btScalar>(mBounds.mMin.y()), aabbMin.y()));
|
|
|
|
aabbMin.setY(std::min(static_cast<btScalar>(mBounds.mMax.y()), aabbMin.y()));
|
|
|
|
|
|
|
|
aabbMax.setX(std::max(static_cast<btScalar>(mBounds.mMin.x()), aabbMax.x()));
|
|
|
|
aabbMax.setX(std::min(static_cast<btScalar>(mBounds.mMax.x()), aabbMax.x()));
|
|
|
|
aabbMax.setY(std::max(static_cast<btScalar>(mBounds.mMin.y()), aabbMax.y()));
|
|
|
|
aabbMax.setY(std::min(static_cast<btScalar>(mBounds.mMax.y()), aabbMax.y()));
|
2018-10-28 13:54:47 +00:00
|
|
|
|
2019-11-29 20:17:52 +00:00
|
|
|
transformBoundingBox(transform.inverse(), aabbMin, aabbMax);
|
2018-10-28 13:54:47 +00:00
|
|
|
|
2019-11-29 20:17:52 +00:00
|
|
|
auto wrapper = makeProcessTriangleCallback([&] (btVector3* triangle, int partId, int triangleIndex)
|
|
|
|
{
|
|
|
|
std::array<btVector3, 3> transformed;
|
|
|
|
for (std::size_t i = 0; i < 3; ++i)
|
|
|
|
transformed[i] = transform(triangle[i]);
|
|
|
|
callback.processTriangle(transformed.data(), partId, triangleIndex);
|
|
|
|
});
|
2018-10-28 13:54:47 +00:00
|
|
|
|
2019-11-29 20:17:52 +00:00
|
|
|
shape.processAllTriangles(&wrapper, aabbMin, aabbMax);
|
2018-03-13 22:49:08 +00:00
|
|
|
}
|
|
|
|
}
|