Add voxel scale to openvdb metadata.

To be able to retrieve that information from a generated grid alone.

To avoid the copying of input mesh (for scaling) when doing the hollowing

Also remove some unused stuff from OpenVDBUtils
This commit is contained in:
tamasmeszaros 2020-12-17 13:38:09 +01:00
parent 7cb3e729ee
commit e57eca0289
3 changed files with 70 additions and 90 deletions

View File

@ -22,74 +22,52 @@ namespace Slic3r {
class TriangleMeshDataAdapter { class TriangleMeshDataAdapter {
public: public:
const TriangleMesh &mesh; const TriangleMesh &mesh;
float voxel_scale;
size_t polygonCount() const { return mesh.its.indices.size(); } size_t polygonCount() const { return mesh.its.indices.size(); }
size_t pointCount() const { return mesh.its.vertices.size(); } size_t pointCount() const { return mesh.its.vertices.size(); }
size_t vertexCount(size_t) const { return 3; } size_t vertexCount(size_t) const { return 3; }
// Return position pos in local grid index space for polygon n and vertex v // Return position pos in local grid index space for polygon n and vertex v
void getIndexSpacePoint(size_t n, size_t v, openvdb::Vec3d& pos) const; // The actual mesh will appear to openvdb as scaled uniformly by voxel_size
// And the voxel count per unit volume can be affected this way.
void getIndexSpacePoint(size_t n, size_t v, openvdb::Vec3d& pos) const
{
auto vidx = size_t(mesh.its.indices[n](Eigen::Index(v)));
Slic3r::Vec3d p = mesh.its.vertices[vidx].cast<double>() * voxel_scale;
pos = {p.x(), p.y(), p.z()};
}
TriangleMeshDataAdapter(const TriangleMesh &m, float voxel_sc = 1.f)
: mesh{m}, voxel_scale{voxel_sc} {};
}; };
class Contour3DDataAdapter {
public:
const sla::Contour3D &mesh;
size_t polygonCount() const { return mesh.faces3.size() + mesh.faces4.size(); }
size_t pointCount() const { return mesh.points.size(); }
size_t vertexCount(size_t n) const { return n < mesh.faces3.size() ? 3 : 4; }
// Return position pos in local grid index space for polygon n and vertex v
void getIndexSpacePoint(size_t n, size_t v, openvdb::Vec3d& pos) const;
};
void TriangleMeshDataAdapter::getIndexSpacePoint(size_t n,
size_t v,
openvdb::Vec3d &pos) const
{
auto vidx = size_t(mesh.its.indices[n](Eigen::Index(v)));
Slic3r::Vec3d p = mesh.its.vertices[vidx].cast<double>();
pos = {p.x(), p.y(), p.z()};
}
void Contour3DDataAdapter::getIndexSpacePoint(size_t n,
size_t v,
openvdb::Vec3d &pos) const
{
size_t vidx = 0;
if (n < mesh.faces3.size()) vidx = size_t(mesh.faces3[n](Eigen::Index(v)));
else vidx = size_t(mesh.faces4[n - mesh.faces3.size()](Eigen::Index(v)));
Slic3r::Vec3d p = mesh.points[vidx];
pos = {p.x(), p.y(), p.z()};
}
// TODO: Do I need to call initialize? Seems to work without it as well but the // TODO: Do I need to call initialize? Seems to work without it as well but the
// docs say it should be called ones. It does a mutex lock-unlock sequence all // docs say it should be called ones. It does a mutex lock-unlock sequence all
// even if was called previously. // even if was called previously.
openvdb::FloatGrid::Ptr mesh_to_grid(const TriangleMesh &mesh, openvdb::FloatGrid::Ptr mesh_to_grid(const TriangleMesh & mesh,
const openvdb::math::Transform &tr, const openvdb::math::Transform &tr,
float exteriorBandWidth, float voxel_scale,
float interiorBandWidth, float exteriorBandWidth,
int flags) float interiorBandWidth,
int flags)
{ {
openvdb::initialize(); openvdb::initialize();
TriangleMeshPtrs meshparts = mesh.split(); TriangleMeshPtrs meshparts = mesh.split();
auto it = std::remove_if(meshparts.begin(), meshparts.end(), auto it = std::remove_if(meshparts.begin(), meshparts.end(),
[](TriangleMesh *m){ [](TriangleMesh *m){
m->require_shared_vertices(); m->require_shared_vertices();
return !m->is_manifold() || m->volume() < EPSILON; return !m->is_manifold() || m->volume() < EPSILON;
}); });
meshparts.erase(it, meshparts.end()); meshparts.erase(it, meshparts.end());
openvdb::FloatGrid::Ptr grid; openvdb::FloatGrid::Ptr grid;
for (TriangleMesh *m : meshparts) { for (TriangleMesh *m : meshparts) {
auto subgrid = openvdb::tools::meshToVolume<openvdb::FloatGrid>( auto subgrid = openvdb::tools::meshToVolume<openvdb::FloatGrid>(
TriangleMeshDataAdapter{*m}, tr, exteriorBandWidth, TriangleMeshDataAdapter{*m, voxel_scale}, tr, exteriorBandWidth,
interiorBandWidth, flags); interiorBandWidth, flags);
if (grid && subgrid) openvdb::tools::csgUnion(*grid, *subgrid); if (grid && subgrid) openvdb::tools::csgUnion(*grid, *subgrid);
@ -106,19 +84,9 @@ openvdb::FloatGrid::Ptr mesh_to_grid(const TriangleMesh &mesh,
interiorBandWidth, flags); interiorBandWidth, flags);
} }
return grid; grid->insertMeta("voxel_scale", openvdb::FloatMetadata(voxel_scale));
}
openvdb::FloatGrid::Ptr mesh_to_grid(const sla::Contour3D &mesh, return grid;
const openvdb::math::Transform &tr,
float exteriorBandWidth,
float interiorBandWidth,
int flags)
{
openvdb::initialize();
return openvdb::tools::meshToVolume<openvdb::FloatGrid>(
Contour3DDataAdapter{mesh}, tr, exteriorBandWidth, interiorBandWidth,
flags);
} }
template<class Grid> template<class Grid>
@ -128,20 +96,25 @@ sla::Contour3D _volumeToMesh(const Grid &grid,
bool relaxDisorientedTriangles) bool relaxDisorientedTriangles)
{ {
openvdb::initialize(); openvdb::initialize();
std::vector<openvdb::Vec3s> points; std::vector<openvdb::Vec3s> points;
std::vector<openvdb::Vec3I> triangles; std::vector<openvdb::Vec3I> triangles;
std::vector<openvdb::Vec4I> quads; std::vector<openvdb::Vec4I> quads;
openvdb::tools::volumeToMesh(grid, points, triangles, quads, isovalue, openvdb::tools::volumeToMesh(grid, points, triangles, quads, isovalue,
adaptivity, relaxDisorientedTriangles); adaptivity, relaxDisorientedTriangles);
float scale = 1.;
try {
scale = grid.template metaValue<float>("voxel_scale");
} catch (...) { }
sla::Contour3D ret; sla::Contour3D ret;
ret.points.reserve(points.size()); ret.points.reserve(points.size());
ret.faces3.reserve(triangles.size()); ret.faces3.reserve(triangles.size());
ret.faces4.reserve(quads.size()); ret.faces4.reserve(quads.size());
for (auto &v : points) ret.points.emplace_back(to_vec3d(v)); for (auto &v : points) ret.points.emplace_back(to_vec3d(v) / scale);
for (auto &v : triangles) ret.faces3.emplace_back(to_vec3i(v)); for (auto &v : triangles) ret.faces3.emplace_back(to_vec3i(v));
for (auto &v : quads) ret.faces4.emplace_back(to_vec4i(v)); for (auto &v : quads) ret.faces4.emplace_back(to_vec4i(v));
@ -166,9 +139,18 @@ sla::Contour3D grid_to_contour3d(const openvdb::FloatGrid &grid,
relaxDisorientedTriangles); relaxDisorientedTriangles);
} }
openvdb::FloatGrid::Ptr redistance_grid(const openvdb::FloatGrid &grid, double iso, double er, double ir) openvdb::FloatGrid::Ptr redistance_grid(const openvdb::FloatGrid &grid,
double iso,
double er,
double ir)
{ {
return openvdb::tools::levelSetRebuild(grid, float(iso), float(er), float(ir)); auto new_grid = openvdb::tools::levelSetRebuild(grid, float(iso),
float(er), float(ir));
// Copies voxel_scale metadata, if it exists.
new_grid->insertMeta(*grid.deepCopyMeta());
return new_grid;
} }
} // namespace Slic3r } // namespace Slic3r

