void process(const vector<string> &args, MyWindow *w) { int i; ArgData a = processArgs(args); Debugging::setOutStream(cout); Mesh m(a.filename); if(m.vertices.size() == 0) { cout << "Error reading file. Aborting." << endl; exit(0); return; } for(i = 0; i < (int)m.vertices.size(); ++i) m.vertices[i].pos = a.meshTransform * m.vertices[i].pos; m.normalizeBoundingBox(); m.computeVertexNormals(); Skeleton given = a.skeleton; given.scale(a.skelScale * 0.7); if(a.stopAtMesh) { //if early bailout w->addMesh(new StaticDisplayMesh(m)); return; } PinocchioOutput o; if(!a.noFit) { //do everything o = autorig(given, m); } else { //skip the fitting step--assume the skeleton is already correct for the mesh TreeType *distanceField = constructDistanceField(m); VisTester<TreeType> *tester = new VisTester<TreeType>(distanceField); o.embedding = a.skeleton.fGraph().verts; for(i = 0; i < (int)o.embedding.size(); ++i) o.embedding[i] = m.toAdd + o.embedding[i] * m.scale; o.attachment = new Attachment(m, a.skeleton, o.embedding, tester); delete tester; delete distanceField; } if(o.embedding.size() == 0) { cout << "Error embedding" << endl; exit(0); } if(a.motionname.size() > 0) { w->addMesh(new DefMesh(m, given, o.embedding, *(o.attachment), new Motion(a.motionname))); } else { w->addMesh(new StaticDisplayMesh(m)); for(i = 1; i < (int)o.embedding.size(); ++i) { w->addLine(LineSegment(o.embedding[i], o.embedding[given.fPrev()[i]], Vector3(.5, .5, 0), 4.)); } } //output skeleton embedding for(i = 0; i < (int)o.embedding.size(); ++i) o.embedding[i] = (o.embedding[i] - m.toAdd) / m.scale; ofstream os("skeleton.out"); for(i = 0; i < (int)o.embedding.size(); ++i) { os << i << " " << o.embedding[i][0] << " " << o.embedding[i][1] << " " << o.embedding[i][2] << " " << a.skeleton.fPrev()[i] << endl; } //output attachment std::ofstream astrm("attachment.out"); for(i = 0; i < (int)m.vertices.size(); ++i) { Vector<double, -1> v = o.attachment->getWeights(i); for(int j = 0; j < v.size(); ++j) { double d = floor(0.5 + v[j] * 10000.) / 10000.; astrm << d << " "; } astrm << endl; } delete o.attachment; }
void process(const vector<string> &args, MyWindow *w) { int i; // 读入输入参数的信息,初始化skeleton为humanskeleton ArgData a = processArgs(args); Debugging::setOutStream(cout); Mesh m(a.filename); if(m.vertices.size() == 0) { cout << "Error reading file. Aborting." << endl; exit(0); return; } for(i = 0; i < (int)m.vertices.size(); ++i) m.vertices[i].pos = a.meshTransform * m.vertices[i].pos; // 将坐标空间中的点调整到[0, 1]之间 m.normalizeBoundingBox(); m.computeVertexNormals(); Skeleton given = a.skeleton; given.scale(a.skelScale * 0.01); for(i = 1; i < (int)given.fGraph().verts.size(); ++i) { w->addOriginLines(LineSegment(given.fGraph().verts[i], given.fGraph().verts[given.fPrev()[i]], Vector3(.0, .5, 0.5), 4.)); } w->addOriginPoints(given.fGraph().verts); w->setCIdx(given.cfMapV); if(a.stopAtMesh) { //if early bailout w->addMesh(new StaticDisplayMesh(m)); return; } PinocchioOutput o; if(!a.noFit) { //do everything o = autorig(given, m); } else { //skip the fitting step--assume the skeleton is already correct for the mesh TreeType *distanceField = constructDistanceField(m); VisTester<TreeType> *tester = new VisTester<TreeType>(distanceField); o.embedding = a.skeleton.fGraph().verts; for(i = 0; i < (int)o.embedding.size(); ++i) o.embedding[i] = m.toAdd + o.embedding[i] * m.scale; o.attachment = new Attachment(m, a.skeleton, o.embedding, tester); delete tester; delete distanceField; } if(o.embedding.size() == 0) { cout << "Error embedding" << endl; exit(0); } if(a.motionname.size() > 0) { w->addMesh(new DefMesh(m, given, o.embedding, *(o.attachment), new Motion(a.motionname))); } else { w->addMesh(new StaticDisplayMesh(m)); w->addSphere(o.spheres); w->addMatchPoint(o.embedding); w->addDiscreteEmbedV(o.discreteEmbedding); for (i = 0; i < (int)o.embeddingIdx.size(); ++i) { w->addEmbeddingV(o.ptGraph.verts[o.embeddingIdx[i]]); } for (i = 1; i < (int)o.ptGraph.edges.size(); ++i) { vector<int> edge = o.ptGraph.edges[i]; for (int j = 0; j < (int)edge.size(); ++j) { if (edge[j] < i) { w->addExtractLines( LineSegment(o.ptGraph.verts[i], o.ptGraph.verts[edge[j]], Vector3(0, 1.0000, 0.4980), 2) ); } } } for (i = 0; i < (int)o.limbVerts.size(); ++i) { w->addLimbVerts(o.ptGraph.verts[i]); } for(i = 1; i < (int)o.embedding.size(); ++i) { //LineSegment(const Vector3 &inP1, const Vector3 &inP2,const Vector3 &inColor , double inThickness = 1.) w->addLine(LineSegment(o.embedding[i], o.embedding[given.fPrev()[i]], Vector3(.5, .5, 0), 4.)); } } //output skeleton embedding for(i = 0; i < (int)o.embedding.size(); ++i) o.embedding[i] = (o.embedding[i] - m.toAdd) / m.scale; ofstream os("skeleton.out"); for(i = 0; i < (int)o.embedding.size(); ++i) { os << i << " " << o.embedding[i][0] << " " << o.embedding[i][1] << " " << o.embedding[i][2] << " " << a.skeleton.fPrev()[i] << endl; } //output attachment std::ofstream astrm("attachment.out"); for(i = 0; i < (int)m.vertices.size(); ++i) { Vector<double, -1> v = o.attachment->getWeights(i); for(int j = 0; j < v.size(); ++j) { double d = floor(0.5 + v[j] * 10000.) / 10000.; astrm << d << " "; } astrm << endl; } delete o.attachment; }
AttachmentPrivate1(const Mesh &mesh, const Skeleton &skeleton, const vector<Vector3> &match, const VisibilityTester *tester, double initialHeatWeight) { int i, j; int nv = mesh.vertices.size(); //compute edges vector<vector<int> > edges(nv); for(i = 0; i < nv; ++i) { int cur, start; cur = start = mesh.vertices[i].edge; do { edges[i].push_back(mesh.edges[cur].vertex); cur = mesh.edges[mesh.edges[cur].prev].twin; } while(cur != start); } weights.resize(nv); int bones = skeleton.fGraph().verts.size() - 1; for(i = 0; i < nv; ++i) // initialize the weights vectors so they are big enough weights[i][bones - 1] = 0.; vector<vector<double> > boneDists(nv); vector<vector<bool> > boneVis(nv); for(i = 0; i < nv; ++i) { boneDists[i].resize(bones, -1); boneVis[i].resize(bones); Vector3 cPos = mesh.vertices[i].pos; vector<Vector3> normals; for(j = 0; j < (int)edges[i].size(); ++j) { int nj = (j + 1) % edges[i].size(); Vector3 v1 = mesh.vertices[edges[i][j]].pos - cPos; Vector3 v2 = mesh.vertices[edges[i][nj]].pos - cPos; normals.push_back((v1 % v2).normalize()); } double minDist = 1e37; for(j = 1; j <= bones; ++j) { const Vector3 &v1 = match[j], &v2 = match[skeleton.fPrev()[j]]; boneDists[i][j - 1] = sqrt(distsqToSeg(cPos, v1, v2)); minDist = min(boneDists[i][j - 1], minDist); } for(j = 1; j <= bones; ++j) { //the reason we don't just pick the closest bone is so that if two are //equally close, both are factored in. if(boneDists[i][j - 1] > minDist * 1.0001) continue; const Vector3 &v1 = match[j], &v2 = match[skeleton.fPrev()[j]]; Vector3 p = projToSeg(cPos, v1, v2); boneVis[i][j - 1] = tester->canSee(cPos, p) && vectorInCone(cPos - p, normals); } } //We have -Lw+Hw=HI, same as (H-L)w=HI, with (H-L)=DA (with D=diag(1./area)) //so w = A^-1 (HI/D) vector<vector<pair<int, double> > > A(nv); vector<double> D(nv, 0.), H(nv, 0.); vector<int> closest(nv, -1); for(i = 0; i < nv; ++i) { //get areas for(j = 0; j < (int)edges[i].size(); ++j) { int nj = (j + 1) % edges[i].size(); D[i] += ((mesh.vertices[edges[i][j]].pos - mesh.vertices[i].pos) % (mesh.vertices[edges[i][nj]].pos - mesh.vertices[i].pos)).length(); } D[i] = 1. / (1e-10 + D[i]); //get bones double minDist = 1e37; for(j = 0; j < bones; ++j) { if(boneDists[i][j] < minDist && boneVis[i][j]) { closest[i] = j; minDist = boneDists[i][j]; } } for(j = 0; j < bones; ++j) if(boneVis[i][j] && boneDists[i][j] <= minDist * 1.00001) H[i] += initialHeatWeight / SQR(1e-8 + boneDists[i][closest[i]]); //get laplacian double sum = 0.; for(j = 0; j < (int)edges[i].size(); ++j) { int nj = (j + 1) % edges[i].size(); int pj = (j + edges[i].size() - 1) % edges[i].size(); Vector3 v1 = mesh.vertices[i].pos - mesh.vertices[edges[i][pj]].pos; Vector3 v2 = mesh.vertices[edges[i][j]].pos - mesh.vertices[edges[i][pj]].pos; Vector3 v3 = mesh.vertices[i].pos - mesh.vertices[edges[i][nj]].pos; Vector3 v4 = mesh.vertices[edges[i][j]].pos - mesh.vertices[edges[i][nj]].pos; double cot1 = (v1 * v2) / (1e-6 + (v1 % v2).length()); double cot2 = (v3 * v4) / (1e-6 + (v3 % v4).length()); sum += (cot1 + cot2); if(edges[i][j] > i) //check for triangular here because sum should be computed regardless continue; A[i].push_back(make_pair(edges[i][j], -cot1 - cot2)); } A[i].push_back(make_pair(i, sum + H[i] / D[i])); sort(A[i].begin(), A[i].end()); } nzweights.resize(nv); SPDMatrix Am(A); LLTMatrix *Ainv = Am.factor(); if(Ainv == NULL) return; for(j = 0; j < bones; ++j) { vector<double> rhs(nv, 0.); for(i = 0; i < nv; ++i) { if(boneVis[i][j] && boneDists[i][j] <= boneDists[i][closest[i]] * 1.00001) rhs[i] = H[i] / D[i]; } Ainv->solve(rhs); for(i = 0; i < nv; ++i) { if(rhs[i] > 1.) rhs[i] = 1.; //clip just in case if(rhs[i] > 1e-8) nzweights[i].push_back(make_pair(j, rhs[i])); } } for(i = 0; i < nv; ++i) { double sum = 0.; for(j = 0; j < (int)nzweights[i].size(); ++j) sum += nzweights[i][j].second; for(j = 0; j < (int)nzweights[i].size(); ++j) { nzweights[i][j].second /= sum; weights[i][nzweights[i][j].first] = nzweights[i][j].second; } } delete Ainv; return; }