// // Copyright 2014 DreamWorks Animation LLC. // // Licensed under the Apache License, Version 2.0 (the "Apache License") // with the following modification; you may not use this file except in // compliance with the Apache License and the following modification to it: // Section 6. Trademarks. is deleted and replaced with: // // 6. Trademarks. This License does not grant permission to use the trade // names, trademarks, service marks, or product names of the Licensor // and its affiliates, except as required to comply with Section 4(c) of // the License and to reproduce the content of the NOTICE file. // // You may obtain a copy of the Apache License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the Apache License with the above modification is // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the Apache License for the specific // language governing permissions and limitations under the Apache License. // #include "../sdc/crease.h" #include "../vtr/types.h" #include "../vtr/level.h" #include "../vtr/triRefinement.h" #include #include #include namespace OpenSubdiv { namespace OPENSUBDIV_VERSION { namespace Vtr { // // Simple constructor, destructor and basic initializers: // TriRefinement::TriRefinement(Level const & parent, Level & child, Sdc::Options const & options) : Refinement(parent, child, options) { _splitType = Sdc::SPLIT_TO_TRIS; _regFaceSize = 3; } TriRefinement::~TriRefinement() { } // // Methods for construct the parent-to-child mapping // void TriRefinement::allocateParentChildIndices() { // // Initialize the vectors of indices mapping parent components to those child components // that will originate from each. // // // Beware these child-counts when Loop subdivision supports N-sided faces in the cage // - there will 2*(N-2) additional face-child-faces for each N-sided face // - there will 2*(N-2)+1 additional face-child-edges for each N-sided face // - there will 1 face-child-vertex for each N-sided face // Can consider these reasonable estimates and grow as needed later -- but be clear // about it if so. // int faceChildFaceCount = _parent->getNumFaces() * 4; int faceChildEdgeCount = (int) _parent->_faceEdgeIndices.size(); int edgeChildEdgeCount = (int) _parent->_edgeVertIndices.size(); int faceChildVertCount = 0; int edgeChildVertCount = _parent->getNumEdges(); int vertChildVertCount = _parent->getNumVertices(); // // First initialize the count/offset vectors for the child-faces and child-edges of // parent faces. For now we can use the parent's face-vert counts for the child-edges // of faces, but we must use a local vector for the child-faces. // // This will be more necessary (and need adjustment) when N-sided faces are supported. // _localFaceChildFaceCountsAndOffsets.resize(_parent->getNumFaces() * 2, 4); for (int i = 0; i < _parent->getNumFaces(); ++i) { _localFaceChildFaceCountsAndOffsets[i*2 + 1] = 4 * i; } _faceChildFaceCountsAndOffsets = IndexArray(&_localFaceChildFaceCountsAndOffsets[0], (int)_localFaceChildFaceCountsAndOffsets.size()); _faceChildEdgeCountsAndOffsets = _parent->shareFaceVertCountsAndOffsets(); // // Given we will be ignoring initial values with uniform refinement and assigning all // directly, initializing here is a waste... // Index initValue = 0; _faceChildFaceIndices.resize(faceChildFaceCount, initValue); _faceChildEdgeIndices.resize(faceChildEdgeCount, initValue); _edgeChildEdgeIndices.resize(edgeChildEdgeCount, initValue); _faceChildVertIndex.resize(faceChildVertCount, initValue); _edgeChildVertIndex.resize(edgeChildVertCount, initValue); _vertChildVertIndex.resize(vertChildVertCount, initValue); } // // Methods to populate the face-vertex relation of the child Level: // - child faces only originate from parent faces // void TriRefinement::populateFaceVertexRelation() { // Both face-vertex and face-edge share the face-vertex counts/offsets within a // Level, so be sure not to re-initialize it if already done: // if (_child->_faceVertCountsAndOffsets.size() == 0) { populateFaceVertexCountsAndOffsets(); } _child->_faceVertIndices.resize(_child->getNumFaces() * 3); populateFaceVerticesFromParentFaces(); } void TriRefinement::populateFaceVertexCountsAndOffsets() { _child->_faceVertCountsAndOffsets.resize(_child->getNumFaces() * 2, 3); for (int i = 0; i < _child->getNumFaces(); ++i) { _child->_faceVertCountsAndOffsets[i*2 + 1] = i * 3; } } void TriRefinement::populateFaceVerticesFromParentFaces() { for (Index pFace = 0; pFace < _parent->getNumFaces(); ++pFace) { ConstIndexArray pFaceVerts = _parent->getFaceVertices(pFace), pFaceEdges = _parent->getFaceEdges(pFace), pFaceChildren = getFaceChildFaces(pFace); assert(pFaceVerts.size() == 3); assert(pFaceChildren.size() == 4); Index cVertsOfPEdges[3]; cVertsOfPEdges[0] = _edgeChildVertIndex[pFaceEdges[0]]; cVertsOfPEdges[1] = _edgeChildVertIndex[pFaceEdges[1]]; cVertsOfPEdges[2] = _edgeChildVertIndex[pFaceEdges[2]]; // // For the child face at vertex I (where I is 0..2), the child vertex // of vertex I becomes the I'th vertex of its child face. This matches // the pattern for quads of irregular faces for Catmark. // // The orientation for the 4th "interior" face is unclear -- it begins // with the child vertex of the 2nd edge of the triangle. According // to the notes with the Hbr implementation "the ordering of vertices // here is done to preserve parameteric space as best we can." // if (IndexIsValid(pFaceChildren[0])) { IndexArray cFaceVerts = _child->getFaceVertices(pFaceChildren[0]); cFaceVerts[0] = _vertChildVertIndex[pFaceVerts[0]]; cFaceVerts[1] = cVertsOfPEdges[0]; cFaceVerts[2] = cVertsOfPEdges[2]; } if (IndexIsValid(pFaceChildren[1])) { IndexArray cFaceVerts = _child->getFaceVertices(pFaceChildren[1]); cFaceVerts[0] = cVertsOfPEdges[0]; cFaceVerts[1] = _vertChildVertIndex[pFaceVerts[1]]; cFaceVerts[2] = cVertsOfPEdges[1]; } if (IndexIsValid(pFaceChildren[2])) { IndexArray cFaceVerts = _child->getFaceVertices(pFaceChildren[2]); cFaceVerts[0] = cVertsOfPEdges[2]; cFaceVerts[1] = cVertsOfPEdges[1]; cFaceVerts[2] = _vertChildVertIndex[pFaceVerts[2]]; } if (IndexIsValid(pFaceChildren[3])) { IndexArray cFaceVerts = _child->getFaceVertices(pFaceChildren[3]); cFaceVerts[0] = cVertsOfPEdges[1]; cFaceVerts[1] = cVertsOfPEdges[2]; cFaceVerts[2] = cVertsOfPEdges[0]; } } } // // Methods to populate the face-vertex relation of the child Level: // - child faces only originate from parent faces // void TriRefinement::populateFaceEdgeRelation() { // Both face-vertex and face-edge share the face-vertex counts/offsets, so be sure // not to re-initialize it if already done: // if (_child->_faceVertCountsAndOffsets.size() == 0) { populateFaceVertexCountsAndOffsets(); } _child->_faceEdgeIndices.resize(_child->getNumFaces() * 3); populateFaceEdgesFromParentFaces(); } void TriRefinement::populateFaceEdgesFromParentFaces() { for (Index pFace = 0; pFace < _parent->getNumFaces(); ++pFace) { ConstIndexArray pFaceVerts = _parent->getFaceVertices(pFace), pFaceEdges = _parent->getFaceEdges(pFace), pFaceChildFaces = getFaceChildFaces(pFace), pFaceChildEdges = getFaceChildEdges(pFace); assert(pFaceChildFaces.size() == 4); assert(pFaceChildEdges.size() == 3); Index pEdgeChildEdges[3][2]; for (int i = 0; i < 3; ++i) { Index pEdge = pFaceEdges[i]; ConstIndexArray cEdges = getEdgeChildEdges(pEdge); ConstIndexArray pEdgeVerts = _parent->getEdgeVertices(pEdge); // Be careful to consider degenerate edge when orienting here: bool edgeReversedWrtFace = (pEdgeVerts[0] != pEdgeVerts[1]) && (pFaceVerts[i] != pEdgeVerts[0]); pEdgeChildEdges[i][0] = cEdges[edgeReversedWrtFace]; pEdgeChildEdges[i][1] = cEdges[!edgeReversedWrtFace]; } if (IndexIsValid(pFaceChildFaces[0])) { IndexArray cFaceEdges = _child->getFaceEdges(pFaceChildFaces[0]); cFaceEdges[0] = pEdgeChildEdges[0][0]; cFaceEdges[1] = pFaceChildEdges[0]; cFaceEdges[2] = pEdgeChildEdges[2][1]; } if (IndexIsValid(pFaceChildFaces[1])) { IndexArray cFaceEdges = _child->getFaceEdges(pFaceChildFaces[1]); cFaceEdges[0] = pEdgeChildEdges[0][1]; cFaceEdges[1] = pEdgeChildEdges[1][0]; cFaceEdges[2] = pFaceChildEdges[1]; } if (IndexIsValid(pFaceChildFaces[2])) { IndexArray cFaceEdges = _child->getFaceEdges(pFaceChildFaces[2]); cFaceEdges[0] = pFaceChildEdges[2]; cFaceEdges[1] = pEdgeChildEdges[1][1]; cFaceEdges[2] = pEdgeChildEdges[2][0]; } if (IndexIsValid(pFaceChildFaces[3])) { IndexArray cFaceEdges = _child->getFaceEdges(pFaceChildFaces[3]); cFaceEdges[0] = pFaceChildEdges[2]; cFaceEdges[1] = pFaceChildEdges[0]; cFaceEdges[2] = pFaceChildEdges[1]; } } } // // Methods to populate the edge-vertex relation of the child Level: // - child edges originate from parent faces and edges // void TriRefinement::populateEdgeVertexRelation() { _child->_edgeVertIndices.resize(_child->getNumEdges() * 2); populateEdgeVerticesFromParentFaces(); populateEdgeVerticesFromParentEdges(); } void TriRefinement::populateEdgeVerticesFromParentFaces() { for (Index pFace = 0; pFace < _parent->getNumFaces(); ++pFace) { ConstIndexArray pFaceEdges = _parent->getFaceEdges(pFace), pFaceChildEdges = getFaceChildEdges(pFace); assert(pFaceEdges.size() == 3); assert(pFaceChildEdges.size() == 3); Index pEdgeChildVerts[3]; pEdgeChildVerts[0] = _edgeChildVertIndex[pFaceEdges[0]]; pEdgeChildVerts[1] = _edgeChildVertIndex[pFaceEdges[1]]; pEdgeChildVerts[2] = _edgeChildVertIndex[pFaceEdges[2]]; if (IndexIsValid(pFaceChildEdges[0])) { IndexArray cEdgeVerts = _child->getEdgeVertices(pFaceChildEdges[0]); cEdgeVerts[0] = pEdgeChildVerts[0]; cEdgeVerts[1] = pEdgeChildVerts[2]; } if (IndexIsValid(pFaceChildEdges[1])) { IndexArray cEdgeVerts = _child->getEdgeVertices(pFaceChildEdges[1]); cEdgeVerts[0] = pEdgeChildVerts[1]; cEdgeVerts[1] = pEdgeChildVerts[0]; } if (IndexIsValid(pFaceChildEdges[2])) { IndexArray cEdgeVerts = _child->getEdgeVertices(pFaceChildEdges[2]); cEdgeVerts[0] = pEdgeChildVerts[2]; cEdgeVerts[1] = pEdgeChildVerts[1]; } } } void TriRefinement::populateEdgeVerticesFromParentEdges() { for (Index pEdge = 0; pEdge < _parent->getNumEdges(); ++pEdge) { ConstIndexArray pEdgeVerts = _parent->getEdgeVertices(pEdge), pEdgeChildEdges = getEdgeChildEdges(pEdge); if (IndexIsValid(pEdgeChildEdges[0])) { IndexArray cEdgeVerts = _child->getEdgeVertices(pEdgeChildEdges[0]); cEdgeVerts[0] = _edgeChildVertIndex[pEdge]; cEdgeVerts[1] = _vertChildVertIndex[pEdgeVerts[0]]; } if (IndexIsValid(pEdgeChildEdges[1])) { IndexArray cEdgeVerts = _child->getEdgeVertices(pEdgeChildEdges[1]); cEdgeVerts[0] = _edgeChildVertIndex[pEdge]; cEdgeVerts[1] = _vertChildVertIndex[pEdgeVerts[1]]; } } } // // Methods to populate the edge-face relation of the child Level: // - child edges originate from parent faces and edges // - sparse refinement poses challenges with allocation here // - we need to update the counts/offsets as we populate // void TriRefinement::populateEdgeFaceRelation() { // // This is essentially the same as the quad-split version except for the // sizing estimates: // - every child-edge within a face will have 2 incident faces // - every child-edge from a edge may have N incident faces // - use the parents edge-face count for this // int childEdgeFaceIndexSizeEstimate = (int)_faceChildEdgeIndices.size() * 2 + (int)_parent->_edgeFaceIndices.size() * 2; _child->_edgeFaceCountsAndOffsets.resize(_child->getNumEdges() * 2); _child->_edgeFaceIndices.resize(childEdgeFaceIndexSizeEstimate); _child->_edgeFaceLocalIndices.resize(childEdgeFaceIndexSizeEstimate); // Update _maxEdgeFaces from the parent level before calling the // populateEdgeFacesFromParent methods below, as these may further // update _maxEdgeFaces. _child->_maxEdgeFaces = _parent->_maxEdgeFaces; populateEdgeFacesFromParentFaces(); populateEdgeFacesFromParentEdges(); // Revise the over-allocated estimate based on what is used (as indicated in the // count/offset for the last vertex) and trim the index vector accordingly: childEdgeFaceIndexSizeEstimate = _child->getNumEdgeFaces(_child->getNumEdges()-1) + _child->getOffsetOfEdgeFaces(_child->getNumEdges()-1); _child->_edgeFaceIndices.resize(childEdgeFaceIndexSizeEstimate); _child->_edgeFaceLocalIndices.resize(childEdgeFaceIndexSizeEstimate); } void TriRefinement::populateEdgeFacesFromParentFaces() { for (Index pFace = 0; pFace < _parent->getNumFaces(); ++pFace) { ConstIndexArray pFaceChildFaces = getFaceChildFaces(pFace), pFaceChildEdges = getFaceChildEdges(pFace); assert(pFaceChildFaces.size() == 4); assert(pFaceChildEdges.size() == 3); // Every child-edge of a face potentially shares the middle child face: Index cFaceMiddle = pFaceChildFaces[3]; bool isFaceMiddleValid = IndexIsValid(cFaceMiddle); for (int j = 0; j < pFaceChildEdges.size(); ++j) { Index cEdge = pFaceChildEdges[j]; if (IndexIsValid(cEdge)) { // Reserve enough edge-faces, populate and trim as needed: _child->resizeEdgeFaces(cEdge, 2); IndexArray cEdgeFaces = _child->getEdgeFaces(cEdge); LocalIndexArray cEdgeInFace = _child->getEdgeFaceLocalIndices(cEdge); int cEdgeFaceCount = 0; if (IndexIsValid(pFaceChildFaces[j])) { cEdgeFaces[cEdgeFaceCount] = pFaceChildFaces[j]; cEdgeInFace[cEdgeFaceCount] = (LocalIndex) ((j + 1) % 3); cEdgeFaceCount++; } if (isFaceMiddleValid) { cEdgeFaces[cEdgeFaceCount] = cFaceMiddle; cEdgeInFace[cEdgeFaceCount] = (LocalIndex) ((j + 1) % 3); cEdgeFaceCount++; } _child->trimEdgeFaces(cEdge, cEdgeFaceCount); } } } } void TriRefinement::populateEdgeFacesFromParentEdges() { for (Index pEdge = 0; pEdge < _parent->getNumEdges(); ++pEdge) { ConstIndexArray pEdgeChildEdges = getEdgeChildEdges(pEdge); if (!IndexIsValid(pEdgeChildEdges[0]) && !IndexIsValid(pEdgeChildEdges[1])) continue; ConstIndexArray pEdgeFaces = _parent->getEdgeFaces(pEdge); ConstLocalIndexArray pEdgeInFace = _parent->getEdgeFaceLocalIndices(pEdge); ConstIndexArray pEdgeVerts = _parent->getEdgeVertices(pEdge); for (int j = 0; j < 2; ++j) { Index cEdge = pEdgeChildEdges[j]; if (!IndexIsValid(cEdge)) continue; // // Reserve enough edge-faces, populate and trim as needed: // _child->resizeEdgeFaces(cEdge, pEdgeFaces.size()); IndexArray cEdgeFaces = _child->getEdgeFaces(cEdge); LocalIndexArray cEdgeInFace = _child->getEdgeFaceLocalIndices(cEdge); // // Each parent face may contribute an incident child face: // // For each incident face and local-index, we immediately know // the two child faces that are associated with the two child edges. // We just need to identify how to pair them based on edge direction. // // Note also here, that we could identify the pairs of child faces // once for the parent before dealing with each child edge (we do the // "find edge in face search" twice here as a result). We will // generally have 2 or 1 incident face to the parent edge so we // can put the child-pairs on the stack. // // Here's a more promising alternative -- instead of iterating // through the child edges to "pull" data from the parent, iterate // through the parent edges' faces and apply valid child faces to // the appropriate child edge. We should be able to use end-verts // of the parent edge to get the corresponding child face for each, // but we can't avoid a vert-in-face search and a subsequent parity // test of the end-vert. // int cEdgeFaceCount = 0; for (int i = 0; i < pEdgeFaces.size(); ++i) { Index pFace = pEdgeFaces[i]; int edgeInFace = pEdgeInFace[i]; ConstIndexArray pFaceVerts = _parent->getFaceVertices(pFace), pFaceChildren = getFaceChildFaces(pFace); // Inspect either this child of the face or the next -- be careful // to consider degenerate edge when orienting here: int childOfEdge = (pEdgeVerts[0] == pEdgeVerts[1]) ? j : (pFaceVerts[edgeInFace] != pEdgeVerts[j]); int childInFace = edgeInFace + childOfEdge; if (childInFace == pFaceVerts.size()) childInFace = 0; if (IndexIsValid(pFaceChildren[childInFace])) { cEdgeFaces[cEdgeFaceCount] = pFaceChildren[childInFace]; cEdgeInFace[cEdgeFaceCount] = (LocalIndex) edgeInFace; cEdgeFaceCount++; } } _child->trimEdgeFaces(cEdge, cEdgeFaceCount); } } } // // Methods to populate the vertex-face relation of the child Level: // - child vertices originate from parent faces, edges and vertices // - sparse refinement poses challenges with allocation here: // - we need to update the counts/offsets as we populate // - note this imposes ordering constraints and inhibits concurrency // void TriRefinement::populateVertexFaceRelation() { // // Unlike quad-splitting, we don't have to consider vertices originating from // faces. We also have to consider 3 faces for every incident face for vertices // originating from edges. // int childVertFaceIndexSizeEstimate = (int)_parent->_edgeFaceIndices.size() * 3 + (int)_parent->_vertFaceIndices.size(); _child->_vertFaceCountsAndOffsets.resize(_child->getNumVertices() * 2); _child->_vertFaceIndices.resize( childVertFaceIndexSizeEstimate); _child->_vertFaceLocalIndices.resize( childVertFaceIndexSizeEstimate); // Remember -- no vertices-from-faces to consider here (until N-gon support) if (getFirstChildVertexFromVertices() == 0) { populateVertexFacesFromParentVertices(); populateVertexFacesFromParentEdges(); } else { populateVertexFacesFromParentEdges(); populateVertexFacesFromParentVertices(); } // Revise the over-allocated estimate based on what is used (as indicated in the // count/offset for the last vertex) and trim the index vectors accordingly: childVertFaceIndexSizeEstimate = _child->getNumVertexFaces(_child->getNumVertices()-1) + _child->getOffsetOfVertexFaces(_child->getNumVertices()-1); _child->_vertFaceIndices.resize( childVertFaceIndexSizeEstimate); _child->_vertFaceLocalIndices.resize(childVertFaceIndexSizeEstimate); } void TriRefinement::populateVertexFacesFromParentEdges() { for (Index pEdge = 0; pEdge < _parent->getNumEdges(); ++pEdge) { Index cVert = _edgeChildVertIndex[pEdge]; if (!IndexIsValid(cVert)) continue; ConstIndexArray pEdgeFaces = _parent->getEdgeFaces(pEdge); ConstLocalIndexArray pEdgeInFace = _parent->getEdgeFaceLocalIndices(pEdge); // // Reserve enough vert-faces, populate and trim to the actual size: // _child->resizeVertexFaces(cVert, 2 * pEdgeFaces.size()); IndexArray cVertFaces = _child->getVertexFaces(cVert); LocalIndexArray cVertInFace = _child->getVertexFaceLocalIndices(cVert); int cVertFaceCount = 0; for (int i = 0; i < pEdgeFaces.size(); ++i) { Index pFace = pEdgeFaces[i]; int edgeInFace = pEdgeInFace[i]; // // Identify the corresponding three child faces for this parent face and // their orientation wrt the child vertex to which they are incident -- // since we have the desired ordering of child faces from the parent face, // we don't care about the orientation of the parent edge. // LocalIndex leadingFace = (LocalIndex) ((edgeInFace + 1) % 3); LocalIndex middleFace = (LocalIndex) 3; LocalIndex trailingFace = (LocalIndex) edgeInFace; LocalIndex leadingLocalIndex = (LocalIndex) edgeInFace; LocalIndex middleLocalIndex = (LocalIndex) ((edgeInFace + 2) % 3); LocalIndex trailingLocalIndex = (LocalIndex) ((edgeInFace + 1) % 3); // // Now simply assign those of the three child faces that are valid: // ConstIndexArray pFaceChildFaces = getFaceChildFaces(pFace); assert(pFaceChildFaces.size() == 4); Index cFace = pFaceChildFaces[leadingFace]; if (IndexIsValid(cFace)) { cVertFaces[cVertFaceCount] = cFace; cVertInFace[cVertFaceCount] = leadingLocalIndex; cVertFaceCount++; } cFace = pFaceChildFaces[middleFace]; if (IndexIsValid(cFace)) { cVertFaces[cVertFaceCount] = cFace; cVertInFace[cVertFaceCount] = middleLocalIndex; cVertFaceCount++; } cFace = pFaceChildFaces[trailingFace]; if (IndexIsValid(cFace)) { cVertFaces[cVertFaceCount] = cFace; cVertInFace[cVertFaceCount] = trailingLocalIndex; cVertFaceCount++; } } _child->trimVertexFaces(cVert, cVertFaceCount); } } void TriRefinement::populateVertexFacesFromParentVertices() { for (Index pVert = 0; pVert < _parent->getNumVertices(); ++pVert) { Index cVert = _vertChildVertIndex[pVert]; if (!IndexIsValid(cVert)) continue; // // Inspect the parent vert's faces: // ConstIndexArray pVertFaces = _parent->getVertexFaces(pVert); ConstLocalIndexArray pVertInFace = _parent->getVertexFaceLocalIndices(pVert); // // Reserve enough vert-faces, populate and trim to the actual size: // _child->resizeVertexFaces(cVert, pVertFaces.size()); IndexArray cVertFaces = _child->getVertexFaces(cVert); LocalIndexArray cVertInFace = _child->getVertexFaceLocalIndices(cVert); int cVertFaceCount = 0; for (int i = 0; i < pVertFaces.size(); ++i) { Index pFace = pVertFaces[i]; LocalIndex pFaceChild = pVertInFace[i]; Index cFace = getFaceChildFaces(pFace)[pFaceChild]; if (IndexIsValid(cFace)) { cVertFaces[cVertFaceCount] = cFace; cVertInFace[cVertFaceCount] = pFaceChild; cVertFaceCount++; } } _child->trimVertexFaces(cVert, cVertFaceCount); } } // // Methods to populate the vertex-edge relation of the child Level: // - child vertices originate from parent faces, edges and vertices // - sparse refinement poses challenges with allocation here: // - we need to update the counts/offsets as we populate // - note this imposes ordering constraints and inhibits concurrency // void TriRefinement::populateVertexEdgeRelation() { // // Notes on allocating/initializing the vertex-edge counts/offsets vector: // // Be aware of scheme-specific decisions here, e.g.: // - no verts from parent faces for Loop // - more interior edges and faces for verts from parent edges for Loop // - no guaranteed "neighborhood" around Bilinear verts from verts // // If uniform subdivision, vert-edge count will be: // - 2 + 2*N faces incident parent edge for verts from parent edges // - same as parent vert for verts from parent verts // If sparse subdivision, vert-edge count will be: // - non-trivial function of child faces in parent face // - 1 child face will always result in 2 child edges // * 2 child faces can mean 3 or 4 child edges // - 3 child faces will always result in 4 child edges // - 1 or 2 + N faces incident parent edge for verts from parent edges // - where the 1 or 2 is number of child edges of parent edge // - any end vertex will require all N child faces (catmark) // - same as parent vert for verts from parent verts (catmark) // int childVertEdgeIndexSizeEstimate = (int)_parent->_edgeFaceIndices.size() * 2 + _parent->getNumEdges() * 2 + (int)_parent->_vertEdgeIndices.size(); _child->_vertEdgeCountsAndOffsets.resize(_child->getNumVertices() * 2); _child->_vertEdgeIndices.resize( childVertEdgeIndexSizeEstimate); _child->_vertEdgeLocalIndices.resize( childVertEdgeIndexSizeEstimate); if (getFirstChildVertexFromVertices() == 0) { populateVertexEdgesFromParentVertices(); populateVertexEdgesFromParentEdges(); } else { populateVertexEdgesFromParentEdges(); populateVertexEdgesFromParentVertices(); } // Revise the over-allocated estimate based on what is used (as indicated in the // count/offset for the last vertex) and trim the index vectors accordingly: childVertEdgeIndexSizeEstimate = _child->getNumVertexEdges(_child->getNumVertices()-1) + _child->getOffsetOfVertexEdges(_child->getNumVertices()-1); _child->_vertEdgeIndices.resize( childVertEdgeIndexSizeEstimate); _child->_vertEdgeLocalIndices.resize(childVertEdgeIndexSizeEstimate); } void TriRefinement::populateVertexEdgesFromParentEdges() { for (Index pEdge = 0; pEdge < _parent->getNumEdges(); ++pEdge) { Index cVert = _edgeChildVertIndex[pEdge]; if (!IndexIsValid(cVert)) continue; // // First inspect the parent edge -- its parent faces then its child edges: // ConstIndexArray pEdgeFaces = _parent->getEdgeFaces(pEdge); ConstLocalIndexArray pEdgeInFace = _parent->getEdgeFaceLocalIndices(pEdge); ConstIndexArray pEdgeVerts = _parent->getEdgeVertices(pEdge), pEdgeChildEdges = getEdgeChildEdges(pEdge); // // Reserve enough vert-edges, populate and trim to the actual size: // _child->resizeVertexEdges(cVert, pEdgeFaces.size() + 2); IndexArray cVertEdges = _child->getVertexEdges(cVert); LocalIndexArray cVertInEdge = _child->getVertexEdgeLocalIndices(cVert); // // We need to order the incident edges around the vertex appropriately: // - one child edge of the parent edge ("leading" in face 0) // - two child edges interior to face 0 // - one other child edge of the parent edge ("trailing" in face 0) // - child edges of all remaining faces // Be careful to place the leading/trailing child edges of the parent edge // correctly -- edges are not directed their orientation may vary. The // interior child edges are appropriately oriented wrt their parent face. // // Also need to consider no faces at all, in which case we just want the // child edges of the parent edge. // int cVertEdgeCount = 0; // We only care about edge reversal in the first iteration -- in which // the child edges of the parent edges are assigned. Other iterations // only assign the child edges from the incident parent face: bool pEdgeReversed = false; Index cEdgeOfEdge0 = INDEX_INVALID, cEdgeOfEdge1 = INDEX_INVALID; for (int i = 0; i < pEdgeFaces.size(); ++i) { Index pFace = pEdgeFaces[i]; int edgeInFace = pEdgeInFace[i]; ConstIndexArray pFaceChildEdges = getFaceChildEdges(pFace); // Test the orientation of a non-degenerate edge in the first face: if (i == 0) { if (pEdgeVerts[0] != pEdgeVerts[1]) { pEdgeReversed = (_parent->getFaceVertices(pFace)[edgeInFace] != pEdgeVerts[0]); } cEdgeOfEdge0 = pEdgeChildEdges[!pEdgeReversed]; cEdgeOfEdge1 = pEdgeChildEdges[pEdgeReversed]; } // // Identify the two interior and incident child edges within the face -- // bracketed by the child edges of the parent edge when dealing with the // first face: // Index cEdgeOfFace0 = pFaceChildEdges[(edgeInFace + 1) % 3]; Index cEdgeOfFace1 = pFaceChildEdges[edgeInFace]; if ((i == 0) && IndexIsValid(cEdgeOfEdge0)) { cVertEdges[cVertEdgeCount] = cEdgeOfEdge0; cVertInEdge[cVertEdgeCount] = 0; cVertEdgeCount++; } if (IndexIsValid(cEdgeOfFace0)) { cVertEdges[cVertEdgeCount] = cEdgeOfFace0; cVertInEdge[cVertEdgeCount] = 1; cVertEdgeCount++; } if (IndexIsValid(cEdgeOfFace1)) { cVertEdges[cVertEdgeCount] = cEdgeOfFace1; cVertInEdge[cVertEdgeCount] = 0; cVertEdgeCount++; } if ((i == 0) && IndexIsValid(cEdgeOfEdge1)) { cVertEdges[cVertEdgeCount] = cEdgeOfEdge1; cVertInEdge[cVertEdgeCount] = 0; cVertEdgeCount++; } } _child->trimVertexEdges(cVert, cVertEdgeCount); } } void TriRefinement::populateVertexEdgesFromParentVertices() { for (Index pVert = 0; pVert < _parent->getNumVertices(); ++pVert) { Index cVert = _vertChildVertIndex[pVert]; if (!IndexIsValid(cVert)) continue; // // Inspect the parent vert's edges first: // ConstIndexArray pVertEdges = _parent->getVertexEdges(pVert); ConstLocalIndexArray pVertInEdge = _parent->getVertexEdgeLocalIndices(pVert); // // Reserve enough vert-edges, populate and trim to the actual size: // _child->resizeVertexEdges(cVert, pVertEdges.size()); IndexArray cVertEdges = _child->getVertexEdges(cVert); LocalIndexArray cVertInEdge = _child->getVertexEdgeLocalIndices(cVert); int cVertEdgeCount = 0; for (int i = 0; i < pVertEdges.size(); ++i) { Index cEdge = getEdgeChildEdges(pVertEdges[i])[pVertInEdge[i]]; if (IndexIsValid(cEdge)) { cVertEdges[cVertEdgeCount] = cEdge; cVertInEdge[cVertEdgeCount] = 1; cVertEdgeCount++; } } _child->trimVertexEdges(cVert, cVertEdgeCount); } } // // Methods to populate child-component indices for sparse selection: // // Need to find a better place for these anon helper methods now that they are required // both in the base class and the two subclasses for quad- and tri-splitting... // namespace { Index const IndexSparseMaskNeighboring = (1 << 0); Index const IndexSparseMaskSelected = (1 << 1); inline void markSparseIndexNeighbor(Index& index) { index = IndexSparseMaskNeighboring; } inline void markSparseIndexSelected(Index& index) { index = IndexSparseMaskSelected; } } void TriRefinement::markSparseFaceChildren() { assert(_parentFaceTag.size() > 0); // // For each parent face: // All boundary edges will be adequately marked as a result of the pass over the // edges above and boundary vertices marked by selection. So all that remains is to // identify the child faces and interior child edges for a face requiring neighboring // child faces. // For each corner vertex selected, we need to mark the corresponding child face, // the two interior child edges and shared child vertex in the middle. // for (Index pFace = 0; pFace < parent().getNumFaces(); ++pFace) { // // Mark all descending child components of a selected face. Otherwise inspect // its incident vertices to see if anything neighboring has been selected -- // requiring partial refinement of this face. // // Remember that a selected face cannot be transitional, and that only a // transitional face will be partially refined. // IndexArray fChildFaces = getFaceChildFaces(pFace); IndexArray fChildEdges = getFaceChildEdges(pFace); assert(fChildFaces.size() == 4); assert(fChildEdges.size() == 3); ConstIndexArray fVerts = parent().getFaceVertices(pFace); SparseTag& pFaceTag = _parentFaceTag[pFace]; if (pFaceTag._selected) { markSparseIndexSelected(fChildFaces[0]); markSparseIndexSelected(fChildFaces[1]); markSparseIndexSelected(fChildFaces[2]); markSparseIndexSelected(fChildFaces[3]); markSparseIndexSelected(fChildEdges[0]); markSparseIndexSelected(fChildEdges[1]); markSparseIndexSelected(fChildEdges[2]); pFaceTag._transitional = 0; } else { int marked = _parentVertexTag[fVerts[0]]._selected + _parentVertexTag[fVerts[1]]._selected + _parentVertexTag[fVerts[2]]._selected; if (marked) { // // If marked, see if we have any transitional edges, in which case we // need to include the middle face: // ConstIndexArray fEdges = parent().getFaceEdges(pFace); pFaceTag._transitional = (unsigned char) ((_parentEdgeTag[fEdges[0]]._transitional << 0) | (_parentEdgeTag[fEdges[1]]._transitional << 1) | (_parentEdgeTag[fEdges[2]]._transitional << 2)); // Now mark the child faces and their associated edges: // if (pFaceTag._transitional) { markSparseIndexNeighbor(fChildFaces[3]); markSparseIndexNeighbor(fChildEdges[0]); markSparseIndexNeighbor(fChildEdges[1]); markSparseIndexNeighbor(fChildEdges[2]); } if (_parentVertexTag[fVerts[0]]._selected) { markSparseIndexNeighbor(fChildFaces[0]); markSparseIndexNeighbor(fChildEdges[0]); } if (_parentVertexTag[fVerts[1]]._selected) { markSparseIndexNeighbor(fChildFaces[1]); markSparseIndexNeighbor(fChildEdges[1]); } if (_parentVertexTag[fVerts[2]]._selected) { markSparseIndexNeighbor(fChildFaces[2]); markSparseIndexNeighbor(fChildEdges[2]); } } } } } } // end namespace Vtr } // end namespace OPENSUBDIV_VERSION } // end namespace OpenSubdiv