Skip to content

Commit fadd164

Browse files
MeshShape: adopt TriMesh internal representation (issue #453) (#2325)
Co-authored-by: Jeongseok Lee <[email protected]>
1 parent cfa3d66 commit fadd164

File tree

72 files changed

+4056
-1116
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

72 files changed

+4056
-1116
lines changed

.github/workflows/publish_dartpy.yml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,15 +98,16 @@ jobs:
9898
uses: mozilla-actions/[email protected]
9999
with:
100100
disable_annotations: true
101-
# Enable only when GitHub cache backend is available; otherwise skip.
102-
use-gha-cache: ${{ env.ACTIONS_CACHE_URL != '' }}
103101

104102
- name: Configure environment for compiler cache
105103
if: (matrix.skip-on-commit != true) || github.event_name == 'pull_request' || startsWith(github.ref, 'refs/tags/v')
106104
uses: ./.github/actions/configure-compiler-cache
107105

108106
- name: Build wheel
109107
if: (matrix.skip-on-commit != true) || github.event_name == 'pull_request' || startsWith(github.ref, 'refs/tags/v')
108+
env:
109+
# Work around occasional sccache spawn failures on ubuntu-latest + Python 3.14 wheel builds.
110+
DART_DISABLE_COMPILER_CACHE: ${{ (matrix.os == 'ubuntu-latest' && matrix.python-version == '314') && 'ON' || 'OFF' }}
110111
run: pixi run -e py${{ matrix.python-version }}-wheel wheel-build
111112

112113
- name: Repair wheel

AGENTS.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ This file is a pointer board for agents working in this repository. Keep it conc
55
## Read First
66

77
- Architectural, build, and workflow expectations live in `docs/onboarding` (start with `docs/onboarding/ci-cd.md` and `docs/onboarding/build-system.md`).
8-
- The day-to-day pixi workflow (install, config, build, test) is documented in `docs/onboarding/building.md`.
8+
- The day-to-day pixi workflow (install, config, build, lint, test) is documented in `docs/onboarding/building.md` and `docs/onboarding/testing.md`.
99
- Coding standards, formatting, and contribution flow are in `CONTRIBUTING.md`.
1010
- Feature‑specific notes belong beside the code (e.g., README in the component directory) or in `docs/`.
1111
- Unified model loading API (`dart::io`) is documented in `docs/onboarding/io-parsing.md`.

cmake/DARTFindDependencies.cmake

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,15 @@ if(DART_BUILD_GUI)
165165
${IMGUI_BACKEND_HEADERS}
166166
)
167167

168+
if(WIN32 AND BUILD_SHARED_LIBS)
169+
# ImGui does not export symbols by default; ensure an import library is
170+
# generated so dart-gui can link against dart-imgui-lib on Windows.
171+
set_target_properties(
172+
${imgui_library_name}
173+
PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON
174+
)
175+
endif()
176+
168177
# Configure include directories
169178
# Build tree: use fetched source directory
170179
# Install tree: use standard include paths (like system-installed imgui)

dart/collision/bullet/BulletCollisionDetector.cpp

Lines changed: 59 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@
6060
#include <algorithm>
6161
#include <vector>
6262

