-
Notifications
You must be signed in to change notification settings - Fork 39
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
SubMesh::RecalculateNormals improvement #609
Changes from 9 commits
1ca2962
66c69c7
3882da1
3ea5134
e22e6ff
b0605b8
0ba046a
fe8b008
833962c
cd01fa6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,8 +18,8 @@ | |
#include <algorithm> | ||
#include <limits> | ||
#include <map> | ||
#include <optional> | ||
#include <string> | ||
#include <vector> | ||
|
||
#include "gz/math/Helpers.hh" | ||
|
||
|
@@ -573,10 +573,56 @@ void SubMesh::FillArrays(double **_vertArr, int **_indArr) const | |
} | ||
} | ||
|
||
namespace { | ||
// Simple way to find neighbors by grouping all vertices | ||
// by X coordinate with (ordered) map. KD-tree maybe better | ||
// but not sure about construction overhead | ||
struct Neighbors | ||
{ | ||
Neighbors(const std::vector<unsigned int> &_indices, | ||
const std::vector<gz::math::Vector3d> &_vertices) | ||
: vertices(_vertices) | ||
{ | ||
for (unsigned int i = 0; i < _indices.size(); ++i) | ||
{ | ||
const auto index = _indices[i]; | ||
this->neighbors[_vertices[index].X()].push_back(index); | ||
} | ||
} | ||
|
||
template<typename Visitor> | ||
void Visit(const gz::math::Vector3d &_point, Visitor _v) const | ||
{ | ||
auto it = this->neighbors.find(_point.X()); | ||
// find smaller acceptable value | ||
while (it != this->neighbors.begin()) | ||
{ | ||
auto prev = it; | ||
--prev; | ||
if (!gz::math::equal(prev->first, _point.X())) | ||
break; | ||
it = prev; | ||
} | ||
while (it != this->neighbors.end() | ||
&& gz::math::equal(it->first, _point.X())) | ||
{ | ||
for (const auto index : it->second) | ||
if (this->vertices[index] == _point) | ||
_v(index); | ||
++it; | ||
} | ||
} | ||
|
||
private: std::map<double, std::vector<unsigned int>> neighbors; | ||
private: const std::vector<gz::math::Vector3d> &vertices; | ||
}; | ||
} // namespace | ||
|
||
////////////////////////////////////////////////// | ||
void SubMesh::RecalculateNormals() | ||
{ | ||
if (this->dataPtr->normals.size() < 3u) | ||
if (this->dataPtr->indices.empty() | ||
|| this->dataPtr->indices.size() % 3u != 0) | ||
return; | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It feels like it also should check: There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. +1, I think it's good to be explicit and check that it's a TRIANGLES primitive type. I think other primitive types don't quite work yet but this is just in case better support is implemented for other types in the future. |
||
// Reset all the normals | ||
|
@@ -586,6 +632,8 @@ void SubMesh::RecalculateNormals() | |
if (this->dataPtr->normals.size() != this->dataPtr->vertices.size()) | ||
this->dataPtr->normals.resize(this->dataPtr->vertices.size()); | ||
|
||
Neighbors neighbors(this->dataPtr->indices, this->dataPtr->vertices); | ||
|
||
// For each face, which is defined by three indices, calculate the normals | ||
for (unsigned int i = 0; i < this->dataPtr->indices.size(); i+= 3) | ||
{ | ||
|
@@ -597,14 +645,11 @@ void SubMesh::RecalculateNormals() | |
this->dataPtr->vertices[this->dataPtr->indices[i+2]]; | ||
gz::math::Vector3d n = gz::math::Vector3d::Normal(v1, v2, v3); | ||
|
||
for (unsigned int j = 0; j < this->dataPtr->vertices.size(); ++j) | ||
{ | ||
gz::math::Vector3d v = this->dataPtr->vertices[j]; | ||
if (v == v1 || v == v2 || v == v3) | ||
for (const auto &point : {v1, v2, v3}) | ||
neighbors.Visit(point, [&](const unsigned int index) | ||
{ | ||
this->dataPtr->normals[j] += n; | ||
} | ||
} | ||
this->dataPtr->normals[index] += n; | ||
}); | ||
} | ||
|
||
// Normalize the results | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you add some documentation to explain the logic in this function? I think it's to find and include all indices of vertices that are within the tolerance of the
math::equal
checks, so that their normals all count towards the final calculation?