Major refactor of the construction of Far::PatchTable:

- new PatchTableBuilder class now implements PatchTableFactory::Create()
        - population of tables now independent of scheme or patch type
        - nested LocalPointHelper handles local point sharing and stencils
    - new PatchBuilder class encapsulates patch queries and conversions:
        - provides patch types associated with schemes and client options
        - handles all topological queries about patches in the base class
        - subclasses for the three subdivision schemes to support conversions
        - conversions encapsulated in new SparseMatrix class for re-use
    - removed Far end-cap factory classes and Far::GregoryBasis
    - extended adaptive refinement to support Bilinear scheme (not enabled)
    - extended Vtr::StackBuffer to avoid compiler inefficiencies
This commit is contained in:
barry 2018-05-08 17:24:14 -07:00
parent 171629fbd8
commit 5e8e123d73
26 changed files with 5490 additions and 3397 deletions

View File

@ -25,12 +25,12 @@
#-------------------------------------------------------------------------------
# source & headers
set(SOURCE_FILES
bilinearPatchBuilder.cpp
catmarkPatchBuilder.cpp
error.cpp
endCapBSplineBasisPatchFactory.cpp
endCapGregoryBasisPatchFactory.cpp
endCapLegacyGregoryPatchFactory.cpp
gregoryBasis.cpp
loopPatchBuilder.cpp
patchBasis.cpp
patchBuilder.cpp
patchDescriptor.cpp
patchMap.cpp
patchTable.cpp
@ -45,11 +45,12 @@ set(SOURCE_FILES
)
set(PRIVATE_HEADER_FILES
gregoryBasis.h
endCapBSplineBasisPatchFactory.h
endCapGregoryBasisPatchFactory.h
endCapLegacyGregoryPatchFactory.h
bilinearPatchBuilder.h
catmarkPatchBuilder.h
loopPatchBuilder.h
patchBasis.h
patchBuilder.h
sparseMatrix.h
stencilBuilder.h
)

View File

@ -0,0 +1,93 @@
//
// Copyright 2018 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 "../far/bilinearPatchBuilder.h"
#include <cassert>
#include <cstdio>
namespace OpenSubdiv {
namespace OPENSUBDIV_VERSION {
using Vtr::internal::Level;
using Vtr::internal::FVarLevel;
using Vtr::internal::Refinement;
namespace Far {
namespace {
//
// The patch type associated with each basis for Bilinear -- quickly indexed
// from an array. The patch type here is essentially the quad form of each
// basis.
//
PatchDescriptor::Type patchTypeFromBasisArray[] = {
PatchDescriptor::NON_PATCH, // undefined
PatchDescriptor::QUADS, // regular
PatchDescriptor::GREGORY_BASIS, // Gregory
PatchDescriptor::QUADS, // linear
PatchDescriptor::NON_PATCH }; // Bezier -- for future use
};
BilinearPatchBuilder::BilinearPatchBuilder(
TopologyRefiner const& refiner, Options const& options) :
PatchBuilder(refiner, options) {
_regPatchType = patchTypeFromBasisArray[_options.regBasisType];
_irregPatchType = (_options.irregBasisType == BASIS_UNSPECIFIED)
? _regPatchType
: patchTypeFromBasisArray[_options.irregBasisType];
_nativePatchType = PatchDescriptor::QUADS;
_linearPatchType = PatchDescriptor::QUADS;
}
BilinearPatchBuilder::~BilinearPatchBuilder() {
}
PatchDescriptor::Type
BilinearPatchBuilder::patchTypeFromBasis(BasisType basis) const {
return patchTypeFromBasisArray[(int)basis];
}
int
BilinearPatchBuilder::convertToPatchType(SourcePatch const & sourcePatch,
PatchDescriptor::Type patchType,
SparseMatrix<float> & matrix) const {
assert("Conversion from Bilinear patches to other bases not yet supported" == 0);
// For suppressing warnings until implemented...
if (sourcePatch.GetNumSourcePoints() == 0) return -1;
if (patchType == PatchDescriptor::NON_PATCH) return -1;
if (matrix.GetNumRows() <= 0) return -1;
return -1;
}
} // end namespace Far
} // end namespace OPENSUBDIV_VERSION
} // end namespace OpenSubdiv

View File

@ -0,0 +1,65 @@
//
// Copyright 2017 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.
//
#ifndef OPENSUBDIV3_FAR_BILINEAR_PATCH_BUILDER_H
#define OPENSUBDIV3_FAR_BILINEAR_PATCH_BUILDER_H
#include "../version.h"
#include "../far/patchBuilder.h"
namespace OpenSubdiv {
namespace OPENSUBDIV_VERSION {
namespace Far {
//
// BilinearPatchBuilder
//
// Declaration of PatchBuilder subclass supporting Sdc::SCHEME_BILINEAR.
// Required virtual methods are included, along with any customizations
// local to their implementation.
//
class BilinearPatchBuilder : public PatchBuilder {
public:
BilinearPatchBuilder(TopologyRefiner const& refiner, Options const& options);
virtual ~BilinearPatchBuilder();
protected:
virtual PatchDescriptor::Type patchTypeFromBasis(BasisType basis) const;
virtual int convertToPatchType(SourcePatch const & sourcePatch,
PatchDescriptor::Type patchType,
SparseMatrix<float> & matrix) const;
};
} // end namespace Far
} // end namespace OPENSUBDIV_VERSION
using namespace OPENSUBDIV_VERSION;
} // end namespace OpenSubdiv
#endif /* OPENSUBDIV3_FAR_BILINEAR_PATCH_BUILDER_H */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,68 @@
//
// Copyright 2017 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.
//
#ifndef OPENSUBDIV3_FAR_CATMARK_PATCH_BUILDER_H
#define OPENSUBDIV3_FAR_CATMARK_PATCH_BUILDER_H
#include "../version.h"
#include "../far/patchBuilder.h"
namespace OpenSubdiv {
namespace OPENSUBDIV_VERSION {
namespace Far {
//
// CatmarkPatchBuilder
//
// Declaration of PatchBuilder subclass supporting Sdc::SCHEME_CATMARK.
// Required virtual methods are included, along with any customizations
// local to their implementation.
//
class CatmarkPatchBuilder : public PatchBuilder {
public:
CatmarkPatchBuilder(TopologyRefiner const& refiner, Options const& options);
virtual ~CatmarkPatchBuilder();
protected:
virtual PatchDescriptor::Type patchTypeFromBasis(BasisType basis) const;
virtual int convertToPatchType(SourcePatch const & sourcePatch,
PatchDescriptor::Type patchType,
SparseMatrix<float> & matrix) const;
private:
typedef SparseMatrix<float> ConversionMatrix;
};
} // end namespace Far
} // end namespace OPENSUBDIV_VERSION
using namespace OPENSUBDIV_VERSION;
} // end namespace OpenSubdiv
#endif /* OPENSUBDIV3_FAR_CATMARK_PATCH_BUILDER_H */

View File

@ -1,548 +0,0 @@
//
// Copyright 2015 Pixar
//
// 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 "../far/gregoryBasis.h"
#include "../far/endCapBSplineBasisPatchFactory.h"
#include "../far/error.h"
#include "../far/stencilTableFactory.h"
#include "../far/topologyRefiner.h"
#include <cassert>
#include <cmath>
#include <cstring>
namespace OpenSubdiv {
namespace OPENSUBDIV_VERSION {
namespace Far {
namespace {
#ifdef __INTEL_COMPILER
#pragma warning (push)
#pragma warning disable 1572
#endif
inline bool isWeightNonZero(float w) { return (w != 0.0f); }
#ifdef __INTEL_COMPILER
#pragma warning (pop)
#endif
}
EndCapBSplineBasisPatchFactory::EndCapBSplineBasisPatchFactory(
TopologyRefiner const & refiner,
StencilTable * vertexStencils,
StencilTable * varyingStencils) :
_vertexStencils(vertexStencils), _varyingStencils(varyingStencils),
_refiner(&refiner), _numVertices(0), _numPatches(0) {
// Sanity check: the mesh must be adaptively refined
assert(! refiner.IsUniform());
// Reserve the patch point stencils. Ideally topology refiner
// would have an API to return how many endcap patches will be required.
// Instead we conservatively estimate by the number of patches at the
// finest level.
int numMaxLevelFaces = refiner.GetLevel(refiner.GetMaxLevel()).GetNumFaces();
// we typically use 7 patch points for each bspline endcap.
int numPatchPointsExpected = numMaxLevelFaces * 7;
// limits to 100M (=800M bytes) entries for the reserved size.
int numStencilsExpected = (int) std::min<long>((long)numPatchPointsExpected * 16,
100*1024*1024);
_vertexStencils->reserve(numPatchPointsExpected, numStencilsExpected);
if (_varyingStencils) {
// varying stencils use only 1 index with weight=1.0
_varyingStencils->reserve(numPatchPointsExpected, numPatchPointsExpected);
}
}
ConstIndexArray
EndCapBSplineBasisPatchFactory::GetPatchPoints(
Vtr::internal::Level const * level, Index thisFace,
Vtr::internal::Level::VSpan const cornerSpans[],
int levelVertOffset, int fvarChannel) {
//
// We can only use a faster method directly with B-Splines when we have a
// single interior irregular corner. We defer to an intermediate Gregory
// patch in all other cases, i.e. the presence of any boundary, more than
// one irregular vertex or use of the partial neighborhood at any corner
// (not a true boundary wrt the corner vertex, but imposed by some other
// feature -- inf-sharp crease, face-varying discontinuity, etc).
//
// Assume we don't need to use a Gregory patch until we identify a feature
// at any corner that indicates we do.
//
Vtr::ConstIndexArray facePoints = level->getFaceVertices(thisFace);
int irregCornerIndex = -1;
bool useGregoryPatch = (fvarChannel >= 0);
for (int corner = 0; (corner < 4) && !useGregoryPatch; ++corner) {
Vtr::internal::Level::VTag vtag = level->getVertexTag(facePoints[corner]);
if ((vtag._rule != Sdc::Crease::RULE_SMOOTH) || cornerSpans[corner].isAssigned()) {
useGregoryPatch = true;
}
if (vtag._xordinary) {
if (irregCornerIndex < 0) {
irregCornerIndex = corner;
} else {
useGregoryPatch = true;
}
}
}
if (useGregoryPatch) {
return getPatchPointsFromGregoryBasis(
level, thisFace, cornerSpans, facePoints,
levelVertOffset, fvarChannel);
} else {
return getPatchPoints(
level, thisFace, irregCornerIndex, facePoints,
levelVertOffset, fvarChannel);
}
}
ConstIndexArray
EndCapBSplineBasisPatchFactory::getPatchPointsFromGregoryBasis(
Vtr::internal::Level const * level, Index thisFace,
Vtr::internal::Level::VSpan const cornerSpans[],
ConstIndexArray facePoints, int levelVertOffset, int fvarChannel) {
// XXX: For now, always create new 16 indices for each patch.
// we'll optimize later to share all regular control points with
// other patches as well as try to make extra-ordinary verts watertight.
int offset = (fvarChannel < 0)
? _refiner->GetNumVerticesTotal()
: _refiner->GetNumFVarValuesTotal(fvarChannel);
for (int i = 0; i < 16; ++i) {
_patchPoints.push_back(_numVertices + offset);
++_numVertices;
}
GregoryBasis::ProtoBasis basis(*level, thisFace, cornerSpans, levelVertOffset, fvarChannel);
// XXX: temporary hack. we should traverse topology and find existing
// vertices if available
//
// Reorder gregory basis stencils into regular bezier
GregoryBasis::Point const *bezierCP[16];
bezierCP[0] = &basis.P[0];
bezierCP[1] = &basis.Ep[0];
bezierCP[2] = &basis.Em[1];
bezierCP[3] = &basis.P[1];
bezierCP[4] = &basis.Em[0];
bezierCP[5] = &basis.Fp[0]; // arbitrary
bezierCP[6] = &basis.Fp[1]; // arbitrary
bezierCP[7] = &basis.Ep[1];
bezierCP[8] = &basis.Ep[3];
bezierCP[9] = &basis.Fp[3]; // arbitrary
bezierCP[10] = &basis.Fp[2]; // arbitrary
bezierCP[11] = &basis.Em[2];
bezierCP[12] = &basis.P[3];
bezierCP[13] = &basis.Em[3];
bezierCP[14] = &basis.Ep[2];
bezierCP[15] = &basis.P[2];
// all stencils should have the same capacity.
int stencilCapacity = basis.P[0].GetCapacity();
// Apply basis conversion from bezier to b-spline
float Q[4][4] = {{ 6, -7, 2, 0},
{ 0, 2, -1, 0},
{ 0, -1, 2, 0},
{ 0, 2, -7, 6} };
Vtr::internal::StackBuffer<GregoryBasis::Point, 16> H(16);
for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j) {
H[i*4+j].Clear(stencilCapacity);
for (int k = 0; k < 4; ++k) {
if (isWeightNonZero(Q[i][k])) {
H[i*4+j].AddWithWeight(*bezierCP[j+k*4], Q[i][k]);
}
}
}
}
for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j) {
GregoryBasis::Point p(stencilCapacity);
for (int k = 0; k < 4; ++k) {
if (isWeightNonZero(Q[j][k])) {
p.AddWithWeight(H[i*4+k], Q[j][k]);
}
}
GregoryBasis::AppendToStencilTable(p, _vertexStencils);
}
}
if (_varyingStencils) {
int varyingIndices[] = { 0, 0, 1, 1,
0, 0, 1, 1,
3, 3, 2, 2,
3, 3, 2, 2,};
for (int i = 0; i < 16; ++i) {
int varyingIndex = facePoints[varyingIndices[i]] + levelVertOffset;
_varyingStencils->_sizes.push_back(1);
_varyingStencils->_indices.push_back(varyingIndex);
_varyingStencils->_weights.push_back(1.0f);
}
}
++_numPatches;
return ConstIndexArray(&_patchPoints[(_numPatches-1)*16], 16);
}
void
EndCapBSplineBasisPatchFactory::computeLimitStencils(
Vtr::internal::Level const *level,
ConstIndexArray facePoints, int vid, int fvarChannel,
GregoryBasis::Point *P, GregoryBasis::Point *Ep, GregoryBasis::Point *Em)
{
int maxvalence = level->getMaxValence();
Vtr::internal::StackBuffer<Index, 40> manifoldRing;
manifoldRing.SetSize(maxvalence*2);
int ringSize =
level->gatherQuadRegularRingAroundVertex(
facePoints[vid], manifoldRing, fvarChannel);
// note: this function has not yet supported boundary.
assert((ringSize & 1) == 0);
int valence = ringSize/2;
int stencilCapacity = ringSize + 1;
Index start = -1, prev = -1;
{
int ip = (vid+1)%4, im = (vid+3)%4;
for (int i = 0; i < valence; ++i) {
if (manifoldRing[i*2] == facePoints[ip])
start = i;
if (manifoldRing[i*2] == facePoints[im])
prev = i;
}
}
assert(start > -1 && prev > -1);
GregoryBasis::Point e0, e1;
e0.Clear(stencilCapacity);
e1.Clear(stencilCapacity);
float t = 2.0f * float(M_PI) / float(valence);
float ef = 1.0f / (valence * (cosf(t) + 5.0f +
sqrtf((cosf(t) + 9) * (cosf(t) + 1)))/16.0f);
for (int i = 0; i < valence; ++i) {
Index ip = (i+1)%valence;
Index idx_neighbor = (manifoldRing[2*i + 0]),
idx_diagonal = (manifoldRing[2*i + 1]),
idx_neighbor_p = (manifoldRing[2*ip + 0]);
float d = float(valence)+5.0f;
GregoryBasis::Point f(4);
f.AddWithWeight(facePoints[vid], float(valence)/d);
f.AddWithWeight(idx_neighbor_p, 2.0f/d);
f.AddWithWeight(idx_neighbor, 2.0f/d);
f.AddWithWeight(idx_diagonal, 1.0f/d);
P->AddWithWeight(f, 1.0f/float(valence));
float c0 = 0.5f*cosf((float(2*M_PI) * float(i)/float(valence)))
+ 0.5f*cosf((float(2*M_PI) * float(ip)/float(valence)));
float c1 = 0.5f*sinf((float(2*M_PI) * float(i)/float(valence)))
+ 0.5f*sinf((float(2*M_PI) * float(ip)/float(valence)));
e0.AddWithWeight(f, c0*ef);
e1.AddWithWeight(f, c1*ef);
}
*Ep = *P;
Ep->AddWithWeight(e0, cosf((float(2*M_PI) * float(start)/float(valence))));
Ep->AddWithWeight(e1, sinf((float(2*M_PI) * float(start)/float(valence))));
*Em = *P;
Em->AddWithWeight(e0, cosf((float(2*M_PI) * float(prev)/float(valence))));
Em->AddWithWeight(e1, sinf((float(2*M_PI) * float(prev)/float(valence))));
}
ConstIndexArray
EndCapBSplineBasisPatchFactory::getPatchPoints(
Vtr::internal::Level const *level, Index thisFace,
Index extraOrdinaryIndex, ConstIndexArray facePoints,
int levelVertOffset, int fvarChannel) {
// Fast B-spline endcap construction.
//
// This function assumes the patch is not on boundary
// and it contains only 1 extraordinary vertex.
// The location of the extraordinary vertex can be one of
// 0-ring quad corner.
//
// B-Spline control point gathering indices
//
// [5] (4)---(15)--(14) 0 : extraordinary vertex
// | | |
// | | | 1,2,3,9,10,11,12,13 :
// (6)----0-----3-----13 B-Spline control points, gathered by
// | | | | traversing topology
// | | | |
// (7)----1-----2-----12 (5) :
// | | | | Fitted patch point (from limit position)
// | | | |
// (8)----9-----10----11 (4),(6),(7),(8),(14),(15) :
// Fitted patch points
// (from limit tangents and bezier CP)
//
static int const rotation[4][16] = {
/*= 0 ring =*/ /* ================ 1 ring ================== */
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 ,14, 15},
{ 1, 2, 3, 0, 7, 8, 9, 10, 11, 12, 13, 14, 15, 4, 5, 6},
{ 2, 3, 0, 1, 10, 11, 12, 13, 14, 15, 4, 5, 6, 7, 8, 9},
{ 3, 0, 1, 2, 13, 14, 15, 4, 5, 6, 7, 8, 9, 10, 11, 12}};
int maxvalence = level->getMaxValence();
int stencilCapacity = 2*maxvalence + 16;
GregoryBasis::Point P(stencilCapacity), Em(stencilCapacity), Ep(stencilCapacity);
computeLimitStencils(level, facePoints, extraOrdinaryIndex, fvarChannel, &P, &Em, &Ep);
P.OffsetIndices(levelVertOffset);
Em.OffsetIndices(levelVertOffset);
Ep.OffsetIndices(levelVertOffset);
// returning patch indices (a mix of cage vertices and patch points)
int patchPoints[16];
// first, we traverse the topology to gather 15 vertices. This process is
// similar to Vtr::Level::gatherQuadRegularInteriorPatchPoints
int pointIndex = 0;
int vid = extraOrdinaryIndex;
// 0-ring
patchPoints[pointIndex++] = facePoints[0] + levelVertOffset;
patchPoints[pointIndex++] = facePoints[1] + levelVertOffset;
patchPoints[pointIndex++] = facePoints[2] + levelVertOffset;
patchPoints[pointIndex++] = facePoints[3] + levelVertOffset;
// 1-ring
ConstIndexArray thisFaceVerts = level->getFaceVertices(thisFace);
for (int i = 0; i < 4; ++i) {
Index v = thisFaceVerts[i];
ConstIndexArray vFaces = level->getVertexFaces(v);
ConstLocalIndexArray vInFaces = level->getVertexFaceLocalIndices(v);
if (i != vid) {
// regular corner
int thisFaceInVFaces = vFaces.FindIndexIn4Tuple(thisFace);
int intFaceInVFaces = (thisFaceInVFaces + 2) & 0x3;
Index intFace = vFaces[intFaceInVFaces];
int vInIntFace = vInFaces[intFaceInVFaces];
ConstIndexArray intFacePoints = level->getFaceVertices(intFace);
patchPoints[pointIndex++] =
intFacePoints[(vInIntFace + 1)&3] + levelVertOffset;
patchPoints[pointIndex++] =
intFacePoints[(vInIntFace + 2)&3] + levelVertOffset;
patchPoints[pointIndex++] =
intFacePoints[(vInIntFace + 3)&3] + levelVertOffset;
} else {
// irregular corner
int thisFaceInVFaces = vFaces.FindIndex(thisFace);
int valence = vFaces.size();
{
// first
int intFaceInVFaces = (thisFaceInVFaces + 1) % valence;
Index intFace = vFaces[intFaceInVFaces];
int vInIntFace = vInFaces[intFaceInVFaces];
ConstIndexArray intFacePoints = level->getFaceVertices(intFace);
patchPoints[pointIndex++] =
intFacePoints[(vInIntFace+3)&3] + levelVertOffset;
}
{
// middle: (n-vertices) needs a limit stencil. skip for now
pointIndex++;
}
{
// end
int intFaceInVFaces = (thisFaceInVFaces + (valence-1)) %valence;
Index intFace = vFaces[intFaceInVFaces];
int vInIntFace = vInFaces[intFaceInVFaces];
ConstIndexArray intFacePoints = level->getFaceVertices(intFace);
patchPoints[pointIndex++] =
intFacePoints[(vInIntFace+1)&3] + levelVertOffset;
}
}
}
// stencils for patch points
GregoryBasis::Point X5(stencilCapacity),
X6(stencilCapacity),
X7(stencilCapacity),
X8(stencilCapacity),
X4(stencilCapacity),
X15(stencilCapacity),
X14(stencilCapacity);
// limit tangent : Em
// X6 = 1/3 * ( 36Em - 16P0 - 8P1 - 2P2 - 4P3 - P6 - 2P7)
// X7 = 1/3 * (-18Em + 8P0 + 4P1 + P2 + 2P3 + 2P6 + 4P7)
// X8 = X6 + (P8-P6)
X6.AddWithWeight(Em, 36.0f/3.0f);
X6.AddWithWeight(patchPoints[rotation[vid][0]], -16.0f/3.0f);
X6.AddWithWeight(patchPoints[rotation[vid][1]], -8.0f/3.0f);
X6.AddWithWeight(patchPoints[rotation[vid][2]], -2.0f/3.0f);
X6.AddWithWeight(patchPoints[rotation[vid][3]], -4.0f/3.0f);
X6.AddWithWeight(patchPoints[rotation[vid][6]], -1.0f/3.0f);
X6.AddWithWeight(patchPoints[rotation[vid][7]], -2.0f/3.0f);
X7.AddWithWeight(Em, -18.0f/3.0f);
X7.AddWithWeight(patchPoints[rotation[vid][0]], 8.0f/3.0f);
X7.AddWithWeight(patchPoints[rotation[vid][1]], 4.0f/3.0f);
X7.AddWithWeight(patchPoints[rotation[vid][2]], 1.0f/3.0f);
X7.AddWithWeight(patchPoints[rotation[vid][3]], 2.0f/3.0f);
X7.AddWithWeight(patchPoints[rotation[vid][6]], 2.0f/3.0f);
X7.AddWithWeight(patchPoints[rotation[vid][7]], 4.0f/3.0f);
X8 = X6;
X8.AddWithWeight(patchPoints[rotation[vid][8]], 1.0f);
X8.AddWithWeight(patchPoints[rotation[vid][6]], -1.0f);
// limit tangent : Ep
// X4 = 1/3 * ( 36EP - 16P0 - 4P1 - 2P15 - 2P2 - 8P3 - P4)
// X15 = 1/3 * (-18EP + 8P0 + 2P1 + 4P15 + P2 + 4P3 + 2P4)
// X14 = X4 + (P14 - P4)
X4.AddWithWeight(Ep, 36.0f/3.0f);
X4.AddWithWeight(patchPoints[rotation[vid][0]], -16.0f/3.0f);
X4.AddWithWeight(patchPoints[rotation[vid][1]], -4.0f/3.0f);
X4.AddWithWeight(patchPoints[rotation[vid][2]], -2.0f/3.0f);
X4.AddWithWeight(patchPoints[rotation[vid][3]], -8.0f/3.0f);
X4.AddWithWeight(patchPoints[rotation[vid][4]], -1.0f/3.0f);
X4.AddWithWeight(patchPoints[rotation[vid][15]], -2.0f/3.0f);
X15.AddWithWeight(Ep, -18.0f/3.0f);
X15.AddWithWeight(patchPoints[rotation[vid][0]], 8.0f/3.0f);
X15.AddWithWeight(patchPoints[rotation[vid][1]], 2.0f/3.0f);
X15.AddWithWeight(patchPoints[rotation[vid][2]], 1.0f/3.0f);
X15.AddWithWeight(patchPoints[rotation[vid][3]], 4.0f/3.0f);
X15.AddWithWeight(patchPoints[rotation[vid][4]], 2.0f/3.0f);
X15.AddWithWeight(patchPoints[rotation[vid][15]], 4.0f/3.0f);
X14 = X4;
X14.AddWithWeight(patchPoints[rotation[vid][14]], 1.0f);
X14.AddWithWeight(patchPoints[rotation[vid][4]], -1.0f);
// limit corner (16th free vert)
// X5 = 36LP - 16P0 - 4(P1 + P3 + P4 + P6) - (P2 + P7 + P15)
X5.AddWithWeight(P, 36.0f);
X5.AddWithWeight(patchPoints[rotation[vid][0]], -16.0f);
X5.AddWithWeight(patchPoints[rotation[vid][1]], -4.0f);
X5.AddWithWeight(patchPoints[rotation[vid][3]], -4.0f);
X5.AddWithWeight(X4, -4.0f);
X5.AddWithWeight(X6, -4.0f);
X5.AddWithWeight(patchPoints[rotation[vid][2]], -1.0f);
X5.AddWithWeight(X7, -1.0f);
X5.AddWithWeight(X15, -1.0f);
// [5] (4)---(15)--(14) 0 : extraordinary vertex
// | | |
// | | | 1,2,3,9,10,11,12,13 :
// (6)----0-----3-----13 B-Spline control points, gathered by
// | | | | traversing topology
// | | | |
// (7)----1-----2-----12 (5) :
// | | | | Fitted patch point (from limit position)
// | | | |
// (8)----9-----10----11 (4),(6),(7),(8),(14),(15) :
//
// patch point stencils will be stored in this order
// (Em) 6, 7, 8, (Ep) 4, 15, 14, (P) 5
int offset = (fvarChannel < 0)
? _refiner->GetNumVerticesTotal()
: _refiner->GetNumFVarValuesTotal(fvarChannel);
int varyingIndex0 = facePoints[vid] + levelVertOffset;
int varyingIndex1 = facePoints[(vid+1)&3] + levelVertOffset;
int varyingIndex3 = facePoints[(vid+3)&3] + levelVertOffset;
// push back to stencils;
patchPoints[3* vid + 6] = (_numVertices++) + offset;
GregoryBasis::AppendToStencilTable(X6, _vertexStencils);
if (_varyingStencils) {
GregoryBasis::AppendToStencilTable(varyingIndex0, _varyingStencils);
}
patchPoints[3*((vid+1)%4) + 4] = (_numVertices++) + offset;
GregoryBasis::AppendToStencilTable(X7, _vertexStencils);
if (_varyingStencils) {
GregoryBasis::AppendToStencilTable(varyingIndex1, _varyingStencils);
}
patchPoints[3*((vid+1)%4) + 5] = (_numVertices++) + offset;
GregoryBasis::AppendToStencilTable(X8, _vertexStencils);
if (_varyingStencils) {
GregoryBasis::AppendToStencilTable(varyingIndex1, _varyingStencils);
}
patchPoints[3* vid + 4] = (_numVertices++) + offset;
GregoryBasis::AppendToStencilTable(X4, _vertexStencils);
if (_varyingStencils) {
GregoryBasis::AppendToStencilTable(varyingIndex0, _varyingStencils);
}
patchPoints[3*((vid+3)%4) + 6] = (_numVertices++) + offset;
GregoryBasis::AppendToStencilTable(X15, _vertexStencils);
if (_varyingStencils) {
GregoryBasis::AppendToStencilTable(varyingIndex3, _varyingStencils);
}
patchPoints[3*((vid+3)%4) + 5] = (_numVertices++) + offset;
GregoryBasis::AppendToStencilTable(X14, _vertexStencils);
if (_varyingStencils) {
GregoryBasis::AppendToStencilTable(varyingIndex3, _varyingStencils);
}
patchPoints[3*vid + 5] = (_numVertices++) + offset;
GregoryBasis::AppendToStencilTable(X5, _vertexStencils);
if (_varyingStencils) {
GregoryBasis::AppendToStencilTable(varyingIndex0, _varyingStencils);
}
// reorder into UV row-column
static int const permuteRegular[16] =
{ 5, 6, 7, 8, 4, 0, 1, 9, 15, 3, 2, 10, 14, 13, 12, 11 };
for (int i = 0; i < 16; ++i) {
_patchPoints.push_back(patchPoints[permuteRegular[i]]);
}
++_numPatches;
return ConstIndexArray(&_patchPoints[(_numPatches-1)*16], 16);
}
} // end namespace Far
} // end namespace OPENSUBDIV_VERSION
} // end namespace OpenSubdiv

