#include "Mesh.h" #include "gl.h" #include #include #include #include #include using namespace std; using namespace glm; static const uvec3::value_type InvalidIndex = numeric_limits::max(); 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() { normals.clear(); normals.resize(positions.size(), vec3(0)); #pragma omp parallel for 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])); normals[a] += faceNormal; normals[b] += faceNormal; normals[c] += faceNormal; } for (size_t i = 0; i < normals.size(); i++) normals[i] = normalize(normals[i]); } void Mesh::generateFaceNormals() { faceNormals.clear(); faceNormals.resize(indices.size(), vec3(uninitialize)); #pragma omp parallel for for (size_t i = 0; i < indices.size(); i++) { int a = indices[i].x, b = indices[i].y, c = indices[i].z; faceNormals[i] = normalize( cross(positions[b] - positions[a], positions[c] - positions[a])); } } void Mesh::generateEdges() { edges.clear(); map, uint32_t> edgeMap; for (size_t iTri = 0; iTri < indices.size(); iTri++) { uvec3 idx = indices[iTri]; 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); auto key = std::make_pair(edge1.x, edge1.y); auto it1 = edgeMap.find(key); if (it1 != edgeMap.end()) { edges[it1->second].w = iTri; } else { size_t idx = edges.size(); edges.push_back(edge1); edgeMap[key] = idx; } } } } void Mesh::generateTangentBasis() { for (size_t i = 0; i < positions.size(); i += 3) { // Shortcuts for vertices vec3 & v0 = positions[i + 0]; vec3 & v1 = positions[i + 1]; vec3 & v2 = positions[i + 2]; // Shortcuts for UVs vec2 & uv0 = texcoords[i + 0]; vec2 & uv1 = texcoords[i + 1]; vec2 & uv2 = texcoords[i + 2]; // 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); } } void Mesh::generateAdjacent() { adjacents.resize(indices.size(), uvec3(InvalidIndex)); 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; } } } } 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 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 { assert(adjacents.size() == indices.size()); Mesh mesh; vector processed(indices.size(), false); for (size_t i = 0; i < indices.size(); i++) { if (processed[i]) continue; vector faces; map vertexMap; vec3 normal = faceNormals[i]; // check all adjacent faces stack 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()) { uint32_t newIdx = mesh.positions.size(); mesh.positions.push_back(positions[idx[k]]); if (normals.size()) mesh.normals.push_back(normals[idx[k]]); vertexMap[idx[k]] = newIdx; idx[k] = newIdx; } else { idx[k] = it->second; } } mesh.indices.push_back(idx); } } 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); } void Mesh::save(std::string filename) const { std::ofstream out(filename.c_str()); save(out); }