mirror of
https://github.com/PixarAnimationStudios/OpenSubdiv
synced 2024-11-08 21:30:06 +00:00
Adding VSpan to standardize representation of partial rings around vertices:
- added definition and gathering method to Vtr::Level - extended Far::EndCap...PatchFactories with VSpan[4] for patch corners - extended Far::EndCapGregoryPatchFactory to avoid last level assumption - adapted Far::PatchTableFactory to use above extensions - extended Far::GregoryBasis to recognize VSpan corners - simplified Far::GregoryBasis treatement of boundaries - fixed bug in Far::GregoryBasis related to smooth corners
This commit is contained in:
parent
fc9bbb154b
commit
2d33a6ebf4
@ -77,6 +77,7 @@ EndCapBSplineBasisPatchFactory::EndCapBSplineBasisPatchFactory(
|
||||
ConstIndexArray
|
||||
EndCapBSplineBasisPatchFactory::GetPatchPoints(
|
||||
Vtr::internal::Level const * level, Index thisFace,
|
||||
Vtr::internal::Level::VSpan const cornerSpans[],
|
||||
PatchTableFactory::PatchFaceTag const *levelPatchTags,
|
||||
int levelVertOffset) {
|
||||
|
||||
@ -85,7 +86,7 @@ EndCapBSplineBasisPatchFactory::GetPatchPoints(
|
||||
// if it's boundary, fallback to use GregoryBasis
|
||||
if (patchTag._boundaryCount > 0) {
|
||||
return getPatchPointsFromGregoryBasis(
|
||||
level, thisFace, facePoints, levelVertOffset);
|
||||
level, thisFace, cornerSpans, facePoints, levelVertOffset);
|
||||
}
|
||||
|
||||
// there's a short-cut when the face contains only 1 extraordinary vertex.
|
||||
@ -99,7 +100,7 @@ EndCapBSplineBasisPatchFactory::GetPatchPoints(
|
||||
// more than one extraoridinary vertices.
|
||||
// fallback to use GregoryBasis
|
||||
return getPatchPointsFromGregoryBasis(
|
||||
level, thisFace, facePoints, levelVertOffset);
|
||||
level, thisFace, cornerSpans, facePoints, levelVertOffset);
|
||||
}
|
||||
irregular = i;
|
||||
}
|
||||
@ -113,6 +114,7 @@ EndCapBSplineBasisPatchFactory::GetPatchPoints(
|
||||
ConstIndexArray
|
||||
EndCapBSplineBasisPatchFactory::getPatchPointsFromGregoryBasis(
|
||||
Vtr::internal::Level const * level, Index thisFace,
|
||||
Vtr::internal::Level::VSpan const cornerSpans[],
|
||||
ConstIndexArray facePoints, int levelVertOffset) {
|
||||
|
||||
// XXX: For now, always create new 16 indices for each patch.
|
||||
@ -124,7 +126,7 @@ EndCapBSplineBasisPatchFactory::getPatchPointsFromGregoryBasis(
|
||||
_patchPoints.push_back(_numVertices + offset);
|
||||
++_numVertices;
|
||||
}
|
||||
GregoryBasis::ProtoBasis basis(*level, thisFace, levelVertOffset, -1);
|
||||
GregoryBasis::ProtoBasis basis(*level, thisFace, cornerSpans, levelVertOffset, -1);
|
||||
// XXX: temporary hack. we should traverse topology and find existing
|
||||
// vertices if available
|
||||
//
|
||||
|
@ -80,12 +80,14 @@ public:
|
||||
///
|
||||
ConstIndexArray GetPatchPoints(
|
||||
Vtr::internal::Level const * level, Index faceIndex,
|
||||
Vtr::internal::Level::VSpan const cornerSpans[],
|
||||
PatchTableFactory::PatchFaceTag const * levelPatchTags,
|
||||
int levelVertOffset);
|
||||
|
||||
private:
|
||||
ConstIndexArray getPatchPointsFromGregoryBasis(
|
||||
Vtr::internal::Level const * level, Index thisFace,
|
||||
Vtr::internal::Level::VSpan const cornerSpans[],
|
||||
ConstIndexArray facePoints,
|
||||
int levelVertOffset);
|
||||
|
||||
|
@ -77,7 +77,8 @@ EndCapGregoryBasisPatchFactory::Create(TopologyRefiner const & refiner,
|
||||
// Gregory patches are end-caps: they only exist on max-level
|
||||
Vtr::internal::Level const & level = refiner.getLevel(refiner.GetMaxLevel());
|
||||
|
||||
GregoryBasis::ProtoBasis basis(level, faceIndex, 0, fvarChannel);
|
||||
// Is this method used/supported? If so, needs corner spans (and vert offset?)...
|
||||
GregoryBasis::ProtoBasis basis(level, faceIndex, 0, 0, fvarChannel);
|
||||
GregoryBasis * result = new GregoryBasis;
|
||||
basis.Copy(result);
|
||||
|
||||
@ -86,16 +87,14 @@ EndCapGregoryBasisPatchFactory::Create(TopologyRefiner const & refiner,
|
||||
}
|
||||
|
||||
bool
|
||||
EndCapGregoryBasisPatchFactory::addPatchBasis(Index faceIndex,
|
||||
EndCapGregoryBasisPatchFactory::addPatchBasis(Vtr::internal::Level const & level, Index faceIndex,
|
||||
Vtr::internal::Level::VSpan const cornerSpans[],
|
||||
bool verticesMask[4][5],
|
||||
int levelVertOffset) {
|
||||
|
||||
// Gregory patches only exist on the hight
|
||||
Vtr::internal::Level const & level = _refiner->getLevel(_refiner->GetMaxLevel());
|
||||
|
||||
// Gather the CVs that influence the Gregory patch and their relative
|
||||
// weights in a basis
|
||||
GregoryBasis::ProtoBasis basis(level, faceIndex, levelVertOffset, -1);
|
||||
GregoryBasis::ProtoBasis basis(level, faceIndex, cornerSpans, levelVertOffset, -1);
|
||||
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
if (verticesMask[i][0]) {
|
||||
@ -131,8 +130,10 @@ EndCapGregoryBasisPatchFactory::addPatchBasis(Index faceIndex,
|
||||
ConstIndexArray
|
||||
EndCapGregoryBasisPatchFactory::GetPatchPoints(
|
||||
Vtr::internal::Level const * level, Index faceIndex,
|
||||
Vtr::internal::Level::VSpan const cornerSpans[],
|
||||
PatchTableFactory::PatchFaceTag const * levelPatchTags,
|
||||
int levelVertOffset) {
|
||||
|
||||
// allocate indices (awkward)
|
||||
// assert(Vtr::INDEX_INVALID==0xFFFFFFFF);
|
||||
for (int i = 0; i < 20; ++i) {
|
||||
@ -227,7 +228,7 @@ EndCapGregoryBasisPatchFactory::GetPatchPoints(
|
||||
_faceIndices.push_back(faceIndex);
|
||||
|
||||
// add basis
|
||||
addPatchBasis(faceIndex, newVerticesMask, levelVertOffset);
|
||||
addPatchBasis(*level, faceIndex, cornerSpans, newVerticesMask, levelVertOffset);
|
||||
|
||||
++_numGregoryBasisPatches;
|
||||
|
||||
|
@ -98,6 +98,8 @@ public:
|
||||
/// @param level vtr refinement level
|
||||
///
|
||||
/// @param faceIndex vtr faceIndex at the level
|
||||
//
|
||||
/// @param cornerSpans information about topology for each corner of patch
|
||||
///
|
||||
/// @param levelPatchTags Array of patchTags for all faces in the level
|
||||
///
|
||||
@ -105,6 +107,7 @@ public:
|
||||
///
|
||||
ConstIndexArray GetPatchPoints(
|
||||
Vtr::internal::Level const * level, Index faceIndex,
|
||||
Vtr::internal::Level::VSpan const cornerSpans[],
|
||||
PatchTableFactory::PatchFaceTag const * levelPatchTags,
|
||||
int levelVertOffset);
|
||||
|
||||
@ -112,8 +115,9 @@ private:
|
||||
|
||||
/// Creates a basis for the vertices specified in mask on the face and
|
||||
/// accumates it
|
||||
bool addPatchBasis(Index faceIndex, bool newVerticesMask[4][5],
|
||||
int levelVertOffset);
|
||||
bool addPatchBasis(Vtr::internal::Level const & level, Index faceIndex,
|
||||
Vtr::internal::Level::VSpan const cornerSpans[],
|
||||
bool newVerticesMask[4][5], int levelVertOffset);
|
||||
|
||||
StencilTable *_vertexStencils;
|
||||
StencilTable *_varyingStencils;
|
||||
|
@ -31,6 +31,7 @@
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
#include <cstdio>
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
@ -100,6 +101,7 @@ inline float computeCoefficient(int valence) {
|
||||
|
||||
GregoryBasis::ProtoBasis::ProtoBasis(
|
||||
Vtr::internal::Level const & level, Index faceIndex,
|
||||
Vtr::internal::Level::VSpan const cornerSpans[],
|
||||
int levelVertOffset, int fvarChannel) {
|
||||
|
||||
// XXX: This function is subject to refactor in 3.1
|
||||
@ -110,8 +112,7 @@ GregoryBasis::ProtoBasis::ProtoBasis(
|
||||
assert(facePoints.size()==4);
|
||||
|
||||
int maxvalence = level.getMaxValence(),
|
||||
valences[4],
|
||||
zerothNeighbors[4];
|
||||
valences[4];
|
||||
|
||||
// XXX: a temporary hack for the performance issue
|
||||
// ensure Point has a capacity for the neighborhood of
|
||||
@ -140,29 +141,32 @@ GregoryBasis::ProtoBasis::ProtoBasis(
|
||||
// the first phase
|
||||
|
||||
for (int vid=0; vid<4; ++vid) {
|
||||
|
||||
// save for varying stencils
|
||||
varyingIndex[vid] = facePoints[vid] + levelVertOffset;
|
||||
|
||||
int ringSize =
|
||||
level.gatherQuadRegularRingAroundVertex(
|
||||
facePoints[vid], manifoldRings[vid], fvarChannel);
|
||||
int ringSize = 0;
|
||||
if (cornerSpans[vid]._numFaces == 0) {
|
||||
ringSize = level.gatherQuadRegularRingAroundVertex( facePoints[vid],
|
||||
manifoldRings[vid], fvarChannel);
|
||||
} else {
|
||||
ringSize = level.gatherQuadRegularPartialRingAroundVertex( facePoints[vid],
|
||||
cornerSpans[vid],
|
||||
manifoldRings[vid], fvarChannel);
|
||||
}
|
||||
|
||||
int valence;
|
||||
// when the corner vertex is on a boundary (ring-size is odd), valence is
|
||||
// negated and the ring is padded to replicate the last entry
|
||||
if (ringSize & 1) {
|
||||
// boundary vertex
|
||||
manifoldRings[vid][ringSize] = manifoldRings[vid][ringSize-1];
|
||||
++ringSize;
|
||||
valence = -ringSize/2;
|
||||
valences[vid] = -ringSize/2;
|
||||
} else {
|
||||
valence = ringSize/2;
|
||||
valences[vid] = ringSize/2;
|
||||
}
|
||||
int ivalence = abs(valence);
|
||||
valences[vid] = valence;
|
||||
|
||||
Index boundaryEdgeNeighbors[2],
|
||||
currentNeighbor = 0,
|
||||
zerothNeighbor=0,
|
||||
ibefore=0;
|
||||
int valence = valences[vid];
|
||||
int ivalence = abs(valence);
|
||||
|
||||
for (int i=0; i<ivalence; ++i) {
|
||||
|
||||
@ -175,35 +179,13 @@ GregoryBasis::ProtoBasis::ProtoBasis(
|
||||
idx_neighbor_m = (manifoldRings[vid][2*im + 0]),
|
||||
idx_diagonal_m = (manifoldRings[vid][2*im + 1]);
|
||||
|
||||
bool boundaryNeighbor = (level.getVertexEdges(idx_neighbor).size() >
|
||||
level.getVertexFaces(idx_neighbor).size());
|
||||
|
||||
if (fvarChannel>=0) {
|
||||
// XXXX manuelk need logic to check for boundary in fvar
|
||||
boundaryNeighbor = false;
|
||||
}
|
||||
|
||||
if (boundaryNeighbor) {
|
||||
if (currentNeighbor<2) {
|
||||
boundaryEdgeNeighbors[currentNeighbor] = idx_neighbor;
|
||||
}
|
||||
++currentNeighbor;
|
||||
if (currentNeighbor==1) {
|
||||
ibefore = zerothNeighbor = i;
|
||||
} else {
|
||||
if (i-ibefore==1) {
|
||||
std::swap(boundaryEdgeNeighbors[0], boundaryEdgeNeighbors[1]);
|
||||
zerothNeighbor = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float d = float(ivalence)+5.0f;
|
||||
f[i].Clear(4);
|
||||
f[i].AddWithWeight(facePoints[vid], float(ivalence)/d);
|
||||
f[i].AddWithWeight(idx_neighbor_p, 2.0f/d);
|
||||
f[i].AddWithWeight(idx_neighbor, 2.0f/d);
|
||||
f[i].AddWithWeight(idx_diagonal, 1.0f/d);
|
||||
|
||||
P[vid].AddWithWeight(f[i], 1.0f/float(ivalence));
|
||||
|
||||
int rid = vid * maxvalence + i;
|
||||
@ -214,11 +196,6 @@ GregoryBasis::ProtoBasis::ProtoBasis(
|
||||
r[rid].AddWithWeight(idx_diagonal_m, -1.0f/6.0f);
|
||||
}
|
||||
|
||||
zerothNeighbors[vid] = zerothNeighbor;
|
||||
if (currentNeighbor == 1) {
|
||||
boundaryEdgeNeighbors[1] = boundaryEdgeNeighbors[0];
|
||||
}
|
||||
|
||||
for (int i=0; i<ivalence; ++i) {
|
||||
int im = (i+ivalence-1)%ivalence;
|
||||
float c0 = 0.5f * csf(ivalence-3, 2*i);
|
||||
@ -235,14 +212,14 @@ GregoryBasis::ProtoBasis::ProtoBasis(
|
||||
|
||||
// Boundary gregory case:
|
||||
if (valence < 0) {
|
||||
Index boundaryEdgeNeighbors[2] = { manifoldRings[vid][0],
|
||||
manifoldRings[vid][ringSize-1] };
|
||||
|
||||
P[vid].Clear(stencilCapacity);
|
||||
if (ivalence>2) {
|
||||
P[vid].AddWithWeight(boundaryEdgeNeighbors[0], 1.0f/6.0f);
|
||||
P[vid].AddWithWeight(boundaryEdgeNeighbors[1], 1.0f/6.0f);
|
||||
P[vid].AddWithWeight(facePoints[vid], 4.0f/6.0f);
|
||||
} else {
|
||||
P[vid].AddWithWeight(facePoints[vid], 1.0f);
|
||||
}
|
||||
P[vid].AddWithWeight(boundaryEdgeNeighbors[0], 1.0f/6.0f);
|
||||
P[vid].AddWithWeight(boundaryEdgeNeighbors[1], 1.0f/6.0f);
|
||||
P[vid].AddWithWeight(facePoints[vid], 4.0f/6.0f);
|
||||
|
||||
float k = float(float(ivalence) - 1.0f); //k is the number of faces
|
||||
float c = cosf(float(M_PI)/k);
|
||||
float s = sinf(float(M_PI)/k);
|
||||
@ -250,7 +227,7 @@ GregoryBasis::ProtoBasis::ProtoBasis(
|
||||
float alpha_0k = -((1.0f+2.0f*c)*sqrtf(1.0f+c))/((3.0f*k+c)*sqrtf(1.0f-c));
|
||||
float beta_0 = s/(3.0f*k + c);
|
||||
|
||||
int idx_diagonal = manifoldRings[vid][2*zerothNeighbor + 1];
|
||||
int idx_diagonal = manifoldRings[vid][1];
|
||||
|
||||
e0[vid].Clear(stencilCapacity);
|
||||
e0[vid].AddWithWeight(boundaryEdgeNeighbors[0], 1.0f/6.0f);
|
||||
@ -264,13 +241,11 @@ GregoryBasis::ProtoBasis::ProtoBasis(
|
||||
|
||||
for (int x=1; x<ivalence-1; ++x) {
|
||||
|
||||
Index curri = ((x + zerothNeighbor)%ivalence);
|
||||
|
||||
float alpha = (4.0f*sinf((float(M_PI) * float(x))/k))/(3.0f*k+c),
|
||||
beta = (sinf((float(M_PI) * float(x))/k) + sinf((float(M_PI) * float(x+1))/k))/(3.0f*k+c);
|
||||
|
||||
Index idx_neighbor = manifoldRings[vid][2*curri + 0],
|
||||
idx_diagonal = manifoldRings[vid][2*curri + 1];
|
||||
Index idx_neighbor = manifoldRings[vid][2*x + 0],
|
||||
idx_diagonal = manifoldRings[vid][2*x + 1];
|
||||
|
||||
e1[vid].AddWithWeight(idx_neighbor, alpha);
|
||||
e1[vid].AddWithWeight(idx_diagonal, beta);
|
||||
@ -316,7 +291,7 @@ GregoryBasis::ProtoBasis::ProtoBasis(
|
||||
Point Ep_im = P[im];
|
||||
|
||||
if (valences[ip]<-2) {
|
||||
Index j = (np + prev_p - zerothNeighbors[ip]) % np;
|
||||
Index j = (np + prev_p) % np;
|
||||
Em_ip.AddWithWeight(e0[ip], cosf((float(M_PI)*j)/float(np-1)));
|
||||
Em_ip.AddWithWeight(e1[ip], sinf((float(M_PI)*j)/float(np-1)));
|
||||
} else {
|
||||
@ -325,7 +300,7 @@ GregoryBasis::ProtoBasis::ProtoBasis(
|
||||
}
|
||||
|
||||
if (valences[im]<-2) {
|
||||
Index j = (nm + start_m - zerothNeighbors[im]) % nm;
|
||||
Index j = (nm + start_m) % nm;
|
||||
Ep_im.AddWithWeight(e0[im], cosf((float(M_PI)*j)/float(nm-1)));
|
||||
Ep_im.AddWithWeight(e1[im], sinf((float(M_PI)*j)/float(nm-1)));
|
||||
} else {
|
||||
@ -371,8 +346,8 @@ GregoryBasis::ProtoBasis::ProtoBasis(
|
||||
Fm[vid].AddWithWeight(rp[prev], -1.0f/3.0f);
|
||||
} else if (valences[vid] < -2) {
|
||||
|
||||
Index jp = (ivalence + start - zerothNeighbors[vid]) % ivalence,
|
||||
jm = (ivalence + prev - zerothNeighbors[vid]) % ivalence;
|
||||
Index jp = (ivalence + start) % ivalence,
|
||||
jm = (ivalence + prev) % ivalence;
|
||||
|
||||
float s1 = 3-2*csf(n-3,2)-csf(np-3,2),
|
||||
s2 = 2*csf(n-3,2),
|
||||
|
@ -189,6 +189,7 @@ public:
|
||||
|
||||
ProtoBasis(Vtr::internal::Level const & level,
|
||||
Vtr::Index faceIndex,
|
||||
Vtr::internal::Level::VSpan const cornerSpans[],
|
||||
int levelVertOffset,
|
||||
int fvarChannel);
|
||||
|
||||
|
@ -1223,13 +1223,18 @@ PatchTableFactory::populateAdaptivePatches(
|
||||
// emit end patch. end patch should be in the max level (until we implement DFAS)
|
||||
assert(i==refiner.GetMaxLevel());
|
||||
|
||||
// identify relevant spans around the corner vertices for the irregular patches
|
||||
// (this is just a stub for now -- leaving the span "size" to zero, as constructed,
|
||||
// indicates to use the full neighborhood)...
|
||||
Vtr::internal::Level::VSpan cornerSpans[4];
|
||||
|
||||
// switch endcap patchtype by option
|
||||
switch(context.options.GetEndCapType()) {
|
||||
case Options::ENDCAP_GREGORY_BASIS:
|
||||
{
|
||||
// note: this call will be moved into vtr::level.
|
||||
ConstIndexArray cvs = endCapGregoryBasis->GetPatchPoints(
|
||||
level, faceIndex, levelPatchTags, levelVertOffset);
|
||||
level, faceIndex, cornerSpans, levelPatchTags, levelVertOffset);
|
||||
|
||||
for (int j = 0; j < cvs.size(); ++j) iptrs.GP[j] = cvs[j];
|
||||
iptrs.GP += cvs.size();
|
||||
@ -1244,7 +1249,7 @@ PatchTableFactory::populateAdaptivePatches(
|
||||
case Options::ENDCAP_BSPLINE_BASIS:
|
||||
{
|
||||
ConstIndexArray cvs = endCapBSpline->GetPatchPoints(
|
||||
level, faceIndex, levelPatchTags, levelVertOffset);
|
||||
level, faceIndex, cornerSpans, levelPatchTags, levelVertOffset);
|
||||
|
||||
for (int j = 0; j < cvs.size(); ++j) iptrs.R[j] = cvs[j];
|
||||
iptrs.R += cvs.size();
|
||||
|
@ -650,6 +650,44 @@ Level::gatherQuadRegularRingAroundVertex(
|
||||
return ringIndex;
|
||||
}
|
||||
|
||||
int
|
||||
Level::gatherQuadRegularPartialRingAroundVertex(
|
||||
Index vIndex, VSpan const & span, int ringPoints[], int fvarChannel) const {
|
||||
|
||||
Level const& level = *this;
|
||||
|
||||
assert(! level.isVertexNonManifold(vIndex));
|
||||
|
||||
ConstIndexArray vFaces = level.getVertexFaces(vIndex);
|
||||
ConstLocalIndexArray vInFaces = level.getVertexFaceLocalIndices(vIndex);
|
||||
|
||||
int nFaces = span._numFaces;
|
||||
int leadingEdge = span._leadingVertEdge;
|
||||
|
||||
int ringIndex = 0;
|
||||
for (int i = 0; i < nFaces; ++i) {
|
||||
//
|
||||
// For every incident quad, we want the two vertices clockwise in each face, i.e.
|
||||
// the vertex at the end of the leading edge and the vertex opposite this one:
|
||||
//
|
||||
int fIncident = (leadingEdge + i) % vFaces.size();
|
||||
|
||||
ConstIndexArray fPoints = (fvarChannel < 0)
|
||||
? level.getFaceVertices(vFaces[fIncident])
|
||||
: level.getFaceFVarValues(vFaces[fIncident], fvarChannel);
|
||||
|
||||
int vInThisFace = vInFaces[fIncident];
|
||||
|
||||
ringPoints[ringIndex++] = fPoints[fastMod4(vInThisFace + 1)];
|
||||
ringPoints[ringIndex++] = fPoints[fastMod4(vInThisFace + 2)];
|
||||
|
||||
if (i == nFaces - 1) {
|
||||
ringPoints[ringIndex++] = fPoints[fastMod4(vInThisFace + 3)];
|
||||
}
|
||||
}
|
||||
return ringIndex;
|
||||
}
|
||||
|
||||
//
|
||||
// Gathering the 4 vertices of a quad:
|
||||
//
|
||||
|
@ -149,6 +149,28 @@ public:
|
||||
|
||||
ETag getFaceCompositeETag(ConstIndexArray & faceEdges) const;
|
||||
|
||||
// Additional simple struct to identify a "span" around a vertex, i.e. a
|
||||
// subset of the faces around a vertex delimited by some property (e.g. a
|
||||
// face-varying discontinuity, an inf-sharp edge, etc.)
|
||||
//
|
||||
// The span requires an "origin", i.e. a leading edge or face and a "size"
|
||||
// to fully define its extent. Use of the size is preferred over leading
|
||||
// and trailing edges/faces so that valence is available since for a non-
|
||||
// manifold vertex that cannot be determined from the two extremeties.
|
||||
// There is also a subtle but marginal advantage in using a leading edge
|
||||
// rather than face, but it may be worth using the leading face with the
|
||||
// face count for consistency (both properties defined in terms of faces).
|
||||
//
|
||||
// Currently setting the size to 0 is an indication to use the full
|
||||
// neighborhood rather than a subset -- may want to revisit that choice...
|
||||
//
|
||||
struct VSpan {
|
||||
VSpan() : _numFaces(0), _leadingVertEdge(0) { }
|
||||
|
||||
LocalIndex _numFaces;
|
||||
LocalIndex _leadingVertEdge;
|
||||
};
|
||||
|
||||
public:
|
||||
Level();
|
||||
~Level();
|
||||
@ -284,7 +306,10 @@ public:
|
||||
int gatherQuadRegularCornerPatchPoints( Index fIndex, Index patchPoints[], int cornerVertInFace,
|
||||
int fvarChannel = -1) const;
|
||||
|
||||
int gatherQuadRegularRingAroundVertex(Index vIndex, Index ringPoints[], int fvarChannel = -1) const;
|
||||
int gatherQuadRegularRingAroundVertex(Index vIndex, Index ringPoints[],
|
||||
int fvarChannel = -1) const;
|
||||
int gatherQuadRegularPartialRingAroundVertex(Index vIndex, VSpan const & span, Index ringPoints[],
|
||||
int fvarChannel = -1) const;
|
||||
|
||||
// WIP -- for future use, need to extend for face-varying...
|
||||
int gatherTriRegularInteriorPatchPoints( Index fIndex, Index patchVerts[], int rotation = 0) const;
|
||||
|
Loading…
Reference in New Issue
Block a user