View File

@ -1,115 +0,0 @@
//
// Copyright 2015 Pixar
//
// 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.
//
#ifndef OPENSUBDIV3_FAR_END_CAP_BSPLINE_BASIS_PATCH_FACTORY_H
#define OPENSUBDIV3_FAR_END_CAP_BSPLINE_BASIS_PATCH_FACTORY_H
#include "../far/gregoryBasis.h"
#include "../far/types.h"
#include "../vtr/level.h"
namespace OpenSubdiv {
namespace OPENSUBDIV_VERSION {
namespace Far {
class TopologyRefiner;
/// \brief A BSpline endcap factory
///
/// note: This is an internal use class in PatchTableFactory, and
/// will be replaced with SdcSchemeWorker for mask coefficients
/// and Vtr::Level for topology traversal.
///
class EndCapBSplineBasisPatchFactory {
public:
/// \brief This factory accumulates vertices for bspline basis end cap
///
/// @param refiner TopologyRefiner from which to generate patches
///
/// @param vertexStencils Output stencil table for the patch points
/// (vertex interpolation)
///
/// @param varyingStencils Output stencil table for the patch points
/// (varying interpolation)
///
/// @param shareBoundaryVertices Use same boundary vertices for neighboring
/// patches. It reduces the number of stencils
/// to be used.
///
EndCapBSplineBasisPatchFactory(TopologyRefiner const & refiner,
StencilTable * vertexStencils,
StencilTable * varyingStencils);
/// \brief Returns end patch point indices for \a faceIndex of \a level.
/// Note that end patch points are not included in the vertices in
/// the topologyRefiner, they're expected to come after the end.
/// The returned indices are offset by refiner->GetNumVerticesTotal.
///
/// @param level vtr refinement level
///
/// @param faceIndex vtr faceIndex at the level
///
/// @param levelVertOffset relative offset of patch vertex indices
///
/// @param fvarChannel face-varying channel index
///
ConstIndexArray GetPatchPoints(
Vtr::internal::Level const * level, Index faceIndex,
Vtr::internal::Level::VSpan const cornerSpans[],
int levelVertOffset, int fvarChannel = -1);
private:
ConstIndexArray getPatchPointsFromGregoryBasis(
Vtr::internal::Level const * level, Index thisFace,
Vtr::internal::Level::VSpan const cornerSpans[],
ConstIndexArray facePoints,
int levelVertOffset, int fvarChannel);
ConstIndexArray getPatchPoints(
Vtr::internal::Level const *level, Index thisFace,
Index extraOrdinaryIndex, ConstIndexArray facePoints,
int levelVertOffset, int fvarChannel);
void computeLimitStencils(
Vtr::internal::Level const *level,
ConstIndexArray facePoints, int vid, int fvarChannel,
GregoryBasis::Point *P, GregoryBasis::Point *Ep, GregoryBasis::Point *Em);
StencilTable * _vertexStencils;
StencilTable * _varyingStencils;
TopologyRefiner const *_refiner;
int _numVertices;
int _numPatches;
std::vector<Index> _patchPoints;
};
} // end namespace Far
} // end namespace OPENSUBDIV_VERSION
} // end namespace OpenSubdiv
#endif // OPENSUBDIV3_FAR_END_CAP_BSPLINE_BASIS_PATCH_FACTORY_H

