OpenSubdiv/opensubdiv/vtr/refinement.cpp
barfowl 898d68ae79 Minor additions and revisions to TopologyRefiner interface:
- new Options for Refine() methods for base face and vertex ordering
    - removed ignored/unused "full topology" choice from AdaptiveOptions
    - added base face and vertex ordering logic to Refinement
    - addition of TopologyRefiner members for component counts and max valence
    - refactoring of Level additions to update all new member totals
    - addition of GetMaxValence() to TopologyRefiner
    - updated PatchTablesFactory to user new GetMaxValence() method
    - renaming of "Hole" methods for TopologyRefiner and Vtr::Level
2015-04-01 20:44:33 -07:00

1262 lines
47 KiB
C++

//
// 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 "../sdc/catmarkScheme.h"
#include "../sdc/bilinearScheme.h"
#include "../vtr/types.h"
#include "../vtr/level.h"
#include "../vtr/refinement.h"
#include "../vtr/fvarLevel.h"
#include "../vtr/fvarRefinement.h"
#include "../vtr/maskInterfaces.h"
#include <cassert>
#include <cstdio>
#include <utility>
namespace OpenSubdiv {
namespace OPENSUBDIV_VERSION {
namespace Vtr {
//
// Simple constructor, destructor and basic initializers:
//
Refinement::Refinement(Level const & parent, Level & child, Sdc::Options const& options) :
_parent(&parent),
_child(&child),
_options(options),
_regFaceSize(-1),
_uniform(false),
_faceVertsFirst(false),
_childFaceFromFaceCount(0),
_childEdgeFromFaceCount(0),
_childEdgeFromEdgeCount(0),
_childVertFromFaceCount(0),
_childVertFromEdgeCount(0),
_childVertFromVertCount(0),
_firstChildFaceFromFace(0),
_firstChildEdgeFromFace(0),
_firstChildEdgeFromEdge(0),
_firstChildVertFromFace(0),
_firstChildVertFromEdge(0),
_firstChildVertFromVert(0) {
assert((child.getDepth() == 0) && (child.getNumVertices() == 0));
child._depth = 1 + parent.getDepth();
}
Refinement::~Refinement() {
for (int i = 0; i < (int)_fvarChannels.size(); ++i) {
delete _fvarChannels[i];
}
}
void
Refinement::initializeChildComponentCounts() {
//
// Assign the child's component counts/inventory based on the child components identified:
//
_child->_faceCount = _childFaceFromFaceCount;
_child->_edgeCount = _childEdgeFromFaceCount + _childEdgeFromEdgeCount;
_child->_vertCount = _childVertFromFaceCount + _childVertFromEdgeCount + _childVertFromVertCount;
}
void
Refinement::initializeSparseSelectionTags() {
_parentFaceTag.resize(_parent->getNumFaces());
_parentEdgeTag.resize(_parent->getNumEdges());
_parentVertexTag.resize(_parent->getNumVertices());
}
//
// The main refinement method -- provides a high-level overview of refinement:
//
// The refinement process is as follows:
// - determine a mapping from parent components to their potential child components
// - for sparse refinement this mapping will be partial
// - determine the reverse mapping from chosen child components back to their parents
// - previously this was optional -- not strictly necessary and comes at added cost
// - does simplify iteration of child components when refinement is sparse
// - propagate/initialize component Tags from parents to their children
// - knowing these Tags for a child component simplifies dealing with it later
// - subdivide the topology, i.e. populate all topology relations for the child Level
// - any subset of the 6 relations in a Level can be created
// - using the minimum required in the last Level is very advantageous
// - subdivide the sharpness values in the child Level
// - subdivide face-varying channels in the child Level
//
void
Refinement::refine(Options refineOptions) {
// This will become redundant when/if assigned on construction:
assert(_parent && _child);
_uniform = !refineOptions._sparse;
_faceVertsFirst = refineOptions._faceVertsFirst;
// We may soon have an option here to suppress refinement of FVar channels...
bool refineOptions_ignoreFVarChannels = false;
bool optionallyRefineFVar = (_parent->getNumFVarChannels() > 0) && !refineOptions_ignoreFVarChannels;
//
// Initialize the parent-to-child and reverse child-to-parent mappings and propagate
// component tags to the new child components:
//
populateParentToChildMapping();
initializeChildComponentCounts();
populateChildToParentMapping();
propagateComponentTags();
//
// Subdivide the topology -- populating only those of the 6 relations specified
// (though we do require the vertex-face relation for refining FVar channels):
//
Relations relationsToPopulate;
if (refineOptions._minimalTopology) {
relationsToPopulate.setAll(false);
relationsToPopulate._faceVertices = true;
} else {
relationsToPopulate.setAll(true);
}
if (optionallyRefineFVar) {
relationsToPopulate._vertexFaces = true;
}
subdivideTopology(relationsToPopulate);
//
// Subdivide the sharpness values and face-varying channels:
// - note there is some dependency of the vertex tag/Rule for semi-sharp vertices
//
subdivideSharpnessValues();
if (optionallyRefineFVar) {
subdivideFVarChannels();
}
// Various debugging support:
//
//printf("Vertex refinement to level %d completed...\n", _child->getDepth());
//_child->print();
//printf(" validating refinement to level %d...\n", _child->getDepth());
//_child->validateTopology();
//assert(_child->validateTopology());
}
//
// Methods for construct the parent-to-child mapping
//
void
Refinement::populateParentToChildMapping() {
allocateParentChildIndices();
//
// If sparse refinement, mark indices of any components in addition to those selected
// so that we have the full neighborhood for selected components:
//
if (!_uniform) {
// Make sure the selection was non-empty -- currently unsupported...
if (_parentVertexTag.size() == 0) {
assert("Unsupported empty sparse refinement detected in Refinement" == 0);
}
markSparseChildComponentIndices();
}
populateParentChildIndices();
}
namespace {
inline bool isSparseIndexMarked(Index index) { return index != 0; }
inline int
sequenceSparseIndexVector(IndexVector& indexVector, int baseValue = 0) {
int validCount = 0;
for (int i = 0; i < (int) indexVector.size(); ++i) {
indexVector[i] = isSparseIndexMarked(indexVector[i])
? (baseValue + validCount++) : INDEX_INVALID;
}
return validCount;
}
inline int
sequenceFullIndexVector(IndexVector& indexVector, int baseValue = 0) {
int indexCount = (int) indexVector.size();
for (int i = 0; i < indexCount; ++i) {
indexVector[i] = baseValue++;
}
return indexCount;
}
}
void
Refinement::populateParentChildIndices() {
//
// Two vertex orderings are currently supported -- ordering vertices refined
// from vertices first, or those refined from faces first. Its possible this
// may be extended to more possibilities. Once the ordering is defined here,
// other than analogous initialization in FVarRefinement, the treatment of
// vertices in blocks based on origin should make the rest of the code
// invariant to ordering changes.
//
// These two blocks now differ only in the utility function that assigns the
// sequential values to the index vectors -- so parameterization/simplification
// is now possible...
//
if (_uniform) {
// child faces:
_firstChildFaceFromFace = 0;
_childFaceFromFaceCount = sequenceFullIndexVector(_faceChildFaceIndices, _firstChildFaceFromFace);
// child edges:
_firstChildEdgeFromFace = 0;
_childEdgeFromFaceCount = sequenceFullIndexVector(_faceChildEdgeIndices, _firstChildEdgeFromFace);
_firstChildEdgeFromEdge = _childEdgeFromFaceCount;
_childEdgeFromEdgeCount = sequenceFullIndexVector(_edgeChildEdgeIndices, _firstChildEdgeFromEdge);
// child vertices:
if (_faceVertsFirst) {
_firstChildVertFromFace = 0;
_childVertFromFaceCount = sequenceFullIndexVector(_faceChildVertIndex, _firstChildVertFromFace);
_firstChildVertFromEdge = _firstChildVertFromFace + _childVertFromFaceCount;
_childVertFromEdgeCount = sequenceFullIndexVector(_edgeChildVertIndex, _firstChildVertFromEdge);
_firstChildVertFromVert = _firstChildVertFromEdge + _childVertFromEdgeCount;
_childVertFromVertCount = sequenceFullIndexVector(_vertChildVertIndex, _firstChildVertFromVert);
} else {
_firstChildVertFromVert = 0;
_childVertFromVertCount = sequenceFullIndexVector(_vertChildVertIndex, _firstChildVertFromVert);
_firstChildVertFromFace = _firstChildVertFromVert + _childVertFromVertCount;
_childVertFromFaceCount = sequenceFullIndexVector(_faceChildVertIndex, _firstChildVertFromFace);
_firstChildVertFromEdge = _firstChildVertFromFace + _childVertFromFaceCount;
_childVertFromEdgeCount = sequenceFullIndexVector(_edgeChildVertIndex, _firstChildVertFromEdge);
}
} else {
// child faces:
_firstChildFaceFromFace = 0;
_childFaceFromFaceCount = sequenceSparseIndexVector(_faceChildFaceIndices, _firstChildFaceFromFace);
// child edges:
_firstChildEdgeFromFace = 0;
_childEdgeFromFaceCount = sequenceSparseIndexVector(_faceChildEdgeIndices, _firstChildEdgeFromFace);
_firstChildEdgeFromEdge = _childEdgeFromFaceCount;
_childEdgeFromEdgeCount = sequenceSparseIndexVector(_edgeChildEdgeIndices, _firstChildEdgeFromEdge);
// child vertices:
if (_faceVertsFirst) {
_firstChildVertFromFace = 0;
_childVertFromFaceCount = sequenceSparseIndexVector(_faceChildVertIndex, _firstChildVertFromFace);
_firstChildVertFromEdge = _firstChildVertFromFace + _childVertFromFaceCount;
_childVertFromEdgeCount = sequenceSparseIndexVector(_edgeChildVertIndex, _firstChildVertFromEdge);
_firstChildVertFromVert = _firstChildVertFromEdge + _childVertFromEdgeCount;
_childVertFromVertCount = sequenceSparseIndexVector(_vertChildVertIndex, _firstChildVertFromVert);
} else {
_firstChildVertFromVert = 0;
_childVertFromVertCount = sequenceSparseIndexVector(_vertChildVertIndex, _firstChildVertFromVert);
_firstChildVertFromFace = _firstChildVertFromVert + _childVertFromVertCount;
_childVertFromFaceCount = sequenceSparseIndexVector(_faceChildVertIndex, _firstChildVertFromFace);
_firstChildVertFromEdge = _firstChildVertFromFace + _childVertFromFaceCount;
_childVertFromEdgeCount = sequenceSparseIndexVector(_edgeChildVertIndex, _firstChildVertFromEdge);
}
}
}
void
Refinement::printParentToChildMapping() const {
printf("Parent-to-child component mapping:\n");
for (Index pFace = 0; pFace < _parent->getNumFaces(); ++pFace) {
printf(" Face %d:\n", pFace);
printf(" Child vert: %d\n", _faceChildVertIndex[pFace]);
printf(" Child faces: ");
ConstIndexArray childFaces = getFaceChildFaces(pFace);
for (int i = 0; i < childFaces.size(); ++i) {
printf(" %d", childFaces[i]);
}
printf("\n");
printf(" Child edges: ");
ConstIndexArray childEdges = getFaceChildEdges(pFace);
for (int i = 0; i < childEdges.size(); ++i) {
printf(" %d", childEdges[i]);
}
printf("\n");
}
for (Index pEdge = 0; pEdge < _parent->getNumEdges(); ++pEdge) {
printf(" Edge %d:\n", pEdge);
printf(" Child vert: %d\n", _edgeChildVertIndex[pEdge]);
ConstIndexArray childEdges = getEdgeChildEdges(pEdge);
printf(" Child edges: %d %d\n", childEdges[0], childEdges[1]);
}
for (Index pVert = 0; pVert < _parent->getNumVertices(); ++pVert) {
printf(" Vert %d:\n", pVert);
printf(" Child vert: %d\n", _vertChildVertIndex[pVert]);
}
}
//
// Methods to construct the child-to-parent mapping:
//
void
Refinement::populateChildToParentMapping() {
ChildTag initialChildTags[2][4];
for (int i = 0; i < 2; ++i) {
for (int j = 0; j < 4; ++j) {
ChildTag & tag = initialChildTags[i][j];
tag._incomplete = (unsigned char)i;
tag._parentType = 0;
tag._indexInParent = (unsigned char)j;
}
}
populateFaceParentVectors(initialChildTags);
populateEdgeParentVectors(initialChildTags);
populateVertexParentVectors(initialChildTags);
}
void
Refinement::populateFaceParentVectors(ChildTag const initialChildTags[2][4]) {
_childFaceTag.resize(_child->getNumFaces());
_childFaceParentIndex.resize(_child->getNumFaces());
populateFaceParentFromParentFaces(initialChildTags);
}
void
Refinement::populateFaceParentFromParentFaces(ChildTag const initialChildTags[2][4]) {
if (_uniform) {
Index cFace = getFirstChildFaceFromFaces();
for (Index pFace = 0; pFace < _parent->getNumFaces(); ++pFace) {
ConstIndexArray cFaces = getFaceChildFaces(pFace);
if (cFaces.size() == 4) {
_childFaceTag[cFace + 0] = initialChildTags[0][0];
_childFaceTag[cFace + 1] = initialChildTags[0][1];
_childFaceTag[cFace + 2] = initialChildTags[0][2];
_childFaceTag[cFace + 3] = initialChildTags[0][3];
_childFaceParentIndex[cFace + 0] = pFace;
_childFaceParentIndex[cFace + 1] = pFace;
_childFaceParentIndex[cFace + 2] = pFace;
_childFaceParentIndex[cFace + 3] = pFace;
cFace += 4;
} else {
bool childTooLarge = (cFaces.size() > 4);
for (int i = 0; i < cFaces.size(); ++i, ++cFace) {
_childFaceTag[cFace] = initialChildTags[0][childTooLarge ? 0 : i];
_childFaceParentIndex[cFace] = pFace;
}
}
}
} else {
// Child faces of faces:
for (Index pFace = 0; pFace < _parent->getNumFaces(); ++pFace) {
bool incomplete = !_parentFaceTag[pFace]._selected;
IndexArray cFaces = getFaceChildFaces(pFace);
if (!incomplete && (cFaces.size() == 4)) {
_childFaceTag[cFaces[0]] = initialChildTags[0][0];
_childFaceTag[cFaces[1]] = initialChildTags[0][1];
_childFaceTag[cFaces[2]] = initialChildTags[0][2];
_childFaceTag[cFaces[3]] = initialChildTags[0][3];
_childFaceParentIndex[cFaces[0]] = pFace;
_childFaceParentIndex[cFaces[1]] = pFace;
_childFaceParentIndex[cFaces[2]] = pFace;
_childFaceParentIndex[cFaces[3]] = pFace;
} else {
bool childTooLarge = (cFaces.size() > 4);
for (int i = 0; i < cFaces.size(); ++i) {
if (IndexIsValid(cFaces[i])) {
_childFaceTag[cFaces[i]] = initialChildTags[incomplete][childTooLarge ? 0 : i];
_childFaceParentIndex[cFaces[i]] = pFace;
}
}
}
}
}
}
void
Refinement::populateEdgeParentVectors(ChildTag const initialChildTags[2][4]) {
_childEdgeTag.resize(_child->getNumEdges());
_childEdgeParentIndex.resize(_child->getNumEdges());
populateEdgeParentFromParentFaces(initialChildTags);
populateEdgeParentFromParentEdges(initialChildTags);
}
void
Refinement::populateEdgeParentFromParentFaces(ChildTag const initialChildTags[2][4]) {
if (_uniform) {
Index cEdge = getFirstChildEdgeFromFaces();
for (Index pFace = 0; pFace < _parent->getNumFaces(); ++pFace) {
ConstIndexArray cEdges = getFaceChildEdges(pFace);
if (cEdges.size() == 4) {
_childEdgeTag[cEdge + 0] = initialChildTags[0][0];
_childEdgeTag[cEdge + 1] = initialChildTags[0][1];
_childEdgeTag[cEdge + 2] = initialChildTags[0][2];
_childEdgeTag[cEdge + 3] = initialChildTags[0][3];
_childEdgeParentIndex[cEdge + 0] = pFace;
_childEdgeParentIndex[cEdge + 1] = pFace;
_childEdgeParentIndex[cEdge + 2] = pFace;
_childEdgeParentIndex[cEdge + 3] = pFace;
cEdge += 4;
} else {
bool childTooLarge = (cEdges.size() > 4);
for (int i = 0; i < cEdges.size(); ++i, ++cEdge) {
_childEdgeTag[cEdge] = initialChildTags[0][childTooLarge ? 0 : i];
_childEdgeParentIndex[cEdge] = pFace;
}
}
}
} else {
for (Index pFace = 0; pFace < _parent->getNumFaces(); ++pFace) {
bool incomplete = !_parentFaceTag[pFace]._selected;
IndexArray cEdges = getFaceChildEdges(pFace);
if (!incomplete && (cEdges.size() == 4)) {
_childEdgeTag[cEdges[0]] = initialChildTags[0][0];
_childEdgeTag[cEdges[1]] = initialChildTags[0][1];
_childEdgeTag[cEdges[2]] = initialChildTags[0][2];
_childEdgeTag[cEdges[3]] = initialChildTags[0][3];
_childEdgeParentIndex[cEdges[0]] = pFace;
_childEdgeParentIndex[cEdges[1]] = pFace;
_childEdgeParentIndex[cEdges[2]] = pFace;
_childEdgeParentIndex[cEdges[3]] = pFace;
} else {
bool childTooLarge = (cEdges.size() > 4);
for (int i = 0; i < cEdges.size(); ++i) {
if (IndexIsValid(cEdges[i])) {
_childEdgeTag[cEdges[i]] = initialChildTags[incomplete][childTooLarge ? 0 : i];
_childEdgeParentIndex[cEdges[i]] = pFace;
}
}
}
}
}
}
void
Refinement::populateEdgeParentFromParentEdges(ChildTag const initialChildTags[2][4]) {
if (_uniform) {
Index cEdge = getFirstChildEdgeFromEdges();
for (Index pEdge = 0; pEdge < _parent->getNumEdges(); ++pEdge, cEdge += 2) {
_childEdgeTag[cEdge + 0] = initialChildTags[0][0];
_childEdgeTag[cEdge + 1] = initialChildTags[0][1];
_childEdgeParentIndex[cEdge + 0] = pEdge;
_childEdgeParentIndex[cEdge + 1] = pEdge;
}
} else {
for (Index pEdge = 0; pEdge < _parent->getNumEdges(); ++pEdge) {
bool incomplete = !_parentEdgeTag[pEdge]._selected;
IndexArray cEdges = getEdgeChildEdges(pEdge);
if (!incomplete) {
_childEdgeTag[cEdges[0]] = initialChildTags[0][0];
_childEdgeTag[cEdges[1]] = initialChildTags[0][1];
_childEdgeParentIndex[cEdges[0]] = pEdge;
_childEdgeParentIndex[cEdges[1]] = pEdge;
} else {
for (int i = 0; i < 2; ++i) {
if (IndexIsValid(cEdges[i])) {
_childEdgeTag[cEdges[i]] = initialChildTags[incomplete][i];
_childEdgeParentIndex[cEdges[i]] = pEdge;
}
}
}
}
}
}
void
Refinement::populateVertexParentVectors(ChildTag const initialChildTags[2][4]) {
if (_uniform) {
_childVertexTag.resize(_child->getNumVertices(), initialChildTags[0][0]);
} else {
_childVertexTag.resize(_child->getNumVertices(), initialChildTags[1][0]);
}
_childVertexParentIndex.resize(_child->getNumVertices());
populateVertexParentFromParentFaces(initialChildTags);
populateVertexParentFromParentEdges(initialChildTags);
populateVertexParentFromParentVertices(initialChildTags);
}
void
Refinement::populateVertexParentFromParentFaces(ChildTag const initialChildTags[2][4]) {
if (getNumChildVerticesFromFaces() == 0) return;
if (_uniform) {
Index cVert = getFirstChildVertexFromFaces();
for (Index pFace = 0; pFace < _parent->getNumFaces(); ++pFace, ++cVert) {
// Child tag was initialized as the complete and only child when allocated
_childVertexParentIndex[cVert] = pFace;
}
} else {
ChildTag const & completeChildTag = initialChildTags[0][0];
for (Index pFace = 0; pFace < _parent->getNumFaces(); ++pFace) {
Index cVert = _faceChildVertIndex[pFace];
if (IndexIsValid(cVert)) {
// Child tag was initialized as incomplete -- reset if complete:
if (_parentFaceTag[pFace]._selected) {
_childVertexTag[cVert] = completeChildTag;
}
_childVertexParentIndex[cVert] = pFace;
}
}
}
}
void
Refinement::populateVertexParentFromParentEdges(ChildTag const initialChildTags[2][4]) {
if (_uniform) {
Index cVert = getFirstChildVertexFromEdges();
for (Index pEdge = 0; pEdge < _parent->getNumEdges(); ++pEdge, ++cVert) {
// Child tag was initialized as the complete and only child when allocated
_childVertexParentIndex[cVert] = pEdge;
}
} else {
ChildTag const & completeChildTag = initialChildTags[0][0];
for (Index pEdge = 0; pEdge < _parent->getNumEdges(); ++pEdge) {
Index cVert = _edgeChildVertIndex[pEdge];
if (IndexIsValid(cVert)) {
// Child tag was initialized as incomplete -- reset if complete:
if (_parentEdgeTag[pEdge]._selected) {
_childVertexTag[cVert] = completeChildTag;
}
_childVertexParentIndex[cVert] = pEdge;
}
}
}
}
void
Refinement::populateVertexParentFromParentVertices(ChildTag const initialChildTags[2][4]) {
if (_uniform) {
Index cVert = getFirstChildVertexFromVertices();
for (Index pVert = 0; pVert < _parent->getNumVertices(); ++pVert, ++cVert) {
// Child tag was initialized as the complete and only child when allocated
_childVertexParentIndex[cVert] = pVert;
}
} else {
ChildTag const & completeChildTag = initialChildTags[0][0];
for (Index pVert = 0; pVert < _parent->getNumVertices(); ++pVert) {
Index cVert = _vertChildVertIndex[pVert];
if (IndexIsValid(cVert)) {
// Child tag was initialized as incomplete but these should be complete:
if (_parentVertexTag[pVert]._selected) {
_childVertexTag[cVert] = completeChildTag;
}
_childVertexParentIndex[cVert] = pVert;
}
}
}
}
//
// Methods to propagate/initialize child component tags from their parent component:
//
void
Refinement::propagateComponentTags() {
populateFaceTagVectors();
populateEdgeTagVectors();
populateVertexTagVectors();
}
void
Refinement::populateFaceTagVectors() {
_child->_faceTags.resize(_child->getNumFaces());
populateFaceTagsFromParentFaces();
}
void
Refinement::populateFaceTagsFromParentFaces() {
//
// Tags for faces originating from faces are inherited from the parent face:
//
Index cFace = getFirstChildFaceFromFaces();
Index cFaceEnd = cFace + getNumChildFacesFromFaces();
for ( ; cFace < cFaceEnd; ++cFace) {
_child->_faceTags[cFace] = _parent->_faceTags[_childFaceParentIndex[cFace]];
}
}
void
Refinement::populateEdgeTagVectors() {
_child->_edgeTags.resize(_child->getNumEdges());
populateEdgeTagsFromParentFaces();
populateEdgeTagsFromParentEdges();
}
void
Refinement::populateEdgeTagsFromParentFaces() {
//
// Tags for edges originating from faces are all constant:
//
Level::ETag eTag;
eTag.clear();
Index cEdge = getFirstChildEdgeFromFaces();
Index cEdgeEnd = cEdge + getNumChildEdgesFromFaces();
for ( ; cEdge < cEdgeEnd; ++cEdge) {
_child->_edgeTags[cEdge] = eTag;
}
}
void
Refinement::populateEdgeTagsFromParentEdges() {
//
// Tags for edges originating from edges are inherited from the parent edge:
//
Index cEdge = getFirstChildEdgeFromEdges();
Index cEdgeEnd = cEdge + getNumChildEdgesFromEdges();
for ( ; cEdge < cEdgeEnd; ++cEdge) {
_child->_edgeTags[cEdge] = _parent->_edgeTags[_childEdgeParentIndex[cEdge]];
}
}
void
Refinement::populateVertexTagVectors() {
_child->_vertTags.resize(_child->getNumVertices());
populateVertexTagsFromParentFaces();
populateVertexTagsFromParentEdges();
populateVertexTagsFromParentVertices();
if (!_uniform) {
for (Index cVert = 0; cVert < _child->getNumVertices(); ++cVert) {
if (_childVertexTag[cVert]._incomplete) {
_child->_vertTags[cVert]._incomplete = true;
}
}
}
}
void
Refinement::populateVertexTagsFromParentFaces() {
//
// Similarly, tags for vertices originating from faces are all constant -- with the
// unfortunate exception of refining level 0, where the faces may be N-sided and so
// introduce new vertices that need to be tagged as extra-ordinary:
//
if (getNumChildVerticesFromFaces() == 0) return;
Level::VTag vTag;
vTag.clear();
vTag._rule = Sdc::Crease::RULE_SMOOTH;
Index cVert = getFirstChildVertexFromFaces();
Index cVertEnd = cVert + getNumChildVerticesFromFaces();
if (_parent->_depth > 0) {
for ( ; cVert < cVertEnd; ++cVert) {
_child->_vertTags[cVert] = vTag;
}
} else {
for ( ; cVert < cVertEnd; ++cVert) {
_child->_vertTags[cVert] = vTag;
if (_parent->getNumFaceVertices(_childVertexParentIndex[cVert]) != _regFaceSize) {
_child->_vertTags[cVert]._xordinary = true;
}
}
}
}
void
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];
vTag._nonManifold = pEdgeTag._nonManifold;
vTag._boundary = pEdgeTag._boundary;
vTag._semiSharpEdges = pEdgeTag._semiSharp;
vTag._rule = (Level::VTag::VTagSize)((pEdgeTag._semiSharp || pEdgeTag._infSharp)
? Sdc::Crease::RULE_CREASE : Sdc::Crease::RULE_SMOOTH);
_child->_vertTags[cVert] = vTag;
}
}
void
Refinement::populateVertexTagsFromParentVertices() {
//
// Tags for vertices originating from vertices are inherited from the parent vertex:
//
Index cVert = getFirstChildVertexFromVertices();
Index cVertEnd = cVert + getNumChildVerticesFromVertices();
for ( ; cVert < cVertEnd; ++cVert) {
_child->_vertTags[cVert] = _parent->_vertTags[_childVertexParentIndex[cVert]];
}
}
//
// Methods to subdivide the topology:
//
// The main method to subdivide topology is fairly simple -- given a set of relations
// to populate it simply tests and populates each relation separately. The method for
// each relation is responsible for appropriate allocation and initialization of all
// data involved, and these are virtual -- provided by a quad- or tri-split subclass.
//
void
Refinement::subdivideTopology(Relations const& applyTo) {
if (applyTo._faceVertices) {
populateFaceVertexRelation();
}
if (applyTo._faceEdges) {
populateFaceEdgeRelation();
}
if (applyTo._edgeVertices) {
populateEdgeVertexRelation();
}
if (applyTo._edgeFaces) {
populateEdgeFaceRelation();
}
if (applyTo._vertexFaces) {
populateVertexFaceRelation();
}
if (applyTo._vertexEdges) {
populateVertexEdgeRelation();
}
//
// Additional members of the child Level not specific to any relation...
// - note in the case of max-valence, the child's max-valence may be less
// than the parent if that maximal parent vertex was not included in the sparse
// refinement (possible when sparse refinement is more general).
// - it may also be more if the base level was fairly trivial, i.e. less
// than the regular valence.
// - NOTE that when/if we support N-gons for tri-splitting, that the valence
// of edge-vertices introduced on the N-gon may be 7 rather than 6, while N may
// be less than both.
//
// In general, we need a better way to deal with max-valence. The fact that
// each topology relation is independent/optional complicates the issue of
// where to keep track of it...
//
int maxRegularValence = (_splitType == Sdc::SPLIT_TO_QUADS) ? 4 : 6;
_child->_maxValence = std::max(_parent->_maxValence, maxRegularValence);
}
//
// Methods to subdivide sharpness values:
//
void
Refinement::subdivideSharpnessValues() {
//
// Subdividing edge and vertex sharpness values are independent, but in order
// to maintain proper classification/tagging of components as semi-sharp, both
// must be computed and the neighborhood inspected to properly update the
// status.
//
// It is possible to clear the semi-sharp status when propagating the tags and
// to reset it (potentially multiple times) when updating the sharpness values.
// The vertex subdivision Rule is also affected by this, which complicates the
// 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();
}
void
Refinement::subdivideEdgeSharpness() {
Sdc::Crease creasing(_options);
_child->_edgeSharpness.clear();
_child->_edgeSharpness.resize(_child->getNumEdges(), Sdc::Crease::SHARPNESS_SMOOTH);
//
// Edge sharpness is passed to child-edges using the parent edge and the
// parent vertex for which the child corresponds. Child-edges are created
// from both parent faces and parent edges, but those child-edges created
// from a parent face should be within the face's interior and so smooth
// (and so previously initialized).
//
// The presence/validity of each parent edges child vert indicates one or
// more child edges.
//
// NOTE -- It is also useful at this time to classify the child vert of
// this edge based on the creasing information here, particularly when a
// non-trivial creasing method like Chaikin is used. This is not being
// done now but is worth considering...
//
float * pVertEdgeSharpness = 0;
if (!creasing.IsUniform()) {
pVertEdgeSharpness = (float *)alloca(_parent->getMaxValence() * sizeof(float));
}
Index cEdge = getFirstChildEdgeFromEdges();
Index cEdgeEnd = cEdge + getNumChildEdgesFromEdges();
for ( ; cEdge < cEdgeEnd; ++cEdge) {
float& cSharpness = _child->_edgeSharpness[cEdge];
Level::ETag& cEdgeTag = _child->_edgeTags[cEdge];
if (cEdgeTag._infSharp) {
cSharpness = Sdc::Crease::SHARPNESS_INFINITE;
} else if (cEdgeTag._semiSharp) {
Index pEdge = _childEdgeParentIndex[cEdge];
float pSharpness = _parent->_edgeSharpness[pEdge];
if (creasing.IsUniform()) {
cSharpness = creasing.SubdivideUniformSharpness(pSharpness);
} else {
ConstIndexArray pEdgeVerts = _parent->getEdgeVertices(pEdge);
Index pVert = pEdgeVerts[_childEdgeTag[cEdge]._indexInParent];
ConstIndexArray pVertEdges = _parent->getVertexEdges(pVert);
for (int i = 0; i < pVertEdges.size(); ++i) {
pVertEdgeSharpness[i] = _parent->_edgeSharpness[pVertEdges[i]];
}
cSharpness = creasing.SubdivideEdgeSharpnessAtVertex(pSharpness, pVertEdges.size(),
pVertEdgeSharpness);
}
if (not Sdc::Crease::IsSharp(cSharpness)) {
cEdgeTag._semiSharp = false;
}
}
}
}
void
Refinement::subdivideVertexSharpness() {
Sdc::Crease creasing(_options);
_child->_vertSharpness.clear();
_child->_vertSharpness.resize(_child->getNumVertices(), Sdc::Crease::SHARPNESS_SMOOTH);
//
// All child-verts originating from faces or edges are initialized as smooth
// above. Only those originating from vertices require "subdivided" values:
//
// Only deal with the subrange of vertices originating from vertices:
Index cVertBegin = getFirstChildVertexFromVertices();
Index cVertEnd = cVertBegin + getNumChildVerticesFromVertices();
for (Index cVert = cVertBegin; cVert < cVertEnd; ++cVert) {
float& cSharpness = _child->_vertSharpness[cVert];
Level::VTag& cVertTag = _child->_vertTags[cVert];
if (cVertTag._infSharp) {
cSharpness = Sdc::Crease::SHARPNESS_INFINITE;
} else if (cVertTag._semiSharp) {
Index pVert = _childVertexParentIndex[cVert];
float pSharpness = _parent->_vertSharpness[pVert];
cSharpness = creasing.SubdivideVertexSharpness(pSharpness);
if (not Sdc::Crease::IsSharp(cSharpness)) {
cVertTag._semiSharp = false;
}
}
}
}
void
Refinement::reclassifySemisharpVertices() {
typedef Level::VTag::VTagSize VTagSize;
Sdc::Crease creasing(_options);
//
// Inspect all vertices derived from edges -- for those whose parent edges were semisharp,
// reset the semisharp tag and the associated Rule according to the sharpness pair for the
// subdivided edges (note this may be better handled when the edge sharpness is computed):
//
Index vertFromEdgeBegin = getFirstChildVertexFromEdges();
Index vertFromEdgeEnd = vertFromEdgeBegin + getNumChildVerticesFromEdges();
for (Index cVert = vertFromEdgeBegin; cVert < vertFromEdgeEnd; ++cVert) {
Level::VTag& cVertTag = _child->_vertTags[cVert];
if (!cVertTag._semiSharpEdges) continue;
Index pEdge = _childVertexParentIndex[cVert];
ConstIndexArray cEdges = getEdgeChildEdges(pEdge);
if (_childVertexTag[cVert]._incomplete) {
// One child edge likely missing -- assume Crease if remaining edge semi-sharp:
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._semiSharpEdges = (sharpEdgeCount > 0);
cVertTag._rule = (VTagSize)(creasing.DetermineVertexVertexRule(0.0, sharpEdgeCount));
}
}
//
// Inspect all vertices derived from vertices -- for those whose parent vertices were
// 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
// here is whether the local topology of child edges exists -- it may have been pruned
// from the last level to reduce memory. If so, we use the parent to identify the
// child edges.
//
// In both cases, we count the number of sharp and semisharp child edges incident the
// child vertex and adjust the "semisharp" and "rule" tags accordingly.
//
Index vertFromVertBegin = getFirstChildVertexFromVertices();
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];
bool sharpVertexDecayed = pVertTag._semiSharp && !cVertTag._semiSharp;
if (pVertTag._semiSharpEdges || sharpVertexDecayed) {
int infSharpEdgeCount = 0;
int semiSharpEdgeCount = 0;
bool cVertEdgesPresent = (_child->getNumVertexEdgesTotal() > 0);
if (cVertEdgesPresent) {
ConstIndexArray cEdges = _child->getVertexEdges(cVert);
for (int i = 0; i < cEdges.size(); ++i) {
Level::ETag cEdgeTag = _child->_edgeTags[cEdges[i]];
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;
}
}
cVertTag._semiSharpEdges = (semiSharpEdgeCount > 0);
if (!cVertTag._semiSharp && !cVertTag._infSharp) {
cVertTag._rule = (VTagSize)(creasing.DetermineVertexVertexRule(0.0,
infSharpEdgeCount + semiSharpEdgeCount));
}
}
}
}
//
// Methods to subdivide face-varying channels:
//
void
Refinement::subdivideFVarChannels() {
assert(_child->_fvarChannels.size() == 0);
assert(this->_fvarChannels.size() == 0);
int channelCount = _parent->getNumFVarChannels();
for (int channel = 0; channel < channelCount; ++channel) {
FVarLevel* parentFVar = _parent->_fvarChannels[channel];
FVarLevel* childFVar = new FVarLevel(*_child);
FVarRefinement* refineFVar = new FVarRefinement(*this, *parentFVar, *childFVar);
refineFVar->applyRefinement();
_child->_fvarChannels.push_back(childFVar);
this->_fvarChannels.push_back(refineFVar);
}
}
//
// Methods to inherit properties between refinements in a hierarchy:
//
void
Refinement::propagateBaseFace(Refinement const * grandParent) {
_childFaceBaseFaceIndex.resize(_child->_faceCount);
if (grandParent == 0) {
_childFaceBaseFaceIndex = _childFaceParentIndex;
} else {
IndexVector & childBaseFace = _childFaceBaseFaceIndex;
IndexVector const & parentBaseFace = grandParent->_childFaceBaseFaceIndex;
for (Index cFace = 0; cFace < _child->_faceCount; ++cFace) {
childBaseFace[cFace] = parentBaseFace[_childFaceParentIndex[cFace]];
}
}
}
//
// Marking of sparse child components -- including those selected and those neighboring...
//
// For schemes requiring neighboring support, this is the equivalent of the "guarantee
// neighbors" in Hbr -- it ensures that all components required to define the limit of
// those "selected" are also generated in the refinement.
//
// The difference with Hbr is that we do this in a single pass for all components once
// "selection" of components of interest has been completed.
//
// Considering two approaches:
// 1) By Vertex neighborhoods:
// - for each base vertex
// - for each incident face
// - test and mark components for its child face
// or
// 2) By Edge and Face contents:
// - for each base edge
// - test and mark local components
// - for each base face
// - test and mark local components
//
// Given a typical quad mesh with N verts, N faces and 2*N edges, determine which is more
// efficient...
//
// Going with (2) initially for simplicity -- certain aspects of (1) are awkward, i.e. the
// identification of child-edges to be marked (trivial in (2). We are also guaranteed with
// (2) that we only visit each component once, i.e. each edge and each face.
//
// Revising the above assessment... (2) has gotten WAY more complicated once the ability to
// select child faces is provided. Given that feature is important to Manuel for support
// of the FarStencilTables we have to assume it will be needed. So we'll try (1) out as it
// will be simpler to get it correct -- we can work on improving performance later.
//
// Complexity added by child component selection:
// - the child vertex of the component can now be selected as part of a child face or
// edge, and so the parent face or edge is not fully selected. So we've had to add another
// bit to the marking masks to indicate when a parent component is "fully selected".
// - selecting a child face creates the situation where child edges of parent edges do
// not have any selected vertex at their ends -- both can be neighboring. This complicated
// the marking of neighboring child edges, which was otherwise trivial -- if any end vertex
// of a child edge (of a parent edge) was selected, the child edge was at least neighboring.
//
// Final note on the marking technique:
// There are currently two values to the marking of child components, which are no
// longer that useful. It is now sufficient, and not likely to be necessary, to distinguish
// between what was selected or added to support it. Ultimately that will be determined by
// inspecting the selected flag on the parent component once the child-to-parent map is in
// place.
//
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
Refinement::markSparseChildComponentIndices() {
//
// There is an explicit ordering here as the work done for vertices is a subset
// of what is required for edges, which in turn is a subset of what is required
// for faces. This ordering and their related implementations tries to avoid
// doing redundant work and accomplishing everything necessary in a single
// iteration through each component type.
//
markSparseVertexChildren();
markSparseEdgeChildren();
markSparseFaceChildren();
}
void
Refinement::markSparseVertexChildren() {
assert(_parentVertexTag.size() > 0);
//
// For each parent vertex:
// - mark the descending child vertex for each selected vertex
//
for (Index pVert = 0; pVert < parent().getNumVertices(); ++pVert) {
if (_parentVertexTag[pVert]._selected) {
markSparseIndexSelected(_vertChildVertIndex[pVert]);
}
}
}
void
Refinement::markSparseEdgeChildren() {
assert(_parentEdgeTag.size() > 0);
//
// For each parent edge:
// - mark the descending child edges and vertex for each selected edge
// - test each end vertex of unselected edges to see if selected:
// - mark both the child edge and the middle child vertex if so
// - set transitional bit for all edges based on selection of incident faces
//
// Note that no edges have been marked "fully selected" -- only their vertices have
// been marked and marking of their child edges deferred to visiting each edge only
// once here.
//
for (Index pEdge = 0; pEdge < parent().getNumEdges(); ++pEdge) {
IndexArray eChildEdges = getEdgeChildEdges(pEdge);
ConstIndexArray eVerts = parent().getEdgeVertices(pEdge);
SparseTag& pEdgeTag = _parentEdgeTag[pEdge];
if (pEdgeTag._selected) {
markSparseIndexSelected(eChildEdges[0]);
markSparseIndexSelected(eChildEdges[1]);
markSparseIndexSelected(_edgeChildVertIndex[pEdge]);
} else {
if (_parentVertexTag[eVerts[0]]._selected) {
markSparseIndexNeighbor(eChildEdges[0]);
markSparseIndexNeighbor(_edgeChildVertIndex[pEdge]);
}
if (_parentVertexTag[eVerts[1]]._selected) {
markSparseIndexNeighbor(eChildEdges[1]);
markSparseIndexNeighbor(_edgeChildVertIndex[pEdge]);
}
}
//
// TAG the parent edges as "transitional" here if only one was selected (or in
// the more general non-manifold case, they are not all selected the same way).
// We use the transitional tags on the edges to TAG the parent face below.
//
// Note -- this is best done now rather than as a post-process as we have more
// explicit information about the selected components. Unless we also tag the
// parent faces as selected, we can't easily tell from the child-faces of the
// edge's incident faces which were generated by selection or neighboring...
//
ConstIndexArray eFaces = parent().getEdgeFaces(pEdge);
if (eFaces.size() == 2) {
pEdgeTag._transitional = (_parentFaceTag[eFaces[0]]._selected !=
_parentFaceTag[eFaces[1]]._selected);
} else if (eFaces.size() < 2) {
pEdgeTag._transitional = false;
} else {
bool isFace0Selected = _parentFaceTag[eFaces[0]]._selected;
pEdgeTag._transitional = false;
for (int i = 1; i < eFaces.size(); ++i) {
if (_parentFaceTag[eFaces[i]]._selected != isFace0Selected) {
pEdgeTag._transitional = true;
break;
}
}
}
}
}
} // end namespace Vtr
} // end namespace OPENSUBDIV_VERSION
} // end namespace OpenSubdiv