#include "Polygoniser.h" #include #include #include #include static const int isocells = 32; Polygonizer::Polygonizer(Density &density, float isolevel) : density(density), isolevel(isolevel) { updateIsocell(); } void Polygonizer::setIsoLevel(float isolevel) { bool needIsocellUpdate = false; if (this->isolevel != isolevel) { this->isolevel = isolevel; needIsocellUpdate = true; } needIsocellUpdate |= (isocellVersion != density.getVersion()); if (needIsocellUpdate) updateIsocell(); } void Polygonizer::updateIsocell() { isocell.clear(); isocell.reserve(isocells * isocells * isocells); float step = 1. / isocells; for (size_t ix = 0; ix < isocells; ix++) { float xmin = ix * step; float xmax = xmin + step; for (size_t iy = 0; iy < isocells; iy++) { float ymin = iy * step; float ymax = ymin + step; float xyz = density(vec3(xmin, ymin, 0)); float Xyz = density(vec3(xmax, ymin, 0)); float xYz = density(vec3(xmin, ymax, 0)); float XYz = density(vec3(xmax, ymax, 0)); bool zAllUnder = (xyz < isolevel) && (Xyz < isolevel) && (xYz < isolevel) && (XYz < isolevel); bool zAllOver = (xyz > isolevel) && (Xyz > isolevel) && (xYz > isolevel) && (XYz > isolevel); for (size_t iz = 0; iz < isocells; iz++) { float zmin = iz * step; float zmax = zmin + step; float xyZ = density(vec3(xmin, ymin, zmax)); float XyZ = density(vec3(xmax, ymin, zmax)); float xYZ = density(vec3(xmin, ymax, zmax)); float XYZ = density(vec3(xmax, ymax, zmax)); bool ZAllUnder = (xyZ < isolevel) && (XyZ < isolevel) && (xYZ < isolevel) && (XYZ < isolevel); bool ZAllOver = (xyZ > isolevel) && (XyZ > isolevel) && (xYZ > isolevel) && (XYZ > isolevel); isocell[ix * isocells * isocells + iy * isocells + iz] = (zAllUnder && ZAllUnder) || (zAllOver && ZAllOver); xyz = xyZ; Xyz = XyZ; xYz = xYZ; XYz = XYZ; zAllUnder = ZAllUnder; zAllOver = ZAllOver; } } } isocellVersion = density.getVersion(); } void Polygonizer::polygonize(const glm::vec3 lower, const glm::vec3 upper, float resolution) { size_t nSteps = 1.f / resolution - 1; size_t nT = 0; for (size_t ix = 0; ix < nSteps; ix++) { double x = (double(ix) + 0.5) * resolution; for (size_t iy = 0; iy < nSteps; iy++) { double y = (double(iy) + 0.5) * resolution; for (size_t iz = 0; iz < nSteps; iz++) { double z = (double(iz) + 0.5) * resolution; GRIDCELL gridCell; gridCell.p[0] = vec3(x, y, z); gridCell.p[1] = vec3(x + resolution, y, z); gridCell.p[2] = vec3(x + resolution, y + resolution, z); gridCell.p[3] = vec3(x, y + resolution, z); gridCell.p[4] = vec3(x, y, z + resolution); gridCell.p[5] = vec3(x + resolution, y, z + resolution); gridCell.p[6] = vec3(x + resolution, y + resolution, z + resolution); gridCell.p[7] = vec3(x, y + resolution, z + resolution); for (size_t iCell = 0; iCell < 8; iCell++) { gridCell.val[iCell] = density(gridCell.p[iCell]); } TRIANGLE tris[6]; int nTris = Polygonise(gridCell, isolevel, tris); nT += nTris; for (int iTri = 0; iTri < nTris; iTri++) { vec3 *ps = tris[iTri].p; // skip degenerate vertices if (all(epsilonEqual(ps[0], ps[1], 1e-8f)) || all(epsilonEqual(ps[0], ps[2], 1e-8f)) || all(epsilonEqual(ps[2], ps[1], 1e-8f))) continue; glm::uvec3 idc; for (size_t k = 0; k < 3; k++) { glm::vec3 &p = tris[iTri].p[k]; std::map::iterator vit = vertexLookup.find(p); if (vit != vertexLookup.end()) { idc[k] = vit->second; } else { idc[k] = vertices.size(); vertices.push_back(p); vertexLookup[p] = idc[k]; } } indices.push_back(idc); } } } } } void Polygonizer::polygonize(float resolution) { vertexLookup.clear(); vertices.clear(); indices.clear(); // coarse scan float coarseResolution = resolution * 10; size_t nSteps = 1.f / resolution - 1; size_t nT = 0; for (size_t ix = 0; ix < nSteps; ix++) { double x = (double(ix) + 0.5) * resolution; for (size_t iy = 0; iy < nSteps; iy++) { double y = (double(iy) + 0.5) * resolution; for (size_t iz = 0; iz < nSteps; iz++) { double z = (double(iz) + 0.5) * resolution; GRIDCELL gridCell; gridCell.p[0] = vec3(x, y, z); gridCell.p[1] = vec3(x + resolution, y, z); gridCell.p[2] = vec3(x + resolution, y + resolution, z); gridCell.p[3] = vec3(x, y + resolution, z); gridCell.p[4] = vec3(x, y, z + resolution); gridCell.p[5] = vec3(x + resolution, y, z + resolution); gridCell.p[6] = vec3(x + resolution, y + resolution, z + resolution); gridCell.p[7] = vec3(x, y + resolution, z + resolution); for (size_t iCell = 0; iCell < 8; iCell++) { gridCell.val[iCell] = density(gridCell.p[iCell]); } TRIANGLE tris[6]; int nTris = Polygonise(gridCell, isolevel, tris); nT += nTris; for (int iTri = 0; iTri < nTris; iTri++) { vec3 *ps = tris[iTri].p; // skip degenerate vertices if (all(epsilonEqual(ps[0], ps[1], 1e-8f)) || all(epsilonEqual(ps[0], ps[2], 1e-8f)) || all(epsilonEqual(ps[2], ps[1], 1e-8f))) continue; glm::uvec3 idc; for (size_t k = 0; k < 3; k++) { glm::vec3 &p = tris[iTri].p[k]; std::map::iterator vit = vertexLookup.find(p); if (vit != vertexLookup.end()) { idc[k] = vit->second; } else { idc[k] = vertices.size(); vertices.push_back(p); vertexLookup[p] = idc[k]; } } indices.push_back(idc); } } } } }