View File

@ -1,251 +0,0 @@
//
// Copyright 2013 Pixar
//
// 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 "../far/gregoryBasis.h"
#include "../far/endCapGregoryBasisPatchFactory.h"
#include "../far/error.h"
#include "../far/stencilTableFactory.h"
#include "../far/topologyRefiner.h"
#include <cassert>
#include <cmath>
#include <cstring>
namespace OpenSubdiv {
namespace OPENSUBDIV_VERSION {
namespace Far {
//
// EndCapGregoryBasisPatchFactory for Vertex StencilTable
//
EndCapGregoryBasisPatchFactory::EndCapGregoryBasisPatchFactory(
TopologyRefiner const & refiner,
StencilTable * vertexStencils,
StencilTable * varyingStencils,
bool shareBoundaryVertices) :
_vertexStencils(vertexStencils), _varyingStencils(varyingStencils),
_refiner(&refiner), _shareBoundaryVertices(shareBoundaryVertices),
_numGregoryBasisVertices(0), _numGregoryBasisPatches(0) {
// Sanity check: the mesh must be adaptively refined
assert(! refiner.IsUniform());
// Reserve the patch point stencils. Ideally topology refiner
// would have an API to return how many endcap patches will be required.
// Instead we conservatively estimate by the number of patches at the
// finest level.
int numMaxLevelFaces = refiner.GetLevel(refiner.GetMaxLevel()).GetNumFaces();
int numPatchPointsExpected = numMaxLevelFaces * 20;
// limits to 100M (=800M bytes) entries for the reserved size.
int numStencilsExpected = (int) std::min<long>((long)numPatchPointsExpected * 16,
100*1024*1024);
_vertexStencils->reserve(numPatchPointsExpected, numStencilsExpected);
if (_varyingStencils) {
// varying stencils use only 1 index with weight=1.0
_varyingStencils->reserve(numPatchPointsExpected, numPatchPointsExpected);
}
}
bool
EndCapGregoryBasisPatchFactory::addPatchBasis(Vtr::internal::Level const & level, Index faceIndex,
Vtr::internal::Level::VSpan const cornerSpans[],
bool verticesMask[4][5],
int levelVertOffset,
int fvarChannel) {
// Gather the CVs that influence the Gregory patch and their relative
// weights in a basis
GregoryBasis::ProtoBasis basis(level, faceIndex, cornerSpans, levelVertOffset, fvarChannel);
for (int i = 0; i < 4; ++i) {
if (verticesMask[i][0]) {
GregoryBasis::AppendToStencilTable(basis.P[i], _vertexStencils);
if (_varyingStencils) {
GregoryBasis::AppendToStencilTable(basis.varyingIndex[i], _varyingStencils);
}
}
if (verticesMask[i][1]) {
GregoryBasis::AppendToStencilTable(basis.Ep[i], _vertexStencils);
if (_varyingStencils) {
GregoryBasis::AppendToStencilTable(basis.varyingIndex[i], _varyingStencils);
}
}
if (verticesMask[i][2]) {
GregoryBasis::AppendToStencilTable(basis.Em[i], _vertexStencils);
if (_varyingStencils) {
GregoryBasis::AppendToStencilTable(basis.varyingIndex[i], _varyingStencils);
}
}
if (verticesMask[i][3]) {
GregoryBasis::AppendToStencilTable(basis.Fp[i], _vertexStencils);
if (_varyingStencils) {
GregoryBasis::AppendToStencilTable(basis.varyingIndex[i], _varyingStencils);
}
}
if (verticesMask[i][4]) {
GregoryBasis::AppendToStencilTable(basis.Fm[i], _vertexStencils);
if (_varyingStencils) {
GregoryBasis::AppendToStencilTable(basis.varyingIndex[i], _varyingStencils);
}
}
}
return true;
}
//
// Populates the topology table used by Gregory-basis patches
//
// Note : 'faceIndex' values are expected to be sorted in ascending order !!!
// Note 2: this code attempts to identify basis vertices shared along
// gregory patch edges
ConstIndexArray
EndCapGregoryBasisPatchFactory::GetPatchPoints(
Vtr::internal::Level const * level, Index faceIndex,
Vtr::internal::Level::VSpan const cornerSpans[],
int levelVertOffset, int fvarChannel) {
// allocate indices (awkward)
// assert(Vtr::INDEX_INVALID==0xFFFFFFFF);
for (int i = 0; i < 20; ++i) {
_patchPoints.push_back(Vtr::INDEX_INVALID);
}
Index * dest = &_patchPoints[_numGregoryBasisPatches * 20];
int gregoryVertexOffset = (fvarChannel < 0)
? _refiner->GetNumVerticesTotal()
: _refiner->GetNumFVarValuesTotal(fvarChannel);
if (_shareBoundaryVertices) {
int levelIndex = level->getDepth();
// Simple struct with encoding of <level,face> index as an unsigned int and a
// comparison method for use with std::bsearch
struct LevelAndFaceIndex {
static inline unsigned int create(unsigned int levelIndexArg, Index faceIndexArg) {
return (levelIndexArg << 28) | (unsigned int) faceIndexArg;
}
static int compare(void const * a, void const * b) {
return *(unsigned int const*)a - *(unsigned int const*)b;
}
};
ConstIndexArray fedges = level->getFaceEdges(faceIndex);
assert(fedges.size()==4);
Vtr::internal::Level::ETag etags[4];
level->getFaceETags(faceIndex, etags, fvarChannel);
for (int i=0; i<4; ++i) {
// Ignore boundary edges (or those with a face-varying discontinuity)
if (etags[i]._boundary) continue;
Index edge = fedges[i];
Index adjFaceIndex = 0;
{ // Gather adjacent faces
ConstIndexArray adjfaces = level->getEdgeFaces(edge);
for (int j=0; j<adjfaces.size(); ++j) {
if (adjfaces[j]==faceIndex) {
// XXXX manuelk if 'edge' is non-manifold, arbitrarily pick the
// next face in the list of adjacent faces
adjFaceIndex = (adjfaces[(j+1)%adjfaces.size()]);
break;
}
}
}
// We are looking for adjacent faces that:
// - exist (no boundary)
// - have already been processed (known CV indices)
// - are also Gregory basis patches
if ((adjFaceIndex != Vtr::INDEX_INVALID) && (adjFaceIndex < faceIndex)) {
if (_levelAndFaceIndices.empty()) {
break;
}
ConstIndexArray aedges = level->getFaceEdges(adjFaceIndex);
int aedge = aedges.FindIndexIn4Tuple(edge);
assert(aedge!=Vtr::INDEX_INVALID);
// Find index of basis in the list of bases already generated
unsigned int adjLevelAndFaceIndex = LevelAndFaceIndex::create(levelIndex, adjFaceIndex);
unsigned int * ptr = (unsigned int *)std::bsearch(&adjLevelAndFaceIndex,
&_levelAndFaceIndices[0],
_levelAndFaceIndices.size(),
sizeof(unsigned int),
LevelAndFaceIndex::compare);
if (ptr == 0) {
break;
}
int adjPatchIndex = (int)(ptr - &_levelAndFaceIndices[0]);
assert(adjPatchIndex>=0 && adjPatchIndex<(int)_levelAndFaceIndices.size());
// Copy the indices of CVs from the face on the other side of the shared edge
static int const gregoryEdgeVerts[4][4] = { { 0, 1, 7, 5},
{ 5, 6, 12, 10},
{10, 11, 17, 15},
{15, 16, 2, 0} };
Index * src = &_patchPoints[adjPatchIndex*20];
for (int j=0; j<4; ++j) {
// invert direction
// note that src indices have already been offset.
dest[gregoryEdgeVerts[i][3-j]] = src[gregoryEdgeVerts[aedge][j]];
}
}
}
_levelAndFaceIndices.push_back(LevelAndFaceIndex::create(levelIndex, faceIndex));
}
bool newVerticesMask[4][5];
for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 5; ++j) {
if (dest[i*5+j]==Vtr::INDEX_INVALID) {
// assign new vertex
dest[i*5+j] =
_numGregoryBasisVertices + gregoryVertexOffset;
++_numGregoryBasisVertices;
newVerticesMask[i][j] = true;
} else {
// share vertex
newVerticesMask[i][j] = false;
}
}
}
// add basis
addPatchBasis(*level, faceIndex, cornerSpans, newVerticesMask, levelVertOffset, fvarChannel);
++_numGregoryBasisPatches;
// return cvs;
return ConstIndexArray(dest, 20);
}
} // end namespace Far
} // end namespace OPENSUBDIV_VERSION
} // end namespace OpenSubdiv

