// LoopSubdiv Inline Functions inline int SDVertex::valence() { SDFace *f = startFace; if (!boundary) { // Compute valence of interior vertex int nf = 1; while ((f = f->nextFace(this)) != startFace) ++nf; return nf; } else { // Compute valence of boundary vertex int nf = 1; while ((f = f->nextFace(this)) != NULL) ++nf; f = startFace; while ((f = f->prevFace(this)) != NULL) ++nf; return nf+1; } }
void SDVertex::oneRing(PbrtPoint *P) { if (!boundary) { // Get one-ring vertices for interior vertex SDFace *face = startFace; do { *P++ = face->nextVert(this)->P; face = face->nextFace(this); } while (face != startFace); } else { // Get one-ring vertices for boundary vertex SDFace *face = startFace, *f2; while ((f2 = face->nextFace(this)) != NULL) face = f2; *P++ = face->nextVert(this)->P; do { *P++ = face->prevVert(this)->P; face = face->prevFace(this); } while (face != NULL); } }
void LoopSubdiv::weightOneRing(SDVertex *destVert, SDVertex *vert, float beta) const { // Put _vert_ one-ring in _Pring_ u_int valence = vert->valence(); SDVertex **Vring = (SDVertex **)alloca(valence * sizeof(SDVertex *)); SDVertex **VR = Vring; // Get one ring vertices for interior vertex SDFace *face = vert->startFace; bool uvSplit = false; do { SDVertex *v = face->v[face->vnum(vert->P)]; if (v->u != vert->u || v->v != vert->v) uvSplit = true; SDVertex *v2 = face->nextVert(vert->P); float vu = v2->u; float vv = v2->v; *VR++ = v2; face = face->nextFace(vert->P); v2 = face->prevVert(vert->P); if (vu != v2->u || vv != v2->v) uvSplit = true; } while (face != vert->startFace); Point P((1 - valence * beta) * vert->P); float u = (1 - valence * beta) * vert->u; float v = (1 - valence * beta) * vert->v; Normal N((1 - valence * beta) * vert->n); for (u_int i = 0; i < valence; ++i) { P += beta * Vring[i]->P; u += beta * Vring[i]->u; v += beta * Vring[i]->v; N += beta * Vring[i]->n; } destVert->P = P; if (uvSplit) { destVert->u = vert->u; destVert->v = vert->v; } else { destVert->u = u; destVert->v = v; } destVert->n = N; }
// LoopSubdiv Method Definitions LoopSubdiv::LoopSubdiv(const Transform *o2w, const Transform *w2o, bool ro, int nfaces, int nvertices, const int *vertexIndices, const PbrtPoint *P, int nl) : Shape(o2w, w2o, ro) { nLevels = nl; // Allocate _LoopSubdiv_ vertices and faces int i; SDVertex *verts = new SDVertex[nvertices]; for (i = 0; i < nvertices; ++i) { verts[i] = SDVertex(P[i]); vertices.push_back(&verts[i]); } SDFace *fs = new SDFace[nfaces]; for (i = 0; i < nfaces; ++i) faces.push_back(&fs[i]); // Set face to vertex pointers const int *vp = vertexIndices; for (i = 0; i < nfaces; ++i) { SDFace *f = faces[i]; for (int j = 0; j < 3; ++j) { SDVertex *v = vertices[vp[j]]; f->v[j] = v; v->startFace = f; } vp += 3; } // Set neighbor pointers in _faces_ set<SDEdge> edges; for (i = 0; i < nfaces; ++i) { SDFace *f = faces[i]; for (int edgeNum = 0; edgeNum < 3; ++edgeNum) { // Update neighbor pointer for _edgeNum_ int v0 = edgeNum, v1 = NEXT(edgeNum); SDEdge e(f->v[v0], f->v[v1]); if (edges.find(e) == edges.end()) { // Handle new edge e.f[0] = f; e.f0edgeNum = edgeNum; edges.insert(e); } else { // Handle previously seen edge e = *edges.find(e); e.f[0]->f[e.f0edgeNum] = f; f->f[edgeNum] = e.f[0]; edges.erase(e); } } } // Finish vertex initialization for (i = 0; i < nvertices; ++i) { SDVertex *v = vertices[i]; SDFace *f = v->startFace; do { f = f->nextFace(v); } while (f && f != v->startFace); v->boundary = (f == NULL); if (!v->boundary && v->valence() == 6) v->regular = true; else if (v->boundary && v->valence() == 4) v->regular = true; else v->regular = false; } }
void LoopSubdiv::weightBoundary(SDVertex *destVert, SDVertex *vert, float beta) const { // Put _vert_ one-ring in _Pring_ u_int valence = vert->valence(); if (displacementMapSharpBoundary) { destVert->P = vert->P; destVert->u = vert->u; destVert->v = vert->v; destVert->n = vert->n; return; } SDVertex **Vring = (SDVertex **)alloca(valence * sizeof(SDVertex *)); SDVertex **VR = Vring; // Get one ring vertices for boundary vertex SDFace *face = vert->startFace, *f2; // Go to the last face in the list while ((f2 = face->nextFace(vert->P)) != NULL) face = f2; // Add the last vertex (on the boundary) *VR++ = face->nextVert(vert->P); // Add all vertices up to the first one (on the boundary) bool uvSplit = false; do { SDVertex *v = face->v[face->vnum(vert->P)]; if (v->u != vert->u || v->v != vert->v) uvSplit = true; SDVertex *v2 = face->prevVert(vert->P); float vu = v2->u; float vv = v2->v; *VR++ = v2; face = face->prevFace(vert->P); if (face) { v2 = face->nextVert(vert->P); if (vu != v2->u || vv != v2->v) uvSplit = true; } } while (face != NULL); Point P((1 - 2 * beta) * vert->P); P += beta * Vring[0]->P; P += beta * Vring[valence - 1]->P; destVert->P = P; if (uvSplit) { destVert->u = vert->u; destVert->v = vert->v; } else { float u = (1.f - 2.f * beta) * vert->u; float v = (1.f - 2.f * beta) * vert->v; u += beta * (Vring[0]->u + Vring[valence - 1]->u); v += beta * (Vring[0]->v + Vring[valence - 1]->v); destVert->u = u; destVert->v = v; } Normal N((1 - 2 * beta) * vert->n); N += beta * Vring[0]->n; N += beta * Vring[valence - 1]->n; destVert->n = N; }
void LoopSubdiv::ApplyDisplacementMap(const vector<SDVertex *> verts) const { // Dade - apply the displacement map SHAPE_LOG(name, LUX_INFO,LUX_NOERROR) << "Applying displacement map to " << verts.size() << " vertices"; SpectrumWavelengths swl; swl.Sample(.5f); for (u_int i = 0; i < verts.size(); i++) { SDVertex *v = verts[i]; // Special use of the child member to detect that // the vertex has already been displaced if (v->child == v) continue; Vector dpdu, dpdv; CoordinateSystem(Vector(v->n), &dpdu, &dpdv); Vector displacement(v->n); SDFace *face = v->startFace; u_int nf = 0; float dl = 0.f; vector<SDVertex *> vlist; vlist.reserve(v->valence()); if (v->boundary) { do { SDVertex *vv = face->v[face->vnum(v->P)]; DifferentialGeometry dg(v->P, v->n, dpdu, dpdv, Normal(0, 0, 0), Normal(0, 0, 0), vv->u, vv->v, NULL); dl += displacementMap->Evaluate(swl, dg); ++nf; if (vv->child != vv) { vlist.push_back(vv); vv->child = vv; } face = face->nextFace(v->P); } while (face); face = v->startFace->prevFace(v->P); while (face) { SDVertex *vv = face->v[face->vnum(v->P)]; DifferentialGeometry dg(v->P, v->n, dpdu, dpdv, Normal(0, 0, 0), Normal(0, 0, 0), vv->u, vv->v, NULL); dl += displacementMap->Evaluate(swl, dg); ++nf; if (vv->child != vv) { vlist.push_back(vv); vv->child = vv; } face = face->prevFace(v->P); } } else { do { SDVertex *vv = face->v[face->vnum(v->P)]; DifferentialGeometry dg(v->P, v->n, dpdu, dpdv, Normal(0, 0, 0), Normal(0, 0, 0), vv->u, vv->v, NULL); dl += displacementMap->Evaluate(swl, dg); ++nf; if (vv->child != vv) { vlist.push_back(vv); vv->child = vv; } face = face->nextFace(v->P); } while (face != v->startFace); } dl = (dl * displacementMapScale / nf + displacementMapOffset); // Average the displacement displacement *= dl; // Apply displacement to all vertices in the list for (u_int j = 0; j < vlist.size(); ++j) vlist[j]->P += displacement; } }
// LoopSubdiv Method Definitions LoopSubdiv::LoopSubdiv(u_int nfaces, u_int nvertices, const int *vertexIndices, const Point *P, const float *uv, const Normal *n, u_int nl, const boost::shared_ptr<Texture<float> > &dismap, float dmscale, float dmoffset, bool dmnormalsmooth, bool dmsharpboundary, bool normalsplit, const string &sname) : displacementMap(dismap), displacementMapScale(dmscale), displacementMapOffset(dmoffset), displacementMapNormalSmooth(dmnormalsmooth), displacementMapSharpBoundary(dmsharpboundary), name(sname) { nLevels = nl; hasUV = (uv != NULL); normalSplit = normalsplit && n != NULL; // Allocate _LoopSubdiv_ vertices and faces SDVertex *verts = new SDVertex[nvertices]; vertices.reserve(nvertices); for (u_int i = 0; i < nvertices; ++i) { if (hasUV) verts[i] = SDVertex(P[i], uv[2 * i], uv[2 * i + 1]); else verts[i] = SDVertex(P[i]); if (normalSplit) verts[i].n = n[i]; vertices.push_back(&verts[i]); } SDFace *fs = new SDFace[nfaces]; faces.reserve(nfaces); for (u_int i = 0; i < nfaces; ++i) faces.push_back(&fs[i]); // Set face to vertex pointers const int *vp = vertexIndices; for (u_int i = 0; i < nfaces; ++i) { SDFace *f = faces[i]; for (u_int j = 0; j < 3; ++j) { SDVertex *v = vertices[vp[j]]; f->v[j] = v; f->f[j] = NULL; f->children[j] = NULL; v->startFace = f; } f->children[3] = NULL; vp += 3; } // Set neighbor pointers in _faces_ set<SDEdge> edges; for (u_int i = 0; i < nfaces; ++i) { SDFace *f = faces[i]; for (u_int edgeNum = 0; edgeNum < 3; ++edgeNum) { // Update neighbor pointer for _edgeNum_ u_int v0 = edgeNum, v1 = NEXT(edgeNum); Normal n0, n1; SDEdge e(f->v[v0], f->v[v1]); if (edges.find(e) == edges.end()) { // Handle new edge e.f[0] = f; e.f0edgeNum = edgeNum; edges.insert(e); } else { // Handle previously-seen edge e = *edges.find(e); e.f[0]->f[e.f0edgeNum] = f; f->f[edgeNum] = e.f[0]; // NOTE - lordcrc - check winding of // other face is opposite of the // current face, otherwise we have // inconsistent winding u_int otherv0 = e.f[0]->vnum(f->v[v0]->P); u_int otherv1 = e.f[0]->vnum(f->v[v1]->P); if (PREV(otherv0) != otherv1) { SHAPE_LOG(name, LUX_ERROR,LUX_CONSISTENCY)<< "Inconsistent vertex winding in mesh, aborting subdivision."; // prevent subdivision nLevels = 0; return; }; edges.erase(e); } } } // Finish vertex initialization for (u_int i = 0; i < nvertices; ++i) { SDVertex *v = vertices[i]; SDFace *f = v->startFace; do { f = f->nextFace(v->P); } while (f && f != v->startFace); v->boundary = (f == NULL); if (!v->boundary && v->valence() == 6) v->regular = true; else if (v->boundary && v->valence() == 4) v->regular = true; else v->regular = false; } }