Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds new function in MeshManager for performing convex decomposition #585

Merged
merged 8 commits into from
Mar 14, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions graphics/include/gz/common/MeshManager.hh
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,21 @@ namespace gz
const Mesh *_m2, const int _operation,
const gz::math::Pose3d &_offset = gz::math::Pose3d::Zero);

/// \brief Perform convex decomposition on a submesh.
/// The submesh is decomposed into multiple convex submeshes. The output
/// submeshes contain vertices and indices but texture coordinates
/// not preserved.
iche033 marked this conversation as resolved.
Show resolved Hide resolved
/// \param[in] _subMesh Input submesh to decompose.
/// \param[in] _maxConvexHulls Maximum number of convex hull submeshes to
/// produce.
/// \param[in] _voxelResolution Voxel resolution to use. Higher value
/// produces more accurate shapes.
/// \return A vector of decomposed submeshes.
public: std::vector<SubMesh> ConvexDecomposition(
const common::SubMesh *_subMesh,
iche033 marked this conversation as resolved.
Show resolved Hide resolved
std::size_t _maxConvexHulls = 16u,
std::size_t _voxelResolution = 200000u);

/// \brief Converts a vector of polylines into a table of vertices and
/// a list of edges (each made of 2 points from the table of vertices.
/// \param[in] _polys the polylines
Expand Down
95 changes: 93 additions & 2 deletions graphics/src/MeshManager.cc
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,23 @@
*/

#include <sys/stat.h>
#include <string>

#include <cctype>
#include <cstdint>
#include <mutex>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <cctype>
#include <vector>

// Suppress warnings for VHACD
#pragma GCC diagnostic push
azeey marked this conversation as resolved.
Show resolved Hide resolved
#pragma GCC diagnostic ignored "-Wfloat-equal"
#pragma GCC diagnostic ignored "-Wswitch-default"
#pragma GCC diagnostic ignored "-Wunused-parameter"
#define ENABLE_VHACD_IMPLEMENTATION 1
#include "VHACD.h"
#pragma GCC diagnostic pop

#ifndef _WIN32
#include "gz/common/GTSMeshUtils.hh"
Expand Down Expand Up @@ -1648,3 +1660,82 @@
this->dataPtr->forceAssimp = true;
}
}

//////////////////////////////////////////////////
std::vector<SubMesh>
MeshManager::ConvexDecomposition(const SubMesh *_subMesh,
std::size_t _maxConvexHulls,
std::size_t _voxelResolution)
{
std::vector<SubMesh> decomposed;

if (!_subMesh)
return decomposed;

Check warning on line 1673 in graphics/src/MeshManager.cc

View check run for this annotation

Codecov / codecov/patch

graphics/src/MeshManager.cc#L1673

Added line #L1673 was not covered by tests

auto vertexCount = _subMesh->VertexCount();
auto indexCount = _subMesh->IndexCount();
auto triangleCount = indexCount / 3u;

float *points = new float[vertexCount * 3u];
iche033 marked this conversation as resolved.
Show resolved Hide resolved
for (std::size_t i = 0; i < vertexCount; ++i)
{
std::size_t idx = i * 3u;
points[idx] = _subMesh->Vertex(i).X();
points[idx + 1] = _subMesh->Vertex(i).Y();
points[idx + 2] = _subMesh->Vertex(i).Z();
}

uint32_t *indices = new uint32_t[indexCount];
iche033 marked this conversation as resolved.
Show resolved Hide resolved
for (std::size_t i = 0; i < indexCount; ++i)
{
indices[i] = _subMesh->Index(i);
}

VHACD::IVHACD *iface = VHACD::CreateVHACD_ASYNC();
VHACD::IVHACD::Parameters parameters;
parameters.m_maxConvexHulls = _maxConvexHulls;
parameters.m_resolution = _voxelResolution;
parameters.m_asyncACD = true;
iface->Compute(points, vertexCount, indices, triangleCount, parameters);
while (!iface->IsReady())
{
std::this_thread::sleep_for(std::chrono::nanoseconds(10000));
}
iche033 marked this conversation as resolved.
Show resolved Hide resolved

if (!iface->GetNConvexHulls())
return decomposed;

Check warning on line 1706 in graphics/src/MeshManager.cc

View check run for this annotation

Codecov / codecov/patch

graphics/src/MeshManager.cc#L1706

Added line #L1706 was not covered by tests
iche033 marked this conversation as resolved.
Show resolved Hide resolved

for (std::size_t n = 0; n < iface->GetNConvexHulls(); ++n)
{
VHACD::IVHACD::ConvexHull ch;
iface->GetConvexHull(n, ch);

SubMesh convexMesh;
for (std::size_t i = 0u; i < ch.m_points.size(); ++i)
{
const VHACD::Vertex &p = ch.m_points[i];
gz::math::Vector3d vertex(p.mX, p.mY, p.mZ);
convexMesh.AddVertex(vertex);

// add dummy normal
auto norm = vertex;
norm.Normalize();
azeey marked this conversation as resolved.
Show resolved Hide resolved
convexMesh.AddNormal(norm);
}

for (std::size_t i = 0u; i < ch.m_triangles.size(); ++i)
{
const VHACD::Triangle &tri = ch.m_triangles[i];
convexMesh.AddIndex(tri.mI0);
convexMesh.AddIndex(tri.mI1);
convexMesh.AddIndex(tri.mI2);
}
decomposed.push_back(convexMesh);
}

delete [] points;
delete [] indices;
iface->Release();

return decomposed;
}
46 changes: 46 additions & 0 deletions graphics/src/MeshManager_TEST.cc
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include "gz/common/config.hh"