View File

@ -1,118 +0,0 @@
//
// Copyright 2013 Pixar
//
// 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.
//
#ifndef OPENSUBDIV3_FAR_END_CAP_GREGORY_BASIS_PATCH_FACTORY_H
#define OPENSUBDIV3_FAR_END_CAP_GREGORY_BASIS_PATCH_FACTORY_H
#include "../far/gregoryBasis.h"
#include "../far/stencilTable.h"
#include "../vtr/level.h"
namespace OpenSubdiv {
namespace OPENSUBDIV_VERSION {
namespace Far {
class TopologyRefiner;
/// \brief A specialized factory to gather Gregory basis control vertices
///
/// note: This is an internal use class in PatchTableFactory, and
/// will be replaced with SdcSchemeWorker for mask coefficients
/// and Vtr::Level for topology traversal.
///
class EndCapGregoryBasisPatchFactory {
public:
///
/// Multi-patch Gregory stencils factory
///
/// \brief This factory accumulates vertex for Gregory basis patch
///
/// @param refiner TopologyRefiner from which to generate patches
///
/// @param vertexStencils Output stencil table for the patch points
/// (vertex interpolation)
///
/// @param varyingStencils Output stencil table for the patch points
/// (varying interpolation)
///
/// @param shareBoundaryVertices Use same boundary vertices for neighboring
/// patches. It reduces the number of stencils
/// to be used.
///
EndCapGregoryBasisPatchFactory(TopologyRefiner const & refiner,
StencilTable *vertexStencils,
StencilTable *varyingStencils,
bool shareBoundaryVertices=true);
/// \brief Returns end patch point indices for \a faceIndex of \a level.
/// Note that end patch points are not included in the vertices in
/// the topologyRefiner, they're expected to come after the end.
/// The returned indices are offset by refiner->GetNumVerticesTotal.
///
/// @param level vtr refinement level
///
/// @param faceIndex vtr faceIndex at the level
//
/// @param cornerSpans information about topology for each corner of patch
/// @param levelVertOffset relative offset of patch vertex indices
///
/// @param fvarChannel face-varying channel index
///
ConstIndexArray GetPatchPoints(
Vtr::internal::Level const * level, Index faceIndex,
Vtr::internal::Level::VSpan const cornerSpans[],
int levelVertOffset, int fvarChannel = -1);
private:
/// Creates a basis for the vertices specified in mask on the face and
/// accumulates it
bool addPatchBasis(Vtr::internal::Level const & level, Index faceIndex,
Vtr::internal::Level::VSpan const cornerSpans[],
bool newVerticesMask[4][5],
int levelVertOffset, int fvarChannel);
StencilTable *_vertexStencils;
StencilTable *_varyingStencils;
TopologyRefiner const *_refiner;
bool _shareBoundaryVertices;
int _numGregoryBasisVertices;
int _numGregoryBasisPatches;
std::vector<Index> _patchPoints;
// Only used when sharing vertices:
std::vector<unsigned int> _levelAndFaceIndices;
};
} // end namespace Far
} // end namespace OPENSUBDIV_VERSION
} // end namespace OpenSubdiv
#endif // OPENSUBDIV3_FAR_END_CAP_GREGORY_BASIS_PATCH_FACTORY_H

View File

@ -1,203 +0,0 @@
//
// Copyright 2015 Pixar
//
// 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 "../far/error.h"
#include "../far/endCapLegacyGregoryPatchFactory.h"
#include "../far/patchTable.h"
#include "../far/topologyRefiner.h"
#include "../vtr/level.h"
namespace OpenSubdiv {
namespace OPENSUBDIV_VERSION {
namespace Far {
EndCapLegacyGregoryPatchFactory::EndCapLegacyGregoryPatchFactory(
TopologyRefiner const &refiner) :
_refiner(refiner) {
}
ConstIndexArray
EndCapLegacyGregoryPatchFactory::GetPatchPoints(
Vtr::internal::Level const * level, Index faceIndex,
Vtr::internal::Level::VSpan const /*cornerSpans*/[],
int levelVertOffset, int fvarChannel) {
// Gregory Regular Patch (4 CVs + quad-offsets / valence tables)
Vtr::ConstIndexArray faceVerts = (fvarChannel < 0)
? level->getFaceVertices(faceIndex)
: level->getFaceFVarValues(faceIndex, fvarChannel);
if (level->getFaceCompositeVTag(faceVerts)._boundary) {
for (int j = 0; j < 4; ++j) {
// apply level offset
_gregoryBoundaryTopology.push_back(faceVerts[j] + levelVertOffset);
}
_gregoryBoundaryFaceIndices.push_back(faceIndex);
return ConstIndexArray(&_gregoryBoundaryTopology[_gregoryBoundaryTopology.size()-4], 4);
} else {
for (int j = 0; j < 4; ++j) {
// apply level offset
_gregoryTopology.push_back(faceVerts[j] + levelVertOffset);
}
_gregoryFaceIndices.push_back(faceIndex);
return ConstIndexArray(&_gregoryTopology[_gregoryTopology.size()-4], 4);
}
}
//
// Populate the quad-offsets table used by Gregory patches
//
static void getQuadOffsets(
Vtr::internal::Level const& level, Index faceIndex, unsigned int offsets[], int fvarChannel) {
Vtr::ConstIndexArray fVerts = (fvarChannel < 0)
? level.getFaceVertices(faceIndex)
: level.getFaceFVarValues(faceIndex, fvarChannel);
for (int i = 0; i < 4; ++i) {
Vtr::Index vIndex = fVerts[i];
Vtr::ConstIndexArray vFaces = level.getVertexFaces(vIndex),
vEdges = level.getVertexEdges(vIndex);
int thisFaceInVFaces = -1;
for (int j = 0; j < vFaces.size(); ++j) {
if (faceIndex == vFaces[j]) {
thisFaceInVFaces = j;
break;
}
}
assert(thisFaceInVFaces != -1);
Index vOffsets[2];
vOffsets[0] = thisFaceInVFaces;
vOffsets[1] = (thisFaceInVFaces + 1)%vEdges.size();
// we have to use the number of incident edges to modulo the local index
// because there could be 2 consecutive edges in the face belonging to
// the Gregory patch.
offsets[i] = vOffsets[0] | (vOffsets[1] << 8);
}
}
void
EndCapLegacyGregoryPatchFactory::Finalize(
int maxValence,
PatchTable::QuadOffsetsTable *quadOffsetsTable,
PatchTable::VertexValenceTable *vertexValenceTable,
int fvarChannel)
{
// populate quad offsets
size_t numGregoryPatches = _gregoryFaceIndices.size();
size_t numGregoryBoundaryPatches = _gregoryBoundaryFaceIndices.size();
size_t numTotalGregoryPatches =
numGregoryPatches + numGregoryBoundaryPatches;
Vtr::internal::Level const &maxLevel = _refiner.getLevel(_refiner.GetMaxLevel());
quadOffsetsTable->resize(numTotalGregoryPatches*4);
if (numTotalGregoryPatches > 0) {
PatchTable::QuadOffsetsTable::value_type *p =
&((*quadOffsetsTable)[0]);
for (size_t i = 0; i < numGregoryPatches; ++i) {
getQuadOffsets(maxLevel, _gregoryFaceIndices[i], p, fvarChannel);
p += 4;
}
for (size_t i = 0; i < numGregoryBoundaryPatches; ++i) {
getQuadOffsets(maxLevel, _gregoryBoundaryFaceIndices[i], p, fvarChannel);
p += 4;
}
}
// populate vertex valences
//
// Now deal with the "vertex valence" table for Gregory patches -- this
// table contains the one-ring of vertices around each vertex. Currently
// it is extremely wasteful for the following reasons:
// - it allocates 2*maxvalence+1 for ALL vertices
// - it initializes the one-ring for ALL vertices
// We use the full size expected (not sure what else relies on that) but
// we avoid initializing
// the vast majority of vertices that are not associated with gregory
// patches -- by having previously marked those that are associated above
// and skipping all others.
//
const int SizePerVertex = 2*maxValence + 1;
PatchTable::VertexValenceTable & vTable = (*vertexValenceTable);
vTable.resize((long)_refiner.GetNumVerticesTotal() * SizePerVertex);
int vOffset = 0;
int levelLast = _refiner.GetMaxLevel();
for (int i = 0; i <= levelLast; ++i) {
Vtr::internal::Level const * level = &_refiner.getLevel(i);
if (i == levelLast) {
long vTableOffset = vOffset * SizePerVertex;
for (int vIndex = 0; vIndex < level->getNumVertices(); ++vIndex) {
int* vTableEntry = &vTable[vTableOffset];
//
// If not marked as a vertex of a gregory patch, just set to 0 to ignore. Otherwise
// gather the one-ring around the vertex and set its resulting size (note the negative
// size used to distinguish between boundary/interior):
//
//if (!gregoryVertexFlags[vIndex + vOffset]) {
vTableEntry[0] = 0;
//} else {
int * ringDest = vTableEntry + 1,
ringSize = level->gatherQuadRegularRingAroundVertex(vIndex, ringDest);
for (int j = 0; j < ringSize; ++j) {
ringDest[j] += vOffset;
}
if (ringSize & 1) {
// boundary vertex : duplicate boundary vertex index
// and store negative valence.
ringSize++;
vTableEntry[ringSize]=vTableEntry[ringSize-1];
vTableEntry[0] = -ringSize/2;
} else {
vTableEntry[0] = ringSize/2;
}
//}
vTableOffset += SizePerVertex;
}
}
vOffset += level->getNumVertices();
}
}
} // end namespace Far
} // end namespace OPENSUBDIV_VERSION
} // end namespace OpenSubdiv

View File

@ -1,87 +0,0 @@
//
// Copyright 2015 Pixar
//
// 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.
//
#ifndef OPENSUBDIV3_FAR_END_CAP_LEGACY_GREGORY_PATCH_FACTORY_H
#define OPENSUBDIV3_FAR_END_CAP_LEGACY_GREGORY_PATCH_FACTORY_H
#include "../far/patchTable.h"
#include "../far/types.h"
#include "../vtr/level.h"
namespace OpenSubdiv {
namespace OPENSUBDIV_VERSION {
namespace Far {
class PatchTable;
class TopologyRefiner;
/// \brief This factory generates legacy (OpenSubdiv 2.x) gregory patches.
///
/// note: This is an internal use class in PatchTableFactory.
/// will be deprecated at some point.
///
class EndCapLegacyGregoryPatchFactory {
public:
EndCapLegacyGregoryPatchFactory(TopologyRefiner const & refiner);
/// \brief Returns end patch point indices for \a faceIndex of \a level.
/// Note that legacy gregory patch points exist in the max level
/// of subdivision in the topologyRefiner.
/// The returned indices are offset by levelVertOffset
///
/// @param level vtr refinement level
///
/// @param faceIndex vtr faceIndex at the level
///
/// @param levelVertOffset relative offset of patch vertex indices
///
/// @param fvarChannel face-varying channel index
///
ConstIndexArray GetPatchPoints(
Vtr::internal::Level const * level, Index faceIndex,
Vtr::internal::Level::VSpan const cornerSpans[],
int levelVertOffset, int fvarChannel = -1);
void Finalize(int maxValence,
PatchTable::QuadOffsetsTable *quadOffsetsTable,
PatchTable::VertexValenceTable *vertexValenceTable,
int fvarChannel = -1);
private:
TopologyRefiner const &_refiner;
std::vector<Index> _gregoryTopology;
std::vector<Index> _gregoryBoundaryTopology;
std::vector<Index> _gregoryFaceIndices;
std::vector<Index> _gregoryBoundaryFaceIndices;
};
} // end namespace Far
} // end namespace OPENSUBDIV_VERSION
} // end namespace OpenSubdiv
#endif // OPENSUBDIV3_FAR_END_CAP_LEGACY_GREGORY_PATCH_FACTORY_H

View File

