asteroidgen/src/Polygoniser.h

118 lines
2.7 KiB
C++

#pragma once
#include <functional>
#include <vector>
#include <map>
#include <glm/vec3.hpp>
#include <glm/gtc/epsilon.hpp>
#include <MarchingCube.h>
#include <logger.h>
#include "Density.h"
struct CompareVec3 {
bool operator()(const glm::vec3 &lhs, const glm::vec3 &rhs) {
static const float epsilon = 1e-5;
if (lhs.x < rhs.x - epsilon)
return true;
else if (lhs.x > rhs.x + epsilon)
return false;
else {
if (lhs.y < rhs.y - epsilon)
return true;
else if (lhs.y > rhs.y + epsilon)
return false;
else {
if (lhs.z < rhs.z - epsilon)
return true;
else if (lhs.z > rhs.z + epsilon)
return false;
else {
return false;
}
}
}
}
};
class Polygonizer {
public:
std::vector<glm::vec3> vertices;
std::vector<glm::uvec3> triangles;
Density &density;
Polygonizer(Density &density) :
density(density) {
}
void polygonize(float isolevel, float resolution) {
vertices.clear();
triangles.clear();
std::map<glm::vec3, int, CompareVec3> vertexLookup;
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];
}
}
triangles.push_back(idc);
}
}
}
}
}
};