topskychen / voxelizer

A fast parallel CPU-based surface & solid voxelizer.
MIT License
76 stars 20 forks source link

Supports output in common formats, such as obj #15

Closed kingui1106 closed 1 year ago

kingui1106 commented 1 year ago

I try to understand binvox or Rawvox. How do I convert it to the representation of the surface model?Like obj, or other common 3D formats.

kingui1106 commented 1 year ago

Based on my own understanding, the following simple code works.But obviously, exporting obj takes up a lot of time and space


/**
 * Write to file with Obj format.
 */
void Voxelizer::WriteObj() {
    if (option_.Verbose()) std::cout << "writing voxels to file..." << std::endl;
    int lx = 0, ux = size_x_ - 1, ly = 0, uy = size_y_ - 1, lz = 0, uz = size_z_ - 1;

    std::ofstream* output = new std::ofstream(option_.OutFilePath().c_str(), std::ios::out);
    if (option_.Verbose())
        std::cout << "dim : " << size_x_ << " x " << size_y_ << " x " << size_z_ << std::endl;
    if (option_.Verbose()) std::cout << "lower bound : " << (*lb_) << std::endl;
    if (option_.Verbose()) std::cout << "voxel size : " << (*unit_)[0] << " " << (*unit_)[1] << " " << (*unit_)[2] << std::endl;

    Vec3f minP((double)(*lb_)[0], (double)(*lb_)[1], (double)(*lb_)[2]);
    Vec3f size((double)(*unit_)[0], (double)(*unit_)[1], (double)(*unit_)[2]);
    //
    // write data
    //
     //The obj index starts at 1
    int idx = 1;

    //trigulate faces
    bool trigulate = false;
    VoxelIndex count = 0;
    for (int x = lx; x <= ux; ++x) {
        for (int y = ly; y <= uy; ++y) {
            for (int z = lz; z <= uz; ++z) {
                if (Filled(x, y, z)) {
                    auto _write_vertex = [&](const Vec3f& _p)->void
                    {
                        *output << "v " << _p[0] << ' ' << _p[1] << ' ' << _p[2] << std::endl;

                    };

                    Vec3f p0 = Vec3f(x * size[0], y * size[1], z * size[2]) + minP;
                    Vec3f p1 = Vec3f(p0[0] + size[0], p0[1], p0[2]);
                    Vec3f p2 = Vec3f(p0[0] , p0[1], p0[2]+ size[2]);
                    Vec3f p3 = Vec3f(p0[0] + size[0], p0[1], p0[2] + size[2]);
                    Vec3f p4 = Vec3f(p0[0] , p0[1] + size[1], p0[2]);
                    Vec3f p5 = Vec3f(p0[0] + size[0], p0[1] + size[1], p0[2]);
                    Vec3f p6 = Vec3f(p0[0] , p0[1] + size[1], p0[2] + size[2]);
                    Vec3f p7 = Vec3f(p0[0] + size[0], p0[1] + size[1], p0[2] + size[2]);

                    _write_vertex(p0);
                    _write_vertex(p1);
                    _write_vertex(p2);
                    _write_vertex(p3);
                    _write_vertex(p4);
                    _write_vertex(p5);
                    _write_vertex(p6);
                    _write_vertex(p7);

                    int idx0 = idx + 0;
                    int idx1 = idx + 1;
                    int idx2 = idx + 2;
                    int idx3 = idx + 3;
                    int idx4 = idx + 4;
                    int idx5 = idx + 5;
                    int idx6 = idx + 6;
                    int idx7 = idx + 7;

                    /* 
                        6 ----- 7
                       /|      /|
                      2 ----- 3 |
                      | |     | |
                      | 4 ----- 5
                      |/      |/
                      0 ----- 1
                 */

                    if(!trigulate){
                        *output << "f " << idx0 << " " << idx1 << " " << idx3 << " " << idx2 << std::endl;
                        *output << "f " << idx5 << " " << idx4 << " " << idx6 << " " << idx7 << std::endl;
                        *output << "f " << idx2 << " " << idx3 << " " << idx7 << " " << idx6 << std::endl;
                        *output << "f " << idx4 << " " << idx5 << " " << idx1 << " " << idx0 << std::endl;
                        *output << "f " << idx0 << " " << idx2 << " " << idx6 << " " << idx4 << std::endl;
                        *output << "f " << idx3 << " " << idx1 << " " << idx5 << " " << idx7 << std::endl;
                    }
                    else
                    {
                        *output << "f " << idx0 << " " << idx1 << " " << idx3 << std::endl;
                        *output << "f " << idx0 << " " << idx3 << " " << idx2 << std::endl;
                        *output << "f " << idx5 << " " << idx4 << " " << idx6 << std::endl;
                        *output << "f " << idx5 << " " << idx6 << " " << idx7 << std::endl;
                        *output << "f " << idx2 << " " << idx3 << " " << idx7 << std::endl;
                        *output << "f " << idx2 << " " << idx7 << " " << idx6 << std::endl;
                        *output << "f " << idx4 << " " << idx5 << " " << idx1 << std::endl;
                        *output << "f " << idx4 << " " << idx1 << " " << idx0 << std::endl;
                        *output << "f " << idx0 << " " << idx2 << " " << idx6 << std::endl;
                        *output << "f " << idx0 << " " << idx6 << " " << idx4 << std::endl;
                        *output << "f " << idx3 << " " << idx1 << " " << idx5 << std::endl;
                        *output << "f " << idx3 << " " << idx5 << " " << idx7 << std::endl;
                    }

                    idx += 8;
                    ++count;
                }
            }
        }
    }
    output->close();
    if (option_.Verbose()) std::cout << "wrote " << count << " voxels" << std::endl;
}
topskychen commented 1 year ago

Yes, this is one correct way to export obj technically. To save some time and space, you may 1) use the surface mode in voxelization 2) instead generating 8 vertex, you may use the center point as the only vertex (assume your voxel is not too large), and the model should look similar

Btw, may I ask what is motivation to export the voxels as an obj? since the input of the voxelizer is already an obj. if it is for simplification, an alternative is mesh simplification method.

topskychen commented 1 year ago

Yes, this is one correct way to export obj technically. To save some time and space, you may 1) use the surface mode in voxelization 2) instead generating 8 vertex, you may use the center point as the only vertex (assume your voxel is not too large), and the model should look similar

Btw, may I ask what is motivation to export the voxels as an obj? since the input of the voxelizer is already an obj. if it is for simplification, an alternative is mesh simplification method.

kingui1106 commented 1 year ago

Yes, this is one correct way to export obj technically. To save some time and space, you may

  1. use the surface mode in voxelization
  2. instead generating 8 vertex, you may use the center point as the only vertex (assume your voxel is not too large), and the model should look similar

Btw, may I ask what is motivation to export the voxels as an obj? since the input of the voxelizer is already an obj. if it is for simplification, an alternative is mesh simplification method.

Just want to get the expression of the voxel, and obj easy visualization.