@ -1,478 +0,0 @@
//
// Copyright 2013 Pixar
//
// 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 "../far/gregoryBasis.h"
#include "../far/error.h"
#include "../far/stencilTableFactory.h"
#include "../far/topologyRefiner.h"
#include "../vtr/stackBuffer.h"
#include <cassert>
#include <cmath>
#include <cstring>
#include <cstdio>
namespace OpenSubdiv {
namespace OPENSUBDIV_VERSION {
namespace Far {
inline float computeCoefficient(int valence) {
// precomputed coefficient table up to valence 29
static float efTable[] = {
0, 0, 0,
0.812816f, 0.500000f, 0.363644f, 0.287514f,
0.238688f, 0.204544f, 0.179229f, 0.159657f,
0.144042f, 0.131276f, 0.120632f, 0.111614f,
0.103872f, 0.09715f, 0.0912559f, 0.0860444f,
0.0814022f, 0.0772401f, 0.0734867f, 0.0700842f,
0.0669851f, 0.0641504f, 0.0615475f, 0.0591488f,
0.0569311f, 0.0548745f, 0.0529621f
};
assert(valence > 0);
if (valence < 30) return efTable[valence];
float t = 2.0f * float(M_PI) / float(valence);
return 1.0f / (valence * (cosf(t) + 5.0f +
sqrtf((cosf(t) + 9) * (cosf(t) + 1)))/16.0f);
}
//
// There is a long and unclear history to the details of the patch conversion here...
//
// The formulae for computing the Gregory patch points do not follow the more widely
// accepted work of Loop, Shaefer et al or Myles et al. The formulae for the limit
// points and tangents also ultimately need to be retrieved from Sdc::Scheme to
// ensure they conform, so future factoring of the formulae is still necessary.
//
// This implementation is in the process of iterative refactoring to adapt it for
// more general use. The method is currently divided into four stages -- some of
// which will eventually be moved externally and/or made into methods of their own:
//
// - gather complete topology information for all four corners of the patch
// - compute the vertex-points and intermediate values used below
// - compute the edge-points
// - compute the face-points (which depend on multiple edge-points)
//
GregoryBasis::ProtoBasis::ProtoBasis(
Vtr::internal::Level const & level, Index faceIndex,
Vtr::internal::Level::VSpan const cornerSpans[],
int levelVertOffset, int fvarChannel) {
//
// The first stage -- gather topology information for the entire patch:
//
// This stage is intentionally separated from any computation as the information
// gathered here for each corner vertex (one-ring, valence, etc.) will eventually
// be passed to this function in a more general and compact form. We have to
// be careful with face-varying channels to query the topology from the vertices
// of the level, while computing the patch basis from the points (fvar values).
//
Vtr::ConstIndexArray faceVerts = level.getFaceVertices(faceIndex);
Vtr::ConstIndexArray facePoints = (fvarChannel < 0)
? faceVerts
: level.getFaceFVarValues(faceIndex, fvarChannel);
// Should be use a "local" max valence here in future
// A discontinuous edge in the fvar topology can increase the valence by one.
int maxvalence = level.getMaxValence() + int(fvarChannel>=0);
Vtr::internal::StackBuffer<Index, 40> manifoldRings[4];
manifoldRings[0].SetSize(maxvalence*2);
manifoldRings[1].SetSize(maxvalence*2);
manifoldRings[2].SetSize(maxvalence*2);
manifoldRings[3].SetSize(maxvalence*2);
bool cornerBoundary[4];
int cornerValences[4];
int cornerNumFaces[4];
int cornerPatchFace[4];
float cornerFaceAngle[4];
// Sum the number of source vertices contributing to the patch, which define the
// size of the stencil for each "point" involved. We just want an upper bound
// here for now, so sum the vertices from the neighboring rings at each corner,
// but don't count the shared face points multiple times.
int stencilCapacity = 4;
for (int corner = 0; corner < 4; ++corner) {
// save for varying stencils
varyingIndex[corner] = faceVerts[corner] + levelVertOffset;
// Gather the (partial) one-ring around the corner vertex:
int ringSize = 0;
if (!cornerSpans[corner].isAssigned()) {
ringSize = level.gatherQuadRegularRingAroundVertex( faceVerts[corner],
manifoldRings[corner], fvarChannel);
} else {
ringSize = level.gatherQuadRegularPartialRingAroundVertex( faceVerts[corner],
cornerSpans[corner],
manifoldRings[corner], fvarChannel);
}
stencilCapacity += ringSize - 3;
// Cache topology information about the corner for ease of use later:
if (ringSize & 1) {
cornerBoundary[corner] = true;
cornerNumFaces[corner] = (ringSize - 1) / 2;
cornerValences[corner] = cornerNumFaces[corner] + 1;
cornerFaceAngle[corner] = float(M_PI) / float(cornerNumFaces[corner]);
// Necessary to pad the ring to even size for the f[] and r[] computations...
manifoldRings[corner][ringSize] = manifoldRings[corner][ringSize-1];
} else {
cornerBoundary[corner] = false;
cornerNumFaces[corner] = ringSize / 2;
cornerValences[corner] = cornerNumFaces[corner];
cornerFaceAngle[corner] = 2.0f * float(M_PI) / float(cornerNumFaces[corner]);
}
// Identify the patch-face within the ring of faces for the corner (which
// will later be identified externally and specified directly):
int nEdgeVerts = cornerValences[corner];
Index vNext = facePoints[(corner + 1) % 4];
Index vPrev = facePoints[(corner + 3) % 4];
cornerPatchFace[corner] = -1;
for (int i = 0; i < nEdgeVerts; ++i) {
int iPrev = (i + 1) % nEdgeVerts;
if ((manifoldRings[corner][2*i] == vNext) && (manifoldRings[corner][2*iPrev] == vPrev)) {
cornerPatchFace[corner] = i;
break;
}
}
assert(cornerPatchFace[corner] != -1);
}
//
// The first computation pass...
//
// Compute vertex-point (P) and intermediate values (f[] and r[]) for each corner
//
Point e0[4], e1[4];
Vtr::internal::StackBuffer<Point, 10> f(maxvalence);
Vtr::internal::StackBuffer<Point, 40> r(maxvalence*4);
for (int corner = 0; corner < 4; ++corner) {
Index vCorner = facePoints[corner];
int cornerValence = cornerValences[corner];
//
// Compute intermediate f[] and r[] vectors:
//
// The f[] are used to compute position and limit tangents for the interior case,
// which should eventually be computed directly with Sdc::Scheme methods -- so
// these f[] will ultimately be made obsolete.
//
// The r[] are only used in computing face points Fp and Fm, and of the r[] that
// are allocated and computed for every edge of every corner vertex, only two are
// used for each corner vertex. Aside from only computing the subset of r[] needed,
// these can be deferred to direct computation as part of Fp and Fm as they serve
// no other purpose.
//
// Note also that the computations of each f[] and r[] do not take into account
// boundaries and relies on padding of the rings to provide an indexable value in
// these cases.
//
for (int i = 0; i < cornerValence; ++i) {
int iPrev = (i+cornerValence-1)%cornerValence;
int iNext = (i+1)%cornerValence;
// Identify the vertex at the end of each edge along with the previous and
// next face- and edge-vertex in the ring:
Index vEdge = (manifoldRings[corner][2*i]);
Index vFaceNext = (manifoldRings[corner][2*i + 1]);
Index vEdgeNext = (manifoldRings[corner][2*iNext]);
Index vEdgePrev = (manifoldRings[corner][2*iPrev]);
Index vFacePrev = (manifoldRings[corner][2*iPrev + 1]);
float denom = 1.0f / (float(cornerValence) + 5.0f);
f[i].Clear(4);
f[i].AddWithWeight(vCorner, float(cornerValence) * denom);
f[i].AddWithWeight(vEdgeNext, 2.0f * denom);
f[i].AddWithWeight(vEdge, 2.0f * denom);
f[i].AddWithWeight(vFaceNext, denom);
int rid = corner * maxvalence + i;
r[rid].Clear(4);
r[rid].AddWithWeight(vEdgeNext, 1.0f / 3.0f);
r[rid].AddWithWeight(vEdgePrev, -1.0f / 3.0f);
r[rid].AddWithWeight(vFaceNext, 1.0f / 6.0f);
r[rid].AddWithWeight(vFacePrev, -1.0f / 6.0f);
}
//
// Compute the vertex point P[] and intermediate limit tangents e0 and e1:
//
// The limit tangents e0 and e1 should be computed from Sdc::Scheme methods.
// But these explicit limit tangents vectors are not needed as intermediate
// results as the Ep and Em can be computed more directly from the limit
// masks for the tangent vectors.
//
if (cornerSpans[corner]._sharp) {
P[corner].Clear(stencilCapacity);
P[corner].AddWithWeight(vCorner, 1.0f);
// Approximating these for now, pending future investigation...
e0[corner].Clear(stencilCapacity);
e0[corner].AddWithWeight(facePoints[corner], 2.0f / 3.0f);
e0[corner].AddWithWeight(facePoints[(corner+1)%4], 1.0f / 3.0f);
e1[corner].Clear(stencilCapacity);
e1[corner].AddWithWeight(facePoints[corner], 2.0f / 3.0f);
e1[corner].AddWithWeight(facePoints[(corner+3)%4], 1.0f / 3.0f);
} else if (! cornerBoundary[corner]) {
float theta = cornerFaceAngle[corner];
float posScale = 1.0f / float(cornerValence);
float tanScale = computeCoefficient(cornerValence);
P[corner].Clear(stencilCapacity);
e0[corner].Clear(stencilCapacity);
e1[corner].Clear(stencilCapacity);
for (int i=0; i<cornerValence; ++i) {
int iPrev = (i+cornerValence-1) % cornerValence;
P[corner].AddWithWeight(f[i], posScale);
float c0 = tanScale * 0.5f * cosf(float(i) * theta);
e0[corner].AddWithWeight(f[i], c0);
e0[corner].AddWithWeight(f[iPrev], c0);
float c1 = tanScale * 0.5f * sinf(float(i) * theta);
e1[corner].AddWithWeight(f[i], c1);
e1[corner].AddWithWeight(f[iPrev], c1);
}
} else {
Index vEdgeLeading = manifoldRings[corner][0];
Index vEdgeTrailing = manifoldRings[corner][2*cornerValence-1];
P[corner].Clear(stencilCapacity);
P[corner].AddWithWeight(vEdgeLeading, 1.0f / 6.0f);
P[corner].AddWithWeight(vEdgeTrailing, 1.0f / 6.0f);
P[corner].AddWithWeight(vCorner, 4.0f / 6.0f);
float k = float(cornerNumFaces[corner]);
float theta = cornerFaceAngle[corner];
float c = cosf(theta);
float s = sinf(theta);
float div3kc = 1.0f / (3.0f*k+c);
float gamma = -4.0f * s * div3kc;
float alpha_0k = -((1.0f+2.0f*c) * sqrtf(1.0f+c)) * div3kc / sqrtf(1.0f-c);
float beta_0 = s * div3kc;
Index vEdge = manifoldRings[corner][0];
Index vFace = manifoldRings[corner][1];
e0[corner].Clear(stencilCapacity);
e0[corner].AddWithWeight(vEdgeLeading, 1.0f / 6.0f);
e0[corner].AddWithWeight(vEdgeTrailing, -1.0f / 6.0f);
e1[corner].Clear(stencilCapacity);
e1[corner].AddWithWeight(vCorner, gamma);
e1[corner].AddWithWeight(vEdgeLeading, alpha_0k);
e1[corner].AddWithWeight(vFace, beta_0);
e1[corner].AddWithWeight(vEdgeTrailing, alpha_0k);
for (int i = 1; i < cornerValence - 1; ++i) {
float alpha = 4.0f * sinf(float(i)*theta) * div3kc;
float beta = (sinf(float(i)*theta) + sinf(float(i+1)*theta)) * div3kc;
vEdge = manifoldRings[corner][2*i + 0];
vFace = manifoldRings[corner][2*i + 1];
e1[corner].AddWithWeight(vEdge, alpha);
e1[corner].AddWithWeight(vFace, beta);
}
e1[corner] *= 1.0f / 3.0f;
}
}
//
// The second computation pass...
//
// Compute the edge points Ep and Em first. These can be computed local to the corner,
// unlike the face points, whose computation requires edge points from adjacent corners
// and so are computed in a final pass after all edge points are available.
//
// Consider merging this pass with the previous, now that face points have been deferred
// to a separate third pass.
//
// Note that computation of Ep and Em here use intermediate limit tangents e0 and e1 and
// compute rotations of these for Ep and Em. The masks for the limit tangents can be
// rotated topologically to avoid the explicit rotation here (at least for the interior
// case -- boundary case still warrants it until there is more flexibility in limit
// tangent masks orientation in Sdc)
//
for (int corner = 0; corner < 4; ++corner) {
// Identify edges in the ring pointing to the next and previous corner of the patch:
int iEdgeNext = cornerPatchFace[corner];
int iEdgePrev = (cornerPatchFace[corner] + 1) % cornerValences[corner];
float faceAngle = cornerFaceAngle[corner];
float faceAngleNext = faceAngle * float(iEdgeNext);
float faceAnglePrev = faceAngle * float(iEdgePrev);
if (cornerSpans[corner]._sharp) {
Ep[corner] = e0[corner];
Em[corner] = e1[corner];
} else if (! cornerBoundary[corner]) {
Ep[corner] = P[corner];
Ep[corner].AddWithWeight(e0[corner], cosf(faceAngleNext));
Ep[corner].AddWithWeight(e1[corner], sinf(faceAngleNext));
Em[corner] = P[corner];
Em[corner].AddWithWeight(e0[corner], cosf(faceAnglePrev));
Em[corner].AddWithWeight(e1[corner], sinf(faceAnglePrev));
} else if (cornerNumFaces[corner] > 1) {
Ep[corner] = P[corner];
Ep[corner].AddWithWeight(e0[corner], cosf(faceAngleNext));
Ep[corner].AddWithWeight(e1[corner], sinf(faceAngleNext));
Em[corner] = P[corner];
Em[corner].AddWithWeight(e0[corner], cosf(faceAnglePrev));
Em[corner].AddWithWeight(e1[corner], sinf(faceAnglePrev));
} else {
// Edge points are on the control polygon here (with P midway between):
Ep[corner].Clear(stencilCapacity);
Ep[corner].AddWithWeight(facePoints[corner], 2.0f / 3.0f);
Ep[corner].AddWithWeight(facePoints[(corner+1)%4], 1.0f / 3.0f);
Em[corner].Clear(stencilCapacity);
Em[corner].AddWithWeight(facePoints[corner], 2.0f / 3.0f);
Em[corner].AddWithWeight(facePoints[(corner+3)%4], 1.0f / 3.0f);
}
}
//
// The third pass...
//
// Compute the face points Fp and Fm in terms of the vertex (P) and edge points (Ep and
// Em) previously computed.
//
for (int corner = 0; corner < 4; ++corner) {
int cornerNext = (corner+1) % 4;
int cornerOpp = (corner+2) % 4;
int cornerPrev = (corner+3) % 4;
// Identify edges in the ring pointing to the next and previous corner of the
// patch and the intermediate r[] associated with each:
Point const * rp = &r[corner*maxvalence];
Point const & rEdgeNext = rp[cornerPatchFace[corner]];
Point const & rEdgePrev = rp[(cornerPatchFace[corner] + 1) % cornerValences[corner]];
// Coefficients to arrange the face points for tangent continuity across edges:
float cosCorner = cosf(cornerFaceAngle[corner]);
float cosPrev = cosf(cornerFaceAngle[cornerPrev]);
float cosNext = cosf(cornerFaceAngle[cornerNext]);
float s1 = 3.0f - 2.0f * cosCorner - cosNext;
float s2 = 2.0f * cosCorner;
float s3 = 3.0f - 2.0f * cosCorner - cosPrev;
if (! cornerBoundary[corner]) {
Fp[corner].Clear(stencilCapacity);
Fp[corner].AddWithWeight(P[corner], cosNext / 3.0f);
Fp[corner].AddWithWeight(Ep[corner], s1 / 3.0f);
Fp[corner].AddWithWeight(Em[cornerNext], s2 / 3.0f);
Fp[corner].AddWithWeight(rEdgeNext, 1.0f / 3.0f);
Fm[corner].Clear(stencilCapacity);
Fm[corner].AddWithWeight(P[corner], cosPrev / 3.0f);
Fm[corner].AddWithWeight(Em[corner], s3 / 3.0f);
Fm[corner].AddWithWeight(Ep[cornerPrev], s2 / 3.0f);
Fm[corner].AddWithWeight(rEdgePrev, -1.0f / 3.0f);
} else if (cornerNumFaces[corner] > 1) {
Fp[corner].Clear(stencilCapacity);
Fp[corner].AddWithWeight(P[corner], cosNext / 3.0f);
Fp[corner].AddWithWeight(Ep[corner], s1 / 3.0f);
Fp[corner].AddWithWeight(Em[cornerNext], s2 / 3.0f);
Fp[corner].AddWithWeight(rEdgeNext, 1.0f / 3.0f);
Fm[corner].Clear(stencilCapacity);
Fm[corner].AddWithWeight(P[corner], cosPrev / 3.0f);
Fm[corner].AddWithWeight(Em[corner], s3 / 3.0f);
Fm[corner].AddWithWeight(Ep[cornerPrev], s2 / 3.0f);
Fm[corner].AddWithWeight(rEdgePrev, -1.0f / 3.0f);
if (cornerBoundary[cornerPrev]) {
Fp[corner].Clear(stencilCapacity);
Fp[corner].AddWithWeight(P[corner], cosNext / 3.0f);
Fp[corner].AddWithWeight(Ep[corner], s1 / 3.0f);
Fp[corner].AddWithWeight(Em[cornerNext], s2 / 3.0f);
Fp[corner].AddWithWeight(rEdgeNext, 1.0f / 3.0f);
Fm[corner] = Fp[corner];
} else if (cornerBoundary[cornerNext]) {
Fm[corner].Clear(stencilCapacity);
Fm[corner].AddWithWeight(P[corner], cosPrev / 3.0f);
Fm[corner].AddWithWeight(Em[corner], s3 / 3.0f);
Fm[corner].AddWithWeight(Ep[cornerPrev], s2 / 3.0f);
Fm[corner].AddWithWeight(rEdgePrev, -1.0f / 3.0f);
Fp[corner] = Fm[corner];
}
} else {
Fp[corner].Clear(stencilCapacity);
Fp[corner].AddWithWeight(facePoints[corner], 4.0f / 9.0f);
Fp[corner].AddWithWeight(facePoints[cornerOpp], 1.0f / 9.0f);
Fp[corner].AddWithWeight(facePoints[cornerNext], 2.0f / 9.0f);
Fp[corner].AddWithWeight(facePoints[cornerPrev], 2.0f / 9.0f);
Fm[corner] = Fp[corner];
}
}
//
// Offset stencil indices...
//
// These stencils are currently created relative to the level and have levelVertOffset
// to make them absolute indices. But we will be localizing these to the patch itself
// and so any association/mapping with vertices or face-varying values in a Level will
// be handled externally.
//
for (int corner = 0; corner < 4; ++corner) {
P[corner].OffsetIndices(levelVertOffset);
Ep[corner].OffsetIndices(levelVertOffset);
Em[corner].OffsetIndices(levelVertOffset);
Fp[corner].OffsetIndices(levelVertOffset);
Fm[corner].OffsetIndices(levelVertOffset);
}
}
} // end namespace Far
} // end namespace OPENSUBDIV_VERSION
} // end namespace OpenSubdiv