#include "gz/common/testing/AutoLogFixture.hh"
#include "gz/common/testing/TestPaths.hh"

using namespace gz;

Expand Down Expand Up @@ -289,4 +290,49 @@ TEST_F(MeshManager, Remove)
mgr->RemoveAll();
EXPECT_FALSE(mgr->HasMesh("sphere"));
}

/////////////////////////////////////////////////
TEST_F(MeshManager, ConvexDecomposition)
{
auto mgr = common::MeshManager::Instance();
const common::Mesh *boxMesh = mgr->Load(
common::testing::TestFile("data", "box.dae"));

ASSERT_NE(nullptr, boxMesh);
EXPECT_EQ(1u, boxMesh->SubMeshCount());

std::size_t maxConvexHulls = 4;
std::size_t resolution = 1000;
auto decomposed = std::move(mgr->ConvexDecomposition(
boxMesh->SubMeshByIndex(0u).lock().get(), maxConvexHulls, resolution));

// Decomposing a box should just produce a box
EXPECT_EQ(1u, decomposed.size());
common::SubMesh &boxSubmesh = decomposed[0];
// A convex hull of a box should contain exactly 8 vertices
EXPECT_EQ(8u, boxSubmesh.VertexCount());
EXPECT_EQ(8u, boxSubmesh.NormalCount());
EXPECT_EQ(36u, boxSubmesh.IndexCount());

const common::Mesh *drillMesh = mgr->Load(
common::testing::TestFile("data", "cordless_drill",
"meshes", "cordless_drill.dae"));
ASSERT_NE(nullptr, drillMesh);
EXPECT_EQ(1u, drillMesh->SubMeshCount());
decomposed = std::move(mgr->ConvexDecomposition(
drillMesh->SubMeshByIndex(0u).lock().get(), maxConvexHulls, resolution));

// A drill should be decomposed into multiple submeshes
EXPECT_LT(1u, decomposed.size());
EXPECT_GE(maxConvexHulls, decomposed.size());
// Check submeshes are not empty
for (const auto &d : decomposed)
{
const common::SubMesh &drillSubmesh = d;
EXPECT_LT(3u, drillSubmesh.VertexCount());
EXPECT_EQ(drillSubmesh.VertexCount(), drillSubmesh.NormalCount());
EXPECT_LT(3u, drillSubmesh.IndexCount());
}
}

#endif
Loading
Loading