200 lines
5.6 KiB
C++
200 lines
5.6 KiB
C++
#include "Polygoniser.h"
|
|
|
|
#include <functional>
|
|
#include <map>
|
|
|
|
#include <glm/gtc/epsilon.hpp>
|
|
|
|
#include <MarchingCube.h>
|
|
|
|
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<glm::vec3, int>::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<glm::vec3, int>::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);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|