View File

@ -1,226 +0,0 @@
//
// Copyright 2013 Pixar
//
// 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.
//
#ifndef OPENSUBDIV3_FAR_GREGORY_BASIS_H
#define OPENSUBDIV3_FAR_GREGORY_BASIS_H
#include "../vtr/level.h"
#include "../vtr/stackBuffer.h"
#include "../far/types.h"
#include "../far/stencilTable.h"
#include <cstring>
namespace OpenSubdiv {
namespace OPENSUBDIV_VERSION {
namespace Far {
class TopologyRefiner;
/// \brief Container for utilities relating to Gregory patch construction
///
/// The GregoryBasis class has been reduced to a simple container of subclasses and
/// utilities (static methods) used by the EndCap Factories. It remains a class as
/// its methods to support stencil construction currently require it to be a friend
/// of the StencilTable class.
///
class GregoryBasis {
public:
//
// Basis point
//
// Implements arithmetic operators to manipulate the influence of the
// 1-ring control vertices supporting the patch basis
//
class Point {
public:
// 40 means up to valence=10 is on stack
static const int RESERVED_STENCIL_SIZE = 40;
Point(int stencilCapacity=RESERVED_STENCIL_SIZE) : _size(0) {
_stencils.SetSize(stencilCapacity);
}
Point(Point const & other) {
_stencils.SetSize(other._stencils.GetSize());
*this = other;
}
int GetSize() const {
return _size;
}
int GetCapacity() const {
return _stencils.GetSize();
}
void Clear(int capacity) {
_size = 0;
if ((int)_stencils.GetSize() < capacity) {
_stencils.SetSize(capacity);
}
}
void AddWithWeight(Vtr::Index idx, float weight) {
for (int i = 0; i < _size; ++i) {
if (_stencils[i].index == idx) {
_stencils[i].weight += weight;
return;
}
}
assert(_size < (int)_stencils.GetSize());
_stencils[_size].index = idx;
_stencils[_size].weight = weight;
++_size;
}
void AddWithWeight(Point const &src, float weight) {
for (int i = 0; i < src._size; ++i) {
AddWithWeight(src._stencils[i].index,
src._stencils[i].weight * weight);
}
}
Point & operator = (Point const & other) {
Clear(other.GetCapacity());
_size = other._size;
assert(_size <= (int)_stencils.GetSize());
for (int i = 0; i < _size; ++i) {
_stencils[i] = other._stencils[i];
}
return *this;
}
Point & operator *= (float f) {
for (int i=0; i<_size; ++i) {
_stencils[i].weight *= f;
}
return *this;
}
void OffsetIndices(Vtr::Index offset) {
for (int i=0; i<_size; ++i) {
_stencils[i].index += offset;
}
}
void Copy(int ** size, Vtr::Index ** indices, float ** weights) const {
for (int i = 0; i < _size; ++i) {
**indices = _stencils[i].index;
**weights = _stencils[i].weight;
++(*indices);
++(*weights);
}
**size = _size;
++(*size);
}
Vtr::Index GetStencilIndex(int index) const {
return _stencils[index].index;
}
float GetStencilWeight(int index) const {
return _stencils[index].weight;
}
private:
int _size;
struct Stencil {
Vtr::Index index;
float weight;
};
Vtr::internal::StackBuffer<Stencil, RESERVED_STENCIL_SIZE> _stencils;
};
//
// ProtoBasis
//
// Given a Vtr::Level and a face index, gathers all the influences of the
// 1-ring that supports the 20 CVs of a Gregory patch basis.
//
struct ProtoBasis {
ProtoBasis(Vtr::internal::Level const & level,
Vtr::Index faceIndex,
Vtr::internal::Level::VSpan const cornerSpans[],
int levelVertOffset,
int fvarChannel);
// Control Vertices based on :
// "Approximating Subdivision Surfaces with Gregory Patches for Hardware
// Tessellation" Loop, Schaefer, Ni, Castano (ACM ToG Siggraph Asia
// 2009)
//
// P3 e3- e2+ P2
// O--------O--------O--------O
// | | | |
// | | | |
// | | f3- | f2+ |
// | O O |
// e3+ O------O O------O e2-
// | f3+ f2- |
// | |
// | |
// | f0- f1+ |
// e0- O------O O------O e1+
// | O O |
// | | f0+ | f1- |
// | | | |
// | | | |
// O--------O--------O--------O
// P0 e0+ e1- P1
//
Point P[4], Ep[4], Em[4], Fp[4], Fm[4];
// for varying interpolation
Vtr::Index varyingIndex[4];
};
// for basis point stencil
static void AppendToStencilTable(GregoryBasis::Point const &p,
StencilTable *table) {
int size = p.GetSize();
table->_sizes.push_back(size);
for (int i = 0; i < size; ++i) {
table->_indices.push_back(p.GetStencilIndex(i));
table->_weights.push_back(p.GetStencilWeight(i));
}
}
// for varying stencil (just copy)
static void AppendToStencilTable(int index, StencilTable *table) {
table->_sizes.push_back(1);
table->_indices.push_back(index);
table->_weights.push_back(1.f);
}
};
} // end namespace Far
} // end namespace OPENSUBDIV_VERSION
} // end namespace OpenSubdiv
#endif /* OPENSUBDIV3_FAR_GREGORY_BASIS_H */

View File

@ -0,0 +1,92 @@
//
// Copyright 2018 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 "../far/loopPatchBuilder.h"
#include <cassert>
#include <cstdio>
namespace OpenSubdiv {
namespace OPENSUBDIV_VERSION {
using Vtr::internal::Level;
using Vtr::internal::FVarLevel;
using Vtr::internal::Refinement;
namespace Far {
namespace {
//
// The patch type associated with each basis for Loop -- quickly indexed
// from an array.
//
PatchDescriptor::Type patchTypeFromBasisArray[] = {
PatchDescriptor::NON_PATCH, // undefined
PatchDescriptor::LOOP, // regular
PatchDescriptor::NON_PATCH, // Gregory
PatchDescriptor::TRIANGLES, // linear
PatchDescriptor::NON_PATCH }; // Bezier -- for future use
};
LoopPatchBuilder::LoopPatchBuilder(
TopologyRefiner const& refiner, Options const& options) :
PatchBuilder(refiner, options) {
_regPatchType = patchTypeFromBasisArray[_options.regBasisType];
_irregPatchType = (_options.irregBasisType == BASIS_UNSPECIFIED)
? _regPatchType
: patchTypeFromBasisArray[_options.irregBasisType];
_nativePatchType = PatchDescriptor::LOOP;
_linearPatchType = PatchDescriptor::TRIANGLES;
}
LoopPatchBuilder::~LoopPatchBuilder() {
}
PatchDescriptor::Type
LoopPatchBuilder::patchTypeFromBasis(BasisType basis) const {
return patchTypeFromBasisArray[(int)basis];
}
int
LoopPatchBuilder::convertToPatchType(SourcePatch const & sourcePatch,
PatchDescriptor::Type patchType,
SparseMatrix<float> & matrix) const {
assert("Non-linear patches for Loop not yet supported" == 0);
// For suppressing warnings until implemented...
if (sourcePatch.GetNumSourcePoints() == 0) return -1;
if (patchType == PatchDescriptor::NON_PATCH) return -1;
if (matrix.GetNumRows() <= 0) return -1;
return -1;
}
} // end namespace Far
} // end namespace OPENSUBDIV_VERSION
} // end namespace OpenSubdiv

View File

