asteroidgen/src/Polygoniser.cpp

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);
}
}
}
}
}