Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
paralelize mesh chunking
Browse files Browse the repository at this point in the history
malytomas committed Dec 12, 2023

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
1 parent 7a3a744 commit 1a232df
Showing 3 changed files with 123 additions and 43 deletions.
1 change: 1 addition & 0 deletions sources/include/cage-core/meshAlgorithms.h
Original file line number Diff line number Diff line change
@@ -109,6 +109,7 @@ namespace cage
struct CAGE_CORE_API MeshChunkingConfig
{
Real maxSurfaceArea;
bool parallelize = false;
};
CAGE_CORE_API Holder<PointerRange<Holder<Mesh>>> meshChunking(const Mesh *msh, const MeshChunkingConfig &config);

142 changes: 101 additions & 41 deletions sources/libcore/mesh/meshAlgorithms.cpp
Original file line number Diff line number Diff line change
@@ -1506,57 +1506,117 @@ namespace cage
return 2;
}

Aabb clippingBox(const Aabb &box, uint32 axis, Real pos, bool second = false)
{
const Vec3 c = box.center();
const Vec3 hs = box.size() * 0.6; // slightly larger box to avoid clipping due to floating point imprecisions
Aabb r = Aabb(c - hs, c + hs);
if (second)
r.a[axis] = pos;
else
r.b[axis] = pos;
return r;
}

std::vector<Holder<Mesh>> meshChunkingImpl(Holder<Mesh> mesh, const MeshChunkingConfig &config)
{
const Real myArea = meshSurfaceArea(+mesh);
if (myArea > config.maxSurfaceArea)
{
const Aabb myBox = mesh->boundingBox();
const uint32 a = boxLongestAxis(myBox);
Real bestSplitPosition = 0.5;
Real bestSplitScore = Real::Infinity();
for (Real position : { 0.3, 0.4, 0.45, 0.5, 0.55, 0.6, 0.7 })
struct Common : private Immovable
{
const Mesh *mesh = nullptr;
MeshChunkingConfig config;
Real myArea;
Aabb myBox;
uint32 axis = m;

Aabb clippingBox(Real position, bool second) const
{
Holder<Mesh> p = mesh->copy();
meshClip(+p, clippingBox(myBox, a, interpolate(myBox.a[a], myBox.b[a], position)));
const Real area = meshSurfaceArea(+p);
const Real score = abs(0.5 - area / myArea);
if (score < bestSplitScore)
{
bestSplitScore = score;
bestSplitPosition = position;
}
const Vec3 c = myBox.center();
const Vec3 hs = myBox.size() * 0.6; // slightly larger box to avoid clipping due to floating point imprecisions
Aabb r = Aabb(c - hs, c + hs);
const Real s = interpolate(r.a[axis], r.b[axis], position);
if (second)
r.a[axis] = s;
else
r.b[axis] = s;
return r;
}
const Real split = interpolate(myBox.a[a], myBox.b[a], bestSplitPosition);
Holder<Mesh> m1 = mesh->copy();
Holder<Mesh> m2 = mesh->copy();
meshClip(+m1, clippingBox(myBox, a, split));
meshClip(+m2, clippingBox(myBox, a, split, true));
std::vector<Holder<Mesh>> result = meshChunkingImpl(std::move(m1), config);
std::vector<Holder<Mesh>> r2 = meshChunkingImpl(std::move(m2), config);
for (auto &it : r2)
result.push_back(std::move(it));
return result;
}
else
} common;
common.config = config;
common.mesh = +mesh;

common.myArea = meshSurfaceArea(+mesh);
if (common.myArea < config.maxSurfaceArea)
{
// no more splitting is required
std::vector<Holder<Mesh>> result;
result.push_back(std::move(mesh));
return result;
}

common.myBox = mesh->boundingBox();
common.axis = boxLongestAxis(common.myBox);

struct Split
{
const Common *common = nullptr;
Real position = Real::Nan();
mutable Real score = Real::Nan();

void operator()() const
{
Holder<Mesh> p = common->mesh->copy();
meshClip(+p, common->clippingBox(position, false));
const Real area = meshSurfaceArea(+p);
score = abs(0.5 - area / common->myArea);
}
};
static constexpr const std::array<Real, 7> Positions = { 0.3, 0.4, 0.45, 0.5, 0.55, 0.6, 0.7 };
const Real *splitIt = Positions.data();
std::array<Split, 7> splits = {};
for (Split &s : splits)
{
s.common = &common;
s.position = *splitIt++;
}

if (config.parallelize)
tasksRunBlocking<Split>("meshChunking (splits)", splits);
else
{
for (Split &s : splits)
s();
}

Real bestSplitPosition = Real::Nan();
Real bestSplitScore = Real::Infinity();
for (const Split &s : splits)
{
if (s.score < bestSplitScore)
{
bestSplitScore = s.score;
bestSplitPosition = s.position;
}
}
CAGE_ASSERT(valid(bestSplitPosition));

struct Half
{
const Common *common = nullptr;
Aabb box;
mutable std::vector<Holder<Mesh>> r;

void operator()() const
{
Holder<Mesh> tmp = common->mesh->copy();
meshClip(+tmp, box);
r = meshChunkingImpl(std::move(tmp), common->config);
}
};
std::array<Half, 2> halves = {};
for (Half &h : halves)
h.common = &common;
halves[0].box = common.clippingBox(bestSplitPosition, false);
halves[1].box = common.clippingBox(bestSplitPosition, true);

if (config.parallelize)
tasksRunBlocking<Half>("meshChunking (recurse)", halves);
else
{
halves[0]();
halves[1]();
}

for (auto &it : halves[1].r)
halves[0].r.push_back(std::move(it));
return std::move(halves[0].r);
}
}

23 changes: 21 additions & 2 deletions sources/test-core/mesh.cpp
Original file line number Diff line number Diff line change
@@ -488,7 +488,7 @@ namespace
}

{
CAGE_TESTCASE("chunking");
CAGE_TESTCASE("chunking (serial)");
auto p = makeSphere();
MeshChunkingConfig cfg;
constexpr Real initialAreaImplicit = 4 * Real::Pi() * sqr(10);
@@ -502,7 +502,26 @@ namespace
CAGE_TEST(it->facesCount() > 0);
CAGE_TEST(it->indicesCount() > 0);
CAGE_TEST(it->type() == MeshTypeEnum::Triangles);
it->exportFile(Stringizer() + "meshes/algorithms/chunking/" + index++ + ".obj");
it->exportFile(Stringizer() + "meshes/algorithms/chunkingSerial/" + index++ + ".obj");
}
}

{
CAGE_TESTCASE("chunking (parallel)");
auto p = makeSphere();
MeshChunkingConfig cfg;
constexpr Real initialAreaImplicit = 4 * Real::Pi() * sqr(10);
constexpr Real targetChunks = 10;
cfg.maxSurfaceArea = initialAreaImplicit / targetChunks;
const auto res = meshChunking(+p, cfg);
CAGE_TEST(res.size() > targetChunks / 2 && res.size() < targetChunks * 2);
uint32 index = 0;
for (const auto &it : res)
{
CAGE_TEST(it->facesCount() > 0);
CAGE_TEST(it->indicesCount() > 0);
CAGE_TEST(it->type() == MeshTypeEnum::Triangles);
it->exportFile(Stringizer() + "meshes/algorithms/chunkingParallel/" + index++ + ".obj");
}
}

0 comments on commit 1a232df

Please sign in to comment.