diff --git a/opensubdiv/far/topologyRefiner.cpp b/opensubdiv/far/topologyRefiner.cpp index fbbb25c8..c1f930af 100644 --- a/opensubdiv/far/topologyRefiner.cpp +++ b/opensubdiv/far/topologyRefiner.cpp @@ -523,7 +523,7 @@ TopologyRefiner::selectFeatureAdaptiveComponents(Vtr::SparseSelector& selector) // support regular patches with one corner or one boundary, i.e. with one or more // smooth interior vertices. selectFace = true; - } else if (compFaceVTag._semiSharp) { + } else if (compFaceVTag._semiSharp || compFaceVTag._semiSharpEdges) { // Any semi-sharp feature at or around the vertex warrants isolation -- unless we // optimize for the single-crease patch, i.e. only edge sharpness of a constant value // along the entire regular patch boundary (quickly exclude the Corner case first): @@ -552,17 +552,25 @@ TopologyRefiner::selectFeatureAdaptiveComponents(Vtr::SparseSelector& selector) // boundary patch, so don't isolate. selectFace = false; } else { - // This is the last case with at least one Corner (infinitely-sharp) vertex and one - // Smooth (interior) vertex. Distinguish the regular corner case from others -- this - // is where the _corner tag on the vertex would help but we still need ensure that no - // vertex other than the corner is sharp, and so inspection of each is unavoidable... - unsigned int boundaryCount = level._vertTags[faceVerts[0]]._boundary, - infSharpCount = level._vertTags[faceVerts[0]]._infSharp; - for (int i = 1; i < faceVerts.size(); ++i) { - boundaryCount += level._vertTags[faceVerts[i]]._boundary; - infSharpCount += level._vertTags[faceVerts[i]]._infSharp; + // The last case with at least one Corner vertex and one Smooth (interior) vertex -- + // distinguish the regular corner case from others: + if (not compFaceVTag._corner) { + // We may consider interior sharp corners as regular in future, but for now we + // only accept a topological corner for the regular corner case: + selectFace = true; + } else if (level.getDepth() > 0) { + // A true corner at a subdivided level -- adjacent verts must be Crease and the + // opposite Smooth so we must have a regular corner: + selectFace = false; + } else { + // Make sure the adjacent boundary vertices were not sharpened, or equivalently, + // that only one corner is sharp: + unsigned int infSharpCount = level._vertTags[faceVerts[0]]._infSharp; + for (int i = 1; i < faceVerts.size(); ++i) { + infSharpCount += level._vertTags[faceVerts[i]]._infSharp; + } + selectFace = (infSharpCount != 1); } - selectFace = (boundaryCount != 3) || (infSharpCount != 1); } // diff --git a/opensubdiv/far/topologyRefinerFactory.cpp b/opensubdiv/far/topologyRefinerFactory.cpp index b83ef072..bef78c58 100644 --- a/opensubdiv/far/topologyRefinerFactory.cpp +++ b/opensubdiv/far/topologyRefinerFactory.cpp @@ -175,8 +175,9 @@ TopologyRefinerFactoryBase::prepareComponentTagsAndSharpness(TopologyRefiner& re // Sharpen the vertex before using it in conjunction with incident edge // properties to determine the semi-sharp tag and rule: // - bool isCorner = (vFaces.size() == 1) && (vEdges.size() == 2); - if (isCorner && sharpenCornerVerts) { + bool isTopologicalCorner = (vFaces.size() == 1) && (vEdges.size() == 2); + bool isSharpenedCorner = isTopologicalCorner && sharpenCornerVerts; + if (isSharpenedCorner) { vSharpness = Sdc::Crease::SHARPNESS_INFINITE; } else if (vTag._nonManifold && sharpenNonManFeatures) { // Don't sharpen the vertex if a non-manifold crease: @@ -185,9 +186,9 @@ TopologyRefinerFactoryBase::prepareComponentTagsAndSharpness(TopologyRefiner& re } } - vTag._infSharp = Sdc::Crease::IsInfinite(vSharpness); - - vTag._semiSharp = Sdc::Crease::IsSemiSharp(vSharpness) || (semiSharpEdgeCount > 0); + vTag._infSharp = Sdc::Crease::IsInfinite(vSharpness); + vTag._semiSharp = Sdc::Crease::IsSemiSharp(vSharpness); + vTag._semiSharpEdges = (semiSharpEdgeCount > 0); vTag._rule = (Vtr::Level::VTag::VTagSize)creasing.DetermineVertexVertexRule(vSharpness, sharpEdgeCount); @@ -196,8 +197,9 @@ TopologyRefinerFactoryBase::prepareComponentTagsAndSharpness(TopologyRefiner& re // tag is still being considered, but regardless, it depends on the Sdc::Scheme... // vTag._boundary = (vFaces.size() < vEdges.size()); - if (isCorner) { - vTag._xordinary = !sharpenCornerVerts; + vTag._corner = isSharpenedCorner; + if (vTag._corner) { + vTag._xordinary = false; } else if (vTag._boundary) { vTag._xordinary = (vFaces.size() != schemeRegularBoundaryValence); } else { diff --git a/opensubdiv/vtr/fvarRefinement.cpp b/opensubdiv/vtr/fvarRefinement.cpp index 3185c5d1..27348b80 100644 --- a/opensubdiv/vtr/fvarRefinement.cpp +++ b/opensubdiv/vtr/fvarRefinement.cpp @@ -554,16 +554,20 @@ FVarRefinement::reclassifySemisharpValues() { if (_refinement._childVertexTag[cVert]._incomplete) continue; // If the parent vertex wasn't semi-sharp, the child vertex and values can't be: - Index pVert = _refinement.getChildVertexParentIndex(cVert); - if (!_parentLevel._vertTags[pVert]._semiSharp) continue; + Index pVert = _refinement.getChildVertexParentIndex(cVert); + Level::VTag pVertTags = _parentLevel._vertTags[pVert]; + + if (!pVertTags._semiSharp && !pVertTags._semiSharpEdges) continue; // If the child vertex is still sharp, all values remain unaffected: - if (!Sdc::Crease::IsSmooth(_childLevel._vertSharpness[cVert])) continue; + Level::VTag cVertTags = _childLevel._vertTags[cVert]; + + if (cVertTags._semiSharp || cVertTags._infSharp) continue; // If the child is no longer semi-sharp, we can just clear those values marked // (i.e. make them creases, others may remain corners) and continue: // - if (!_childLevel._vertTags[cVert]._semiSharp) { + if (!cVertTags._semiSharp && !cVertTags._semiSharpEdges) { for (int j = 0; j < cValueTags.size(); ++j) { if (cValueTags[j]._semiSharp) { FVarLevel::ValueTag cValueTagOld = cValueTags[j]; @@ -626,11 +630,6 @@ float FVarRefinement::getFractionalWeight(Index pVert, LocalIndex pSibling, Index cVert, LocalIndex /* cSibling */) const { - // Should only be called when the parent was semi-sharp but this child vertex - // value (not necessarily the child vertex as a whole) is no longer semi-sharp: - assert(_parentLevel._vertTags[pVert]._semiSharp); - assert(!_childLevel._vertTags[cVert]._incomplete); - // // Need to identify sharpness values for edges within the spans for both the // parent and child... diff --git a/opensubdiv/vtr/level.cpp b/opensubdiv/vtr/level.cpp index 23fe4fa6..8bd2d307 100644 --- a/opensubdiv/vtr/level.cpp +++ b/opensubdiv/vtr/level.cpp @@ -517,9 +517,11 @@ Level::print(const Refinement* pRefinement) const { printf(" vert %4d:", i); printf(" rule = %s", ruleString((Sdc::Crease::Rule)vTag._rule)); printf(", boundary = %d", (int)vTag._boundary); + printf(", corner = %d", (int)vTag._corner); printf(", xordinary = %d", (int)vTag._xordinary); - printf(", semiSharp = %d", (int)vTag._semiSharp); printf(", infSharp = %d", (int)vTag._infSharp); + printf(", semiSharp = %d", (int)vTag._semiSharp); + printf(", semiSharpEdges = %d", (int)vTag._semiSharpEdges); printf("\n"); } fflush(stdout); diff --git a/opensubdiv/vtr/level.h b/opensubdiv/vtr/level.h index 0c430de9..56a93651 100644 --- a/opensubdiv/vtr/level.h +++ b/opensubdiv/vtr/level.h @@ -135,17 +135,24 @@ public: // level. // struct VTag { - typedef unsigned short VTagSize; - VTag() { } - VTagSize _nonManifold : 1; // fixed - VTagSize _xordinary : 1; // fixed - VTagSize _boundary : 1; // fixed - VTagSize _infSharp : 1; // fixed - VTagSize _semiSharp : 1; // variable - VTagSize _rule : 4; // variable when _semiSharp - VTagSize _incomplete : 1; // variable for sparse refinement + // When cleared, the VTag ALMOST represents a smooth, regular, interior + // vertex -- the Type enum requires a bit be explicitly set for Smooth, + // so that must be done explicitly if desired on initialization. + void clear() { std::memset(this, 0, sizeof(VTag)); } + + typedef unsigned short VTagSize; + + VTagSize _nonManifold : 1; // fixed + VTagSize _xordinary : 1; // fixed + VTagSize _boundary : 1; // fixed + VTagSize _corner : 1; // fixed + VTagSize _infSharp : 1; // fixed + VTagSize _semiSharp : 1; // variable + VTagSize _semiSharpEdges : 1; // variable + VTagSize _rule : 4; // variable when _semiSharp + VTagSize _incomplete : 1; // variable for sparse refinement // On deck -- coming soon... //VTagSize _constSharp : 1; // variable when _semiSharp @@ -153,20 +160,25 @@ public: //VTagSize _editsApplied : 1; // variable }; struct ETag { - typedef unsigned char ETagSize; - ETag() { } + // When cleared, the ETag represents a smooth, manifold, interior edge + void clear() { std::memset(this, 0, sizeof(ETag)); } + + typedef unsigned char ETagSize; + ETagSize _nonManifold : 1; // fixed ETagSize _boundary : 1; // fixed ETagSize _infSharp : 1; // fixed ETagSize _semiSharp : 1; // variable }; struct FTag { - typedef unsigned char FTagSize; - FTag() { } + void clear() { std::memset(this, 0, sizeof(FTag)); } + + typedef unsigned char FTagSize; + FTagSize _hole : 1; // fixed // On deck -- coming soon... diff --git a/opensubdiv/vtr/refinement.cpp b/opensubdiv/vtr/refinement.cpp index 57a86ea7..f41e512d 100644 --- a/opensubdiv/vtr/refinement.cpp +++ b/opensubdiv/vtr/refinement.cpp @@ -665,10 +665,7 @@ Refinement::populateEdgeTagsFromParentFaces() { // Tags for edges originating from faces are all constant: // Level::ETag eTag; - eTag._nonManifold = 0; - eTag._boundary = 0; - eTag._infSharp = 0; - eTag._semiSharp = 0; + eTag.clear(); Index cEdge = getFirstChildEdgeFromFaces(); Index cEdgeEnd = cEdge + getNumChildEdgesFromFaces(); @@ -717,13 +714,8 @@ Refinement::populateVertexTagsFromParentFaces() { if (getNumChildVerticesFromFaces() == 0) return; Level::VTag vTag; - vTag._nonManifold = 0; - vTag._xordinary = 0; - vTag._boundary = 0; - vTag._infSharp = 0; - vTag._semiSharp = 0; - vTag._rule = Sdc::Crease::RULE_SMOOTH; - vTag._incomplete = 0; + vTag.clear(); + vTag._rule = Sdc::Crease::RULE_SMOOTH; Index cVert = getFirstChildVertexFromFaces(); Index cVertEnd = cVert + getNumChildVerticesFromFaces(); @@ -749,22 +741,25 @@ Refinement::populateVertexTagsFromParentEdges() { // Tags for vertices originating from edges are initialized according to the tags // of the parent edge: // + Level::VTag vTag; + vTag.clear(); + for (Index pEdge = 0; pEdge < _parent->getNumEdges(); ++pEdge) { Index cVert = _edgeChildVertIndex[pEdge]; if (!IndexIsValid(cVert)) continue; + // From the cleared local VTag, we just need to assign properties dependent + // on the parent edge: Level::ETag const& pEdgeTag = _parent->_edgeTags[pEdge]; - Level::VTag& cVertTag = _child->_vertTags[cVert]; - cVertTag._nonManifold = pEdgeTag._nonManifold; - cVertTag._xordinary = false; - cVertTag._boundary = pEdgeTag._boundary; - cVertTag._infSharp = false; + vTag._nonManifold = pEdgeTag._nonManifold; + vTag._boundary = pEdgeTag._boundary; + vTag._semiSharpEdges = pEdgeTag._semiSharp; - cVertTag._semiSharp = pEdgeTag._semiSharp; - cVertTag._rule = (Level::VTag::VTagSize)((pEdgeTag._semiSharp || pEdgeTag._infSharp) + vTag._rule = (Level::VTag::VTagSize)((pEdgeTag._semiSharp || pEdgeTag._infSharp) ? Sdc::Crease::RULE_CREASE : Sdc::Crease::RULE_SMOOTH); - cVertTag._incomplete = 0; + + _child->_vertTags[cVert] = vTag; } } void @@ -851,9 +846,13 @@ Refinement::subdivideSharpnessValues() { // process. So for now we apply a post-process to explicitly handle all // semi-sharp vertices. // + + // These methods will update sharpness tags local to the edges and vertices: subdivideEdgeSharpness(); subdivideVertexSharpness(); + // This method uses local sharpness tags (set above) to update vertex tags that + // reflect the neighborhood of the vertex (e.g. its rule): reclassifySemisharpVertices(); } @@ -910,7 +909,9 @@ Refinement::subdivideEdgeSharpness() { cSharpness = creasing.SubdivideEdgeSharpnessAtVertex(pSharpness, pVertEdges.size(), pVertEdgeSharpness); } - cEdgeTag._semiSharp = Sdc::Crease::IsSharp(cSharpness); + if (not Sdc::Crease::IsSharp(cSharpness)) { + cEdgeTag._semiSharp = false; + } } } } @@ -942,11 +943,8 @@ Refinement::subdivideVertexSharpness() { float pSharpness = _parent->_vertSharpness[pVert]; cSharpness = creasing.SubdivideVertexSharpness(pSharpness); - - if (!Sdc::Crease::IsSharp(cSharpness)) { - // Need to visit edge neighborhood to determine if still semisharp... - // cVertTag._infSharp = ...? - // See the "reclassify" method below... + if (not Sdc::Crease::IsSharp(cSharpness)) { + cVertTag._semiSharp = false; } } } @@ -969,7 +967,7 @@ Refinement::reclassifySemisharpVertices() { for (Index cVert = vertFromEdgeBegin; cVert < vertFromEdgeEnd; ++cVert) { Level::VTag& cVertTag = _child->_vertTags[cVert]; - if (!cVertTag._semiSharp) continue; + if (!cVertTag._semiSharpEdges) continue; Index pEdge = _childVertexParentIndex[cVert]; @@ -977,21 +975,21 @@ Refinement::reclassifySemisharpVertices() { if (_childVertexTag[cVert]._incomplete) { // One child edge likely missing -- assume Crease if remaining edge semi-sharp: - cVertTag._semiSharp = (IndexIsValid(cEdges[0]) && _child->_edgeTags[cEdges[0]]._semiSharp) || - (IndexIsValid(cEdges[1]) && _child->_edgeTags[cEdges[1]]._semiSharp); - cVertTag._rule = (VTagSize)(cVertTag._semiSharp ? Sdc::Crease::RULE_CREASE : Sdc::Crease::RULE_SMOOTH); + cVertTag._semiSharpEdges = (IndexIsValid(cEdges[0]) && _child->_edgeTags[cEdges[0]]._semiSharp) || + (IndexIsValid(cEdges[1]) && _child->_edgeTags[cEdges[1]]._semiSharp); + cVertTag._rule = (VTagSize)(cVertTag._semiSharpEdges ? Sdc::Crease::RULE_CREASE : Sdc::Crease::RULE_SMOOTH); } else { int sharpEdgeCount = _child->_edgeTags[cEdges[0]]._semiSharp + _child->_edgeTags[cEdges[1]]._semiSharp; - cVertTag._semiSharp = (sharpEdgeCount > 0); - cVertTag._rule = (VTagSize)(creasing.DetermineVertexVertexRule(0.0, sharpEdgeCount)); + cVertTag._semiSharpEdges = (sharpEdgeCount > 0); + cVertTag._rule = (VTagSize)(creasing.DetermineVertexVertexRule(0.0, sharpEdgeCount)); } } // // Inspect all vertices derived from vertices -- for those whose parent vertices were - // semisharp, reset the semisharp tag and the associated Rule based on the neighborhood - // of child edges around the child vertex. + // semisharp (inherited in the child vert's tag), inspect and reset the semisharp tag + // and the associated Rule (based on neighboring child edges around the child vertex). // // We should never find such a vertex "incomplete" in a sparse refinement as a parent // vertex is either selected or not, but never neighboring. So the only complication @@ -1006,47 +1004,56 @@ Refinement::reclassifySemisharpVertices() { Index vertFromVertEnd = vertFromVertBegin + getNumChildVerticesFromVertices(); for (Index cVert = vertFromVertBegin; cVert < vertFromVertEnd; ++cVert) { + Index pVert = _childVertexParentIndex[cVert]; + Level::VTag const& pVertTag = _parent->_vertTags[pVert]; + + // Skip if parent not semi-sharp: + if (!pVertTag._semiSharp && !pVertTag._semiSharpEdges) continue; + + // + // We need to inspect the child neighborhood's sharpness when either semi-sharp + // edges were present around the parent vertex, or the parent vertex sharpness + // decayed: + // Level::VTag& cVertTag = _child->_vertTags[cVert]; - if (!cVertTag._semiSharp) continue; - // If the vertex is still sharp, it remains the semisharp Corner its parent was... - if (_child->_vertSharpness[cVert] > 0.0) continue; + bool sharpVertexDecayed = pVertTag._semiSharp && !cVertTag._semiSharp; - // - // See if we can use the vert-edges of the child vertex: - // - int sharpEdgeCount = 0; - int semiSharpEdgeCount = 0; + if (pVertTag._semiSharpEdges || sharpVertexDecayed) { + int infSharpEdgeCount = 0; + int semiSharpEdgeCount = 0; - bool cVertEdgesPresent = (_child->getNumVertexEdgesTotal() > 0); - if (cVertEdgesPresent) { - IndexArray const cEdges = _child->getVertexEdges(cVert); + bool cVertEdgesPresent = (_child->getNumVertexEdgesTotal() > 0); + if (cVertEdgesPresent) { + IndexArray const cEdges = _child->getVertexEdges(cVert); - for (int i = 0; i < cEdges.size(); ++i) { - Level::ETag cEdgeTag = _child->_edgeTags[cEdges[i]]; + for (int i = 0; i < cEdges.size(); ++i) { + Level::ETag cEdgeTag = _child->_edgeTags[cEdges[i]]; - sharpEdgeCount += cEdgeTag._semiSharp || cEdgeTag._infSharp; - semiSharpEdgeCount += cEdgeTag._semiSharp; + infSharpEdgeCount += cEdgeTag._infSharp; + semiSharpEdgeCount += cEdgeTag._semiSharp; + } + } else { + ConstIndexArray pEdges = _parent->getVertexEdges(pVert); + ConstLocalIndexArray pVertInEdge = _parent->getVertexEdgeLocalIndices(pVert); + + for (int i = 0; i < pEdges.size(); ++i) { + ConstIndexArray cEdgePair = getEdgeChildEdges(pEdges[i]); + + Index cEdge = cEdgePair[pVertInEdge[i]]; + Level::ETag cEdgeTag = _child->_edgeTags[cEdge]; + + infSharpEdgeCount += cEdgeTag._infSharp; + semiSharpEdgeCount += cEdgeTag._semiSharp; + } } - } else { - Index pVert = _childVertexParentIndex[cVert]; + cVertTag._semiSharpEdges = (semiSharpEdgeCount > 0); - ConstIndexArray pEdges = _parent->getVertexEdges(pVert); - ConstLocalIndexArray pVertInEdge = _parent->getVertexEdgeLocalIndices(pVert); - - for (int i = 0; i < pEdges.size(); ++i) { - ConstIndexArray cEdgePair = getEdgeChildEdges(pEdges[i]); - - Index cEdge = cEdgePair[pVertInEdge[i]]; - Level::ETag cEdgeTag = _child->_edgeTags[cEdge]; - - sharpEdgeCount += cEdgeTag._semiSharp || cEdgeTag._infSharp; - semiSharpEdgeCount += cEdgeTag._semiSharp; + if (!cVertTag._semiSharp && !cVertTag._infSharp) { + cVertTag._rule = (VTagSize)(creasing.DetermineVertexVertexRule(0.0, + infSharpEdgeCount + semiSharpEdgeCount)); } } - - cVertTag._semiSharp = (semiSharpEdgeCount > 0); - cVertTag._rule = (VTagSize)(creasing.DetermineVertexVertexRule(0.0, sharpEdgeCount)); } }