@ -0,0 +1,65 @@
//
// Copyright 2017 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.
//
#ifndef OPENSUBDIV3_FAR_LOOP_PATCH_BUILDER_H
#define OPENSUBDIV3_FAR_LOOP_PATCH_BUILDER_H
#include "../version.h"
#include "../far/patchBuilder.h"
namespace OpenSubdiv {
namespace OPENSUBDIV_VERSION {
namespace Far {
//
// LoopPatchBuilder
//
// Declaration of PatchBuilder subclass supporting Sdc::SCHEME_LOOP.
// Required virtual methods are included, along with any customizations
// local to their implementation.
//
class LoopPatchBuilder : public PatchBuilder {
public:
LoopPatchBuilder(TopologyRefiner const& refiner, Options const& options);
virtual ~LoopPatchBuilder();
protected:
virtual PatchDescriptor::Type patchTypeFromBasis(BasisType basis) const;
virtual int convertToPatchType(SourcePatch const & sourcePatch,
PatchDescriptor::Type patchType,
SparseMatrix<float> & matrix) const;
};
} // end namespace Far
} // end namespace OPENSUBDIV_VERSION
using namespace OPENSUBDIV_VERSION;
} // end namespace OpenSubdiv
#endif /* OPENSUBDIV3_FAR_LOOP_PATCH_BUILDER_H */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,321 @@
//
// Copyright 2017 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.
//
#ifndef OPENSUBDIV3_FAR_PATCH_BUILDER_H
#define OPENSUBDIV3_FAR_PATCH_BUILDER_H
#include "../version.h"
#include "../sdc/types.h"
#include "../far/types.h"
#include "../far/topologyRefiner.h"
#include "../far/patchDescriptor.h"
#include "../far/patchParam.h"
#include "../far/ptexIndices.h"
#include "../far/sparseMatrix.h"
namespace OpenSubdiv {
namespace OPENSUBDIV_VERSION {
namespace Far {
//
// SourcePatch
//
// This is a local utility class that captures the full local topology of an
// arbitrarily irregular patch, i.e. a patch which may have one or all corners
// irregular. Given the topology at each corner the entire collection of
// points involved is identified and oriented consistently.
//
// Note (barfowl):
// This was originally a class internal to PatchBuilder, but there is some
// redundancy between it and the Level::VSpan used more publicly to identify
// irregular corner topology. Replacing VSpan with SourcePatch is now under
// consideration, and doing so will impact its public/private interface (which
// was left public to give PatchBuilder access).
// A simpler constructor to initialize an instance given a set of Corners
// would also be preferable if made more public (i.e. public for use within
// the library, not exported to clients) -- eliminating the need for the
// explicit initialization and required call to the Finalize() method that
// the PatchBuilder currently performs internally.
//
class SourcePatch {
public:
struct Corner {
Corner() { std::memset(this, 0, sizeof(Corner)); }
LocalIndex _numFaces; // valence of corner vertex
LocalIndex _patchFace; // location of patch within incident faces
unsigned short _boundary : 1;
unsigned short _sharp : 1;
unsigned short _dart : 1;
// For internal bookkeeping -- consider hiding or moving elsewhere
unsigned short _sharesWithPrev : 1;
unsigned short _sharesWithNext : 1;
unsigned short _val2Interior : 1;
unsigned short _val2Adjacent : 1;
};
public:
SourcePatch() { std::memset(this, sizeof(SourcePatch), 0); }
~SourcePatch() { }
void Finalize(); // To be called after all Corners have been initialized
int GetNumSourcePoints() const { return _numSourcePoints; }
int GetMaxValence() const { return _maxValence; }
int GetMaxRingSize() const { return _maxRingSize; }
int GetCornerRingSize(int corner) const { return _ringSizes[corner]; }
int GetCornerRingPoints(int corner, int points[]) const;
void Print(const char * label, const Index * patchPoints = 0);
// public/private access needs to be reviewed when/if used more publicly
//private:
public:
// The SourcePatch is fully defined by its Corner members
Corner _corners[4];
// Additional members (derived from Corners) to help assemble corner rings:
int _numSourcePoints;
int _maxValence;
int _maxRingSize;
int _ringSizes[4];
int _localRingSizes[4];
int _localRingOffsets[4];
};
//
// PatchBuilder
//
// This is the main class to assist the identification of limit surface
// patches for assembly into other, larger datatypes. The PatchBuilder takes
// a const reference to a TopologyRefiner and is intended to support both
// adaptive and uniformly refined hierarchies.
//
// PatchBuilder is an abstract base class with a subclass derived to support
// each subdivision scheme. Only two (pure) virtual methods are required
// (other than the required destructor):
//
// - determine the patch type for a subdivision scheme given a more
// general basis specification (e.g. Bezier, Gregory, Linear, etc)
//
// - convert the vertices in the subdivision hierarchy into points of a
// specified patch type, using computations specific to that scheme
//
// The base class handles the more general topological analysis that
// determines the nature of a patch associated with each face -- providing
// both queries to the client, along with more involved methods to extract
// or convert data associated with the patches. There is no concrete "Patch"
// class to which all clients would be required to conform. The queries and
// data returned are provided for clients to assemble into patches or other
// aggregates as they see fit.
//
// This is intended as an internal/private class for use within the library
// for now -- possibly to be exported for use by clients when/if its
// interface is appropriate and stable.
//
class PatchBuilder {
public:
//
// A PatchBuilder is constructed given a patch "basis" rather than a
// "type" to use with the subdivision scheme involved. The relevant
// explicit patch types will be determined from the basis and scheme:
//
enum BasisType {
BASIS_UNSPECIFIED,
BASIS_REGULAR,
BASIS_GREGORY,
BASIS_LINEAR,
BASIS_BEZIER // to be supported in future
};
//
// Required Options specify a patch basis to use for both regular and
// irregular patches -- sparing the client the need to repeatedly
// specify these for each face considered. Other options are included
// to support legacy approximations:
//
struct Options {
Options() : regBasisType(BASIS_UNSPECIFIED),
irregBasisType(BASIS_UNSPECIFIED),
fillMissingBoundaryPoints(false),
approxInfSharpWithSmooth(false),
approxSmoothCornerWithSharp(false) { }
BasisType regBasisType;
BasisType irregBasisType;
bool fillMissingBoundaryPoints;
bool approxInfSharpWithSmooth;
bool approxSmoothCornerWithSharp;
};
public:
static PatchBuilder* Create(TopologyRefiner const& refiner,
Options const& options);
virtual ~PatchBuilder();
//
// High-level queries related to the subdivision scheme of the refiner, the
// patch types associated with it and those chosen to represent its faces:
//
int GetRegularFaceSize() const { return _schemeRegFaceSize; }
BasisType GetRegularBasisType() const { return _options.regBasisType; }
BasisType GetIrregularBasisType() const { return _options.irregBasisType; }
PatchDescriptor::Type GetRegularPatchType() const { return _regPatchType; }
PatchDescriptor::Type GetIrregularPatchType() const { return _irregPatchType; }
PatchDescriptor::Type GetNativePatchType() const { return _nativePatchType; }
PatchDescriptor::Type GetLinearPatchType() const { return _linearPatchType; }
//
// Face-level queries to determine presence of patches:
//
bool IsFaceAPatch(int level, Index face) const;
bool IsFaceALeaf(int level, Index face) const;
//
// Patch-level topological queries:
//
bool IsPatchRegular(int level, Index face, int fvc = -1) const;
int GetRegularPatchBoundaryMask(int level, Index face, int fvc = -1) const;
void GetIrregularPatchCornerSpans(int level, Index face,
Vtr::internal::Level::VSpan cornerSpans[4], int fvc = -1) const;
bool DoesFaceVaryingPatchMatch(int level, Index face, int fvc) const {
return _refiner.getLevel(level).doesFaceFVarTopologyMatch(face, fvc);
}
//
// Patch-level control point retrieval and methods for converting source
// points to a set of local points in a different basis
//
int GetRegularPatchPoints(int level, Index face,
int regBoundaryMask, // compute internally when < 0
Index patchPoints[],
int fvc = -1) const;
int GetIrregularPatchConversionMatrix(int level, Index face,
Vtr::internal::Level::VSpan const cornerSpans[],
SparseMatrix<float> & matrix) const;
int GetIrregularPatchSourcePoints(int level, Index face,
Vtr::internal::Level::VSpan const cornerSpans[],
Index sourcePoints[],
int fvc = -1) const;
//
// Queries related to "single-crease" patches -- currently a subset of
// regular interior patches:
//
struct SingleCreaseInfo {
int creaseEdgeInFace;
float creaseSharpness;
};
bool IsRegularSingleCreasePatch(int level, Index face,
SingleCreaseInfo & info) const;
//
// Computing the PatchParam -- note the regrettable dependency on
// PtexIndices but PatchParam is essentially tied to it indefinitely.
// Better to pass it in than have the PatchBuilder build its own
// PtexIndices.
//
// Consider creating a PatchParamFactory which can manage the PtexIndices
// along with this method. It will then be able to generate additional
// data to accelerate these computations.
//
PatchParam ComputePatchParam(int level, Index face,
PtexIndices const& ptexIndices,
int boundaryMask = 0, bool computeTransitionMask = false) const;
protected:
PatchBuilder(TopologyRefiner const& refiner, Options const& options);
// Internal methods supporting topology queries:
bool isPatchSmoothCorner(int level, Index face, int fvc) const;
int getRegularFacePoints(int level, Index face,
Index patchPoints[], int fvc) const;
int getQuadRegularPatchPoints(int level, Index face,
int regBoundaryMask, Index patchPoints[], int fvc) const;
int getTriRegularPatchPoints(int level, Index face,
int regBoundaryMask, Index patchPoints[], int fvc) const;
// Internal methods using the SourcePatch:
int assembleIrregularSourcePatch(int level, Index face,
Vtr::internal::Level::VSpan const cornerSpans[],
SourcePatch & sourcePatch) const;
int gatherIrregularSourcePoints(int level, Index face,
Vtr::internal::Level::VSpan const cornerSpans[],
SourcePatch & sourcePatch,
Index patchPoints[], int fvc) const;
// Internal methods asserting features not yet completed:
void assertTriangularPatchesNotYetSupportedHere() const;
protected:
//
// Virtual methods to be provided by subclass for each scheme:
//
virtual PatchDescriptor::Type patchTypeFromBasis(BasisType basis) const = 0;
virtual int convertToPatchType(SourcePatch const & sourcePatch,
PatchDescriptor::Type patchType,
SparseMatrix<float> & matrix) const = 0;
protected:
TopologyRefiner const& _refiner;
Options const _options;
Sdc::SchemeType _schemeType;
int _schemeRegFaceSize;
int _schemeNeighborhood;
PatchDescriptor::Type _regPatchType;
PatchDescriptor::Type _irregPatchType;
PatchDescriptor::Type _nativePatchType;
PatchDescriptor::Type _linearPatchType;
};
} // end namespace Far
} // end namespace OPENSUBDIV_VERSION
using namespace OPENSUBDIV_VERSION;
} // end namespace OpenSubdiv
#endif /* OPENSUBDIV3_FAR_PATCH_BUILDER_H */

View File

@ -452,7 +452,7 @@ public:
protected:
friend class PatchTableFactory;
friend class PatchTableBuilder;
// Factory constructor
PatchTable(int maxvalence);

File diff suppressed because it is too large Load Diff

View File

