Пример #1
0
int main(int argc, char* argv[]) {
  
  if(argc != 4) {
    std::cout << "SDFGen - A utility for converting closed oriented triangle meshes into grid-based signed distance fields.\n";
    std::cout << "\nThe output file format is:";
    std::cout << "<ni> <nj> <nk>\n";
    std::cout << "<origin_x> <origin_y> <origin_z>\n";
    std::cout << "<dx>\n";
    std::cout << "<value_1> <value_2> <value_3> [...]\n\n";
    
    std::cout << "(ni,nj,nk) are the integer dimensions of the resulting distance field.\n";
    std::cout << "(origin_x,origin_y,origin_z) is the 3D position of the grid origin.\n";
    std::cout << "<dx> is the grid spacing.\n\n";
    std::cout << "<value_n> are the signed distance data values, in ascending order of i, then j, then k.\n";

    std::cout << "The output filename will match that of the input, with the OBJ suffix replaced with SDF.\n\n";

    std::cout << "Usage: SDFGen <filename> <dx> <padding>\n\n";
    std::cout << "Where:\n";
    std::cout << "\t<filename> specifies a Wavefront OBJ (text) file representing a *triangle* mesh (no quad or poly meshes allowed). File must use the suffix \".obj\".\n";
    std::cout << "\t<dx> specifies the length of grid cell in the resulting distance field.\n";
    std::cout << "\t<padding> specifies the number of cells worth of padding between the object bound box and the boundary of the distance field grid. Minimum is 1.\n\n";
    
    exit(-1);
  }

  std::string filename(argv[1]);
  if(filename.size() < 5 || filename.substr(filename.size()-4) != std::string(".obj")) {
    std::cerr << "Error: Expected OBJ file with filename of the form <name>.obj.\n";
    exit(-1);
  }

  std::stringstream arg2(argv[2]);
  float dx;
  arg2 >> dx;
  
  std::stringstream arg3(argv[3]);
  int padding;
  arg3 >> padding;

  if(padding < 1) padding = 1;
  //start with a massive inside out bound box.
  Vec3f min_box(std::numeric_limits<float>::max(),std::numeric_limits<float>::max(),std::numeric_limits<float>::max()), 
    max_box(-std::numeric_limits<float>::max(),-std::numeric_limits<float>::max(),-std::numeric_limits<float>::max());
  
  std::cout << "Reading data.\n";

  std::ifstream infile(argv[1]);
  if(!infile) {
    std::cerr << "Failed to open. Terminating.\n";
    exit(-1);
  }

  int ignored_lines = 0;
  std::string line;
  std::vector<Vec3f> vertList;
  std::vector<Vec3ui> faceList;
  while(!infile.eof()) {
    std::getline(infile, line);

    //.obj files sometimes contain vertex normals indicated by "vn"
    if(line.substr(0,1) == std::string("v") && line.substr(0,2) != std::string("vn")){
      std::stringstream data(line);
      char c;
      Vec3f point;
      data >> c >> point[0] >> point[1] >> point[2];
      vertList.push_back(point);
      update_minmax(point, min_box, max_box);
    }
    else if(line.substr(0,1) == std::string("f")) {
Пример #2
0
void ModelMesher::generateOffsetSurface(double offset)
{
    if(m->activeNode == nullptr) return;
    auto n = m->activeNode;
    n->vis_property["isSmoothShading"].setValue(true);

    switch(m->QObject::property("meshingIsThick").toInt()){
    case 0: break;
    case 1: offset *= 1.5; break;
    case 2: offset *= 2; break;
    }

    double dx = 0.015;

    std::vector<SDFGen::Vec3f> vertList;
    std::vector<SDFGen::Vec3ui> faceList;

    //start with a massive inside out bound box.
    SDFGen::Vec3f min_box(std::numeric_limits<float>::max(),std::numeric_limits<float>::max(),std::numeric_limits<float>::max()),
        max_box(-std::numeric_limits<float>::max(),-std::numeric_limits<float>::max(),-std::numeric_limits<float>::max());

    Structure::Curve* curve = dynamic_cast<Structure::Curve*>(n);
    Structure::Sheet* sheet = dynamic_cast<Structure::Sheet*>(n);

    //generate "tri-mesh" from skeleton geometry
    if(curve)
    {
        QVector<QVector3D> cpts;
        for(auto p : curve->controlPoints()) cpts << QVector3D(p[0],p[1],p[2]);
        cpts = GeometryHelper::uniformResampleCount(cpts, cpts.size() * 5);

        int vi = 0;

        for(size_t i = 1; i < cpts.size(); i++){
            SDFGen::Vec3f p0 (cpts[i-1][0],cpts[i-1][1],cpts[i-1][2]);
            SDFGen::Vec3f p1 (cpts[i][0],cpts[i][1],cpts[i][2]);
            SDFGen::Vec3f p2 = (p0 + p1) * 0.5;

            vertList.push_back(p0);
            vertList.push_back(p1);
            vertList.push_back(p2);

            faceList.push_back(SDFGen::Vec3ui(vi+0,vi+1,vi+2));
            vi += 3;

            update_minmax(p0, min_box, max_box);
            update_minmax(p1, min_box, max_box);
            update_minmax(p2, min_box, max_box);
        }
    }

    if(sheet)
    {
        // Build surface geometry if needed
        auto & surface = sheet->surface;
        if(surface.quads.empty()){
            double resolution = (surface.mCtrlPoint.front().front()
                                 - surface.mCtrlPoint.back().back()).norm() * 0.1;
            surface.generateSurfaceQuads( resolution );
        }

        int vi = 0;

        for(auto quad : surface.quads)
        {
            QVector<SDFGen::Vec3f> p;
            for(int i = 0; i < 4; i++){
                SDFGen::Vec3f point(quad.p[i][0],quad.p[i][1],quad.p[i][2]);
                p << point;
                update_minmax(point, min_box, max_box);
            }

            vertList.push_back(p[0]);
            vertList.push_back(p[1]);
            vertList.push_back(p[2]);
            faceList.push_back(SDFGen::Vec3ui(vi+0,vi+1,vi+2));
            vi += 3;

            vertList.push_back(p[0]);
            vertList.push_back(p[2]);
            vertList.push_back(p[3]);
            faceList.push_back(SDFGen::Vec3ui(vi+0,vi+1,vi+2));
            vi += 3;
        }
    }

    int padding = 10;
    SDFGen::Vec3f unit(1,1,1);
    min_box -= unit*padding*dx;
    max_box += unit*padding*dx;
    SDFGen::Vec3ui sizes = SDFGen::Vec3ui((max_box - min_box)/dx);

    if (faceList.empty() || vertList.empty()) return;

    Array3f phi_grid;
    SDFGen::make_level_set3(faceList, vertList, min_box, dx, sizes[0], sizes[1], sizes[2], phi_grid, false, offset * 2.0);

    ScalarVolume volume = initScalarVolume(sizes[0], sizes[1], sizes[2], (sizes[0] + sizes[1] + sizes[2])*dx);

    for(int i = 0; i < sizes[0]; i++){
        for(int j = 0; j < sizes[1]; j++){
            for(int k = 0; k < sizes[2]; k++){
                volume[k][j][i] = phi_grid(i,j,k);
            }
        }
    }

    // Mesh surface from volume using marching cubes
    auto mesh = march(volume, offset);

    QSharedPointer<SurfaceMeshModel> newMesh = QSharedPointer<SurfaceMeshModel>(new SurfaceMeshModel());

    int vi = 0;
    for(auto tri : mesh){
        std::vector<SurfaceMeshModel::Vertex> verts;
        for(auto p : tri){
            Vector3 voxel(p.x, p.y, p.z);
            Vector3 pos = (voxel * dx) + Vector3(min_box[0],min_box[1],min_box[2]);
            newMesh->add_vertex(pos);
            verts.push_back(SurfaceMeshModel::Vertex(vi++));
        }
        newMesh->add_face(verts);
    }

    GeometryHelper::meregeVertices<Vector3>(newMesh.data());

    newMesh->updateBoundingBox();
    newMesh->update_face_normals();
    newMesh->update_vertex_normals();

	n->property["mesh"].setValue(newMesh);
	n->property["mesh_filename"].setValue(QString("meshes/%1.obj").arg(n->id));
}