// // Copyright (C) Pixar. All rights reserved. // // This license governs use of the accompanying software. If you // use the software, you accept this license. If you do not accept // the license, do not use the software. // // 1. Definitions // The terms "reproduce," "reproduction," "derivative works," and // "distribution" have the same meaning here as under U.S. // copyright law. A "contribution" is the original software, or // any additions or changes to the software. // A "contributor" is any person or entity that distributes its // contribution under this license. // "Licensed patents" are a contributor's patent claims that read // directly on its contribution. // // 2. Grant of Rights // (A) Copyright Grant- Subject to the terms of this license, // including the license conditions and limitations in section 3, // each contributor grants you a non-exclusive, worldwide, // royalty-free copyright license to reproduce its contribution, // prepare derivative works of its contribution, and distribute // its contribution or any derivative works that you create. // (B) Patent Grant- Subject to the terms of this license, // including the license conditions and limitations in section 3, // each contributor grants you a non-exclusive, worldwide, // royalty-free license under its licensed patents to make, have // made, use, sell, offer for sale, import, and/or otherwise // dispose of its contribution in the software or derivative works // of the contribution in the software. // // 3. Conditions and Limitations // (A) No Trademark License- This license does not grant you // rights to use any contributor's name, logo, or trademarks. // (B) If you bring a patent claim against any contributor over // patents that you claim are infringed by the software, your // patent license from such contributor to the software ends // automatically. // (C) If you distribute any portion of the software, you must // retain all copyright, patent, trademark, and attribution // notices that are present in the software. // (D) If you distribute any portion of the software in source // code form, you may do so only under this license by including a // complete copy of this license with your distribution. If you // distribute any portion of the software in compiled or object // code form, you may only do so under a license that complies // with this license. // (E) The software is licensed "as-is." You bear the risk of // using it. The contributors give no express warranties, // guarantees or conditions. You may have additional consumer // rights under your local laws which this license cannot change. // To the extent permitted under your local laws, the contributors // exclude the implied warranties of merchantability, fitness for // a particular purpose and non-infringement. // #ifndef HBRSUBDIVISION_H #define HBRSUBDIVISION_H template class HbrFace; template class HbrVertex; template class HbrHalfedge; template class HbrMesh; template class HbrSubdivision { public: HbrSubdivision() : creaseSubdivision(k_CreaseNormal) {} virtual ~HbrSubdivision() {} virtual HbrSubdivision* Clone() const = 0; // How to subdivide a face virtual void Refine(HbrMesh* mesh, HbrFace* face) = 0; // Subdivide a face only at a particular vertex (creating one child) virtual HbrFace* RefineFaceAtVertex(HbrMesh* mesh, HbrFace* face, HbrVertex* vertex) = 0; // Refine all faces around a particular vertex virtual void RefineAtVertex(HbrMesh* mesh, HbrVertex* vertex); // Given an edge, try to ensure the edge's opposite exists by // forcing refinement up the hierarchy virtual void GuaranteeNeighbor(HbrMesh* mesh, HbrHalfedge* edge) = 0; // Given an vertex, ensure all faces in the ring around it exist // by forcing refinement up the hierarchy virtual void GuaranteeNeighbors(HbrMesh* mesh, HbrVertex* vertex) = 0; // Returns true if the vertex, edge, or face has a limit point, // curve, or surface associated with it virtual bool HasLimit(HbrMesh* /* mesh */, HbrFace* /* face */) { return true; } virtual bool HasLimit(HbrMesh* /* mesh */, HbrHalfedge* /* edge */) { return true; } virtual bool HasLimit(HbrMesh* /* mesh */, HbrVertex* /* vertex */) { return true; } // How to turn faces, edges, and vertices into vertices virtual HbrVertex* Subdivide(HbrMesh* mesh, HbrFace* face) = 0; virtual HbrVertex* Subdivide(HbrMesh* mesh, HbrHalfedge* edge) = 0; virtual HbrVertex* Subdivide(HbrMesh* mesh, HbrVertex* vertex) = 0; // Returns true if the vertex is extraordinary in the subdivision scheme virtual bool VertexIsExtraordinary(HbrMesh* /* mesh */, HbrVertex* /* vertex */) { return false; } // Crease subdivision rules. When subdividing a edge with a crease // strength, we get two child subedges, and we need to determine // what weights to assign these subedges. The "normal" rule // is to simply assign the current edge's crease strength - 1 // to both of the child subedges. The "Chaikin" rule looks at the // current edge and incident edges to the current edge's end // vertices, and weighs them; for more information consult // the Geri's Game paper. enum CreaseSubdivision { k_CreaseNormal, k_CreaseChaikin }; CreaseSubdivision GetCreaseSubdivisionMethod() const { return creaseSubdivision; } void SetCreaseSubdivisionMethod(CreaseSubdivision method) { creaseSubdivision = method; } // Figures out how to assign a crease weight on an edge to its // subedge. The subedge must be a child of the parent edge // (either subedge->GetOrgVertex() or subedge->GetDestVertex() // == edge->Subdivide()). The vertex supplied must NOT be // a parent of the subedge; it is either the origin or // destination vertex of edge. void SubdivideCreaseWeight(HbrHalfedge* edge, HbrVertex* vertex, HbrHalfedge* subedge); // Returns the expected number of children faces after subdivision // for a face with the given number of vertices. virtual int GetFaceChildrenCount(int nvertices) const = 0; protected: CreaseSubdivision creaseSubdivision; // Helper routine for subclasses: for a given vertex, sums // contributions from surrounding vertices void AddSurroundingVerticesWithWeight(HbrMesh* mesh, HbrVertex* vertex, float weight, T* data); // Helper routine for subclasses: for a given vertex with a crease // mask, adds contributions from the two crease edges void AddCreaseEdgesWithWeight(HbrMesh* mesh, HbrVertex* vertex, bool next, float weight, T* data); private: // Helper class used by AddSurroundingVerticesWithWeight class SmoothSubdivisionVertexOperator : public HbrVertexOperator { public: SmoothSubdivisionVertexOperator(T* data, bool meshHasEdits, float weight) : m_data(data), m_meshHasEdits(meshHasEdits), m_weight(weight) { } virtual void operator() (HbrVertex &vertex) { // Must ensure vertex edits have been applied if (m_meshHasEdits) { vertex.GuaranteeNeighbors(); } m_data->AddWithWeight(vertex.GetData(), m_weight); } private: T* m_data; const bool m_meshHasEdits; const float m_weight; }; // Helper class used by AddCreaseEdgesWithWeight class CreaseSubdivisionHalfedgeOperator : public HbrHalfedgeOperator { public: CreaseSubdivisionHalfedgeOperator(HbrVertex *vertex, T* data, bool meshHasEdits, bool next, float weight) : m_vertex(vertex), m_data(data), m_meshHasEdits(meshHasEdits), m_next(next), m_weight(weight), m_count(0) { } virtual void operator() (HbrHalfedge &edge) { if (m_count < 2 && edge.IsSharp(m_next)) { HbrVertex* a = edge.GetDestVertex(); if (a == m_vertex) a = edge.GetOrgVertex(); // Must ensure vertex edits have been applied if (m_meshHasEdits) { a->GuaranteeNeighbors(); } m_data->AddWithWeight(a->GetData(), m_weight); m_count++; } } private: HbrVertex* m_vertex; T* m_data; const bool m_meshHasEdits; const bool m_next; const float m_weight; int m_count; }; private: // Helper class used by RefineAtVertex. class RefineFaceAtVertexOperator : public HbrFaceOperator { public: RefineFaceAtVertexOperator(HbrSubdivision* subdivision, HbrMesh* mesh, HbrVertex *vertex) : m_subdivision(subdivision), m_mesh(mesh), m_vertex(vertex) { } virtual void operator() (HbrFace &face) { m_subdivision->RefineFaceAtVertex(m_mesh, &face, m_vertex); } private: HbrSubdivision* const m_subdivision; HbrMesh* const m_mesh; HbrVertex* const m_vertex; }; }; template void HbrSubdivision::RefineAtVertex(HbrMesh* mesh, HbrVertex* vertex) { GuaranteeNeighbors(mesh, vertex); RefineFaceAtVertexOperator op(this, mesh, vertex); vertex->ApplyOperatorSurroundingFaces(op); } template void HbrSubdivision::SubdivideCreaseWeight(HbrHalfedge* edge, HbrVertex* vertex, HbrHalfedge* subedge) { float sharpness = edge->GetSharpness(); // In all methods, if the parent edge is infinitely sharp, the // child edge is also infinitely sharp if (sharpness >= HbrHalfedge::k_InfinitelySharp) { subedge->SetSharpness(HbrHalfedge::k_InfinitelySharp); } // Chaikin's curve subdivision: use 3/4 of the parent sharpness, // plus 1/4 of crease sharpnesses incident to vertex else if (creaseSubdivision == HbrSubdivision::k_CreaseChaikin) { float childsharp = 0.0f; // Add 1/4 of the sharpness of all crease edges incident to // the vertex (other than this crease edge) std::list*> edges; vertex->GuaranteeNeighbors(); vertex->GetSurroundingEdges(edges); int n = 0; for (typename std::list*>::iterator ei = edges.begin(); ei != edges.end(); ++ei) { if (*ei == edge) continue; if ((*ei)->GetSharpness() > HbrHalfedge::k_Smooth) { childsharp += (*ei)->GetSharpness(); n++; } } if (n) { childsharp = childsharp * 0.25f / n; } // Add 3/4 of the sharpness of this crease edge childsharp += sharpness * 0.75f; childsharp -= 1.0f; if (childsharp < (float) HbrHalfedge::k_Smooth) { childsharp = (float) HbrHalfedge::k_Smooth; } subedge->SetSharpness(childsharp); } else { sharpness -= 1.0f; if (sharpness < (float) HbrHalfedge::k_Smooth) { sharpness = (float) HbrHalfedge::k_Smooth; } subedge->SetSharpness(sharpness); } } template void HbrSubdivision::AddSurroundingVerticesWithWeight(HbrMesh* mesh, HbrVertex* vertex, float weight, T* data) { SmoothSubdivisionVertexOperator op(data, mesh->HasVertexEdits(), weight); vertex->ApplyOperatorSurroundingVertices(op); } template void HbrSubdivision::AddCreaseEdgesWithWeight(HbrMesh* mesh, HbrVertex* vertex, bool next, float weight, T* data) { CreaseSubdivisionHalfedgeOperator op(vertex, data, mesh->HasVertexEdits(), next, weight); vertex->ApplyOperatorSurroundingEdges(op); } #endif /* HBRSUBDIVISION_H */