2017-10-29 05:28:00 +01:00
|
|
|
#include "Mesh.h"
|
2017-11-03 00:22:38 +01:00
|
|
|
#include "gl.h"
|
2017-10-29 05:28:00 +01:00
|
|
|
|
|
|
|
#include <glm/geometric.hpp>
|
|
|
|
|
|
|
|
#include <map>
|
2017-11-02 03:44:44 +01:00
|
|
|
#include <limits>
|
|
|
|
#include <stack>
|
2017-11-03 00:22:38 +01:00
|
|
|
#include <fstream>
|
2017-10-29 05:28:00 +01:00
|
|
|
|
|
|
|
using namespace std;
|
|
|
|
using namespace glm;
|
|
|
|
|
2017-11-02 03:44:44 +01:00
|
|
|
static const uvec3::value_type InvalidIndex =
|
|
|
|
numeric_limits<uvec3::value_type>::max();
|
|
|
|
|
2017-11-03 00:22:38 +01:00
|
|
|
Mesh::Mesh() {
|
|
|
|
|
|
|
|
}
|
|
|
|
Mesh::Mesh(Mesh &other) {
|
|
|
|
positions = other.positions;
|
|
|
|
normals = other.normals;
|
|
|
|
texcoords = other.texcoords;
|
|
|
|
|
|
|
|
faceNormals = other.faceNormals;
|
|
|
|
indices = other.indices;
|
|
|
|
patches = other.patches;
|
|
|
|
edges = other.edges;
|
|
|
|
|
|
|
|
adjacents = other.adjacents;
|
|
|
|
tangents = other.tangents;
|
|
|
|
bitangents = other.bitangents;
|
|
|
|
}
|
|
|
|
|
|
|
|
Mesh::Mesh(Mesh &&other) {
|
|
|
|
positions.swap(other.positions);
|
|
|
|
normals.swap(other.normals);
|
|
|
|
texcoords.swap(other.texcoords);
|
|
|
|
|
|
|
|
faceNormals.swap(other.faceNormals);
|
|
|
|
indices.swap(other.indices);
|
|
|
|
patches.swap(other.patches);
|
|
|
|
edges.swap(other.edges);
|
|
|
|
|
|
|
|
adjacents.swap(other.adjacents);
|
|
|
|
tangents.swap(other.tangents);
|
|
|
|
bitangents.swap(other.bitangents);
|
|
|
|
}
|
|
|
|
|
|
|
|
Mesh& Mesh::operator=(Mesh &&other) {
|
|
|
|
positions.swap(other.positions);
|
|
|
|
normals.swap(other.normals);
|
|
|
|
texcoords.swap(other.texcoords);
|
|
|
|
|
|
|
|
faceNormals.swap(other.faceNormals);
|
|
|
|
indices.swap(other.indices);
|
|
|
|
patches.swap(other.patches);
|
|
|
|
edges.swap(other.edges);
|
|
|
|
|
|
|
|
adjacents.swap(other.adjacents);
|
|
|
|
tangents.swap(other.tangents);
|
|
|
|
bitangents.swap(other.bitangents);
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Mesh::generateNormals() {
|
2017-10-29 05:28:00 +01:00
|
|
|
normals.clear();
|
2017-11-02 03:44:44 +01:00
|
|
|
normals.resize(positions.size(), vec3(0));
|
2017-11-03 00:22:38 +01:00
|
|
|
#pragma omp parallel for
|
2017-11-02 03:44:44 +01:00
|
|
|
for (size_t i = 0; i < indices.size(); i++) {
|
|
|
|
int a = indices[i].x, b = indices[i].y, c = indices[i].z;
|
|
|
|
vec3 faceNormal = normalize(
|
|
|
|
cross(positions[b] - positions[a],
|
|
|
|
positions[c] - positions[a]));
|
2017-10-29 05:28:00 +01:00
|
|
|
normals[a] += faceNormal;
|
|
|
|
normals[b] += faceNormal;
|
|
|
|
normals[c] += faceNormal;
|
|
|
|
}
|
|
|
|
for (size_t i = 0; i < normals.size(); i++)
|
|
|
|
normals[i] = normalize(normals[i]);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2017-11-03 00:22:38 +01:00
|
|
|
void Mesh::generateFaceNormals() {
|
|
|
|
faceNormals.clear();
|
|
|
|
faceNormals.resize(indices.size(), vec3(uninitialize));
|
|
|
|
#pragma omp parallel for
|
2017-11-02 03:44:44 +01:00
|
|
|
for (size_t i = 0; i < indices.size(); i++) {
|
|
|
|
int a = indices[i].x, b = indices[i].y, c = indices[i].z;
|
2017-11-03 00:22:38 +01:00
|
|
|
faceNormals[i] = normalize(
|
2017-11-02 03:44:44 +01:00
|
|
|
cross(positions[b] - positions[a],
|
|
|
|
positions[c] - positions[a]));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-03 00:22:38 +01:00
|
|
|
void Mesh::generateEdges() {
|
2017-10-29 05:28:00 +01:00
|
|
|
edges.clear();
|
|
|
|
map<pair<uint32_t, uint32_t>, uint32_t> edgeMap;
|
2017-11-02 03:44:44 +01:00
|
|
|
for (size_t iTri = 0; iTri < indices.size(); iTri++) {
|
|
|
|
uvec3 idx = indices[iTri];
|
2017-10-29 05:28:00 +01:00
|
|
|
for (size_t k = 0; k < 3; k++) {
|
|
|
|
int a = idx[k];
|
|
|
|
int b = idx[(k + 1) % 3];
|
|
|
|
uvec4 edge1(std::min(a, b), std::max(a, b), iTri, 0);
|
2017-11-02 03:44:44 +01:00
|
|
|
auto key = std::make_pair(edge1.x, edge1.y);
|
|
|
|
auto it1 = edgeMap.find(key);
|
2017-10-29 05:28:00 +01:00
|
|
|
if (it1 != edgeMap.end()) {
|
2017-11-02 03:44:44 +01:00
|
|
|
edges[it1->second].w = iTri;
|
2017-10-29 05:28:00 +01:00
|
|
|
} else {
|
2017-11-02 03:44:44 +01:00
|
|
|
size_t idx = edges.size();
|
2017-10-29 05:28:00 +01:00
|
|
|
edges.push_back(edge1);
|
2017-11-02 03:44:44 +01:00
|
|
|
edgeMap[key] = idx;
|
2017-10-29 05:28:00 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-03 00:22:38 +01:00
|
|
|
void Mesh::generateTangentBasis() {
|
2017-10-29 05:28:00 +01:00
|
|
|
|
2017-11-02 03:44:44 +01:00
|
|
|
for (size_t i = 0; i < positions.size(); i += 3) {
|
2017-10-29 05:28:00 +01:00
|
|
|
|
|
|
|
// Shortcuts for vertices
|
2017-11-02 03:44:44 +01:00
|
|
|
vec3 & v0 = positions[i + 0];
|
|
|
|
vec3 & v1 = positions[i + 1];
|
|
|
|
vec3 & v2 = positions[i + 2];
|
2017-10-29 05:28:00 +01:00
|
|
|
|
|
|
|
// Shortcuts for UVs
|
2017-11-02 03:44:44 +01:00
|
|
|
vec2 & uv0 = texcoords[i + 0];
|
|
|
|
vec2 & uv1 = texcoords[i + 1];
|
|
|
|
vec2 & uv2 = texcoords[i + 2];
|
2017-10-29 05:28:00 +01:00
|
|
|
|
|
|
|
// Edges of the triangle : postion delta
|
|
|
|
vec3 deltaPos1 = v1 - v0;
|
|
|
|
vec3 deltaPos2 = v2 - v0;
|
|
|
|
|
|
|
|
// UV delta
|
|
|
|
vec2 deltaUV1 = uv1 - uv0;
|
|
|
|
vec2 deltaUV2 = uv2 - uv0;
|
|
|
|
|
|
|
|
float r = 1.0f / (deltaUV1.x * deltaUV2.y - deltaUV1.y * deltaUV2.x);
|
|
|
|
vec3 tangent = (deltaPos1 * deltaUV2.y - deltaPos2 * deltaUV1.y) * r;
|
|
|
|
vec3 bitangent = (deltaPos2 * deltaUV1.x - deltaPos1 * deltaUV2.x) * r;
|
|
|
|
// Set the same tangent for all three vertices of the triangle.
|
|
|
|
// They will be merged later, in vboindexer.cpp
|
|
|
|
tangents.push_back(tangent);
|
|
|
|
tangents.push_back(tangent);
|
|
|
|
tangents.push_back(tangent);
|
|
|
|
|
|
|
|
// Same thing for binormals
|
|
|
|
bitangents.push_back(bitangent);
|
|
|
|
bitangents.push_back(bitangent);
|
|
|
|
bitangents.push_back(bitangent);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
2017-11-02 03:44:44 +01:00
|
|
|
|
2017-11-03 00:22:38 +01:00
|
|
|
void Mesh::generateAdjacent() {
|
|
|
|
adjacents.resize(indices.size(), uvec3(InvalidIndex));
|
2017-11-02 03:44:44 +01:00
|
|
|
for (size_t i = 0; i < edges.size(); i++) {
|
|
|
|
int a = edges[i].z;
|
|
|
|
int b = edges[i].w;
|
|
|
|
|
|
|
|
uvec3 &aa = adjacents[a];
|
|
|
|
for (size_t j = 0; j < 3; j++) {
|
|
|
|
if (aa[j] == InvalidIndex) {
|
|
|
|
aa[j] = b;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
uvec3 &ab = adjacents[b];
|
|
|
|
for (size_t j = 0; j < 3; j++) {
|
|
|
|
if (ab[j] == InvalidIndex) {
|
|
|
|
ab[j] = a;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-03 00:22:38 +01:00
|
|
|
void Mesh::moveToMean() {
|
|
|
|
vec3 mean(0);
|
|
|
|
for (size_t i = 0; i < positions.size(); i++) {
|
|
|
|
mean += positions[i];
|
|
|
|
}
|
|
|
|
mean *= vec3(1.f / positions.size());
|
|
|
|
for (size_t i = 0; i < positions.size(); i++) {
|
|
|
|
positions[i] -= mean;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Mesh::smooth() {
|
|
|
|
if (positions.size() == 0 || indices.size() == 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
vec3v_t cogs(positions.size(), vec3(0.f));
|
|
|
|
vector<int> valence(positions.size(), 0);
|
|
|
|
|
|
|
|
for (size_t iTri = 0; iTri < indices.size(); iTri++) {
|
|
|
|
const uvec3 &idx = indices[iTri];
|
|
|
|
for (size_t iE = 0; iE < 3; iE++) {
|
|
|
|
valence[idx[iE]] += 2;
|
|
|
|
cogs[idx[iE]] += positions[idx[(iE + 1) % 3]];
|
|
|
|
cogs[idx[iE]] += positions[idx[(iE + 2) % 3]];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
for (v_it = mesh.vertices_begin(); v_it != v_end; ++v_it) {
|
|
|
|
cog[0] = cog[1] = cog[2] = valence = 0.0;
|
|
|
|
|
|
|
|
for (vv_it = mesh.vv_iter(*v_it); vv_it.is_valid(); ++vv_it) {
|
|
|
|
cog += mesh.point(*vv_it);
|
|
|
|
++valence;
|
|
|
|
}
|
|
|
|
cogs.push_back(cog / valence);
|
|
|
|
}
|
|
|
|
for (v_it = mesh.vertices_begin(), cog_it = cogs.begin(); v_it != v_end;
|
|
|
|
++v_it, ++cog_it)
|
|
|
|
if (!mesh.is_boundary(*v_it))
|
|
|
|
mesh.set_point(*v_it, *cog_it);
|
|
|
|
|
|
|
|
*/
|
|
|
|
#pragma omp parallel for
|
|
|
|
for (size_t i = 0; i < positions.size(); i++) {
|
|
|
|
// vtx[i] = vtx[i] * vec3(0.8)
|
|
|
|
// + cogs[i] * vec3(0.2f / valence[i]);
|
|
|
|
positions[i] = cogs[i] * vec3(1.f / valence[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Mesh::saveAttrib(std::ostream &out, const char *prefix,
|
|
|
|
const vec3v_t &elements) const {
|
|
|
|
for (size_t i = 0; i < elements.size(); i++) {
|
|
|
|
out << prefix << elements[i].x << " " << elements[i].y << " "
|
|
|
|
<< elements[i].z << "\n";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Mesh::saveAttrib(std::ostream &out, const char *prefix,
|
|
|
|
const vec2v_t &elements) const {
|
|
|
|
for (size_t i = 0; i < elements.size(); i++) {
|
|
|
|
out << prefix << elements[i].x << " " << elements[i].y << "\n";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Mesh::saveFaces(std::ostream &out, const uvec3v_t &incdices,
|
|
|
|
size_t attribs) const {
|
|
|
|
for (size_t i = 0; i < incdices.size(); i++) {
|
|
|
|
out << "f";
|
|
|
|
|
|
|
|
for (size_t j = 0; j < 3; j++) {
|
|
|
|
int v = incdices[i][j] + 1;
|
|
|
|
out << " " << v;
|
|
|
|
if (attribs > 1)
|
|
|
|
out << "/" << v;
|
|
|
|
if (attribs > 2)
|
|
|
|
out << "/" << v;
|
|
|
|
out << " ";
|
|
|
|
}
|
|
|
|
|
|
|
|
out << "\n";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Mesh Mesh::createPatched(float threshold) const {
|
2017-11-02 03:44:44 +01:00
|
|
|
assert(adjacents.size() == indices.size());
|
2017-11-03 00:22:38 +01:00
|
|
|
Mesh mesh;
|
2017-11-02 03:44:44 +01:00
|
|
|
vector<bool> processed(indices.size(), false);
|
|
|
|
|
|
|
|
for (size_t i = 0; i < indices.size(); i++) {
|
|
|
|
if (processed[i])
|
|
|
|
continue;
|
|
|
|
vector<uint32_t> faces;
|
|
|
|
map<uint32_t, uint32_t> vertexMap;
|
|
|
|
|
|
|
|
vec3 normal = faceNormals[i];
|
|
|
|
|
|
|
|
// check all adjacent faces
|
|
|
|
stack<uint32_t> facesToCheck;
|
|
|
|
facesToCheck.push(i);
|
|
|
|
while (facesToCheck.size()) {
|
|
|
|
uint32_t face = facesToCheck.top();
|
|
|
|
facesToCheck.pop();
|
|
|
|
if (face == InvalidIndex || processed[face])
|
|
|
|
continue;
|
|
|
|
if (dot(normal, faceNormals[face]) > threshold) {
|
|
|
|
faces.push_back(face);
|
|
|
|
//normal = normalize(normal + 0.5f * faceNormals[face]);
|
|
|
|
processed[face] = true;
|
|
|
|
facesToCheck.push(adjacents[face].x);
|
|
|
|
facesToCheck.push(adjacents[face].y);
|
|
|
|
facesToCheck.push(adjacents[face].z);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// fill new arrays
|
|
|
|
for (size_t j = 0; j < faces.size(); j++) {
|
|
|
|
uvec3 idx = indices[faces[j]];
|
|
|
|
for (size_t k = 0; k < 3; k++) {
|
|
|
|
auto it = vertexMap.find(idx[k]);
|
|
|
|
if (it == vertexMap.end()) {
|
2017-11-03 00:22:38 +01:00
|
|
|
uint32_t newIdx = mesh.positions.size();
|
|
|
|
mesh.positions.push_back(positions[idx[k]]);
|
|
|
|
if (normals.size())
|
|
|
|
mesh.normals.push_back(normals[idx[k]]);
|
2017-11-02 03:44:44 +01:00
|
|
|
vertexMap[idx[k]] = newIdx;
|
|
|
|
idx[k] = newIdx;
|
|
|
|
} else {
|
|
|
|
idx[k] = it->second;
|
|
|
|
}
|
|
|
|
}
|
2017-11-03 00:22:38 +01:00
|
|
|
mesh.indices.push_back(idx);
|
2017-11-02 03:44:44 +01:00
|
|
|
}
|
|
|
|
}
|
2017-11-03 00:22:38 +01:00
|
|
|
return mesh;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Mesh::save(std::ostream &out) const {
|
|
|
|
size_t nAttribs = 1;
|
|
|
|
saveAttrib(out, "v ", positions);
|
|
|
|
if (normals.size()) {
|
|
|
|
nAttribs++;
|
|
|
|
saveAttrib(out, "vn ", normals);
|
|
|
|
}
|
|
|
|
if (texcoords.size()) {
|
|
|
|
nAttribs++;
|
|
|
|
saveAttrib(out, "vt ", texcoords);
|
|
|
|
}
|
|
|
|
saveFaces(out, indices, nAttribs);
|
|
|
|
}
|
2017-11-02 03:44:44 +01:00
|
|
|
|
2017-11-03 00:22:38 +01:00
|
|
|
void Mesh::save(std::string filename) const {
|
|
|
|
std::ofstream out(filename.c_str());
|
|
|
|
save(out);
|
2017-11-02 03:44:44 +01:00
|
|
|
}
|
|
|
|
|