63+
#include <cmath>
64+
6365
namespace dart {
6466
namespace collision {
6567

@@ -91,17 +93,15 @@ std::unique_ptr<btCollisionShape> createBulletEllipsoidMesh(
9193
std::unique_ptr<btCollisionShape> createBulletEllipsoidMultiSphere(
9294
const Eigen::Vector3d& radii);
9395

94-
std::unique_ptr<btCollisionShape> createBulletCollisionShapeFromAssimpScene(
95-
const Eigen::Vector3d& scale, const aiScene* scene);
96-
97-
std::unique_ptr<btCollisionShape> createBulletCollisionShapeFromAssimpMesh(
98-
const aiMesh* mesh);
96+
std::unique_ptr<btCollisionShape> createBulletCollisionShapeFromTriMesh(
97+
const Eigen::Vector3d& scale,
98+
const std::shared_ptr<math::TriMesh<double>>& mesh);
9999

100100
template <typename HeightmapShapeT>
101101
std::unique_ptr<BulletCollisionShape> createBulletCollisionShapeFromHeightmap(
102102
const HeightmapShapeT* heightMap);
103103

104-
bool isConvex(const aiMesh* mesh, float threshold = 0.001);
104+
bool isConvex(const math::TriMesh<double>& mesh, float threshold = 0.001f);
105105

106106
} // anonymous namespace
107107

@@ -649,17 +649,19 @@ BulletCollisionDetector::createBulletCollisionShape(
649649
std::move(bulletCollisionShape));
650650
} else if (const auto shapeMesh = shape->as<MeshShape>()) {
651651
const auto scale = shapeMesh->getScale();
652-
const auto mesh = shapeMesh->getMesh();
652+
const auto triMesh = shapeMesh->getTriMesh();
653653

654654
auto bulletCollisionShape
655-
= createBulletCollisionShapeFromAssimpScene(scale, mesh);
655+
= createBulletCollisionShapeFromTriMesh(scale, triMesh);
656656

657657
return std::make_unique<BulletCollisionShape>(
658658
std::move(bulletCollisionShape));
659659
} else if (const auto softMeshShape = shape->as<SoftMeshShape>()) {
660-
const auto mesh = softMeshShape->getAssimpMesh();
660+
const auto triMesh = softMeshShape->getTriMesh();
661+
const Eigen::Vector3d scale = Eigen::Vector3d::Ones();
661662

662-
auto bulletCollisionShape = createBulletCollisionShapeFromAssimpMesh(mesh);
663+
auto bulletCollisionShape
664+
= createBulletCollisionShapeFromTriMesh(scale, triMesh);
663665

664666
return std::make_unique<BulletCollisionShape>(
665667
std::move(bulletCollisionShape));
@@ -1015,62 +1017,40 @@ std::unique_ptr<btCollisionShape> createBulletEllipsoidMultiSphere(
10151017
}
10161018

10171019
//==============================================================================
1018-
std::unique_ptr<btCollisionShape> createBulletCollisionShapeFromAssimpScene(
1019-
const Eigen::Vector3d& scale, const aiScene* scene)
1020+
std::unique_ptr<btCollisionShape> createBulletCollisionShapeFromTriMesh(
1021+
const Eigen::Vector3d& scale,
1022+
const std::shared_ptr<math::TriMesh<double>>& mesh)
10201023
{
1021-
auto triMesh = new btTriangleMesh();
1022-
1023-
for (auto i = 0u; i < scene->mNumMeshes; ++i) {
1024-
for (auto j = 0u; j < scene->mMeshes[i]->mNumFaces; ++j) {
1025-
btVector3 vertices[3];
1026-
for (auto k = 0u; k < 3; ++k) {
1027-
const aiVector3D& vertex
1028-
= scene->mMeshes[i]
1029-
->mVertices[scene->mMeshes[i]->mFaces[j].mIndices[k]];
1030-
vertices[k] = btVector3(
1031-
vertex.x * scale[0], vertex.y * scale[1], vertex.z * scale[2]);
1032-
}
1033-
triMesh->addTriangle(vertices[0], vertices[1], vertices[2]);
1034-
}
1035-
}
1036-
const bool makeConvexMesh
1037-
= scene->mNumMeshes == 1 && isConvex(scene->mMeshes[0]);
1038-
if (makeConvexMesh) {
1039-
auto convexMeshShape = std::make_unique<btConvexTriangleMeshShape>(triMesh);
1040-
convexMeshShape->setMargin(0.0f);
1041-
convexMeshShape->setUserPointer(triMesh);
1042-
return convexMeshShape;
1043-
} else {
1044-
auto gimpactMeshShape = std::make_unique<btGImpactMeshShape>(triMesh);
1045-
gimpactMeshShape->updateBound();
1046-
gimpactMeshShape->setUserPointer(triMesh);
1047-
return gimpactMeshShape;
1024+
if (!mesh) {
1025+
return nullptr;
10481026
}
1049-
}
10501027

1051-
//==============================================================================
1052-
std::unique_ptr<btCollisionShape> createBulletCollisionShapeFromAssimpMesh(
1053-
const aiMesh* mesh)
1054-
{
10551028
auto triMesh = new btTriangleMesh();
10561029

1057-
for (auto i = 0u; i < mesh->mNumFaces; ++i) {
1058-
btVector3 vertices[3];
1059-
for (auto j = 0u; j < 3; ++j) {
1060-
const aiVector3D& vertex = mesh->mVertices[mesh->mFaces[i].mIndices[j]];
1061-
vertices[j] = btVector3(vertex.x, vertex.y, vertex.z);
1030+
const auto& vertices = mesh->getVertices();
1031+
const auto& triangles = mesh->getTriangles();
1032+
1033+
for (const auto& triangle : triangles) {
1034+
btVector3 btVertices[3];
1035+
for (auto k = 0u; k < 3; ++k) {
1036+
const auto& vertex = vertices[triangle[k]];
1037+
btVertices[k] = btVector3(
1038+
vertex.x() * scale[0], vertex.y() * scale[1], vertex.z() * scale[2]);
10621039
}
1063-
triMesh->addTriangle(vertices[0], vertices[1], vertices[2]);
1040+
triMesh->addTriangle(btVertices[0], btVertices[1], btVertices[2]);
10641041
}
10651042

1066-
const bool makeConvexMesh = isConvex(mesh);
1043+
const bool makeConvexMesh = isConvex(*mesh);
1044+
10671045
if (makeConvexMesh) {
10681046
auto convexMeshShape = std::make_unique<btConvexTriangleMeshShape>(triMesh);
10691047
convexMeshShape->setMargin(0.0f);
1048+
convexMeshShape->setUserPointer(triMesh);
10701049
return convexMeshShape;
10711050
} else {
10721051
auto gimpactMeshShape = std::make_unique<btGImpactMeshShape>(triMesh);
10731052
gimpactMeshShape->updateBound();
1053+
gimpactMeshShape->setUserPointer(triMesh);
10741054
return gimpactMeshShape;
10751055
}
10761056
}
@@ -1144,43 +1124,54 @@ std::unique_ptr<BulletCollisionShape> createBulletCollisionShapeFromHeightmap(
11441124
}
11451125

11461126
//==============================================================================
1147-
bool isConvex(const aiMesh* mesh, float threshold)
1127+
bool isConvex(const math::TriMesh<double>& mesh, float threshold)
11481128
{
1149-
// Check whether all the other vertices on the mesh is on the internal side of
1150-
// the face, assuming that the direction of the normal of the face is pointing
1151-
// external side.
1129+
// Check whether all the other vertices on the mesh are on the internal side
1130+
// of the face, assuming that the direction of the normal of the face is
1131+
// pointing to the external side.
11521132
//
11531133
// Reference: https://stackoverflow.com/a/40056279/3122234
1134+
const auto& points = mesh.getVertices();
1135+
const auto& triangles = mesh.getTriangles();
1136+
1137+
if (points.empty() || triangles.empty()) {
1138+
return false;
1139+
}
11541140

1155-
const auto points = mesh->mVertices;
11561141
btVector3 vertices[3];
1157-
for (auto i = 0u; i < mesh->mNumFaces; ++i) {
1142+
for (const auto& triangle : triangles) {
11581143
for (auto j = 0u; j < 3; ++j) {
1159-
const aiVector3D& vertex = mesh->mVertices[mesh->mFaces[i].mIndices[j]];
1160-
vertices[j] = btVector3(vertex.x, vertex.y, vertex.z);
1144+
const auto& vertex = points[triangle[j]];
1145+
vertices[j] = btVector3(vertex.x(), vertex.y(), vertex.z());
11611146
}
11621147
const btVector3& A = vertices[0];
11631148
const btVector3 B = vertices[1] - A;
11641149
const btVector3 C = vertices[2] - A;
11651150

1166-
const btVector3 BCNorm = B.cross(C).normalized();
1151+
const btVector3 BCNormRaw = B.cross(C);
1152+
const btScalar normSquared = BCNormRaw.length2();
1153+
if (normSquared <= btScalar(0.0)) {
1154+
continue;
1155+
}
1156+
const btVector3 BCNorm = BCNormRaw / btSqrt(normSquared);
11671157

1168-
const float checkPoint
1169-
= btVector3(
1170-
points[0].x - A.x(), points[0].y - A.y(), points[0].z - A.z())
1171-
.dot(BCNorm);
1158+
const float checkPoint = btVector3(
1159+
points[0].x() - A.x(),
1160+
points[0].y() - A.y(),
1161+
points[0].z() - A.z())
1162+
.dot(BCNorm);
11721163

1173-
for (auto j = 0u; j < mesh->mNumVertices; ++j) {
1174-
float dist
1175-
= btVector3(
1176-
points[j].x - A.x(), points[j].y - A.y(), points[j].z - A.z())
1164+
for (const auto& point : points) {
1165+
const float dist
1166+
= btVector3(point.x() - A.x(), point.y() - A.y(), point.z() - A.z())
11771167
.dot(BCNorm);
11781168
if ((std::abs(checkPoint) > threshold) && (std::abs(dist) > threshold)
11791169
&& (checkPoint * dist < 0.0f)) {
11801170
return false;
11811171
}
11821172
}
11831173
}
1174+
11841175
return true;
11851176
}
11861177

dart/collision/bullet/BulletCollisionDetector.hpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,6 @@
3838
#include <dart/collision/bullet/BulletCollisionShape.hpp>
3939
#include <dart/collision/bullet/BulletInclude.hpp>
4040

41-
#include <assimp/scene.h>
42-
4341
#include <unordered_map>
4442
#include <vector>
4543

dart/collision/fcl/CollisionShapes.hpp

Lines changed: 2 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -39,43 +39,13 @@
3939

4040
#include <dart/math/Constants.hpp>
4141

42-
#include <assimp/scene.h>
43-
4442
#include <cmath>
4543

4644
namespace dart {
4745
namespace collision {
4846

49-
template <class BV>
50-
::fcl::BVHModel<BV>* createMesh(
51-
double _scaleX,
52-
double _scaleY,
53-
double _scaleZ,
54-
const aiScene* _mesh,
55-
const dart::collision::fcl::Transform3& _transform)
56-
{
57-
DART_ASSERT(_mesh);
58-
::fcl::BVHModel<BV>* model = new ::fcl::BVHModel<BV>;
59-
model->beginModel();
60-
61-
for (unsigned int i = 0; i < _mesh->mNumMeshes; i++) {
62-
for (unsigned int j = 0; j < _mesh->mMeshes[i]->mNumFaces; j++) {
63-
dart::collision::fcl::Vector3 vertices[3];
64-
for (unsigned int k = 0; k < 3; k++) {
65-
const aiVector3D& vertex
66-
= _mesh->mMeshes[i]
67-
->mVertices[_mesh->mMeshes[i]->mFaces[j].mIndices[k]];
68-
vertices[k] = dart::collision::fcl::Vector3(
69-
vertex.x * _scaleX, vertex.y * _scaleY, vertex.z * _scaleZ);
70-
vertices[k] = dart::collision::fcl::transform(_transform, vertices[k]);
71-
}
72-
model->addTriangle(vertices[0], vertices[1], vertices[2]);
73-
}
74-
}
75-
76-
model->endModel();
77-
return model;
78-
}
47+
// Deprecated aiScene-based createMesh removed - use TriMesh-based alternatives
48+
// in FCLCollisionDetector instead
7949

8050
template <class BV>
8151
::fcl::BVHModel<BV>* createEllipsoid(

0 commit comments

Comments
 (0)