Пример #1
0
	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;
		
}