void LoopSubdiv::GenerateNormals(const vector<SDVertex *> v) { // Compute vertex tangents on limit surface u_int ringSize = 16; Point *Pring = new Point[ringSize]; for (u_int i = 0; i < v.size(); ++i) { SDVertex *vert = v[i]; Vector S(0,0,0), T(0,0,0); u_int valence = vert->valence(); if (valence > ringSize) { ringSize = valence; delete[] Pring; Pring = new Point[ringSize]; } vert->oneRing(Pring); if (!vert->boundary) { // Compute tangents of interior face for (u_int k = 0; k < valence; ++k) { S += cosf(2.f*M_PI*k/valence) * Vector(Pring[k]); T += sinf(2.f*M_PI*k/valence) * Vector(Pring[k]); } } else { // Compute tangents of boundary face S = Pring[valence-1] - Pring[0]; if (valence == 2) T = Vector(Pring[0] + Pring[1] - 2 * vert->P); else if (valence == 3) T = Pring[1] - vert->P; else if (valence == 4) // regular T = Vector(-1*Pring[0] + 2*Pring[1] + 2*Pring[2] + -1*Pring[3] + -2*vert->P); else { float theta = M_PI / static_cast<float>(valence - 1); T = Vector(sinf(theta) * (Pring[0] + Pring[valence-1])); for (u_int k = 1; k < valence - 1; ++k) { float wt = (2*cosf(theta) - 2) * sinf((k) * theta); T += Vector(wt * Pring[k]); } T = -T; } } vert->n = Normal(Normalize(Cross(T, S))); } }
void LoopSubdiv::Refine(vector<Reference<Shape> > &refined) const { vector<SDFace *> f = faces; vector<SDVertex *> v = vertices; MemoryArena arena; for (int i = 0; i < nLevels; ++i) { // Update _f_ and _v_ for next level of subdivision vector<SDFace *> newFaces; vector<SDVertex *> newVertices; // Allocate next level of children in mesh tree for (uint32_t j = 0; j < v.size(); ++j) { v[j]->child = arena.Alloc<SDVertex>(); v[j]->child->regular = v[j]->regular; v[j]->child->boundary = v[j]->boundary; newVertices.push_back(v[j]->child); } for (uint32_t j = 0; j < f.size(); ++j) for (int k = 0; k < 4; ++k) { f[j]->children[k] = arena.Alloc<SDFace>(); newFaces.push_back(f[j]->children[k]); } // Update vertex positions and create new edge vertices // Update vertex positions for even vertices for (uint32_t j = 0; j < v.size(); ++j) { if (!v[j]->boundary) { // Apply one-ring rule for even vertex if (v[j]->regular) v[j]->child->P = weightOneRing(v[j], 1.f/16.f); else v[j]->child->P = weightOneRing(v[j], beta(v[j]->valence())); } else { // Apply boundary rule for even vertex v[j]->child->P = weightBoundary(v[j], 1.f/8.f); } } // Compute new odd edge vertices map<SDEdge, SDVertex *> edgeVerts; for (uint32_t j = 0; j < f.size(); ++j) { SDFace *face = f[j]; for (int k = 0; k < 3; ++k) { // Compute odd vertex on _k_th edge SDEdge edge(face->v[k], face->v[NEXT(k)]); SDVertex *vert = edgeVerts[edge]; if (!vert) { // Create and initialize new odd vertex vert = arena.Alloc<SDVertex>(); newVertices.push_back(vert); vert->regular = true; vert->boundary = (face->f[k] == NULL); vert->startFace = face->children[3]; // Apply edge rules to compute new vertex position if (vert->boundary) { vert->P = 0.5f * edge.v[0]->P; vert->P += 0.5f * edge.v[1]->P; } else { vert->P = 3.f/8.f * edge.v[0]->P; vert->P += 3.f/8.f * edge.v[1]->P; vert->P += 1.f/8.f * face->otherVert(edge.v[0], edge.v[1])->P; vert->P += 1.f/8.f * face->f[k]->otherVert(edge.v[0], edge.v[1])->P; } edgeVerts[edge] = vert; } } } // Update new mesh topology // Update even vertex face pointers for (uint32_t j = 0; j < v.size(); ++j) { SDVertex *vert = v[j]; int vertNum = vert->startFace->vnum(vert); vert->child->startFace = vert->startFace->children[vertNum]; } // Update face neighbor pointers for (uint32_t j = 0; j < f.size(); ++j) { SDFace *face = f[j]; for (int k = 0; k < 3; ++k) { // Update children _f_ pointers for siblings face->children[3]->f[k] = face->children[NEXT(k)]; face->children[k]->f[NEXT(k)] = face->children[3]; // Update children _f_ pointers for neighbor children SDFace *f2 = face->f[k]; face->children[k]->f[k] = f2 ? f2->children[f2->vnum(face->v[k])] : NULL; f2 = face->f[PREV(k)]; face->children[k]->f[PREV(k)] = f2 ? f2->children[f2->vnum(face->v[k])] : NULL; } } // Update face vertex pointers for (uint32_t j = 0; j < f.size(); ++j) { SDFace *face = f[j]; for (int k = 0; k < 3; ++k) { // Update child vertex pointer to new even vertex face->children[k]->v[k] = face->v[k]->child; // Update child vertex pointer to new odd vertex SDVertex *vert = edgeVerts[SDEdge(face->v[k], face->v[NEXT(k)])]; face->children[k]->v[NEXT(k)] = vert; face->children[NEXT(k)]->v[k] = vert; face->children[3]->v[k] = vert; } } // Prepare for next level of subdivision f = newFaces; v = newVertices; } // Push vertices to limit surface PbrtPoint *Plimit = new PbrtPoint[v.size()]; for (uint32_t i = 0; i < v.size(); ++i) { if (v[i]->boundary) Plimit[i] = weightBoundary(v[i], 1.f/5.f); else Plimit[i] = weightOneRing(v[i], gamma(v[i]->valence())); } for (uint32_t i = 0; i < v.size(); ++i) v[i]->P = Plimit[i]; // Compute vertex tangents on limit surface vector<Normal> Ns; Ns.reserve(v.size()); vector<PbrtPoint> Pring(16, PbrtPoint()); for (uint32_t i = 0; i < v.size(); ++i) { SDVertex *vert = v[i]; Vector S(0,0,0), T(0,0,0); int valence = vert->valence(); if (valence > (int)Pring.size()) Pring.resize(valence); vert->oneRing(&Pring[0]); if (!vert->boundary) { // Compute tangents of interior face for (int k = 0; k < valence; ++k) { S += cosf(2.f*M_PI*k/valence) * Vector(Pring[k]); T += sinf(2.f*M_PI*k/valence) * Vector(Pring[k]); } } else { // Compute tangents of boundary face S = Pring[valence-1] - Pring[0]; if (valence == 2) T = Vector(Pring[0] + Pring[1] - 2 * vert->P); else if (valence == 3) T = Pring[1] - vert->P; else if (valence == 4) // regular T = Vector(-1*Pring[0] + 2*Pring[1] + 2*Pring[2] + -1*Pring[3] + -2*vert->P); else { float theta = M_PI / float(valence-1); T = Vector(sinf(theta) * (Pring[0] + Pring[valence-1])); for (int k = 1; k < valence-1; ++k) { float wt = (2*cosf(theta) - 2) * sinf((k) * theta); T += Vector(wt * Pring[k]); } T = -T; } } Ns.push_back(Normal(Cross(S, T))); } // Create _TriangleMesh_ from subdivision mesh uint32_t ntris = uint32_t(f.size()); int *verts = new int[3*ntris]; int *vp = verts; uint32_t totVerts = uint32_t(v.size()); map<SDVertex *, int> usedVerts; for (uint32_t i = 0; i < totVerts; ++i) usedVerts[v[i]] = i; for (uint32_t i = 0; i < ntris; ++i) { for (int j = 0; j < 3; ++j) { *vp = usedVerts[f[i]->v[j]]; ++vp; } } ParamSet paramSet; paramSet.AddInt("indices", verts, 3*ntris); paramSet.AddPoint("P", Plimit, totVerts); paramSet.AddNormal("N", &Ns[0], int(Ns.size())); refined.push_back(CreateTriangleMeshShape(ObjectToWorld, WorldToObject, ReverseOrientation, paramSet)); delete[] verts; delete[] Plimit; }