Fixed face-varying cases where the sharpness of values are inter-dependent:

- added ValueTag indicating sharpness dependency on another value
    - updated base level tagging to identify dependent semi-sharp values
    - updated refinement to consider dependency when reassessing semi-sharpness
    - updated interpolation to use dependent fractional weight when necessary
This commit is contained in:
barfowl 2014-10-24 16:15:22 -07:00
parent 5f810a0f8e
commit 69e6da8fab
4 changed files with 131 additions and 87 deletions

View File

@ -1210,8 +1210,15 @@ TopologyRefiner::faceVaryingInterpolateChildVertsFromVerts(
float vWeight = 0.75f;
float eWeight = 0.125f;
if (parentFVar.isValueSemiSharp(parentFVar.getVertexValueIndex(vert, pSibling))) {
float wCorner = refineFVar.getFractionalWeight(vert, pSibling, cVert, cSibling);
int pVertValueIndex = parentFVar.getVertexValueIndex(vert, pSibling);
if (parentFVar.isValueSemiSharp(pVertValueIndex)) {
//
// If made sharp because of the other sibling, use the fractional weight
// from that other sibling (should only occur when there are 2):
//
float wCorner = parentFVar.isValueDepSharp(pVertValueIndex)
? refineFVar.getFractionalWeight(vert, !pSibling, cVert, !cSibling)
: refineFVar.getFractionalWeight(vert, pSibling, cVert, cSibling);
float wCrease = 1.0f - wCorner;
vWeight = wCrease * 0.75f + wCorner;

View File

@ -49,7 +49,11 @@ namespace Vtr {
// Simple (for now) constructor and destructor:
//
FVarLevel::FVarLevel(Level const& level) :
_level(level), _isLinear(false), _hasSmoothBoundaries(false), _valueCount(0) {
_level(level),
_isLinear(false),
_hasSmoothBoundaries(false),
_hasDependentSharpness(false),
_valueCount(0) {
}
FVarLevel::~FVarLevel() {
@ -108,7 +112,8 @@ FVarLevel::completeTopologyFromFaceValues() {
//
// Given the growing number of options and behaviors to support, this is likely going
// to get another pass. It may be worth identifying the behavior for each "feature",
// i.e. determine smooth or sharp for corners, creases and darts...
// i.e. determine smooth or sharp for corners, creases and darts, but the fact that
// the rule for one value may be dependent on that of another complicates this.
//
using Sdc::Options;
@ -120,35 +125,17 @@ FVarLevel::completeTopologyFromFaceValues() {
_hasSmoothBoundaries = (fvarOptions != Options::FVAR_LINEAR_ALL) &&
(fvarOptions != Options::FVAR_LINEAR_BOUNDARIES);
_hasDependentSharpness = (fvarOptions == Options::FVAR_LINEAR_CORNERS_PLUS1) ||
(fvarOptions == Options::FVAR_LINEAR_CORNERS_PLUS2);
bool geomCornersAreSmooth = (geomOptions != Options::VVAR_BOUNDARY_EDGE_AND_CORNER);
bool fvarCornersAreSharp = (fvarOptions != Options::FVAR_LINEAR_NONE);
bool makeCornersSharp = geomCornersAreSmooth && fvarCornersAreSharp;
//
// Two "options" conditionally sharpen all values for a vertex depending on the collective topology
// around the vertex rather than of the topology of the value itself within its disjoint region.
//
// Historically Hbr will sharpen all values if there are more than 3 values associated with a vertex
// (making at least 3 discts or boundary edges) while the option to sharpen corners is enabled. This
// is still being done for now but is not desirable in some cases and may become optional (consider
// two adjacent UV sets with smooth UV boundaries, then splitting one of them in two -- the other
// UV set will have its boundary sharpened at the vertex where the other was split).
//
// The "propogate corners" associated with the smooth boundary and sharp corners option will sharpen
// all values if any one is a corner. This preserves the sharpness of a concave corner in regular
// areas where one face is made a corner. Since the above option has historically sharpened all
// values in cases where there are more than 2 values at a vertex, its unclear what the intent of
// "propagate corners" is if more than 2 are present.
//
bool cornersPlus1 = (fvarOptions == Options::FVAR_LINEAR_CORNERS_PLUS1);
bool cornersPlus2 = (fvarOptions == Options::FVAR_LINEAR_CORNERS_PLUS2);
bool sharpenBothIfOneCorner = (fvarOptions == Options::FVAR_LINEAR_CORNERS_PLUS2);
bool considerEntireVertex = cornersPlus1 || cornersPlus2;
bool sharpenAllIfMoreThan2 = considerEntireVertex;
bool sharpenAllIfAnyCorner = cornersPlus2;
bool sharpenDarts = cornersPlus2 || !_hasSmoothBoundaries;
bool sharpenDarts = sharpenBothIfOneCorner || !_hasSmoothBoundaries;
//
// Its awkward and potentially inefficient to try and accomplish everything in one
@ -324,6 +311,9 @@ FVarLevel::completeTopologyFromFaceValues() {
ValueTag valueTagSemiSharp = valueTagMismatch;
valueTagSemiSharp._semiSharp = true;
ValueTag valueTagDepSharp = valueTagSemiSharp;
valueTagDepSharp._depSharp = true;
for (int vIndex = 0; vIndex < _level.getNumVertices(); ++vIndex) {
IndexArray const vFaces = _level.getVertexFaces(vIndex);
LocalIndexArray const vInFace = _level.getVertexFaceLocalIndices(vIndex);
@ -371,7 +361,7 @@ FVarLevel::completeTopologyFromFaceValues() {
bool allCornersAreSharp = !_hasSmoothBoundaries ||
Sdc::Crease::IsInfinite(vSharpness) ||
(sharpenAllIfMoreThan2 && (vValueCount > 2)) ||
(_hasDependentSharpness && (vValueCount > 2)) ||
(sharpenDarts && (vValueCount == 1) && !vIsBoundary) ||
_level._vertTags[vIndex]._nonManifold;
if (allCornersAreSharp) {
@ -379,10 +369,8 @@ FVarLevel::completeTopologyFromFaceValues() {
}
//
// Values may be a mix of sharp corners and smooth boundaries...
//
// Gather information about the "span" of faces for each value. Use the results
// in one last chance for all values to be made sharp via interpolation options...
// Values may be a mix of sharp corners and smooth boundaries -- start by
// gathering information about the "span" of faces for each value:
//
assert(sizeof(ValueSpan) <= sizeof(int));
ValueSpan * vValueSpans = (ValueSpan *) indexBuffer;
@ -390,43 +378,58 @@ FVarLevel::completeTopologyFromFaceValues() {
gatherValueSpans(vIndex, vValueSpans);
bool testForSmoothBoundaries = true;
if (sharpenAllIfAnyCorner) {
for (int i = 0; i < vValueCount; ++i) {
if (vValueSpans[i]._size == 1) {
testForSmoothBoundaries = false;
break;
}
//
// Spans are identified as sharp (disjoint) or smooth based on their own local
// topology, but depending on the specified options, the sharpness of one span
// may be dependent on the sharpness of another. Mark both as infinitely sharp
// where possible to avoid re-assessing this dependency as sharpness is reduced
// during refinement.
//
allCornersAreSharp = false;
bool hasDependentValuesToSharpen = false;
if (_hasDependentSharpness && (vValueCount == 2)) {
// Detect interior inf-sharp (or discts) edge:
allCornersAreSharp = vValueSpans[0]._disjoint || vValueSpans[1]._disjoint;
// Detect a sharp corner, making both sharp:
if (sharpenBothIfOneCorner) {
allCornersAreSharp |= (vValueSpans[0]._size == 1) || (vValueSpans[1]._size == 1);
}
// If only one semi-sharp, need to mark the other as dependent on it:
hasDependentValuesToSharpen = vValueSpans[0]._semiSharp != vValueSpans[1]._semiSharp;
}
if (allCornersAreSharp) {
continue;
}
//
// Test each vertex value to determine if it is a smooth boundary (crease) -- if not
// disjoint and not a sharp corner, tag as a smooth boundary and identify its ends.
// Note if semi-sharp, and do not tag it as a crease now -- the refinement will tag
// it once all sharpness has decayed to zero:
// Inspect each vertex value to determine if it is a smooth boundary (crease) and tag
// it accordingly. If not semi-sharp, be sure to consider those values sharpened by
// the topology of other values.
//
if (testForSmoothBoundaries) {
for (int i = 0; i < vValueCount; ++i) {
ValueSpan& vSpan = vValueSpans[i];
for (int i = 0; i < vValueCount; ++i) {
ValueSpan& vSpan = vValueSpans[i];
if (!vSpan._disjoint && ((vSpan._size > 1) || !fvarCornersAreSharp)) {
Index valueIndex = (i == 0) ? vIndex : (vSiblingOffset + i - 1);
if (!vSpan._disjoint && ((vSpan._size > 1) || !fvarCornersAreSharp)) {
Index valueIndex = (i == 0) ? vIndex : (vSiblingOffset + i - 1);
if ((vSpan._semiSharp > 0) || (vSharpness > 0)) {
_vertValueTags[valueIndex] = valueTagSemiSharp;
} else {
_vertValueTags[valueIndex] = valueTagCrease;
}
if ((vSpan._semiSharp > 0) || Sdc::Crease::IsSharp(vSharpness)) {
_vertValueTags[valueIndex] = valueTagSemiSharp;
} else if (hasDependentValuesToSharpen) {
_vertValueTags[valueIndex] = valueTagDepSharp;
} else {
_vertValueTags[valueIndex] = valueTagCrease;
}
LocalIndex * endFaces = &_vertValueCreaseEnds[2 * valueIndex];
LocalIndex * endFaces = &_vertValueCreaseEnds[2 * valueIndex];
endFaces[0] = vSpan._start;
if ((i == 0) && (vSpan._start != 0)) {
endFaces[1] = (LocalIndex) (vSpan._start + vSpan._size - 1 - vFaces.size());
} else {
endFaces[1] = vSpan._start + vSpan._size - 1;
}
endFaces[0] = vSpan._start;
if ((i == 0) && (vSpan._start != 0)) {
endFaces[1] = (LocalIndex) (vSpan._start + vSpan._size - 1 - vFaces.size());
} else {
endFaces[1] = vSpan._start + vSpan._size - 1;
}
}
}

View File

@ -118,6 +118,7 @@ public:
ValueTagSize _mismatch : 1; // local FVar topology does not match
ValueTagSize _crease : 1; // value is a crease, otherwise a corner
ValueTagSize _semiSharp : 1; // value is a corner decaying to crease
ValueTagSize _depSharp : 1; // value a corner by dependency on another
};
public:
@ -155,6 +156,7 @@ public:
bool isValueSemiSharp(Index valueIndex) const { return _vertValueTags[valueIndex]._semiSharp; }
bool isValueInfSharp(Index valueIndex) const { return !_vertValueTags[valueIndex]._semiSharp &&
!_vertValueTags[valueIndex]._crease; }
bool isValueDepSharp(Index valueIndex) const { return _vertValueTags[valueIndex]._depSharp; }
// Higher-level topological queries, i.e. values in a neighborhood:
@ -201,6 +203,7 @@ public:
bool _isLinear;
bool _hasSmoothBoundaries;
bool _hasDependentSharpness;
int _valueCount;
//

View File

@ -77,9 +77,10 @@ FVarRefinement::applyRefinement() {
//
// Transfer basic properties from the parent to child level:
//
_child->_options = _parent->_options;
_child->_isLinear = _parent->_isLinear;
_child->_hasSmoothBoundaries = _parent->_hasSmoothBoundaries;
_child->_options = _parent->_options;
_child->_isLinear = _parent->_isLinear;
_child->_hasSmoothBoundaries = _parent->_hasSmoothBoundaries;
_child->_hasDependentSharpness = _parent->_hasDependentSharpness;
//
// It's difficult to know immediately how many child values arise from the
@ -495,6 +496,8 @@ FVarRefinement::reclassifySemisharpValues() {
// their parent values -- we will be able to clear it in many simple cases but
// ultimately will need to inspect each value:
//
bool hasDependentSharpness = _parent->_hasDependentSharpness;
FVarLevel::ValueTag valTagCrease;
valTagCrease.clear();
valTagCrease._mismatch = true;
@ -521,41 +524,69 @@ FVarRefinement::reclassifySemisharpValues() {
//
// We are left with some or no semi-sharp edges in the child vertex. If none
// left the child-vertex will no longer be semi-sharp and we can just clear
// those values marked as semi-sharp. Otherwise, its simplest to assume all
// semi-sharp edges have decayed (so clearing them again) and using the
// remaining semi-sharp edges to reset those values that still are.
//
// So convert all semi-sharp tags to creases and reset those that remain if
// the child vertex is still tagged as semi-sharp:
// those values marked as semi-sharp and continue:
//
int vSiblingOffset = _child->_vertSiblingOffsets[cVert];
int vSiblingCount = _child->_vertSiblingCounts[cVert];
int vValueCount = 1 + vSiblingCount;
if (!_refinement._child->_vertTags[cVert]._semiSharp) {
for (int j = 0; j < vValueCount; ++j) {
int vValueIndex = (j == 0) ? cVert : (vSiblingOffset + j - 1);
if (_child->isValueSemiSharp(vValueIndex)) {
_child->_vertValueTags[vValueIndex] = valTagCrease;
}
}
continue;
}
//
// There are some semi-sharp edges left. For those values tagged as semi-sharp,
// see if they are still semi-sharp and clear those that are not:
//
IndexArray const cVertEdges = _refinement._child->getVertexEdges(cVert);
for (int j = 0; j < vValueCount; ++j) {
int vValueIndex = (j == 0) ? cVert : (vSiblingOffset + j - 1);
if (_child->isValueSemiSharp(vValueIndex)) {
_child->_vertValueTags[vValueIndex] = valTagCrease;
FVarLevel::ValueTag & cValueTag = _child->_vertValueTags[vValueIndex];
if (cValueTag._semiSharp && !cValueTag._depSharp) {
LocalIndex * vCreaseEnds = &_child->_vertValueCreaseEnds[2 * vValueIndex];
bool isStillSemiSharp = false;
if (vCreaseEnds[1] > vCreaseEnds[0]) {
for (int k = vCreaseEnds[0] + 1; !isStillSemiSharp && (k <= vCreaseEnds[1]); ++k) {
isStillSemiSharp = _refinement._child->_edgeTags[cVertEdges[k]]._semiSharp;
}
} else if (vCreaseEnds[0] > vCreaseEnds[1]) {
for (int k = vCreaseEnds[0] + 1; !isStillSemiSharp && (k < cVertEdges.size()); ++k) {
isStillSemiSharp = _refinement._child->_edgeTags[cVertEdges[k]]._semiSharp;
}
for (int k = 0; !isStillSemiSharp && (k <= vCreaseEnds[1]); ++k) {
isStillSemiSharp = _refinement._child->_edgeTags[cVertEdges[k]]._semiSharp;
}
}
if (!isStillSemiSharp) {
cValueTag = valTagCrease;
}
}
}
if (!_refinement._child->_vertTags[cVert]._semiSharp) continue;
//
// Identify the remaining semi-sharp edges and the corresponding values that
// should be retained as semi-sharp:
// Now account for "dependent sharpness" (only matters when we have two values) --
// if one was dependent/sharpened based on the other being sharp, clear the dependency
// tag if it is no longer sharp:
//
SiblingArray const vFaceSiblings = _child->getVertexFaceSiblings(cVert);
if ((vValueCount == 2) && hasDependentSharpness) {
FVarLevel::ValueTag & v0Tag = _child->_vertValueTags[cVert];
FVarLevel::ValueTag & v1Tag = _child->_vertValueTags[vSiblingOffset];
IndexArray const cVertEdges = _refinement._child->getVertexEdges(cVert);
for (int j = 0; j < cVertEdges.size(); ++j) {
if (_refinement._child->_edgeTags[cVertEdges[j]]._semiSharp) {
int jPrev = j ? (j - 1) : (vFaceSiblings.size() - 1);
if (vFaceSiblings[jPrev] == vFaceSiblings[j]) {
int vSibling = vFaceSiblings[j];
int vValueIndex = (vSibling == 0) ? cVert : (vSiblingOffset + vSibling - 1);
_child->_vertValueTags[vValueIndex] = valTagSemiSharp;
}
if (v0Tag._depSharp && !v1Tag._semiSharp) {
v0Tag._depSharp = false;
} else if (v1Tag._depSharp && !v0Tag._semiSharp) {
v1Tag._depSharp = false;
}
}
}
@ -563,8 +594,8 @@ FVarRefinement::reclassifySemisharpValues() {
float
FVarRefinement::getFractionalWeight(Index pVert, Sibling pSibling,
Index cVert, Sibling /* cSibling */) const
{
Index cVert, Sibling /* cSibling */) const {
FVarLevel const& parentFVar = *_parent;
Level const& parent = *_refinement._parent;
Level const& child = *_refinement._child;