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

Output normals with a consistent orientation for convex meshes #48

Merged
merged 12 commits into from
Nov 3, 2023
2 changes: 2 additions & 0 deletions meshing/include/vc/meshing/CalculateNormals.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,5 +84,7 @@ class CalculateNormals

/** Storage for summed normals, organized by vertex ID */
std::vector<cv::Vec3d> vertexNormals_;

bool flippedNormals_;
};
} // namespace volcart::meshing
51 changes: 51 additions & 0 deletions meshing/src/CalculateNormals.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,28 @@ void CalculateNormals::compute_normals_()
{
vertexNormals_ = std::vector<cv::Vec3d>(output_->GetNumberOfPoints(), 0);

// Compute the average mesh coordinates, to use as reference when choosing
// an orientation for the mesh normals. Should produce consistent result on
// convex-ish meshes.
unsigned int pointCount = 0;
ITKPoint pointAverage;
pointAverage.Fill(0.0);
for (auto it = input_->GetPoints()->Begin(); it != input_->GetPoints()->End(); ++it) {
auto point = it.Value();
pointAverage[0] += point[0];
pointAverage[1] += point[1];
pointAverage[2] += point[2];
pointCount++;
}
if (pointCount > 0) {
pointAverage[0] /= pointCount;
pointAverage[1] /= pointCount;
pointAverage[2] /= pointCount;
}
spelufo marked this conversation as resolved.
Show resolved Hide resolved

unsigned int outwardNormalsCount = 0;
unsigned int inwardNormalsCount = 0;
spelufo marked this conversation as resolved.
Show resolved Hide resolved

for (auto cellIt = input_->GetCells()->Begin();
cellIt != input_->GetCells()->End(); ++cellIt) {

Expand All @@ -38,21 +60,37 @@ void CalculateNormals::compute_normals_()

// To-Do: #185

ITKPoint facePoint;
spelufo marked this conversation as resolved.
Show resolved Hide resolved
facePoint.Fill(0.0);

// Collect the vertex info for each point
vert = input_->GetPoint(pointIds[0]);
v0(0) = vert[0];
v0(1) = vert[1];
v0(2) = vert[2];
facePoint[0] += vert[0];
facePoint[1] += vert[1];
facePoint[2] += vert[2];

vert = input_->GetPoint(pointIds[1]);
v1(0) = vert[0];
v1(1) = vert[1];
v1(2) = vert[2];
facePoint[0] += vert[0];
facePoint[1] += vert[1];
facePoint[2] += vert[2];

vert = input_->GetPoint(pointIds[2]);
v2(0) = vert[0];
v2(1) = vert[1];
v2(2) = vert[2];
facePoint[0] += vert[0];
facePoint[1] += vert[1];
facePoint[2] += vert[2];

facePoint[0] /= 3.0;
facePoint[1] /= 3.0;
facePoint[2] /= 3.0;
spelufo marked this conversation as resolved.
Show resolved Hide resolved

// Get the edge vectors
e0 = v2 - v0;
Expand All @@ -62,11 +100,21 @@ void CalculateNormals::compute_normals_()
cv::Vec3d normals;
normals = e1.cross(e0);

// Accumulate the relative direction of the normals for this face.
cv::Vec3d itkVecToCvVec(facePoint[0] - pointAverage[0], facePoint[1] - pointAverage[1], facePoint[2] - pointAverage[2]);
spelufo marked this conversation as resolved.
Show resolved Hide resolved
if (normals.dot(itkVecToCvVec) > 0) {
outwardNormalsCount++;
} else {
inwardNormalsCount++;
}
csparker247 marked this conversation as resolved.
Show resolved Hide resolved

// Add the norm for this face to the running sum for each vertex
vertexNormals_[pointIds[0]] += normals;
vertexNormals_[pointIds[1]] += normals;
vertexNormals_[pointIds[2]] += normals;
}

flippedNormals_ = outwardNormalsCount > inwardNormalsCount;
}

void CalculateNormals::assign_to_mesh_()
Expand All @@ -76,6 +124,9 @@ void CalculateNormals::assign_to_mesh_()
cv::Vec3d norm = vertexNormals_[point.Index()];
cv::normalize(norm, norm);

if (flippedNormals_) {
norm = -norm;
}
output_->SetPointData(point.Index(), norm.val);
}
}