-
I am working on adding some new meshing algorithms to Curv. Given all the work that @mkeeter has done in exploring meshing algorithms, I'd like to use libfive as one of my meshing algorithms. It's just not obvious how to do the integration, so I'm looking for suggestions, documentation and examples. (Eg, has someone successfully done this before in open source?) The only input I have to libfive is a signed distance function that maps [x,y,z] onto a signed distance. That's it. I don't have gradients, I have no ability to do interval arithmetic, etc. I have a vague notion that this should be done by defining a subclass of What I actually want is a C++ function that takes a signed distance function, a bounding box, a grid resolution, and a quality parameter, and returns an indexed triangle mesh. So how do I write this function using libfive? |
Beta Was this translation helpful? Give feedback.
Replies: 4 comments 3 replies
-
Your vague notion is correct! Here's a sketch of an oracle which wraps a function #include "libfive/oracle/oracle_storage.hpp"
class CurvOracle : public libfive::OracleStorage<LIBFIVE_EVAL_ARRAY_SIZE> {
public:
CurvOracle(std::function<float(float, float, float)> f)
: f(f)
{
// Nothing to do here
}
void evalInterval(libfive::Interval& out) override {
// Just pick a big ambiguous value.
out = {-10000.0, 10000.0};
}
void evalPoint(float& out, size_t index=0) override {
const auto pt = points.col(index);
out = f(pt.x(), pt.y(), pt.z());
}
void checkAmbiguous(
Eigen::Block<Eigen::Array<bool, 1, LIBFIVE_EVAL_ARRAY_SIZE>,
1, Eigen::Dynamic> /* out */) override
{
// Nothing to do here, because we can only find one derivative
// per point (points on sharp features may not be handled correctly)
}
// Find one derivative with partial differences
void evalFeatures(boost::container::small_vector<libfive::Feature, 4>& out) override {
const float EPSILON = 1e-6;
float center, dx, dy, dz;
Eigen::Vector3f before = points.col(0);
evalPoint(center);
points.col(0) = before + Eigen::Vector3f(EPSILON, 0.0, 0.0);
evalPoint(dx);
points.col(0) = before + Eigen::Vector3f(0.0, EPSILON, 0.0);
evalPoint(dy);
points.col(0) = before + Eigen::Vector3f(0.0, 0.0, EPSILON);
evalPoint(dz);
points.col(0) = before;
out.push_back(Eigen::Vector3f(
(dx - center) / EPSILON,
(dy - center) / EPSILON,
(dz - center) / EPSILON));
}
protected:
std::function<float(float, float, float)> f;
}; In addition, you need an #include "libfive/oracle/oracle_clause.hpp"
class CurvOracleClause: public libfive::OracleClause
{
public:
CurvOracleClause(std::function<float(float, float, float)> f)
: f(f)
{
// Nothing to do here
}
std::unique_ptr<libfive::Oracle> getOracle() const override {
return std::unique_ptr<libfive::Oracle>(new CurvOracle(f));
}
std::string name() const override { return "CurvOracleClause"; }
protected:
std::function<float(float, float, float)> f;
}; To put this #include "libfive/tree/tree.hpp"
#include "libfive/render/brep/mesh.hpp"
using namespace libfive;
// ...
// Assume you already have std::function<float(float,float,float)> f
auto oc = Tree(std::unique_ptr<OracleClause>(new CurvOracleClause(f));
BRepSettings bs; // edit this to change resolution, quality, etc
Region<3> r({-1, -1, -1}, {1, 1, 1}); // Edit this to change rendering
Mesh::render(oc, r, bs)->saveSTL("out.stl"); (All of this is untested, but should convey the infrastructure to build / use a minimal |
Beta Was this translation helpful? Give feedback.
-
Thanks for the detailed response! I will report back later when this succeeds or fails. |
Beta Was this translation helpful? Give feedback.
-
This question is now answered. I'll address unexpected behaviour by filing github issues. |
Beta Was this translation helpful? Give feedback.
-
More feedback for people who try this. In With certain models, the quality of the result is highly dependent on the value of epsilon. I have a model where Libfive Dual Contouring produces perfect-looking output for CAD-like models with exact distance fields. (Cubes, cylinders, unions, rotations, etc.) The models that have meshing artifacts are the same ones that have "bent" or "twisted" distance fields, where the gradient is different from the surface normal. Since Dual Contouring uses surface normals to position and orient triangles on the surface, I believe that the contract for |
Beta Was this translation helpful? Give feedback.
Your vague notion is correct!
Here's a sketch of an oracle which wraps a function
(float, float, float) -> float
: