void Mesh::subdivideMesh() { //vectors storing all new vertices and faces to update mesh later vector<Vertex*> allNewVerts; vector<Face*> allNewFaces; //compute centroids because they'll be corrupted after the edge vertex addition vector<glm::vec3> centroids; for (int c = 0; c < faces->size(); c++) { faces->at(c)->centroid = faces->at(c)->getCentroid(); centroids.push_back(faces->at(c)->getCentroid()); } //add edge vertices vector<HalfEdge*> hes; for (int i = 0; i < halfedges->size(); i++) { if (!containsOrSym(halfedges->at(i), hes)) { hes.push_back(halfedges->at(i)); } } //move edge vertices according to Catmull-Clark vector<HalfEdge*> newhes; vector<glm::vec3> newpos; HalfEdge* he; HalfEdge* hv; for (int k = 0; k < hes.size(); k++) { hv = hes.at(k); glm::vec3 cent1 = hv->f->centroid; glm::vec3 cent2 = hv->sym->f->centroid; he = addVertex(hes.at(k)); allNewVerts.push_back(he->v); glm::vec3 oldpos = (cent1 + cent2 + *he->next->v->xyz + *he->getPrev()->v->xyz)/4.0f; newpos.push_back(oldpos); newhes.push_back(he); } //For each face, create centroid vertex, create splitting halfedges and set next pointers for the next pass. Face* fa; Vertex* vn; HalfEdge* nh; HalfEdge* newhtocent = 0; HalfEdge* newhtomid = 0; Face* newF; glm::vec3 centr; vector<Face*> newfaces; for (int n = 0; n < faces->size(); n++) { newfaces.clear(); //clear previous face's vector fa = faces->at(n); //initialize and position centroid vertex vn = new Vertex(0, 0, 0, new QString("545")); *vn->xyz = fa->centroid; allNewVerts.push_back(vn); //find a pointer to a newly added midpoint on this face for (int x = 0; x < newhes.size(); x++) { nh = newhes.at(x); if (nh->f == fa) { break; } if (nh->sym->f == fa) { nh = nh->sym->next; break; } } //Traverse the face, fixing pointers and creating split faces, all of which include the centroid HalfEdge* first = nh; while (true) { newF = new Face(NULL, fa->color->x, fa->color->y, fa->color->z, new QString("1010")); newhtomid = new HalfEdge(newF, nh->v, nh->next, NULL); newhtocent = new HalfEdge(newF, vn, newhtomid, NULL); newF->first = newhtocent; allNewFaces.push_back(newF); newfaces.push_back(newF); newhes.push_back(newhtomid); newhes.push_back(newhtocent); nh->next->f = newF; nh = nh->next->next; nh->f = newF; if (nh == first) { break; } } Face* fa2; //Now that the pointers are appropriately set, go back and fix each of the pointers that were left before for (int h = 0; h < newfaces.size(); h++) { nh = newfaces.at(h)->first; nh->next->next->next->next = nh; fa = newfaces.at(h); int q; if (h + 1 == newfaces.size()) { q = 0; } else { q = h + 1; } nh = fa->first; nh->sym = NULL; fa2 = newfaces.at(q); Mesh::connectFaces(fa2->first->next, nh); if (nh->sym == NULL) { cout << "Failed to connect face " << h << " with face " << q << endl; } } //cout << "Finished setting all remaining next pointers! " << endl; //Connect new aligned faces' sym pointers //for (int b = 0; b < newfaces.size(); b++) { /*fa = newfaces.at(b); int q; if (b + 1 == newfaces.size()) { 1 q = 0; } else { q = b + 1; } nh = fa->first; nh->sym = NULL; fa2 = newfaces.at(q); Mesh::connectFaces(nh, fa2->first->next); if (nh->sym == NULL) { cout << "Failed to connect face " << b << " with face " << q << endl; }*/ //} //cout << "Connected all split faces!" << endl; //cout << "Completed face " << n << " !" << endl; } for (int g = 0; g < newhes.size(); g++) { HalfEdge* pos = newhes.at(g); if (g < newpos.size()) { *pos->v->xyz = newpos.at(g); } halfedges->push_back(pos); } //reposition vertices for (int t = 0; t < verts->size(); t++) { vn = verts->at(t); glm::vec3 facesum = glm::vec3(0.0f); vector<HalfEdge*> adjEs = getVertAdjEdges(vn, *halfedges); glm::vec3 edgesum = glm::vec3(0.0f); for (int o = 0; o < adjEs.size(); o++) { edgesum += *adjEs.at(o)->v->xyz; facesum += *adjEs.at(o)->f->first->getPrev()->v->xyz; } float n = static_cast<float>(adjEs.size()); *vn->xyz = (*vn->xyz * ((n-2.0f)/n)) + (facesum/(n*n)) + (edgesum/(n*n)); } for (int y = 0; y < allNewVerts.size(); y++) { verts->push_back(allNewVerts.at(y)); } *faces = allNewFaces; generateVertArray(); generateColorArray(); generateIndArray(); generateNormArray(); cout << "Subdivision complete!" << endl; }