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

Optimizations #106

Merged
merged 7 commits into from
May 11, 2022
Merged
Show file tree
Hide file tree
Changes from all 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
8 changes: 6 additions & 2 deletions collider/src/collider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ Collider::Collider(const VecDH<Box>& leafBB,
*/
template <typename T>
SparseIndices Collider::Collisions(const VecDH<T>& querriesIn) const {
int maxOverlaps = 1 << 20;
int maxOverlaps = querriesIn.size() * 4;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

SparseIndices querryTri(maxOverlaps);
int nOverlaps = 0;
while (1) {
Expand All @@ -282,7 +282,11 @@ SparseIndices Collider::Collisions(const VecDH<T>& querriesIn) const {
break;
else { // if not enough memory was allocated, guess how much will be needed
int lastQuery = querryTri.Get(0).H().back();
maxOverlaps *= 2 * static_cast<float>(querriesIn.size()) / lastQuery;
pca006132 marked this conversation as resolved.
Show resolved Hide resolved
float ratio = static_cast<float>(querriesIn.size()) / lastQuery;
if (ratio > 1000) // do not trust the ratio if it is too large
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

maxOverlaps *= 2;
else
maxOverlaps *= 2 * ratio;
querryTri.Resize(maxOverlaps);
}
}
Expand Down
57 changes: 40 additions & 17 deletions manifold/src/face_op.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ void Manifold::Impl::Face2Tri(const VecDH<int>& faceEdge,
const VecH<Halfedge>& halfedge = halfedge_.H();
const VecH<glm::vec3>& faceNormal = faceNormal_.H();
meshRelation_.triBary.resize(0);
triVerts.reserve(faceEdge.size());
triNormal.reserve(faceEdge.size());
meshRelation_.triBary.H().reserve(faceEdge.size()*3);

for (int face = 0; face < faceEdgeH.size() - 1; ++face) {
const int firstEdge = faceEdgeH[face];
Expand All @@ -50,12 +53,17 @@ void Manifold::Impl::Face2Tri(const VecDH<int>& faceEdge,
ALWAYS_ASSERT(numEdge >= 3, topologyErr, "face has less than three edges.");
const glm::vec3 normal = faceNormal[face];

std::map<int, int> vertBary;
for (int j = firstEdge; j < lastEdge; ++j)
vertBary[halfedge[j].startVert] = halfedgeBary.H()[j];
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call, I bet this could be a big part of why the triangulation step has been scaling worse than it should.

const int startTri = triVerts.size();
auto linearSearch = [](const int* mapping, int value) {
int i = 0;
while (mapping[i] != value)
++i;
return i;
};

if (numEdge == 3) { // Single triangle
int mapping[3] = {halfedge[firstEdge].startVert,
halfedge[firstEdge + 1].startVert,
halfedge[firstEdge + 2].startVert};
glm::ivec3 tri(halfedge[firstEdge].startVert,
halfedge[firstEdge + 1].startVert,
halfedge[firstEdge + 2].startVert);
Expand All @@ -71,7 +79,16 @@ void Manifold::Impl::Face2Tri(const VecDH<int>& faceEdge,

triVerts.push_back(tri);
triNormal.push_back(normal);
meshRelation_.triBary.H().push_back(faceRef.H()[face]);
for (int k : {0, 1, 2}) {
int index = linearSearch(mapping, tri[k]);
meshRelation_.triBary.H().back().vertBary[k] = halfedgeBary.H()[firstEdge + index];
}
} else if (numEdge == 4) { // Pair of triangles
int mapping[4] = {halfedge[firstEdge].startVert,
halfedge[firstEdge + 1].startVert,
halfedge[firstEdge + 2].startVert,
halfedge[firstEdge + 3].startVert};
const glm::mat3x2 projection = GetAxisAlignedProjection(normal);
auto triCCW = [&projection, &vertPos, this](const glm::ivec3 tri) {
return CCW(projection * vertPos[tri[0]], projection * vertPos[tri[1]],
Expand Down Expand Up @@ -111,13 +128,22 @@ void Manifold::Impl::Face2Tri(const VecDH<int>& faceEdge,
}
}

triVerts.push_back(tri0);
triNormal.push_back(normal);
triVerts.push_back(tri1);
triNormal.push_back(normal);
for (auto tri : { tri0, tri1 }) {
triVerts.push_back(tri);
triNormal.push_back(normal);
meshRelation_.triBary.H().push_back(faceRef.H()[face]);
for (int k : {0, 1, 2}) {
int index = linearSearch(mapping, tri[k]);
meshRelation_.triBary.H().back().vertBary[k] = halfedgeBary.H()[firstEdge + index];
}
}
} else { // General triangulation
const glm::mat3x2 projection = GetAxisAlignedProjection(normal);

std::map<int, int> vertBary;
for (int j = firstEdge; j < lastEdge; ++j)
vertBary[halfedge[j].startVert] = halfedgeBary.H()[j];

Polygons polys;
try {
polys = Face2Polygons(face, projection, faceEdgeH);
Expand All @@ -134,18 +160,15 @@ void Manifold::Impl::Face2Tri(const VecDH<int>& faceEdge,
for (auto tri : newTris) {
triVerts.push_back(tri);
triNormal.push_back(normal);
}
}

for (int tri = startTri; tri < triVerts.size(); ++tri) {
meshRelation_.triBary.H().push_back(faceRef.H()[face]);
for (int k : {0, 1, 2}) {
meshRelation_.triBary.H().back().vertBary[k] =
vertBary[triVerts[tri][k]];
meshRelation_.triBary.H().push_back(faceRef.H()[face]);
for (int k : {0, 1, 2}) {
meshRelation_.triBary.H().back().vertBary[k] =
vertBary[tri[k]];
}
}
}
}
faceNormal_ = triNormalOut;
faceNormal_ = std::move(triNormalOut);
CreateAndFixHalfedges(triVertsOut);
}

Expand Down
8 changes: 5 additions & 3 deletions manifold/src/impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -507,17 +507,19 @@ void Manifold::Impl::CreateHalfedges(const VecDH<glm::ivec3>& triVerts) {
*/
void Manifold::Impl::CreateAndFixHalfedges(const VecDH<glm::ivec3>& triVerts) {
const int numTri = triVerts.size();
// drop the old value first to avoid copy
halfedge_.resize(0);
halfedge_.resize(3 * numTri);
VecDH<TmpEdge> edge(3 * numTri);
thrust::for_each_n(zip(countAt(0), triVerts.begin()), numTri,
Tri2Halfedges({halfedge_.ptrH(), edge.ptrH()}));
thrust::for_each_n(zip(countAt(0), triVerts.beginD()), numTri,
Tri2Halfedges({halfedge_.ptrD(), edge.ptrD()}));
// Stable sort is required here so that halfedges from the same face are
// paired together (the triangles were created in face order). In some
// degenerate situations the triangulator can add the same internal edge in
// two different faces, causing this edge to not be 2-manifold. We detect this
// and fix it by swapping one of the identical edges, so it is important that
// we have the edges paired according to their face.
std::stable_sort(edge.begin(), edge.end());
thrust::stable_sort(edge.beginD(), edge.endD());
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this new? I vaguely recall using std:: because thrust didn't have a stable_sort.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From git blame of https://github.com/NVIDIA/thrust/blame/fa54f2c6f1217237953f27ddf67f901b6b34fbdd/testing/stable_sort.cu, it seems that stable_sort is in thrust for over 10 years. Perhaps it is related to cudatoolkit version?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cool, I must have remembered wrong.

thrust::for_each_n(thrust::host, countAt(0), halfedge_.size() / 2,
LinkHalfedges({halfedge_.ptrH(), edge.cptrH()}));
thrust::for_each(thrust::host, countAt(1), countAt(halfedge_.size() / 2),
Expand Down
2 changes: 1 addition & 1 deletion manifold/src/smoothing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -470,7 +470,7 @@ Manifold::Impl::MeshRelationD Manifold::Impl::Subdivide(int n) {
MeshRelationD relation;
relation.barycentric.resize(numTri * VertsPerTri(n + 1));
relation.triBary.resize(n * n * numTri);
MeshRelationD oldMeshRelation = meshRelation_;
MeshRelationD oldMeshRelation = std::move(meshRelation_);
meshRelation_.barycentric.resize(relation.barycentric.size());
meshRelation_.triBary.resize(relation.triBary.size());

Expand Down
4 changes: 2 additions & 2 deletions manifold/src/sort.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -292,8 +292,8 @@ void Manifold::Impl::GatherFaces(const VecDH<int>& faceNew2Old) {

if (faceNormal_.size() == NumTri()) Permute(faceNormal_, faceNew2Old);

VecDH<Halfedge> oldHalfedge(halfedge_);
VecDH<glm::vec4> oldHalfedgeTangent(halfedgeTangent_);
VecDH<Halfedge> oldHalfedge(std::move(halfedge_));
VecDH<glm::vec4> oldHalfedgeTangent(std::move(halfedgeTangent_));
VecDH<int> faceOld2New(oldHalfedge.size() / 3);
thrust::scatter(countAt(0), countAt(numTri), faceNew2Old.beginD(),
faceOld2New.beginD());
Expand Down