@ -35,7 +35,6 @@ namespace OPENSUBDIV_VERSION {
namespace Far {
// Forward declarations (for internal implementation purposes):
class PtexIndices;
class TopologyRefiner;
/// \brief Factory for constructing a PatchTable from a TopologyRefiner
@ -127,40 +126,6 @@ public:
static PatchTable * Create(TopologyRefiner const & refiner,
Options options=Options());
private:
//
// Private helper structures
//
struct BuilderContext;
//
// Methods for allocating and managing the patch table data arrays:
//
static PatchTable * createUniform(TopologyRefiner const & refiner,
Options options);
static PatchTable * createAdaptive(TopologyRefiner const & refiner,
Options options);
//
// High-level methods for identifying and populating patches associated with faces:
//
static void identifyAdaptivePatches(BuilderContext & context);
static void populateAdaptivePatches(BuilderContext & context,
PatchTable * table);
static void allocateVertexTables(BuilderContext const & context,
PatchTable * table);
static void allocateFVarChannels(BuilderContext const & context,
PatchTable * table);
static PatchParam computePatchParam(BuilderContext const & context,
int level, int face,
int boundaryMask, int transitionMask);
public:
// PatchFaceTag
// This simple struct was previously used within the factory to take inventory of

View File

@ -0,0 +1,183 @@
//
// Copyright 2017 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.
//
#ifndef OPENSUBDIV3_FAR_SPARSE_MATRIX_H
#define OPENSUBDIV3_FAR_SPARSE_MATRIX_H
#include "../version.h"
#include "../vtr/array.h"
namespace OpenSubdiv {
namespace OPENSUBDIV_VERSION {
namespace Far {
//
// SparseMatrix
//
// The SparseMatrix class is used by the PatchBuilder to store coefficients
// for a set of patch points derived from some other set of points -- usually
// the refined points in a subdivision level. The compressed sparse row
// format (CSR) is used as it provides us with stencils for points that
// correspond to rows and so can be more directly and efficiently copied.
//
// It has potential for other uses and so may eventually warrant a seperate
// header file of its own. For now, in keeping with the trend of exposing
// classes only where used, it is defined with the PatchBuilder.
//
// We may also want to explore the possibility of being able to assign
// static buffers as members here -- allowing common matrices to be set
// directly rather than repeatedly replicated.
//
template <typename REAL>
class SparseMatrix {
public:
typedef int column_type;
typedef REAL element_type;
public:
// Declaration and access methods:
SparseMatrix() : _numRows(0), _numColumns(0) { }
int GetNumRows() const { return _numRows; }
int GetNumColumns() const { return _numColumns; }
int GetNumElements() const { return _numElements; }
int GetCapacity() const;
int GetRowSize(int rowIndex) const {
return _rowOffsets[rowIndex + 1] - _rowOffsets[rowIndex];
}
Vtr::ConstArray<column_type> GetRowColumns( int rowIndex) const {
return Vtr::ConstArray<column_type>(&_columns[_rowOffsets[rowIndex]],
GetRowSize(rowIndex));
}
Vtr::ConstArray<element_type> GetRowElements(int rowIndex) const {
return Vtr::ConstArray<element_type>(&_elements[_rowOffsets[rowIndex]],
GetRowSize(rowIndex));
}
Vtr::ConstArray<column_type> GetColumns() const {
return Vtr::ConstArray<column_type>(&_columns[0], GetNumElements());
}
Vtr::ConstArray<element_type> GetElements() const {
return Vtr::ConstArray<element_type>(&_elements[0], GetNumElements());
}
public:
// Modification methods
void Resize(int numRows, int numColumns, int numNonZeroEntriesToReserve);
void Copy(SparseMatrix const & srcMatrix);
void SetRowSize(int rowIndex, int size);
Vtr::Array<column_type> SetRowColumns( int rowIndex) {
return Vtr::Array<column_type>(&_columns[_rowOffsets[rowIndex]],
GetRowSize(rowIndex));
}
Vtr::Array<element_type> SetRowElements(int rowIndex) {
return Vtr::Array<element_type>(&_elements[_rowOffsets[rowIndex]],
GetRowSize(rowIndex));
}
private:
// Simple dimensions:
int _numRows;
int _numColumns;
int _numElements;
std::vector<int> _rowOffsets; // remember one more entry here than rows
// XXXX (barfowl) - Note that the use of std::vector for the columns and
// element arrays was causing performance issues in the incremental
// resizing of consecutive rows, so we've been exploring alternatives...
std::vector<column_type> _columns;
std::vector<element_type> _elements;
};
template <typename REAL>
inline int
SparseMatrix<REAL>::GetCapacity() const {
return (int) _elements.capacity();
}
template <typename REAL>
inline void
SparseMatrix<REAL>::Resize(int numRows, int numCols, int numElementsToReserve) {
_numRows = numRows;
_numColumns = numCols;
_numElements = 0;
_rowOffsets.resize(0);
_rowOffsets.resize(_numRows + 1, -1);
_rowOffsets[0] = 0;
if (numElementsToReserve > GetCapacity()) {
_columns.resize(numElementsToReserve);
_elements.resize(numElementsToReserve);
}
}
template <typename REAL>
inline void
SparseMatrix<REAL>::SetRowSize(int rowIndex, int rowSize) {
assert(_rowOffsets[rowIndex] == _numElements);
int & newVectorSize = _rowOffsets[rowIndex + 1];
newVectorSize = _rowOffsets[rowIndex] + rowSize;
_numElements = newVectorSize;
if (newVectorSize > GetCapacity()) {
_columns.resize(newVectorSize);
_elements.resize(newVectorSize);
}
}
template <typename REAL>
inline void
SparseMatrix<REAL>::Copy(SparseMatrix const & src) {
_numRows = src._numRows;
_numColumns = src._numColumns;
_rowOffsets = src._rowOffsets;
_numElements = src._numElements;
_columns = src._elements;
_elements = src._elements;
}
} // end namespace Far
} // end namespace OPENSUBDIV_VERSION
using namespace OPENSUBDIV_VERSION;
} // end namespace OpenSubdiv
#endif /* OPENSUBDIV3_FAR_SPARSE_MATRIX_H */

View File

@ -221,12 +221,7 @@ protected:
{ }
friend class StencilTableFactory;
friend class PatchTableFactory;
// XXX: temporarily, GregoryBasis class will go away.
friend class GregoryBasis;
// XXX: needed to call reserve().
friend class EndCapBSplineBasisPatchFactory;
friend class EndCapGregoryBasisPatchFactory;
friend class PatchTableBuilder;
int _numControlVertices; // number of control vertices

View File

@ -24,7 +24,6 @@
#include "../far/stencilTableFactory.h"
#include "../far/stencilBuilder.h"
#include "../far/endCapGregoryBasisPatchFactory.h"
#include "../far/patchTable.h"
#include "../far/patchTableFactory.h"
#include "../far/patchMap.h"

View File

@ -386,10 +386,16 @@ TopologyRefiner::RefineAdaptive(AdaptiveOptions options) {
lessFeaturesMask.ReduceFeatures(options);
}
//
// Features are not relevant to schemes whose influence does not extend beyond the
// face -- only irregular faces matter in such cases so clear all other features.
// If face-varying channels are considered, make sure non-linear channels are present
// and turn off consideration if none present:
if (moreFeaturesMask.selectFVarFeatures) {
// Ignore consideration of face-varying channels if none present are non-linear:
//
if (Sdc::SchemeTypeTraits::GetLocalNeighborhoodSize(_subdivType) == 0) {
moreFeaturesMask.Clear();
lessFeaturesMask.Clear();
} else if (moreFeaturesMask.selectFVarFeatures) {
bool nonLinearChannelsPresent = false;
for (int channel = 0; channel < _levels[0]->getNumFVarChannels(); ++channel) {
nonLinearChannelsPresent |= !_levels[0]->getFVarLevel(channel).isLinear();
@ -532,6 +538,8 @@ namespace {
doesFaceHaveFeatures(Vtr::internal::Level const& level, Index face,
internal::FeatureMask const & featureMask) {
if (featureMask.IsEmpty()) return false;
using Vtr::internal::Level;
ConstIndexArray fVerts = level.getFaceVertices(face);
@ -663,13 +671,15 @@ void
TopologyRefiner::selectFeatureAdaptiveComponents(Vtr::internal::SparseSelector& selector,
internal::FeatureMask const & featureMask) {
if (featureMask.IsEmpty()) return;
Vtr::internal::Level const& level = selector.getRefinement().parent();
int levelDepth = level.getDepth();
bool selectIrregularFaces = (levelDepth == 0);
if (featureMask.IsEmpty() && !selectIrregularFaces) return;
int numFVarChannels = featureMask.selectFVarFeatures ? level.getNumFVarChannels() : 0;
int regularFaceSize = selector.getRefinement().getRegularFaceSize();
int neighborhood = Sdc::SchemeTypeTraits::GetLocalNeighborhoodSize(_subdivType);
//
// Inspect each face and the properties tagged at all of its corners:
@ -689,14 +699,18 @@ TopologyRefiner::selectFeatureAdaptiveComponents(Vtr::internal::SparseSelector&
// where other faces are selected as a side effect and somewhat undermines the
// whole intent of the per-face traversal.
//
if (levelDepth == 0) {
if (selectIrregularFaces) {
Vtr::ConstIndexArray faceVerts = level.getFaceVertices(face);
if (faceVerts.size() != regularFaceSize) {
for (int i = 0; i < faceVerts.size(); ++i) {
ConstIndexArray fVertFaces = level.getVertexFaces(faceVerts[i]);
for (int j = 0; j < fVertFaces.size(); ++j) {
selector.selectFace(fVertFaces[j]);
if (neighborhood == 0) {
selector.selectFace(face);
} else {
for (int i = 0; i < faceVerts.size(); ++i) {
ConstIndexArray fVertFaces = level.getVertexFaces(faceVerts[i]);
for (int j = 0; j < fVertFaces.size(); ++j) {
selector.selectFace(fVertFaces[j]);
}
}
}
continue;

View File

@ -209,9 +209,8 @@ protected:
template <class MESH>
friend class TopologyRefinerFactory;
friend class TopologyRefinerFactoryBase;
friend class PatchTableFactory;
friend class EndCapGregoryBasisPatchFactory;
friend class EndCapLegacyGregoryPatchFactory;
friend class PatchTableBuilder;
friend class PatchBuilder;
friend class PtexIndices;
friend class PrimvarRefiner;

View File

@ -46,7 +46,7 @@ namespace internal {
// loop with a new size, but resizing in this case reinitializes all elements.
//
template <typename TYPE, unsigned int SIZE>
template <typename TYPE, unsigned int SIZE, bool POD_TYPE = false>
class StackBuffer
{
public:
@ -74,8 +74,8 @@ public:
private:
// Non-copyable:
StackBuffer(const StackBuffer<TYPE,SIZE> &) { }
StackBuffer& operator=(const StackBuffer<TYPE,SIZE> &) { return *this; }
StackBuffer(const StackBuffer<TYPE,SIZE,POD_TYPE> &) { }
StackBuffer& operator=(const StackBuffer<TYPE,SIZE,POD_TYPE> &) { return *this; }
void allocate(size_type capacity);
void deallocate();
@ -97,9 +97,9 @@ private:
//
// Core allocation/deallocation methods:
//
template <typename TYPE, unsigned int SIZE>
template <typename TYPE, unsigned int SIZE, bool POD_TYPE>
inline void
StackBuffer<TYPE,SIZE>::allocate(size_type capacity) {
StackBuffer<TYPE,SIZE,POD_TYPE>::allocate(size_type capacity) {
// Again, is alignment an issue here? C++ spec says new will return pointer
// "suitably aligned" for conversion to pointers of other types, which implies
@ -110,9 +110,9 @@ StackBuffer<TYPE,SIZE>::allocate(size_type capacity) {
_capacity = capacity;
}
template <typename TYPE, unsigned int SIZE>
template <typename TYPE, unsigned int SIZE, bool POD_TYPE>
inline void
StackBuffer<TYPE,SIZE>::deallocate() {
StackBuffer<TYPE,SIZE,POD_TYPE>::deallocate() {
::operator delete(_dynamicData);
@ -121,20 +121,22 @@ StackBuffer<TYPE,SIZE>::deallocate() {
}
//
// Explicit element-wise construction and destruction within allocated memory (we
// rely on the compiler to remove this code for types with empty constructors):
// Explicit element-wise construction and destruction within allocated memory.
// Compilers do not always optimize out the iteration here even when there is
// no construction or destruction, so the POD_TYPE arguement can be used to
// force this when/if it becomes an issue (and it has been in some cases).
//
template <typename TYPE, unsigned int SIZE>
template <typename TYPE, unsigned int SIZE, bool POD_TYPE>
inline void
StackBuffer<TYPE,SIZE>::construct() {
StackBuffer<TYPE,SIZE,POD_TYPE>::construct() {
for (size_type i = 0; i < _size; ++i) {
(void) new (&_data[i]) TYPE;
}
}
template <typename TYPE, unsigned int SIZE>
template <typename TYPE, unsigned int SIZE, bool POD_TYPE>
inline void
StackBuffer<TYPE,SIZE>::destruct() {
StackBuffer<TYPE,SIZE,POD_TYPE>::destruct() {
for (size_type i = 0; i < _size; ++i) {
_data[i].~TYPE();
@ -144,9 +146,9 @@ StackBuffer<TYPE,SIZE>::destruct() {
//
// Inline constructors and destructor:
//
template <typename TYPE, unsigned int SIZE>
template <typename TYPE, unsigned int SIZE, bool POD_TYPE>
inline
StackBuffer<TYPE,SIZE>::StackBuffer() :
StackBuffer<TYPE,SIZE,POD_TYPE>::StackBuffer() :
_data(reinterpret_cast<TYPE*>(_staticData)),
_size(0),
_capacity(SIZE),
@ -154,9 +156,9 @@ StackBuffer<TYPE,SIZE>::StackBuffer() :
}
template <typename TYPE, unsigned int SIZE>
template <typename TYPE, unsigned int SIZE, bool POD_TYPE>
inline
StackBuffer<TYPE,SIZE>::StackBuffer(size_type size) :
StackBuffer<TYPE,SIZE,POD_TYPE>::StackBuffer(size_type size) :
_data(reinterpret_cast<TYPE*>(_staticData)),
_size(size),
_capacity(SIZE),
@ -165,36 +167,44 @@ StackBuffer<TYPE,SIZE>::StackBuffer(size_type size) :
if (size > SIZE) {
allocate(size);
}
construct();
if (!POD_TYPE) {
construct();
}
}
template <typename TYPE, unsigned int SIZE>
template <typename TYPE, unsigned int SIZE, bool POD_TYPE>
inline
StackBuffer<TYPE,SIZE>::~StackBuffer() {
StackBuffer<TYPE,SIZE,POD_TYPE>::~StackBuffer() {
destruct();
if (!POD_TYPE) {
destruct();
}
deallocate();
}
//
// Inline sizing methods:
//
template <typename TYPE, unsigned int SIZE>
template <typename TYPE, unsigned int SIZE, bool POD_TYPE>
inline void
StackBuffer<TYPE,SIZE>::Reserve(size_type capacity) {
StackBuffer<TYPE,SIZE,POD_TYPE>::Reserve(size_type capacity) {
if (capacity > _capacity) {
destruct();
if (!POD_TYPE) {
destruct();
}
deallocate();
allocate(capacity);
}
}
template <typename TYPE, unsigned int SIZE>
template <typename TYPE, unsigned int SIZE, bool POD_TYPE>
inline void
StackBuffer<TYPE,SIZE>::SetSize(size_type size)
StackBuffer<TYPE,SIZE,POD_TYPE>::SetSize(size_type size)
{
destruct();
if (!POD_TYPE) {
destruct();
}
if (size == 0) {
deallocate();
} else if (size > _capacity) {
@ -202,7 +212,9 @@ StackBuffer<TYPE,SIZE>::SetSize(size_type size)
allocate(size);
}
_size = size;
construct();
if (!POD_TYPE) {
construct();
}
}
} // end namespace internal