View File

@ -21,14 +21,16 @@ inline Vec3d to_vec3d(const openvdb::Vec3s &v) { return to_vec3f(v).cast<double>
inline Vec3i to_vec3i(const openvdb::Vec3I &v) { return Vec3i{int(v[0]), int(v[1]), int(v[2])}; } inline Vec3i to_vec3i(const openvdb::Vec3I &v) { return Vec3i{int(v[0]), int(v[1]), int(v[2])}; }
inline Vec4i to_vec4i(const openvdb::Vec4I &v) { return Vec4i{int(v[0]), int(v[1]), int(v[2]), int(v[3])}; } inline Vec4i to_vec4i(const openvdb::Vec4I &v) { return Vec4i{int(v[0]), int(v[1]), int(v[2]), int(v[3])}; }
// Here voxel_scale defines the scaling of voxels which affects the voxel count.
// 1.0 value means a voxel for every unit cube. 2 means the model is scaled to
// be 2x larger and the voxel count is increased by the increment in the scaled
// volume, thus 4 times. This kind a sampling accuracy selection is not
// achievable through the Transform parameter. (TODO: or is it?)
// The resulting grid will contain the voxel_scale in its metadata under the
// "voxel_scale" key to be used in grid_to_mesh function.
openvdb::FloatGrid::Ptr mesh_to_grid(const TriangleMesh & mesh, openvdb::FloatGrid::Ptr mesh_to_grid(const TriangleMesh & mesh,
const openvdb::math::Transform &tr = {}, const openvdb::math::Transform &tr = {},
float exteriorBandWidth = 3.0f, float voxel_scale = 1.f,
float interiorBandWidth = 3.0f,
int flags = 0);
openvdb::FloatGrid::Ptr mesh_to_grid(const sla::Contour3D & mesh,
const openvdb::math::Transform &tr = {},
float exteriorBandWidth = 3.0f, float exteriorBandWidth = 3.0f,
float interiorBandWidth = 3.0f, float interiorBandWidth = 3.0f,
int flags = 0); int flags = 0);

View File

@ -32,48 +32,44 @@ static TriangleMesh _generate_interior(const TriangleMesh &mesh,
double voxel_scale, double voxel_scale,
double closing_dist) double closing_dist)
{ {
TriangleMesh imesh{mesh};
_scale(voxel_scale, imesh);
double offset = voxel_scale * min_thickness; double offset = voxel_scale * min_thickness;
double D = voxel_scale * closing_dist; double D = voxel_scale * closing_dist;
float out_range = 0.1f * float(offset); float out_range = 0.1f * float(offset);
float in_range = 1.1f * float(offset + D); float in_range = 1.1f * float(offset + D);
if (ctl.stopcondition()) return {}; if (ctl.stopcondition()) return {};
else ctl.statuscb(0, L("Hollowing")); else ctl.statuscb(0, L("Hollowing"));
auto gridptr = mesh_to_grid(imesh, {}, out_range, in_range); auto gridptr = mesh_to_grid(mesh, {}, voxel_scale, out_range, in_range);
assert(gridptr); assert(gridptr);
if (!gridptr) { if (!gridptr) {
BOOST_LOG_TRIVIAL(error) << "Returned OpenVDB grid is NULL"; BOOST_LOG_TRIVIAL(error) << "Returned OpenVDB grid is NULL";
return {}; return {};
} }
if (ctl.stopcondition()) return {}; if (ctl.stopcondition()) return {};
else ctl.statuscb(30, L("Hollowing")); else ctl.statuscb(30, L("Hollowing"));
double iso_surface = D;
auto narrowb = double(in_range);
if (closing_dist > .0) { if (closing_dist > .0) {
gridptr = redistance_grid(*gridptr, -(offset + D), double(in_range)); gridptr = redistance_grid(*gridptr, -(offset + D), narrowb, narrowb);
} else { } else {
D = -offset; iso_surface = -offset;
} }
if (ctl.stopcondition()) return {}; if (ctl.stopcondition()) return {};
else ctl.statuscb(70, L("Hollowing")); else ctl.statuscb(70, L("Hollowing"));
double iso_surface = D;
double adaptivity = 0.; double adaptivity = 0.;
auto omesh = grid_to_mesh(*gridptr, iso_surface, adaptivity); auto omesh = grid_to_mesh(*gridptr, iso_surface, adaptivity);
_scale(1. / voxel_scale, omesh);
if (ctl.stopcondition()) return {}; if (ctl.stopcondition()) return {};
else ctl.statuscb(100, L("Hollowing")); else ctl.statuscb(100, L("Hollowing"));
return omesh; return omesh;
} }