mirror of
https://github.com/PixarAnimationStudios/OpenSubdiv
synced 2024-11-09 13:50:05 +00:00
Changed Gregory triangle from cubic/quartic hyrid to full quartic:
- changed Far::PatchDescriptor size for GREGORY_TRIANGLE to 18 - modified Far::LoopPatchBuilder to construct full quartic Gregory patch - fixed Far::LoopPatchBuilder bug related to face points near boundaries - updated Far patch basis evaluation for Gregory and Bezier triangles - updated Osd patch basis evaluation to match Far - updated Osd GLSL patch size for Gregory triangle to 18 - modified Osd GLSL Gregory triangle eval and tess settings for quartic
This commit is contained in:
parent
ee6097b399
commit
a0e72d80c3
@ -313,6 +313,8 @@ namespace {
|
||||
|
||||
int GetSize() const { return _size; }
|
||||
|
||||
void SetWeight(int i, REAL weight) { _weights[i] = weight; }
|
||||
|
||||
void Assign(int rowEntry, Index index, REAL weight) {
|
||||
_indices[rowEntry] = index;
|
||||
_weights[rowEntry] = weight;
|
||||
@ -394,6 +396,31 @@ namespace {
|
||||
}
|
||||
}
|
||||
|
||||
template <typename REAL>
|
||||
void
|
||||
_combineSparsePointsInFullRow(SparseMatrixRow<REAL> & p,
|
||||
REAL aCoeff, SparseMatrixRow<REAL> const & a,
|
||||
REAL bCoeff, SparseMatrixRow<REAL> const & b,
|
||||
int rowSize, REAL * rowBuffer, int * maskBuffer) {
|
||||
|
||||
std::memset(maskBuffer, 0, rowSize * sizeof(int));
|
||||
std::memset(rowBuffer, 0, rowSize * sizeof(REAL));
|
||||
|
||||
_addSparsePointToFullRow(rowBuffer, a, aCoeff, maskBuffer);
|
||||
_addSparsePointToFullRow(rowBuffer, b, bCoeff, maskBuffer);
|
||||
|
||||
int nWeights = 0;
|
||||
for (int i = 0; i < rowSize; ++i) {
|
||||
if (maskBuffer[i]) {
|
||||
p.Assign(nWeights++, maskBuffer[i] - 1, rowBuffer[i]);
|
||||
}
|
||||
}
|
||||
assert(nWeights <= p.GetSize());
|
||||
for (int i = nWeights; i < p.GetSize(); ++i, ++nWeights) {
|
||||
p.Assign(i, 0, 0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename REAL>
|
||||
void
|
||||
_addSparseRowToFull(REAL * fullRow,
|
||||
@ -527,11 +554,19 @@ namespace {
|
||||
// GregoryTriConverter
|
||||
//
|
||||
// The GregoryTriConverter class provides a change-of-basis matrix from source
|
||||
// vertices in a Loop mesh to the 15 control points of a Gregory triangle.
|
||||
// vertices in a Loop mesh to the 18 control points of a quartic Gregory triangle.
|
||||
//
|
||||
// The quartic triangle is first constructed as a cubic/quartic hybrid -- with
|
||||
// cubic boundary curves and cross-boundary continuity formulated in terms of
|
||||
// cubics. The result is then raised to a full quartic once continuity across
|
||||
// all boundaries is achieved. In most cases 2 of the 3 boundaries will be
|
||||
// cubic (though now represented as quartic) and only one boundary need be a
|
||||
// true quartic to meet a regular Box-spline patch.
|
||||
//
|
||||
// Control points are labeled using the convention adopted for quads, with
|
||||
// Ep and Em referring to the "plus" and "minus" edge points and similarly
|
||||
// for the face points Fp and Fm.
|
||||
// for the face points Fp and Fm. The additional quartic "mid-edge" points
|
||||
// associated with each boundary are referred to as M.
|
||||
//
|
||||
template <typename REAL>
|
||||
class GregoryTriConverter {
|
||||
@ -625,6 +660,13 @@ private:
|
||||
Point & fNear, REAL signForSideOfEdge /* -1.0 or 1.0 */,
|
||||
Weight *rowWeights, int *columnMask) const;
|
||||
|
||||
void assignRegularMidEdgePoint(int edgeIndex, Matrix & matrix) const;
|
||||
void computeIrregularMidEdgePoint(int edgeIndex, Matrix & matrix,
|
||||
Weight *rowWeights, int *columnMask) const;
|
||||
|
||||
void promoteCubicEdgePointsToQuartic(Matrix & matrix,
|
||||
Weight *rowWeights, int *columnMask) const;
|
||||
|
||||
private:
|
||||
int _numSourcePoints;
|
||||
int _maxValence;
|
||||
@ -813,6 +855,17 @@ GregoryTriConverter<REAL>::Convert(Matrix & matrix) const {
|
||||
computeIrregularFacePoints(cIndex, matrix, weightBuffer, indexBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
for (int eIndex = 0; eIndex < 3; ++eIndex) {
|
||||
if ((_corners[eIndex].isRegular && _corners[(eIndex+1)%3].isRegular) ||
|
||||
_corners[eIndex].epOnBoundary) {
|
||||
assignRegularMidEdgePoint(eIndex, matrix);
|
||||
} else {
|
||||
computeIrregularMidEdgePoint(eIndex, matrix, weightBuffer, indexBuffer);
|
||||
}
|
||||
}
|
||||
promoteCubicEdgePointsToQuartic(matrix, weightBuffer, indexBuffer);
|
||||
|
||||
if (_hasVal2InteriorCorner) {
|
||||
_removeValence2Duplicates(matrix);
|
||||
}
|
||||
@ -829,7 +882,7 @@ GregoryTriConverter<REAL>::resizeMatrixIsolatedIrregular(
|
||||
int irregPlus = (cornerIndex + 1) % 3;
|
||||
int irregMinus = (cornerIndex + 2) % 3;
|
||||
|
||||
int rowSizes[15];
|
||||
int rowSizes[18];
|
||||
int * rowSizePtr = 0;
|
||||
|
||||
rowSizePtr = rowSizes + irregCorner * 5;
|
||||
@ -853,16 +906,21 @@ GregoryTriConverter<REAL>::resizeMatrixIsolatedIrregular(
|
||||
*rowSizePtr++ = 3 + irregRingSize;
|
||||
*rowSizePtr++ = 5;
|
||||
|
||||
int numElements = 7*irregRingSize + 64;
|
||||
// The 3 quartic mid-edge points are not grouped with corners:
|
||||
rowSizes[15 + irregCorner] = 3 + irregRingSize;
|
||||
rowSizes[15 + irregPlus] = 4;
|
||||
rowSizes[15 + irregMinus] = 3 + irregRingSize;
|
||||
|
||||
_resizeMatrix(matrix, 15, _numSourcePoints, numElements, rowSizes);
|
||||
int numElements = 9*irregRingSize + 74;
|
||||
|
||||
_resizeMatrix(matrix, 18, _numSourcePoints, numElements, rowSizes);
|
||||
}
|
||||
|
||||
template <typename REAL>
|
||||
void
|
||||
GregoryTriConverter<REAL>::resizeMatrixUnisolated(Matrix & matrix) const {
|
||||
|
||||
int rowSizes[15];
|
||||
int rowSizes[18];
|
||||
|
||||
int numElements = 0;
|
||||
|
||||
@ -879,8 +937,8 @@ GregoryTriConverter<REAL>::resizeMatrixUnisolated(Matrix & matrix) const {
|
||||
rowSize[2] = 7;
|
||||
} else {
|
||||
rowSize[0] = 3;
|
||||
rowSize[1] = corner.epOnBoundary ? 2 : 4;
|
||||
rowSize[2] = corner.emOnBoundary ? 2 : 4;
|
||||
rowSize[1] = corner.epOnBoundary ? 3 : 5;
|
||||
rowSize[2] = corner.emOnBoundary ? 3 : 5;
|
||||
}
|
||||
} else {
|
||||
if (corner.isSharp) {
|
||||
@ -895,19 +953,19 @@ GregoryTriConverter<REAL>::resizeMatrixUnisolated(Matrix & matrix) const {
|
||||
} else if (corner.numFaces > 1) {
|
||||
int ringSize = 1 + corner.valence;
|
||||
rowSize[0] = 3;
|
||||
rowSize[1] = corner.epOnBoundary ? 2 : ringSize;
|
||||
rowSize[2] = corner.emOnBoundary ? 2 : ringSize;
|
||||
rowSize[1] = corner.epOnBoundary ? 3 : ringSize;
|
||||
rowSize[2] = corner.emOnBoundary ? 3 : ringSize;
|
||||
} else {
|
||||
rowSize[0] = 3;
|
||||
rowSize[1] = 2;
|
||||
rowSize[2] = 2;
|
||||
rowSize[1] = 3;
|
||||
rowSize[2] = 3;
|
||||
}
|
||||
}
|
||||
numElements += rowSize[0] + rowSize[1] + rowSize[2];
|
||||
|
||||
// Second, the pair of face points:
|
||||
rowSize[3] = 5 - 2 * corner.isCorner;
|
||||
rowSize[4] = 5 - 2 * corner.isCorner;
|
||||
rowSize[3] = 5 - corner.epOnBoundary - corner.emOnBoundary;
|
||||
rowSize[4] = 5 - corner.epOnBoundary - corner.emOnBoundary;
|
||||
if (!corner.fpIsRegular || !corner.fmIsRegular) {
|
||||
int cNext = (cIndex + 1) % 3;
|
||||
int cPrev = (cIndex + 2) % 3;
|
||||
@ -921,8 +979,21 @@ GregoryTriConverter<REAL>::resizeMatrixUnisolated(Matrix & matrix) const {
|
||||
}
|
||||
}
|
||||
numElements += rowSize[3] + rowSize[4];
|
||||
|
||||
// Third, the quartic mid-edge boundary point (edge following corner):
|
||||
int & midEdgeSize = rowSizes[15 + cIndex];
|
||||
|
||||
if (corner.epOnBoundary) {
|
||||
midEdgeSize = 2;
|
||||
} else if (corner.isRegular && _corners[(cIndex+1) % 3].isRegular) {
|
||||
midEdgeSize = 4;
|
||||
} else {
|
||||
// Use face-point size here, which also combines edge-point sizes:
|
||||
midEdgeSize = rowSize[3];
|
||||
}
|
||||
numElements += midEdgeSize;
|
||||
}
|
||||
_resizeMatrix(matrix, 15, _numSourcePoints, numElements, rowSizes);
|
||||
_resizeMatrix(matrix, 18, _numSourcePoints, numElements, rowSizes);
|
||||
}
|
||||
|
||||
template <typename REAL>
|
||||
@ -991,27 +1062,29 @@ GregoryTriConverter<REAL>::assignRegularEdgePoints(int cIndex, Matrix & matrix)
|
||||
if (corner.epOnBoundary) {
|
||||
ep.Assign(0, cIndex, twoThirds);
|
||||
ep.Assign(1, cRing[0], oneThird);
|
||||
assert(ep.GetSize() == 2);
|
||||
ep.Assign(2, cRing[3], 0.0f);
|
||||
assert(ep.GetSize() == 3);
|
||||
} else {
|
||||
ep.Assign(0, cIndex, 0.5f);
|
||||
ep.Assign(1, cRing[1], oneSixth);
|
||||
ep.Assign(2, cRing[2], oneSixth);
|
||||
if (!corner.emOnBoundary) ep.Assign(3, cRing[0], oneSixth);
|
||||
if ( corner.emOnBoundary) ep.Assign(3, cRing[3], oneSixth);
|
||||
assert(ep.GetSize() == 4);
|
||||
ep.Assign(3, cRing[corner.emOnBoundary ? 3 : 0], oneSixth);
|
||||
ep.Assign(4, cRing[corner.emOnBoundary ? 0 : 3], 0.0f);
|
||||
assert(ep.GetSize() == 5);
|
||||
}
|
||||
|
||||
if (corner.emOnBoundary) {
|
||||
em.Assign(0, cIndex, twoThirds);
|
||||
em.Assign(1, cRing[3], oneThird);
|
||||
assert(em.GetSize() == 2);
|
||||
em.Assign(2, cRing[0], 0.0f);
|
||||
assert(em.GetSize() == 3);
|
||||
} else {
|
||||
em.Assign(0, cIndex, 0.5f);
|
||||
em.Assign(1, cRing[1], oneSixth);
|
||||
em.Assign(2, cRing[2], oneSixth);
|
||||
if ( corner.epOnBoundary) em.Assign(3, cRing[0], oneSixth);
|
||||
if (!corner.epOnBoundary) em.Assign(3, cRing[3], oneSixth);
|
||||
assert(em.GetSize() == 4);
|
||||
em.Assign(3, cRing[corner.epOnBoundary ? 0 : 3], oneSixth);
|
||||
em.Assign(4, cRing[corner.epOnBoundary ? 3 : 0], 0.0f);
|
||||
assert(em.GetSize() == 5);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1068,11 +1141,13 @@ GregoryTriConverter<REAL>::computeIrregularEdgePoints(int cIndex,
|
||||
|
||||
ep.Assign(0, cIndex, (REAL) (2.0 / 3.0));
|
||||
ep.Assign(1, (cIndex+1) % 3, (REAL) (1.0 / 3.0));
|
||||
assert(ep.GetSize() == 2);
|
||||
ep.Assign(2, (cIndex+2) % 3, 0.0f);
|
||||
assert(ep.GetSize() == 3);
|
||||
|
||||
em.Assign(0, cIndex, (REAL) (2.0 / 3.0));
|
||||
em.Assign(1, (cIndex+2) % 3, (REAL) (1.0 / 3.0));
|
||||
assert(em.GetSize() == 2);
|
||||
em.Assign(2, (cIndex+1) % 3, 0.0f);
|
||||
assert(em.GetSize() == 3);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1166,7 +1241,8 @@ GregoryTriConverter<REAL>::computeIrregularBoundaryEdgePoints(
|
||||
ep.Assign(0, p0, epWeights[0]);
|
||||
if (corner.epOnBoundary) {
|
||||
ep.Assign(1, p1, epWeights[1]);
|
||||
assert(ep.GetSize() == 2);
|
||||
ep.Assign(2, pN, 0.0f);
|
||||
assert(ep.GetSize() == 3);
|
||||
} else {
|
||||
for (int i = 1; i < weightWidth; ++i) {
|
||||
ep.Assign(i, corner.ringPoints[i-1], epWeights[i]);
|
||||
@ -1179,7 +1255,8 @@ GregoryTriConverter<REAL>::computeIrregularBoundaryEdgePoints(
|
||||
em.Assign(0, p0, emWeights[0]);
|
||||
if (corner.emOnBoundary) {
|
||||
em.Assign(1, pN, emWeights[N]);
|
||||
assert(em.GetSize() == 2);
|
||||
em.Assign(2, p1, 0.0f);
|
||||
assert(em.GetSize() == 3);
|
||||
} else {
|
||||
for (int i = 1; i < weightWidth; ++i) {
|
||||
em.Assign(i, corner.ringPoints[i-1], emWeights[i]);
|
||||
@ -1194,18 +1271,14 @@ int
|
||||
GregoryTriConverter<REAL>::getIrregularFacePointSize(
|
||||
int cIndexNear, int cIndexFar) const {
|
||||
|
||||
CornerTopology const & corner = _corners[cIndexNear];
|
||||
CornerTopology const & adjCorner = _corners[cIndexFar];
|
||||
CornerTopology const & nearCorner = _corners[cIndexNear];
|
||||
CornerTopology const & farCorner = _corners[cIndexFar];
|
||||
|
||||
int thisSize = corner.isSharp
|
||||
? 4
|
||||
: (1 + corner.ringPoints.GetSize());
|
||||
int nearSize = nearCorner.ringPoints.GetSize() - 3;
|
||||
int farSize = farCorner.ringPoints.GetSize() - 3;
|
||||
|
||||
int adjSize = (adjCorner.isSharp || (adjCorner.numFaces <= 3))
|
||||
? 0
|
||||
: (1 + adjCorner.ringPoints.GetSize() - 4);
|
||||
|
||||
return thisSize + adjSize;
|
||||
return 4 + (((nearSize > 0) && !nearCorner.isSharp) ? nearSize : 0)
|
||||
+ (((farSize > 0) && !farCorner.isSharp) ? farSize : 0);
|
||||
}
|
||||
|
||||
template <typename REAL>
|
||||
@ -1284,58 +1357,49 @@ GregoryTriConverter<REAL>::assignRegularFacePoints(int cIndex, Matrix & matrix)
|
||||
int cNext = (cIndex+1) % 3;
|
||||
int cPrev = (cIndex+2) % 3;
|
||||
|
||||
int eNext = corner.isBoundary ? 0 : ((corner.faceInRing + 5) % 6);
|
||||
int ePrev = corner.isBoundary ? 3 : ((corner.faceInRing + 2) % 6);
|
||||
|
||||
int const * cRing = corner.ringPoints;
|
||||
|
||||
// Assign regular Fp and/or Fm:
|
||||
if (corner.fpIsRegular) {
|
||||
Point fp(matrix, 5*cIndex + 3);
|
||||
//
|
||||
// Regular face-points are computed the same for both face-points of a
|
||||
// a corner (fp and fm), so iterate through both and make appropriate
|
||||
// assignments when tagged as regular:
|
||||
//
|
||||
for (int fIsFm = 0; fIsFm < 2; ++fIsFm) {
|
||||
bool fIsRegular = fIsFm ? corner.fmIsRegular : corner.fpIsRegular;
|
||||
if (!fIsRegular) continue;
|
||||
|
||||
Point f(matrix, 5*cIndex + 3 + fIsFm);
|
||||
|
||||
if (corner.isCorner) {
|
||||
fp.Assign(0, cIndex, 0.5f);
|
||||
fp.Assign(1, cNext, 0.25f);
|
||||
fp.Assign(2, cPrev, 0.25f);
|
||||
assert(fp.GetSize() == 3);
|
||||
f.Assign(0, cIndex, 0.5f);
|
||||
f.Assign(1, cNext, 0.25f);
|
||||
f.Assign(2, cPrev, 0.25f);
|
||||
assert(f.GetSize() == 3);
|
||||
} else if (corner.epOnBoundary) {
|
||||
fp.Assign(0, cIndex, (REAL) (11.0 / 24.0));
|
||||
fp.Assign(1, cRing[0], (REAL) ( 7.0 / 24.0));
|
||||
fp.Assign(2, cRing[1], (REAL) ( 5.0 / 24.0));
|
||||
fp.Assign(3, cRing[2], (REAL) ( 1.0 / 24.0));
|
||||
fp.Assign(4, cRing[3], (REAL) ( 0.0 / 24.0));
|
||||
assert(fp.GetSize() == 5);
|
||||
} else {
|
||||
fp.Assign(0, cIndex, (REAL) (10.0 / 24.0));
|
||||
fp.Assign(1, cPrev, 0.25f);
|
||||
fp.Assign(2, cNext, 0.25f);
|
||||
fp.Assign(3, cRing[ePrev], (REAL) ( 1.0 / 24.0));
|
||||
fp.Assign(4, cRing[eNext], (REAL) ( 1.0 / 24.0));
|
||||
assert(fp.GetSize() == 5);
|
||||
}
|
||||
}
|
||||
if (corner.fmIsRegular) {
|
||||
Point fm(matrix, 5*cIndex + 4);
|
||||
|
||||
if (corner.isCorner) {
|
||||
fm.Assign(0, cIndex, 0.5f);
|
||||
fm.Assign(1, cNext, 0.25f);
|
||||
fm.Assign(2, cPrev, 0.25f);
|
||||
assert(fm.GetSize() == 3);
|
||||
// Face is the first/leading face of the boundary ring:
|
||||
f.Assign(0, cIndex, (REAL) (11.0 / 24.0));
|
||||
f.Assign(1, cRing[0], (REAL) ( 7.0 / 24.0));
|
||||
f.Assign(2, cRing[1], (REAL) ( 5.0 / 24.0));
|
||||
f.Assign(3, cRing[2], (REAL) ( 1.0 / 24.0));
|
||||
assert(f.GetSize() == 4);
|
||||
} else if (corner.emOnBoundary) {
|
||||
fm.Assign(0, cIndex, (REAL) (11.0 / 24.0));
|
||||
fm.Assign(1, cRing[0], (REAL) ( 0.0 / 24.0));
|
||||
fm.Assign(2, cRing[1], (REAL) ( 1.0 / 24.0));
|
||||
fm.Assign(3, cRing[2], (REAL) ( 5.0 / 24.0));
|
||||
fm.Assign(4, cRing[3], (REAL) ( 7.0 / 24.0));
|
||||
assert(fm.GetSize() == 5);
|
||||
// Face is the last/trailing face of the boundary ring:
|
||||
f.Assign(0, cIndex, (REAL) (11.0 / 24.0));
|
||||
f.Assign(1, cRing[3], (REAL) ( 7.0 / 24.0));
|
||||
f.Assign(2, cRing[2], (REAL) ( 5.0 / 24.0));
|
||||
f.Assign(3, cRing[1], (REAL) ( 1.0 / 24.0));
|
||||
assert(f.GetSize() == 4);
|
||||
} else {
|
||||
fm.Assign(0, cIndex, (REAL) (10.0 / 24.0));
|
||||
fm.Assign(1, cNext, 0.25f);
|
||||
fm.Assign(2, cPrev, 0.25f);
|
||||
fm.Assign(3, cRing[ePrev], (REAL) ( 1.0 / 24.0));
|
||||
fm.Assign(4, cRing[eNext], (REAL) ( 1.0 / 24.0));
|
||||
assert(fm.GetSize() == 5);
|
||||
// Face is interior or the middle face of the boundary:
|
||||
int eNext = corner.isBoundary ? 0 : ((corner.faceInRing + 5) % 6);
|
||||
int ePrev = corner.isBoundary ? 3 : ((corner.faceInRing + 2) % 6);
|
||||
|
||||
f.Assign(0, cIndex, (REAL) (10.0 / 24.0));
|
||||
f.Assign(1, cPrev, 0.25f);
|
||||
f.Assign(2, cNext, 0.25f);
|
||||
f.Assign(3, cRing[ePrev], (REAL) ( 1.0 / 24.0));
|
||||
f.Assign(4, cRing[eNext], (REAL) ( 1.0 / 24.0));
|
||||
assert(f.GetSize() == 5);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1391,6 +1455,107 @@ GregoryTriConverter<REAL>::computeIrregularFacePoints(int cIndex,
|
||||
if (!corner.fmIsRegular) assert(matrix.GetRowSize(5*cIndex + 4) == fm.GetSize());
|
||||
}
|
||||
|
||||
template <typename REAL>
|
||||
void
|
||||
GregoryTriConverter<REAL>::assignRegularMidEdgePoint(int edgeIndex,
|
||||
Matrix & matrix) const {
|
||||
|
||||
Point M(matrix, 15 + edgeIndex);
|
||||
|
||||
CornerTopology const & corner = _corners[edgeIndex];
|
||||
if (corner.epOnBoundary) {
|
||||
// Trivial boundary edge case -- midway between two corners
|
||||
|
||||
M.Assign(0, edgeIndex, 0.5f);
|
||||
M.Assign(1, (edgeIndex + 1) % 3, 0.5f);
|
||||
assert(M.GetSize() == 2);
|
||||
} else {
|
||||
// Regular case -- two corners and two vertices opposite the edge
|
||||
|
||||
int oppositeInRing = corner.isBoundary ?
|
||||
(corner.faceInRing - 1) : ((corner.faceInRing + 5) % 6);
|
||||
int oppositeVertex = corner.ringPoints[oppositeInRing];
|
||||
|
||||
M.Assign(0, edgeIndex, (REAL) (1.0 / 3.0));
|
||||
M.Assign(1, (edgeIndex + 1) % 3, (REAL) (1.0 / 3.0));
|
||||
M.Assign(2, (edgeIndex + 2) % 3, (REAL) (1.0 / 6.0));
|
||||
M.Assign(3, oppositeVertex, (REAL) (1.0 / 6.0));
|
||||
assert(M.GetSize() == 4);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename REAL>
|
||||
void
|
||||
GregoryTriConverter<REAL>::computeIrregularMidEdgePoint(int edgeIndex, Matrix & matrix,
|
||||
Weight * rowWeights, int * columnMask) const {
|
||||
//
|
||||
// General case -- interpolate midway between cubic edge points E0 and E1:
|
||||
//
|
||||
int cIndex0 = edgeIndex;
|
||||
int cIndex1 = (edgeIndex + 1) % 3;
|
||||
|
||||
Point E0p(matrix, 5 * (cIndex0) + 1);
|
||||
Point E1m(matrix, 5 * (cIndex1) + 2);
|
||||
|
||||
Point M(matrix, 15 + edgeIndex);
|
||||
|
||||
_combineSparsePointsInFullRow(M, (REAL)0.5f, E0p, (REAL)0.5f, E1m,
|
||||
_numSourcePoints, rowWeights, columnMask);
|
||||
}
|
||||
|
||||
template <typename REAL>
|
||||
void
|
||||
GregoryTriConverter<REAL>::promoteCubicEdgePointsToQuartic(Matrix & matrix,
|
||||
Weight * rowWeights, int * columnMask) const {
|
||||
//
|
||||
// Re-assign all regular edge-point weights with quartic coefficients,
|
||||
// so only perform general combinations for the irregular case.
|
||||
//
|
||||
REAL const onBoundaryWeights[3] = { 16, 7, 1 };
|
||||
REAL const regBoundaryWeights[5] = { 13, 3, 3, 4, 1 };
|
||||
REAL const regInteriorWeights[7] = { 12, 4, 3, 1, 0, 1, 3 };
|
||||
|
||||
REAL const oneOver24 = (REAL) (1.0 / 24.0);
|
||||
|
||||
for (int cIndex = 0; cIndex < 3; ++cIndex) {
|
||||
CornerTopology const & corner = _corners[cIndex];
|
||||
|
||||
//
|
||||
// Ordering of weight values for symmetric ep and em is the same, so
|
||||
// we can re-assign in a loop of 2 for {ep, em}
|
||||
//
|
||||
Point P(matrix, 5 * cIndex);
|
||||
|
||||
for (int ePair = 0; ePair < 2; ++ePair) {
|
||||
Point E(matrix, 5 * cIndex + 1 + ePair);
|
||||
|
||||
REAL const * weightsToReassign = 0;
|
||||
|
||||
bool eOnBoundary = ePair ? corner.emOnBoundary : corner.epOnBoundary;
|
||||
if (eOnBoundary && !corner.isSharp) {
|
||||
assert(E.GetSize() == 3);
|
||||
weightsToReassign = onBoundaryWeights;
|
||||
} else if (corner.isRegular) {
|
||||
if (corner.isBoundary) {
|
||||
assert(E.GetSize() == 5);
|
||||
weightsToReassign = regBoundaryWeights;
|
||||
} else {
|
||||
assert(E.GetSize() == 7);
|
||||
weightsToReassign = regInteriorWeights;
|
||||
}
|
||||
}
|
||||
if (weightsToReassign) {
|
||||
for (int i = 0; i < E.GetSize(); ++i) {
|
||||
E.SetWeight(i, weightsToReassign[i] * oneOver24);
|
||||
}
|
||||
} else {
|
||||
_combineSparsePointsInFullRow(E, (REAL)0.25f, P, (REAL)0.75f, E,
|
||||
_numSourcePoints, rowWeights, columnMask);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
template <typename REAL>
|
||||
void
|
||||
@ -1563,46 +1728,68 @@ convertToLoop(SourcePatch const & sourcePatch, SparseMatrix<REAL> & matrix) {
|
||||
//
|
||||
// Unlike quads, there are not enough degrees of freedom in the regular patch
|
||||
// to enforce interpolation of the limit point and tangent at the corner while
|
||||
// preserving the two adjoining boundary curves. That requires constraining
|
||||
// 7 control points but only 6 can be moved without affecting the opposite
|
||||
// boundary curve. At minimum, we need to constrain 9 of the 12 patch points,
|
||||
// which reduces the advantages of a local solution compared to the 7 of 16
|
||||
// control points for the BSplines of Catmark.
|
||||
// preserving the two adjoining boundary curves. Since we end up destroying
|
||||
// neighboring conintuity in doing so, we use a fully constructed Gregory
|
||||
// patch here for the isolated corner case as well as the general case.
|
||||
//
|
||||
// So we might as well compute the Gregory solution and convert back for this
|
||||
// more common case -- in addition to the more general case where it is needed.
|
||||
// Tangent continuity is compromised regardless of what is done here. If a
|
||||
// specific solution for the isolated corner case has advantages in terms of
|
||||
// either surface quality or performance, we can revisit it.
|
||||
// Unfortunately, the regular patch here -- a quartic Box-spline triangle --
|
||||
// is not as flexible as the BSpline patches for Catmark. Unlike BSplines
|
||||
// and Bezier patches, the Box-splines do not span the full space of possible
|
||||
// shapes (only 12 control points in a space spanned by 15 polynomials for
|
||||
// the quartic case). So it is possible to construct shapes with a Gregory
|
||||
// or Bezier triangle that cannot be represented by the Box-spline.
|
||||
//
|
||||
// Use a full 12x12 conversion matrix from a cubic-quartic hybrid Bezier back
|
||||
// to a Box spline patch. Matrix rows and columns are ordered according to
|
||||
// control point orientations used elsewhere. Correllation of points between
|
||||
// the hybrid Bezier and hybrid Gregory points is as follows:
|
||||
// The solution fit a Box-spline patch to the constructed Gregory patch with
|
||||
// 12 constraints: position, first derivatives and mixed partial at each of
|
||||
// the 3 corners. We used the mixed partial (the twist vector) to constrain
|
||||
// the interior of the patch somehow, otherwise results produce a lot of
|
||||
// interior bulging in an effort to satisfy boundary constraints.
|
||||
//
|
||||
// B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 B10 B11
|
||||
// G0 G1 G7 G5 G2 G3,4 G8,9 G6 G11 G13,14 G12 G10
|
||||
// Given both position and tangent continuity here are compromised for the
|
||||
// general case -- and at considerable expense (in terms of computation and
|
||||
// the full set of local control points that result) -- its worth exploring
|
||||
// simpler solutions for the case of the isolated corner.
|
||||
//
|
||||
// For the full 12x15 conversion matrix from 15-point quartic Bezier patch
|
||||
// back to a Box spline patch, the matrix rows and columns are ordered
|
||||
// according to control point orientations used elsewhere. Correllation of
|
||||
// points between the Bezier and Gregory points is as follows:
|
||||
//
|
||||
// Q0 Q1 Q2 Q3 Q4 Q5 Q6 Q7 Q8 Q9 Q10 Q11 Q12 Q13 Q14
|
||||
// G0 G1 G15 G7 G5 G2 G3,4 G8,9 G6 G17 G13,14 G16 G11 G12 G10
|
||||
//
|
||||
// As with conversion from Gregory to BSpline for Catmark, one of the face
|
||||
// points (the positive) is chosen as a Bezier point in the conversion rather
|
||||
// than combining the pair.
|
||||
// points is chosen as a Bezier point in the conversion rather than combining
|
||||
// the pair (which would avoid slight asymmetric artefacts of the choice).
|
||||
//
|
||||
REAL const gregoryToLoopMatrix[12][12] = {
|
||||
{ 6.0f, 1.0f,-3.5f, 0.0f,-10.0f, 4.0f, 6.0f, -0.5f, 5.0f, -8.0f, 1.0f, 0.0f },
|
||||
{ 0.0f, 3.5f, 5.0f, 0.0f, -0.5f, -2.0f, -8.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f },
|
||||
{ 0.0f, 3.0f,-1.5f, 6.0f, 6.0f,-20.0f, 14.0f,-12.5f,-3.0f, 8.0f, 1.0f, 0.0f },
|
||||
{ 6.0f,-10.0f, 5.0f, 0.0f, 1.0f, 4.0f, -8.0f, 1.0f,-3.5f, 6.0f, -0.5f, 0.0f },
|
||||
{ 0.0f, 1.5f,-1.5f, 0.0f, 1.5f, -2.0f, 2.0f, -0.5f,-1.5f, 2.0f, -0.5f, 0.0f },
|
||||
{ 0.0f, -2.0f, 1.0f, 0.0f, -1.0f, 4.0f, 0.0f, 1.0f, 0.5f, -2.0f, -0.5f, 0.0f },
|
||||
{ 0.0f, -2.5f,-5.5f, 6.0f, -6.5f, 22.0f,-14.0f, 5.5f, 2.5f, -6.0f, -0.5f, 0.0f },
|
||||
{ 0.0f, -0.5f, 1.0f, 0.0f, 3.5f, -2.0f, 0.0f, 1.0f, 5.0f, -8.0f, 1.0f, 0.0f },
|
||||
{ 0.0f, -1.0f, 0.5f, 0.0f, -2.0f, 4.0f, -2.0f, -0.5f, 1.0f, 0.0f, 1.0f, 0.0f },
|
||||
{ 0.0f, 7.5f,-3.0f, 0.0f, 7.5f,-26.0f, 8.0f, 1.0f,-3.0f, 8.0f, 1.0f, 0.0f },
|
||||
{ 0.0f, 6.0f,-3.0f, 0.0f, 3.0f,-20.0f, 8.0f, 1.0f,-1.5f, 14.0f,-12.5f, 6.0f },
|
||||
{ 0.0f, -6.5f, 2.5f, 0.0f, -2.5f, 22.0f, -6.0f, -0.5f,-5.5f,-14.0f, 5.5f, 6.0f }
|
||||
REAL const gregoryToLoopMatrix[12][15] = {
|
||||
{ 9.33333f, 5.33333f, -6.f, -0.66666f, 0.33333f,-18.66667f, 4.f, 6.f,
|
||||
-0.66666f, 8.f, -8.f, 0.f, 1.33333f, 1.33333f, -0.666667f},
|
||||
{ 0.33333f, -0.66666f, 8.f, 1.33333f, -0.66666f, -0.66666f, -2.f, -8.f,
|
||||
1.33333f, 0.f, 0.f, 0.f, 1.33333f, 1.33333f, -0.666667f},
|
||||
{-6.66667f, 13.33333f,-14.f, 7.33333f, 8.33333f, 13.33333f,-20.f, 14.f,
|
||||
-16.66667f, -8.f, 8.f, 0.f, 1.33333f, 1.33333f, -0.666667f},
|
||||
{ 9.33333f,-18.66667f, 8.f, 1.33333f, -0.66666f, 5.33333f, 4.f, -8.f,
|
||||
1.33333f, -6.f, 6.f, 0.f, -0.66666f, -0.66666f, 0.333333f},
|
||||
{-1.66667f, 3.33333f, -2.f, -0.66666f, 0.33333f, 3.33333f, -2.f, 2.f,
|
||||
-0.66666f, -2.f, 2.f, 0.f, -0.66666f, -0.66666f, 0.333333f},
|
||||
{ 1.33333f, -2.66667f, 0.f, 1.33333f, -0.66666f, -2.66667f, 4.f, 0.f,
|
||||
1.33333f, 2.f, -2.f, 0.f, -0.66666f, -0.66666f, 0.333333f},
|
||||
{ 6.33333f,-12.66667f, 14.f,-16.66667f, 8.33333f,-12.66667f, 22.f,-14.f,
|
||||
7.33333f, 6.f, -6.f, 0.f, -0.66666f, -0.66666f, 0.333333f},
|
||||
{ 0.33333f, -0.66666f, 0.f, 1.33333f, -0.66666f, -0.66666f, -2.f, 0.f,
|
||||
1.33333f, 8.f, -8.f, 0.f, 1.33333f, 1.33333f, -0.666667f},
|
||||
{ 1.33333f, -2.66667f, 2.f, -0.66666f, 0.33333f, -2.66667f, 4.f, -2.f,
|
||||
-0.66666f, 0.f, 0.f, 0.f, 1.33333f, 1.33333f, -0.666667f},
|
||||
{-7.66667f, 15.33333f, -8.f, 1.33333f, -0.66666f, 15.33333f,-26.f, 8.f,
|
||||
1.33333f, -8.f, 8.f, 0.f, 1.33333f, 1.33333f, -0.666667f},
|
||||
{-6.66667f, 13.33333f, -8.f, 1.33333f, -0.66666f, 13.33333f,-20.f, 8.f,
|
||||
1.33333f,-14.f, 14.f, 0.f, 7.33333f,-16.66667f, 8.333333f},
|
||||
{ 6.33333f,-12.66667f, 6.f, -0.66666f, 0.33333f,-12.66667f, 22.f, -6.f,
|
||||
-0.66666f, 14.f,-14.f, 0.f,-16.66667f, 7.33333f, 8.333333f}
|
||||
};
|
||||
|
||||
int const gRowIndices[12] = { 0, 1, 7, 5, 2, 3, 8, 6, 11, 13, 12, 10 };
|
||||
int const gRowIndices[15] = { 0,1,15,7,5, 2,4,8,6, 17,14,16, 11,12, 10 };
|
||||
|
||||
SparseMatrix<REAL> G;
|
||||
convertToGregory<REAL>(sourcePatch, G);
|
||||
@ -1611,7 +1798,7 @@ convertToLoop(SourcePatch const & sourcePatch, SparseMatrix<REAL> & matrix) {
|
||||
|
||||
for (int i = 0; i < 12; ++i) {
|
||||
REAL const * gRowWeights = gregoryToLoopMatrix[i];
|
||||
_combineSparseMatrixRowsInFull(matrix, i, G, 12, gRowIndices, gRowWeights);
|
||||
_combineSparseMatrixRowsInFull(matrix, i, G, 15, gRowIndices, gRowWeights);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -949,61 +949,26 @@ int EvalBasisBoxSplineTri(REAL s, REAL t,
|
||||
|
||||
|
||||
//
|
||||
// Hybrid (cubic-quartic) Bezier triangle:
|
||||
// Quartic Bezier triangle:
|
||||
//
|
||||
// The regular patch for Loop subdivision is a quartic triangular Box spline
|
||||
// with cubic boundaries. So we need a quartic Bezier patch to represent it
|
||||
// faithfully, but we use a cubic-quartic hybrid to keep the representation
|
||||
// of boundaries as cubic -- useful for a number of purposes, in addition to
|
||||
// reducing the number points required from 15 to 12.
|
||||
// faithfully.
|
||||
//
|
||||
// Ultimately this patch is quartic and its basis functions are of maximum
|
||||
// quartic degree. The formulae for the 15 true quartic basis functions are:
|
||||
// The formulae for the 15 quartic basis functions are:
|
||||
//
|
||||
// 4! i j k
|
||||
// B (u,v,w) = ------- * (u * v * w )
|
||||
// ijk i!j!k!
|
||||
//
|
||||
// for each i + j + k = 4, and the quartic points and corresponding p<i,j,k>
|
||||
// are oriented as follows:
|
||||
// for each i + j + k = 4. The control points (P) and correspondingly
|
||||
// labeled p<i,j,k> are oriented as follows:
|
||||
//
|
||||
// Q14 p040
|
||||
// Q12 Q13 p031 p130
|
||||
// Q9 Q10 Q11 p022 p121 p220
|
||||
// Q5 Q6 Q7 Q8 p013 p112 p211 p310
|
||||
// Q0 Q1 Q2 Q3 Q4 p004 p103 p202 p301 p400
|
||||
//
|
||||
// The points for the corresponding hybrid patch are oriented and numbered:
|
||||
//
|
||||
// H11
|
||||
// H8 H10
|
||||
// H9
|
||||
// H4 H5 H6 H7
|
||||
// H0 H1 H2 H3
|
||||
//
|
||||
// Their corresponding basis functions h(u,v,w) are derived by combining the
|
||||
// quartic basis functions according to degree elevation of their boundary
|
||||
// curves. This leads to the 12 basis functions:
|
||||
//
|
||||
// h[0] = w^3
|
||||
// h[3] = u^3
|
||||
// h[11] = v^3
|
||||
//
|
||||
// h[1] = 3 * u * w^2 * (u + w)
|
||||
// h[2] = 3 * u^2 * w * (u + w)
|
||||
//
|
||||
// h[7] = 3 * u^2 * v * (u + v)
|
||||
// h[10] = 3 * u * v^2 * (u + v)
|
||||
//
|
||||
// h[8] = 3 * v^2 * w * (w + v)
|
||||
// h[10] = 3 * v * w^2 * (v + w)
|
||||
//
|
||||
// h[5] = 12 * u * v * w^2;
|
||||
// h[6] = 12 * u^2 * v * w;
|
||||
// h[9] = 12 * u * v^2 * w;
|
||||
//
|
||||
// These remain compact with at most two trivariate terms, and so relatively
|
||||
// easy to differentiate in this form while keeping the number of terms low.
|
||||
// P14 p040
|
||||
// P12 P13 p031 p130
|
||||
// P9 P10 P11 p022 p121 p220
|
||||
// P5 P6 P7 P8 p013 p112 p211 p310
|
||||
// P0 P1 P2 P3 P4 p004 p103 p202 p301 p400
|
||||
//
|
||||
namespace {
|
||||
template <typename REAL>
|
||||
@ -1014,9 +979,9 @@ namespace {
|
||||
REAL v = t;
|
||||
REAL w = 1 - u - v;
|
||||
|
||||
REAL u2 = u * u;
|
||||
REAL v2 = v * v;
|
||||
REAL w2 = w * w;
|
||||
REAL uu = u * u;
|
||||
REAL vv = v * v;
|
||||
REAL ww = w * w;
|
||||
|
||||
REAL uv = u * v;
|
||||
REAL vw = v * w;
|
||||
@ -1024,110 +989,104 @@ namespace {
|
||||
|
||||
int totalOrder = ds + dt;
|
||||
if (totalOrder == 0) {
|
||||
wB[0] = w*w2;
|
||||
wB[3] = u*u2;
|
||||
wB[11] = v*v2;
|
||||
|
||||
wB[1] = 3 * uw * (uw + w2);
|
||||
wB[2] = 3 * uw * (uw + u2);
|
||||
|
||||
wB[7] = 3 * uv * (uv + u2);
|
||||
wB[10] = 3 * uv * (uv + v2);
|
||||
|
||||
wB[8] = 3 * vw * (vw + v2);
|
||||
wB[4] = 3 * vw * (vw + w2);
|
||||
|
||||
wB[5] = 12 * w2 * uv;
|
||||
wB[6] = 12 * u2 * vw;
|
||||
wB[9] = 12 * v2 * uw;
|
||||
wB[0] = ww * ww;
|
||||
wB[1] = 4 * uw * ww;
|
||||
wB[2] = 6 * uw * uw;
|
||||
wB[3] = 4 * uw * uu;
|
||||
wB[4] = uu * uu;
|
||||
wB[5] = 4 * vw * ww;
|
||||
wB[6] = 12 * ww * uv;
|
||||
wB[7] = 12 * uu * vw;
|
||||
wB[8] = 4 * uv * uu;
|
||||
wB[9] = 6 * vw * vw;
|
||||
wB[10] = 12 * vv * uw;
|
||||
wB[11] = 6 * uv * uv;
|
||||
wB[12] = 4 * vw * vv;
|
||||
wB[13] = 4 * uv * vv;
|
||||
wB[14] = vv * vv;
|
||||
} else if (totalOrder == 1) {
|
||||
if (ds) {
|
||||
wB[0] = -3 * w2;
|
||||
wB[3] = 3 * u2;
|
||||
wB[11] = 0;
|
||||
|
||||
wB[1] = 3 * w * (w2 - uw - 2*u2);
|
||||
wB[2] = -3 * u * (u2 - uw - 2*w2);
|
||||
|
||||
wB[7] = 9 * u2*v + 6 * u*v2;
|
||||
wB[10] = 3 * v*v2 + 6 * u*v2;
|
||||
|
||||
wB[8] = -3 * v*v2 - 6 * v2*w;
|
||||
wB[4] = -9 * v*w2 - 6 * v2*w;
|
||||
|
||||
wB[5] = 12 * vw * (w - 2*u);
|
||||
wB[6] = 12 * uv * (2*w - u);
|
||||
wB[9] = 12 * v2 * (w - u);
|
||||
if (ds == 1) {
|
||||
wB[0] = -4 * ww * w;
|
||||
wB[1] = 4 * ww * (w - 3 * u);
|
||||
wB[2] = 12 * uw * (w - u);
|
||||
wB[3] = 4 * uu * (3 * w - u);
|
||||
wB[4] = 4 * uu * u;
|
||||
wB[5] = -12 * vw * w;
|
||||
wB[6] = 12 * vw * (w - 2 * u);
|
||||
wB[7] = 12 * uv * (2 * w - u);
|
||||
wB[8] = 12 * uv * u;
|
||||
wB[9] = -12 * vv * w;
|
||||
wB[10] = 12 * vv * (w - u);
|
||||
wB[11] = 12 * vv * u;
|
||||
wB[12] = -4 * vv * v;
|
||||
wB[13] = 4 * vv * v;
|
||||
wB[14] = 0;
|
||||
} else {
|
||||
wB[0] = -3 * w2;
|
||||
wB[3] = 0;
|
||||
wB[11] = 3 * v2;
|
||||
|
||||
wB[1] = -9 * u*w2 - 6 * u2*w;
|
||||
wB[2] = -3 * u*u2 - 6 * u2*w;
|
||||
|
||||
wB[7] = 3 * u*u2 + 6 * u2*v;
|
||||
wB[10] = 9 * u*v2 + 6 * u2*v;
|
||||
|
||||
wB[8] = -3 * v * (v2 - vw - 2*w2);
|
||||
wB[4] = 3 * w * (w2 - vw - 2*v2);
|
||||
|
||||
wB[5] = 12 * uw * (w - 2*v);
|
||||
wB[6] = 12 * u2 * (w - v);
|
||||
wB[9] = 12 * uv * (2*w - v);
|
||||
wB[0] = -4 * ww * w;
|
||||
wB[1] = -12 * ww * u;
|
||||
wB[2] = -12 * uu * w;
|
||||
wB[3] = -4 * uu * u;
|
||||
wB[4] = 0;
|
||||
wB[5] = 4 * ww * (w - 3 * v);
|
||||
wB[6] = 12 * uw * (w - 2 * v);
|
||||
wB[7] = 12 * uu * (w - v);
|
||||
wB[8] = 4 * uu * u;
|
||||
wB[9] = 12 * vw * (w - v);
|
||||
wB[10] = 12 * uv * (2 * w - v);
|
||||
wB[11] = 12 * uv * u;;
|
||||
wB[12] = 4 * vv * (3 * w - v);
|
||||
wB[13] = 12 * vv * u;
|
||||
wB[14] = 4 * vv * v;
|
||||
}
|
||||
} else if (totalOrder == 2) {
|
||||
if (ds == 2) {
|
||||
wB[0] = 6 * w;
|
||||
wB[3] = 6 * u;
|
||||
wB[11] = 0;
|
||||
|
||||
wB[1] = 6 * (u2 - uw - 2*w2);
|
||||
wB[2] = 6 * (w2 - uw - 2*u2);
|
||||
|
||||
wB[7] = 6 * v2 + 18 * uv;
|
||||
wB[10] = 6 * v2;
|
||||
|
||||
wB[8] = 6 * v2;
|
||||
wB[4] = 6 * v2 + 18 * vw;
|
||||
|
||||
wB[5] = 24 * (uv - 2*vw);
|
||||
wB[6] = 24 * (vw - 2*uv);
|
||||
wB[9] = -24 * v2;
|
||||
wB[0] = 12 * ww;
|
||||
wB[1] = 24 * (uw - ww);
|
||||
wB[2] = 12 * (uu - 4 * uw + ww);
|
||||
wB[3] = 24 * (uw - uu);
|
||||
wB[4] = 12 * uu;
|
||||
wB[5] = 24 * vw;
|
||||
wB[6] = 24 * (uv - 2 * vw);
|
||||
wB[7] = 24 * (vw - 2 * uv);
|
||||
wB[8] = 24 * uv;
|
||||
wB[9] = 12 * vv;
|
||||
wB[10] = -24 * vv;
|
||||
wB[11] = 12 * vv;
|
||||
wB[12] = 0;
|
||||
wB[13] = 0;
|
||||
wB[14] = 0;
|
||||
} else if (dt == 2) {
|
||||
wB[0] = 6 * w;
|
||||
wB[3] = 0;
|
||||
wB[11] = 6 * v;
|
||||
|
||||
wB[1] = 6 * u2 + 18 * uw;
|
||||
wB[2] = 6 * u2;
|
||||
|
||||
wB[7] = 6 * u2;
|
||||
wB[10] = 6 * u2 + 18 * uv;
|
||||
|
||||
wB[8] = 6 * (w2 - vw - 2*v2);
|
||||
wB[4] = 6 * (v2 - vw - 2*w2);
|
||||
|
||||
wB[5] = 24 * (uv - 2*uw);
|
||||
wB[6] = -24 * u2;
|
||||
wB[9] = 24 * (uw - 2*uv);
|
||||
wB[0] = 12 * ww;
|
||||
wB[1] = 24 * uw;
|
||||
wB[2] = 12 * uu;
|
||||
wB[3] = 0;
|
||||
wB[4] = 0;
|
||||
wB[5] = 24 * (vw - ww);
|
||||
wB[6] = 24 * (uv - 2 * uw);
|
||||
wB[7] = -24 * uu;
|
||||
wB[8] = 0;
|
||||
wB[9] = 12 * (vv - 4 * vw + ww);
|
||||
wB[10] = 24 * (uw - 2 * uv);
|
||||
wB[11] = 12 * uu;
|
||||
wB[12] = 24 * (vw - vv);
|
||||
wB[13] = 24 * uv;
|
||||
wB[14] = 12 * vv;
|
||||
} else {
|
||||
wB[0] = 6 * w;
|
||||
wB[3] = 0;
|
||||
wB[11] = 0;
|
||||
|
||||
wB[1] = 6 * (u2 + uw - 1.5f*w2);
|
||||
wB[2] = -3 * (u2 + 4*uw);
|
||||
|
||||
wB[7] = 9 * u2 + 12 * uv;
|
||||
wB[10] = 9 * v2 + 12 * uv;
|
||||
|
||||
wB[8] = -3 * (v2 + 4*vw);
|
||||
wB[4] = 6 * (v2 + vw - 1.5f*w2);
|
||||
|
||||
wB[5] = 24 * (uv - vw - uw + 0.5f*w2);
|
||||
wB[6] = -24 * (uv - uw + 0.5f*u2);
|
||||
wB[9] = -24 * (uv - vw + 0.5f*v2);
|
||||
wB[0] = 12 * ww;
|
||||
wB[3] = -12 * uu;
|
||||
wB[13] = 12 * vv;
|
||||
wB[11] = 24 * uv;
|
||||
wB[1] = 24 * uw - wB[0];
|
||||
wB[2] = -24 * uw - wB[3];
|
||||
wB[5] = 24 * vw - wB[0];
|
||||
wB[6] = -24 * vw + wB[11] - wB[1];
|
||||
wB[8] = - wB[3];
|
||||
wB[7] = -(wB[11] + wB[2]);
|
||||
wB[9] = wB[13] - wB[5] - wB[0];
|
||||
wB[10] = -(wB[9] + wB[11]);
|
||||
wB[12] = - wB[13];
|
||||
wB[4] = 0;
|
||||
wB[14] = 0;
|
||||
}
|
||||
} else {
|
||||
assert(totalOrder <= 2);
|
||||
@ -1138,8 +1097,8 @@ namespace {
|
||||
template <typename REAL>
|
||||
int
|
||||
EvalBasisBezierTri(REAL s, REAL t,
|
||||
REAL wP[12], REAL wDs[12], REAL wDt[12],
|
||||
REAL wDss[12], REAL wDst[12], REAL wDtt[12]) {
|
||||
REAL wP[15], REAL wDs[15], REAL wDt[15],
|
||||
REAL wDss[15], REAL wDst[15], REAL wDtt[15]) {
|
||||
|
||||
if (wP) {
|
||||
evalBezierTriDerivWeights<REAL>(s, t, 0, 0, wP);
|
||||
@ -1154,61 +1113,73 @@ EvalBasisBezierTri(REAL s, REAL t,
|
||||
evalBezierTriDerivWeights(s, t, 0, 2, wDtt);
|
||||
}
|
||||
}
|
||||
return 12;
|
||||
return 15;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Hybrid (cubic-quartic) Gregory triangle:
|
||||
// Quartic Gregory triangle:
|
||||
//
|
||||
// As with the Bezier triangle, and consistent with Loop, Schaefer at al (in
|
||||
// ("Approximating Subdivision Surfaces with Gregory Patches for Hardware
|
||||
// Tessellation") we use a cubic-quartic hybrid Gregory patch. Like the
|
||||
// quad Gregory patch, this patch uses Bezier basis functions (from the
|
||||
// cubic-quartic hybrid above) and rational multipliers to blend pairs of
|
||||
// interior points (face points).
|
||||
// The 18-point quaritic Gregory patch is an extension of the 15-point
|
||||
// quartic Bezier triangle with the 3 interior points of the Bezier patch
|
||||
// replaced with pairs of points (face points -- fi+ and fi-) that are
|
||||
// rationally combined.
|
||||
//
|
||||
// The point ordering of Gregory patches deviates considerably from the
|
||||
// BSpline and Bezier patches by grouping the 5 points at each corner and
|
||||
// ordering the groups by corner index. This is consistent with the cubic
|
||||
// Gregory quad patch.
|
||||
//
|
||||
// The 3 additional quartic boundary points are currently appended to these
|
||||
// 3 groups of 5 control points. In contrast to the 5 points associated
|
||||
// with each corner, these 3 points are more associated with the edge
|
||||
// between the corner vertices and are equally weighted between the two.
|
||||
//
|
||||
namespace {
|
||||
//
|
||||
// Expanding a set of 12 Bezier basis functions for the 6 (3 pairs) of
|
||||
// rational weights for the 15 Gregory basis functions:
|
||||
// Expanding a set of 15 Bezier basis functions for the 6 (3 pairs) of
|
||||
// rational weights for the 18 Gregory basis functions:
|
||||
//
|
||||
template <typename REAL>
|
||||
void
|
||||
convertBezierWeightsToGregory(REAL const wB[12], REAL const rG[6], REAL wG[15]) {
|
||||
convertBezierWeightsToGregory(REAL const wB[15], REAL const rG[6], REAL wG[18]) {
|
||||
|
||||
wG[0] = wB[0];
|
||||
wG[1] = wB[1];
|
||||
wG[2] = wB[4];
|
||||
wG[3] = wB[5] * rG[0];
|
||||
wG[4] = wB[5] * rG[1];
|
||||
wG[2] = wB[5];
|
||||
wG[3] = wB[6] * rG[0];
|
||||
wG[4] = wB[6] * rG[1];
|
||||
|
||||
wG[5] = wB[3];
|
||||
wG[6] = wB[7];
|
||||
wG[7] = wB[2];
|
||||
wG[8] = wB[6] * rG[2];
|
||||
wG[9] = wB[6] * rG[3];
|
||||
wG[5] = wB[4];
|
||||
wG[6] = wB[8];
|
||||
wG[7] = wB[3];
|
||||
wG[8] = wB[7] * rG[2];
|
||||
wG[9] = wB[7] * rG[3];
|
||||
|
||||
wG[10] = wB[11];
|
||||
wG[11] = wB[8];
|
||||
wG[12] = wB[10];
|
||||
wG[13] = wB[9] * rG[4];
|
||||
wG[14] = wB[9] * rG[5];
|
||||
wG[10] = wB[14];
|
||||
wG[11] = wB[12];
|
||||
wG[12] = wB[13];
|
||||
wG[13] = wB[10] * rG[4];
|
||||
wG[14] = wB[10] * rG[5];
|
||||
|
||||
wG[15] = wB[2];
|
||||
wG[16] = wB[11];
|
||||
wG[17] = wB[9];
|
||||
}
|
||||
} // end namespace
|
||||
|
||||
template <typename REAL>
|
||||
int
|
||||
EvalBasisGregoryTri(REAL s, REAL t,
|
||||
REAL wP[15], REAL wDs[15], REAL wDt[15],
|
||||
REAL wDss[15], REAL wDst[15], REAL wDtt[15]) {
|
||||
REAL wP[18], REAL wDs[18], REAL wDt[18],
|
||||
REAL wDss[18], REAL wDst[18], REAL wDtt[18]) {
|
||||
|
||||
//
|
||||
// Bezier basis functions are denoted with B while the rational multipliers for the
|
||||
// interior points will be denoted G -- so we have B(s,t) and G(s,t) (though we
|
||||
// switch to barycentric (u,v,w) briefly to compute G)
|
||||
//
|
||||
REAL BP[12], BDs[12], BDt[12], BDss[12], BDst[12], BDtt[12];
|
||||
REAL BP[15], BDs[15], BDt[15], BDss[15], BDst[15], BDtt[15];
|
||||
|
||||
REAL G[6] = { 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f };
|
||||
REAL u = s;
|
||||
@ -1254,7 +1225,7 @@ EvalBasisGregoryTri(REAL s, REAL t,
|
||||
convertBezierWeightsToGregory(BDtt, G, wDtt);
|
||||
}
|
||||
}
|
||||
return 15;
|
||||
return 18;
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -76,7 +76,7 @@ int EvalBasisLinearTri(REAL s, REAL t,
|
||||
|
||||
template <typename REAL>
|
||||
int EvalBasisBezierTri(REAL s, REAL t,
|
||||
REAL wP[12], REAL wDs[12] = 0, REAL wDt[12] = 0, REAL wDss[12] = 0, REAL wDst[12] = 0, REAL wDtt[12] = 0);
|
||||
REAL wP[15], REAL wDs[15] = 0, REAL wDt[15] = 0, REAL wDss[15] = 0, REAL wDst[15] = 0, REAL wDtt[15] = 0);
|
||||
|
||||
template <typename REAL>
|
||||
int EvalBasisBoxSplineTri(REAL s, REAL t,
|
||||
@ -84,7 +84,7 @@ int EvalBasisBoxSplineTri(REAL s, REAL t,
|
||||
|
||||
template <typename REAL>
|
||||
int EvalBasisGregoryTri(REAL s, REAL t,
|
||||
REAL wP[15], REAL wDs[15] = 0, REAL wDt[15] = 0, REAL wDss[15] = 0, REAL wDst[15] = 0, REAL wDtt[15] = 0);
|
||||
REAL wP[18], REAL wDs[18] = 0, REAL wDt[18] = 0, REAL wDss[18] = 0, REAL wDst[18] = 0, REAL wDtt[18] = 0);
|
||||
|
||||
|
||||
//
|
||||
|
@ -149,7 +149,7 @@ PatchDescriptor::GetNumControlVertices( Type type ) {
|
||||
case GREGORY :
|
||||
case GREGORY_BOUNDARY : return GetGregoryPatchSize();
|
||||
case GREGORY_BASIS : return GetGregoryBasisPatchSize();
|
||||
case GREGORY_TRIANGLE : return 15;
|
||||
case GREGORY_TRIANGLE : return 18;
|
||||
case TRIANGLES : return 3;
|
||||
case LINES : return 2;
|
||||
case POINTS : return 1;
|
||||
|
@ -1644,11 +1644,13 @@ namespace {
|
||||
{ 0, 0, 1, 0, 0, 1, 1, 2, 2, 1, 2, 2 };
|
||||
static int const gregoryIndices[] =
|
||||
{ 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3 };
|
||||
static int const gregoryTriIndices[] =
|
||||
{ 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 0, 1, 2 };
|
||||
|
||||
if (type == PatchDescriptor::GREGORY_BASIS) {
|
||||
return gregoryIndices;
|
||||
} else if (type == PatchDescriptor::GREGORY_TRIANGLE) {
|
||||
return gregoryIndices;
|
||||
return gregoryTriIndices;
|
||||
} else if (type == PatchDescriptor::REGULAR) {
|
||||
return bsplineIndices;
|
||||
} else if (type == PatchDescriptor::LOOP) {
|
||||
|
@ -1148,7 +1148,7 @@ OsdEvalPatchBezierTriangle(ivec3 patchParam, vec2 UV,
|
||||
}
|
||||
|
||||
void
|
||||
OsdEvalPatchGregoryTriangle(ivec3 patchParam, vec2 UV, vec3 cv[15],
|
||||
OsdEvalPatchGregoryTriangle(ivec3 patchParam, vec2 UV, vec3 cv[18],
|
||||
out vec3 P, out vec3 dPu, out vec3 dPv,
|
||||
out vec3 N, out vec3 dNu, out vec3 dNv)
|
||||
{
|
||||
@ -1167,16 +1167,16 @@ OsdEvalPatchGregoryTriangle(ivec3 patchParam, vec2 UV, vec3 cv[15],
|
||||
bezcv[10].P = (dwu == 0.0) ? cv[13] : ((w*cv[13] + u*cv[14]) / dwu);
|
||||
|
||||
bezcv[ 0].P = cv[ 0];
|
||||
bezcv[ 1].P = 0.25*cv[ 0] + 0.75*cv[ 1];
|
||||
bezcv[ 2].P = 0.5 *cv[ 1] + 0.5 *cv[ 7];
|
||||
bezcv[ 3].P = 0.25*cv[ 5] + 0.75*cv[ 7];
|
||||
bezcv[ 1].P = cv[ 1];
|
||||
bezcv[ 2].P = cv[15];
|
||||
bezcv[ 3].P = cv[ 7];
|
||||
bezcv[ 4].P = cv[ 5];
|
||||
bezcv[ 5].P = 0.25*cv[ 0] + 0.75*cv[ 2];
|
||||
bezcv[ 8].P = 0.25*cv[ 5] + 0.75*cv[ 6];
|
||||
bezcv[ 9].P = 0.5 *cv[ 2] + 0.5 *cv[11];
|
||||
bezcv[11].P = 0.5 *cv[ 6] + 0.5 *cv[12];
|
||||
bezcv[12].P = 0.25*cv[10] + 0.75*cv[11];
|
||||
bezcv[13].P = 0.25*cv[10] + 0.75*cv[12];
|
||||
bezcv[ 5].P = cv[ 2];
|
||||
bezcv[ 8].P = cv[ 6];
|
||||
bezcv[ 9].P = cv[17];
|
||||
bezcv[11].P = cv[16];
|
||||
bezcv[12].P = cv[11];
|
||||
bezcv[13].P = cv[12];
|
||||
bezcv[14].P = cv[10];
|
||||
|
||||
OsdEvalPatchBezierTriangle(patchParam, UV, bezcv, P, dPu, dPv, N, dNu, dNv);
|
||||
|
@ -368,46 +368,6 @@ OsdGetTessLevelsLimitPointsTriangle(vec3 cv[15],
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
OsdGetTessLevelsLimitPointsGregoryTriangle(vec3 cv[15],
|
||||
ivec3 patchParam, out vec4 tessOuterLo, out vec4 tessOuterHi)
|
||||
{
|
||||
// Each edge of a transition patch is adjacent to one or two patches
|
||||
// at the next refined level of subdivision. When the patch control
|
||||
// points have been converted to the Bezier basis, the control points
|
||||
// at the corners are on the limit surface (since a Bezier patch
|
||||
// interpolates its corner control points). We can compute an adaptive
|
||||
// tessellation level for transition edges on the limit surface by
|
||||
// evaluating a limit position at the mid point of each transition edge.
|
||||
|
||||
tessOuterLo = vec4(0);
|
||||
tessOuterHi = vec4(0);
|
||||
|
||||
int transitionMask = OsdGetPatchTransitionMask(patchParam);
|
||||
|
||||
if ((transitionMask & 4) != 0) {
|
||||
vec3 P = Osd_EvalBezierCurveMidPoint(cv[0], cv[2], cv[11], cv[10]);
|
||||
tessOuterLo[0] = OsdComputeTessLevel(cv[0], P);
|
||||
tessOuterHi[0] = OsdComputeTessLevel(cv[10], P);
|
||||
} else {
|
||||
tessOuterLo[0] = OsdComputeTessLevel(cv[0], cv[10]);
|
||||
}
|
||||
if ((transitionMask & 1) != 0) {
|
||||
vec3 P = Osd_EvalBezierCurveMidPoint(cv[0], cv[1], cv[7], cv[5]);
|
||||
tessOuterLo[1] = OsdComputeTessLevel(cv[0], P);
|
||||
tessOuterHi[1] = OsdComputeTessLevel(cv[5], P);
|
||||
} else {
|
||||
tessOuterLo[1] = OsdComputeTessLevel(cv[0], cv[5]);
|
||||
}
|
||||
if ((transitionMask & 2) != 0) {
|
||||
vec3 P = Osd_EvalBezierCurveMidPoint(cv[5], cv[6], cv[12], cv[10]);
|
||||
tessOuterLo[2] = OsdComputeTessLevel(cv[10], P);
|
||||
tessOuterHi[2] = OsdComputeTessLevel(cv[5], P);
|
||||
} else {
|
||||
tessOuterLo[2] = OsdComputeTessLevel(cv[5], cv[10]);
|
||||
}
|
||||
}
|
||||
|
||||
// Round up to the nearest even integer
|
||||
float OsdRoundUpEven(float x) {
|
||||
return 2*ceil(x/2);
|
||||
@ -574,19 +534,6 @@ OsdGetTessLevelsAdaptiveLimitPointsTriangle(vec3 cv[15],
|
||||
tessLevelOuter, tessLevelInner);
|
||||
}
|
||||
|
||||
void
|
||||
OsdGetTessLevelsAdaptiveLimitPointsGregoryTriangle(vec3 cv[15],
|
||||
ivec3 patchParam,
|
||||
out vec4 tessLevelOuter, out vec2 tessLevelInner,
|
||||
out vec4 tessOuterLo, out vec4 tessOuterHi)
|
||||
{
|
||||
OsdGetTessLevelsLimitPointsGregoryTriangle(cv, patchParam,
|
||||
tessOuterLo, tessOuterHi);
|
||||
|
||||
OsdComputeTessLevelsTriangle(tessOuterLo, tessOuterHi,
|
||||
tessLevelOuter, tessLevelInner);
|
||||
}
|
||||
|
||||
void
|
||||
OsdGetTessLevels(vec3 cp0, vec3 cp1, vec3 cp2, vec3 cp3,
|
||||
ivec3 patchParam,
|
||||
|
@ -59,9 +59,9 @@ in block {
|
||||
out block {
|
||||
OsdPerPatchVertexBezier v;
|
||||
OSD_USER_VARYING_DECLARE
|
||||
} outpt[15];
|
||||
} outpt[18];
|
||||
|
||||
layout(vertices = 15) out;
|
||||
layout(vertices = 18) out;
|
||||
|
||||
void main()
|
||||
{
|
||||
@ -82,7 +82,7 @@ void main()
|
||||
vec4 tessLevelOuter = vec4(0);
|
||||
vec2 tessLevelInner = vec2(0);
|
||||
|
||||
OSD_PATCH_CULL(15);
|
||||
OSD_PATCH_CULL(18);
|
||||
|
||||
OsdGetTessLevelsUniformTriangle(patchParam,
|
||||
tessLevelOuter, tessLevelInner,
|
||||
@ -91,10 +91,23 @@ void main()
|
||||
#if defined OSD_ENABLE_SCREENSPACE_TESSELLATION
|
||||
// Gather bezier control points to compute limit surface tess levels
|
||||
vec3 cv[15];
|
||||
for (int i=0; i<15; ++i) {
|
||||
cv[i] = outpt[i].v.P;
|
||||
}
|
||||
OsdGetTessLevelsAdaptiveLimitPointsGregoryTriangle(
|
||||
cv[ 0] = outpt[ 0].v.P;
|
||||
cv[ 1] = outpt[ 1].v.P;
|
||||
cv[ 2] = outpt[15].v.P;
|
||||
cv[ 3] = outpt[ 7].v.P;
|
||||
cv[ 4] = outpt[ 5].v.P;
|
||||
cv[ 5] = outpt[ 2].v.P;
|
||||
cv[ 6] = outpt[ 3].v.P;
|
||||
cv[ 7] = outpt[ 8].v.P;
|
||||
cv[ 8] = outpt[ 6].v.P;
|
||||
cv[ 9] = outpt[17].v.P;
|
||||
cv[10] = outpt[13].v.P;
|
||||
cv[11] = outpt[16].v.P;
|
||||
cv[12] = outpt[11].v.P;
|
||||
cv[13] = outpt[12].v.P;
|
||||
cv[14] = outpt[10].v.P;
|
||||
|
||||
OsdGetTessLevelsAdaptiveLimitPointsTriangle(
|
||||
cv, patchParam,
|
||||
tessLevelOuter, tessLevelInner,
|
||||
tessOuterLo, tessOuterHi);
|
||||
@ -144,8 +157,8 @@ void main()
|
||||
vec3 P = vec3(0), dPu = vec3(0), dPv = vec3(0);
|
||||
vec3 N = vec3(0), dNu = vec3(0), dNv = vec3(0);
|
||||
|
||||
vec3 cv[15];
|
||||
for (int i = 0; i < 15; ++i) {
|
||||
vec3 cv[18];
|
||||
for (int i = 0; i < 18; ++i) {
|
||||
cv[i] = inpt[i].v.P;
|
||||
}
|
||||
|
||||
|
@ -838,15 +838,15 @@ Osd_EvalBasisBoxSplineTri(OSD_REAL s, OSD_REAL t,
|
||||
void
|
||||
Osd_evalBezierTriDerivWeights(
|
||||
OSD_REAL s, OSD_REAL t, int ds, int dt,
|
||||
OSD_OUT_ARRAY(OSD_REAL, wB, 12)) {
|
||||
OSD_OUT_ARRAY(OSD_REAL, wB, 15)) {
|
||||
|
||||
OSD_REAL u = s;
|
||||
OSD_REAL v = t;
|
||||
OSD_REAL w = 1 - u - v;
|
||||
|
||||
OSD_REAL u2 = u * u;
|
||||
OSD_REAL v2 = v * v;
|
||||
OSD_REAL w2 = w * w;
|
||||
OSD_REAL uu = u * u;
|
||||
OSD_REAL vv = v * v;
|
||||
OSD_REAL ww = w * w;
|
||||
|
||||
OSD_REAL uv = u * v;
|
||||
OSD_REAL vw = v * w;
|
||||
@ -854,110 +854,104 @@ Osd_EvalBasisBoxSplineTri(OSD_REAL s, OSD_REAL t,
|
||||
|
||||
int totalOrder = ds + dt;
|
||||
if (totalOrder == 0) {
|
||||
wB[0] = w*w2;
|
||||
wB[3] = u*u2;
|
||||
wB[11] = v*v2;
|
||||
|
||||
wB[1] = 3 * uw * (uw + w2);
|
||||
wB[2] = 3 * uw * (uw + u2);
|
||||
|
||||
wB[7] = 3 * uv * (uv + u2);
|
||||
wB[10] = 3 * uv * (uv + v2);
|
||||
|
||||
wB[8] = 3 * vw * (vw + v2);
|
||||
wB[4] = 3 * vw * (vw + w2);
|
||||
|
||||
wB[5] = 12 * w2 * uv;
|
||||
wB[6] = 12 * u2 * vw;
|
||||
wB[9] = 12 * v2 * uw;
|
||||
wB[0] = ww * ww;
|
||||
wB[1] = 4 * uw * ww;
|
||||
wB[2] = 6 * uw * uw;
|
||||
wB[3] = 4 * uw * uu;
|
||||
wB[4] = uu * uu;
|
||||
wB[5] = 4 * vw * ww;
|
||||
wB[6] = 12 * ww * uv;
|
||||
wB[7] = 12 * uu * vw;
|
||||
wB[8] = 4 * uv * uu;
|
||||
wB[9] = 6 * vw * vw;
|
||||
wB[10] = 12 * vv * uw;
|
||||
wB[11] = 6 * uv * uv;
|
||||
wB[12] = 4 * vw * vv;
|
||||
wB[13] = 4 * uv * vv;
|
||||
wB[14] = vv * vv;
|
||||
} else if (totalOrder == 1) {
|
||||
if (ds != 0) {
|
||||
wB[0] = -3 * w2;
|
||||
wB[3] = 3 * u2;
|
||||
wB[11] = 0;
|
||||
|
||||
wB[1] = 3 * w * (w2 - uw - 2*u2);
|
||||
wB[2] = -3 * u * (u2 - uw - 2*w2);
|
||||
|
||||
wB[7] = 9 * u2*v + 6 * u*v2;
|
||||
wB[10] = 3 * v*v2 + 6 * u*v2;
|
||||
|
||||
wB[8] = -3 * v*v2 - 6 * v2*w;
|
||||
wB[4] = -9 * v*w2 - 6 * v2*w;
|
||||
|
||||
wB[5] = 12 * vw * (w - 2*u);
|
||||
wB[6] = 12 * uv * (2*w - u);
|
||||
wB[9] = 12 * v2 * (w - u);
|
||||
if (ds == 1) {
|
||||
wB[0] = -4 * ww * w;
|
||||
wB[1] = 4 * ww * (w - 3 * u);
|
||||
wB[2] = 12 * uw * (w - u);
|
||||
wB[3] = 4 * uu * (3 * w - u);
|
||||
wB[4] = 4 * uu * u;
|
||||
wB[5] = -12 * vw * w;
|
||||
wB[6] = 12 * vw * (w - 2 * u);
|
||||
wB[7] = 12 * uv * (2 * w - u);
|
||||
wB[8] = 12 * uv * u;
|
||||
wB[9] = -12 * vv * w;
|
||||
wB[10] = 12 * vv * (w - u);
|
||||
wB[11] = 12 * vv * u;
|
||||
wB[12] = -4 * vv * v;
|
||||
wB[13] = 4 * vv * v;
|
||||
wB[14] = 0;
|
||||
} else {
|
||||
wB[0] = -3 * w2;
|
||||
wB[3] = 0;
|
||||
wB[11] = 3 * v2;
|
||||
|
||||
wB[1] = -9 * u*w2 - 6 * u2*w;
|
||||
wB[2] = -3 * u*u2 - 6 * u2*w;
|
||||
|
||||
wB[7] = 3 * u*u2 + 6 * u2*v;
|
||||
wB[10] = 9 * u*v2 + 6 * u2*v;
|
||||
|
||||
wB[8] = -3 * v * (v2 - vw - 2*w2);
|
||||
wB[4] = 3 * w * (w2 - vw - 2*v2);
|
||||
|
||||
wB[5] = 12 * uw * (w - 2*v);
|
||||
wB[6] = 12 * u2 * (w - v);
|
||||
wB[9] = 12 * uv * (2*w - v);
|
||||
wB[0] = -4 * ww * w;
|
||||
wB[1] = -12 * ww * u;
|
||||
wB[2] = -12 * uu * w;
|
||||
wB[3] = -4 * uu * u;
|
||||
wB[4] = 0;
|
||||
wB[5] = 4 * ww * (w - 3 * v);
|
||||
wB[6] = 12 * uw * (w - 2 * v);
|
||||
wB[7] = 12 * uu * (w - v);
|
||||
wB[8] = 4 * uu * u;
|
||||
wB[9] = 12 * vw * (w - v);
|
||||
wB[10] = 12 * uv * (2 * w - v);
|
||||
wB[11] = 12 * uv * u;;
|
||||
wB[12] = 4 * vv * (3 * w - v);
|
||||
wB[13] = 12 * vv * u;
|
||||
wB[14] = 4 * vv * v;
|
||||
}
|
||||
} else if (totalOrder == 2) {
|
||||
if (ds == 2) {
|
||||
wB[0] = 6 * w;
|
||||
wB[3] = 6 * u;
|
||||
wB[11] = 0;
|
||||
|
||||
wB[1] = 6 * (u2 - uw - 2*w2);
|
||||
wB[2] = 6 * (w2 - uw - 2*u2);
|
||||
|
||||
wB[7] = 6 * v2 + 18 * uv;
|
||||
wB[10] = 6 * v2;
|
||||
|
||||
wB[8] = 6 * v2;
|
||||
wB[4] = 6 * v2 + 18 * vw;
|
||||
|
||||
wB[5] = 24 * (uv - 2*vw);
|
||||
wB[6] = 24 * (vw - 2*uv);
|
||||
wB[9] = -24 * v2;
|
||||
wB[0] = 12 * ww;
|
||||
wB[1] = 24 * (uw - ww);
|
||||
wB[2] = 12 * (uu - 4 * uw + ww);
|
||||
wB[3] = 24 * (uw - uu);
|
||||
wB[4] = 12 * uu;
|
||||
wB[5] = 24 * vw;
|
||||
wB[6] = 24 * (uv - 2 * vw);
|
||||
wB[7] = 24 * (vw - 2 * uv);
|
||||
wB[8] = 24 * uv;
|
||||
wB[9] = 12 * vv;
|
||||
wB[10] = -24 * vv;
|
||||
wB[11] = 12 * vv;
|
||||
wB[12] = 0;
|
||||
wB[13] = 0;
|
||||
wB[14] = 0;
|
||||
} else if (dt == 2) {
|
||||
wB[0] = 6 * w;
|
||||
wB[3] = 0;
|
||||
wB[11] = 6 * v;
|
||||
|
||||
wB[1] = 6 * u2 + 18 * uw;
|
||||
wB[2] = 6 * u2;
|
||||
|
||||
wB[7] = 6 * u2;
|
||||
wB[10] = 6 * u2 + 18 * uv;
|
||||
|
||||
wB[8] = 6 * (w2 - vw - 2*v2);
|
||||
wB[4] = 6 * (v2 - vw - 2*w2);
|
||||
|
||||
wB[5] = 24 * (uv - 2*uw);
|
||||
wB[6] = -24 * u2;
|
||||
wB[9] = 24 * (uw - 2*uv);
|
||||
wB[0] = 12 * ww;
|
||||
wB[1] = 24 * uw;
|
||||
wB[2] = 12 * uu;
|
||||
wB[3] = 0;
|
||||
wB[4] = 0;
|
||||
wB[5] = 24 * (vw - ww);
|
||||
wB[6] = 24 * (uv - 2 * uw);
|
||||
wB[7] = -24 * uu;
|
||||
wB[8] = 0;
|
||||
wB[9] = 12 * (vv - 4 * vw + ww);
|
||||
wB[10] = 24 * (uw - 2 * uv);
|
||||
wB[11] = 12 * uu;
|
||||
wB[12] = 24 * (vw - vv);
|
||||
wB[13] = 24 * uv;
|
||||
wB[14] = 12 * vv;
|
||||
} else {
|
||||
wB[0] = 6 * w;
|
||||
wB[3] = 0;
|
||||
wB[11] = 0;
|
||||
|
||||
wB[1] = 6 * (u2 + uw - 1.5f*w2);
|
||||
wB[2] = -3 * (u2 + 4*uw);
|
||||
|
||||
wB[7] = 9 * u2 + 12 * uv;
|
||||
wB[10] = 9 * v2 + 12 * uv;
|
||||
|
||||
wB[8] = -3 * (v2 + 4*vw);
|
||||
wB[4] = 6 * (v2 + vw - 1.5f*w2);
|
||||
|
||||
wB[5] = 24 * (uv - vw - uw + 0.5f*w2);
|
||||
wB[6] = -24 * (uv - uw + 0.5f*u2);
|
||||
wB[9] = -24 * (uv - vw + 0.5f*v2);
|
||||
wB[0] = 12 * ww;
|
||||
wB[3] = -12 * uu;
|
||||
wB[13] = 12 * vv;
|
||||
wB[11] = 24 * uv;
|
||||
wB[1] = 24 * uw - wB[0];
|
||||
wB[2] = -24 * uw - wB[3];
|
||||
wB[5] = 24 * vw - wB[0];
|
||||
wB[6] = -24 * vw + wB[11] - wB[1];
|
||||
wB[8] = - wB[3];
|
||||
wB[7] = -(wB[11] + wB[2]);
|
||||
wB[9] = wB[13] - wB[5] - wB[0];
|
||||
wB[10] = -(wB[9] + wB[11]);
|
||||
wB[12] = - wB[13];
|
||||
wB[4] = 0;
|
||||
wB[14] = 0;
|
||||
}
|
||||
} else {
|
||||
// assert(totalOrder <= 2);
|
||||
@ -969,12 +963,12 @@ OSD_FUNCTION_STORAGE_CLASS
|
||||
// template <typename REAL>
|
||||
int
|
||||
Osd_EvalBasisBezierTri(OSD_REAL s, OSD_REAL t,
|
||||
OSD_OUT_ARRAY(OSD_REAL, wP, 12),
|
||||
OSD_OUT_ARRAY(OSD_REAL, wDs, 12),
|
||||
OSD_OUT_ARRAY(OSD_REAL, wDt, 12),
|
||||
OSD_OUT_ARRAY(OSD_REAL, wDss, 12),
|
||||
OSD_OUT_ARRAY(OSD_REAL, wDst, 12),
|
||||
OSD_OUT_ARRAY(OSD_REAL, wDtt, 12)) {
|
||||
OSD_OUT_ARRAY(OSD_REAL, wP, 15),
|
||||
OSD_OUT_ARRAY(OSD_REAL, wDs, 15),
|
||||
OSD_OUT_ARRAY(OSD_REAL, wDt, 15),
|
||||
OSD_OUT_ARRAY(OSD_REAL, wDss, 15),
|
||||
OSD_OUT_ARRAY(OSD_REAL, wDst, 15),
|
||||
OSD_OUT_ARRAY(OSD_REAL, wDtt, 15)) {
|
||||
|
||||
if (OSD_OPTIONAL(wP)) {
|
||||
Osd_evalBezierTriDerivWeights(s, t, 0, 0, wP);
|
||||
@ -989,40 +983,44 @@ Osd_EvalBasisBezierTri(OSD_REAL s, OSD_REAL t,
|
||||
Osd_evalBezierTriDerivWeights(s, t, 0, 2, wDtt);
|
||||
}
|
||||
}
|
||||
return 12;
|
||||
return 15;
|
||||
}
|
||||
|
||||
|
||||
// namespace {
|
||||
//
|
||||
// Expanding a set of 12 Bezier basis functions for the 6 (3 pairs) of
|
||||
// rational weights for the 15 Gregory basis functions:
|
||||
// Expanding a set of 15 Bezier basis functions for the 6 (3 pairs) of
|
||||
// rational weights for the 18 Gregory basis functions:
|
||||
//
|
||||
OSD_FUNCTION_STORAGE_CLASS
|
||||
// template <typename REAL>
|
||||
void
|
||||
Osd_convertBezierWeightsToGregory(
|
||||
OSD_INOUT_ARRAY(OSD_REAL, wB, 12),
|
||||
OSD_INOUT_ARRAY(OSD_REAL, wB, 15),
|
||||
OSD_INOUT_ARRAY(OSD_REAL, rG, 6),
|
||||
OSD_OUT_ARRAY(OSD_REAL, wG, 15)) {
|
||||
OSD_OUT_ARRAY(OSD_REAL, wG, 18)) {
|
||||
|
||||
wG[0] = wB[0];
|
||||
wG[1] = wB[1];
|
||||
wG[2] = wB[4];
|
||||
wG[3] = wB[5] * rG[0];
|
||||
wG[4] = wB[5] * rG[1];
|
||||
wG[2] = wB[5];
|
||||
wG[3] = wB[6] * rG[0];
|
||||
wG[4] = wB[6] * rG[1];
|
||||
|
||||
wG[5] = wB[3];
|
||||
wG[6] = wB[7];
|
||||
wG[7] = wB[2];
|
||||
wG[8] = wB[6] * rG[2];
|
||||
wG[9] = wB[6] * rG[3];
|
||||
wG[5] = wB[4];
|
||||
wG[6] = wB[8];
|
||||
wG[7] = wB[3];
|
||||
wG[8] = wB[7] * rG[2];
|
||||
wG[9] = wB[7] * rG[3];
|
||||
|
||||
wG[10] = wB[11];
|
||||
wG[11] = wB[8];
|
||||
wG[12] = wB[10];
|
||||
wG[13] = wB[9] * rG[4];
|
||||
wG[14] = wB[9] * rG[5];
|
||||
wG[10] = wB[14];
|
||||
wG[11] = wB[12];
|
||||
wG[12] = wB[13];
|
||||
wG[13] = wB[10] * rG[4];
|
||||
wG[14] = wB[10] * rG[5];
|
||||
|
||||
wG[15] = wB[2];
|
||||
wG[16] = wB[11];
|
||||
wG[17] = wB[9];
|
||||
}
|
||||
// } // end namespace
|
||||
|
||||
@ -1030,19 +1028,19 @@ OSD_FUNCTION_STORAGE_CLASS
|
||||
// template <typename REAL>
|
||||
int
|
||||
Osd_EvalBasisGregoryTri(OSD_REAL s, OSD_REAL t,
|
||||
OSD_OUT_ARRAY(OSD_REAL, wP, 15),
|
||||
OSD_OUT_ARRAY(OSD_REAL, wDs, 15),
|
||||
OSD_OUT_ARRAY(OSD_REAL, wDt, 15),
|
||||
OSD_OUT_ARRAY(OSD_REAL, wDss, 15),
|
||||
OSD_OUT_ARRAY(OSD_REAL, wDst, 15),
|
||||
OSD_OUT_ARRAY(OSD_REAL, wDtt, 15)) {
|
||||
OSD_OUT_ARRAY(OSD_REAL, wP, 18),
|
||||
OSD_OUT_ARRAY(OSD_REAL, wDs, 18),
|
||||
OSD_OUT_ARRAY(OSD_REAL, wDt, 18),
|
||||
OSD_OUT_ARRAY(OSD_REAL, wDss, 18),
|
||||
OSD_OUT_ARRAY(OSD_REAL, wDst, 18),
|
||||
OSD_OUT_ARRAY(OSD_REAL, wDtt, 18)) {
|
||||
|
||||
//
|
||||
// Bezier basis functions are denoted with B while the rational multipliers for the
|
||||
// interior points will be denoted G -- so we have B(s,t) and G(s,t) (though we
|
||||
// switch to barycentric (u,v,w) briefly to compute G)
|
||||
//
|
||||
OSD_REAL BP[12], BDs[12], BDt[12], BDss[12], BDst[12], BDtt[12];
|
||||
OSD_REAL BP[15], BDs[15], BDt[15], BDss[15], BDst[15], BDtt[15];
|
||||
|
||||
OSD_REAL G[6] = OSD_ARRAY_6(OSD_REAL, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f );
|
||||
OSD_REAL u = s;
|
||||
@ -1088,7 +1086,7 @@ Osd_EvalBasisGregoryTri(OSD_REAL s, OSD_REAL t,
|
||||
Osd_convertBezierWeightsToGregory(BDtt, G, wDtt);
|
||||
}
|
||||
}
|
||||
return 15;
|
||||
return 18;
|
||||
}
|
||||
|
||||
#define OSD_PATCH_BASIS_COMPATIBILITY
|
||||
|
@ -92,14 +92,14 @@ OsdEvaluatePatchBasisNormalized(
|
||||
#if OSD_ARRAY_ARG_BOUND_OPTIONAL
|
||||
nPoints = Osd_EvalBasisGregoryTri(s, t, wP, wDs, wDt, wDss, wDst, wDtt);
|
||||
#else
|
||||
OSD_REAL wP15[15], wDs15[15], wDt15[15],
|
||||
wDss15[15], wDst15[15], wDtt15[15];
|
||||
OSD_REAL wP18[18], wDs18[18], wDt18[18],
|
||||
wDss18[18], wDst18[18], wDtt18[18];
|
||||
nPoints = Osd_EvalBasisGregoryTri(
|
||||
s, t, wP15, wDs15, wDt15, wDss15, wDst15, wDtt15);
|
||||
s, t, wP18, wDs18, wDt18, wDss18, wDst18, wDtt18);
|
||||
for (int i=0; i<nPoints; ++i) {
|
||||
wP[i] = wP15[i];
|
||||
wDs[i] = wDs15[i]; wDt[i] = wDt15[i];
|
||||
wDss[i] = wDss15[i]; wDst[i] = wDst15[i]; wDtt[i] = wDtt15[i];
|
||||
wP[i] = wP18[i];
|
||||
wDs[i] = wDs18[i]; wDt[i] = wDt18[i];
|
||||
wDss[i] = wDss18[i]; wDst[i] = wDst18[i]; wDtt[i] = wDtt18[i];
|
||||
}
|
||||
#endif
|
||||
} else if (patchType == OSD_PATCH_DESCRIPTOR_QUADS) {
|
||||
|
Loading…
Reference in New Issue
Block a user