mirror of
https://github.com/PixarAnimationStudios/OpenSubdiv
synced 2025-01-03 13:41:06 +00:00
Merge branch 'rc/v3_3_2'
This commit is contained in:
commit
5b297d8866
@ -31,6 +31,19 @@
|
||||
|
||||
----
|
||||
|
||||
Release 3.3.2
|
||||
=============
|
||||
|
||||
Release 3.3.2 is a minor release with potentially significant performance
|
||||
improvements to the patch pre-processing stages
|
||||
|
||||
**Changes**
|
||||
- Improved performance of PatchTable construction (GitHub Issue #966)
|
||||
- The resulting improved accuracy will produce slight numerical differences in computations involving patches, e.g. StencilTable and PatchTable evaluation
|
||||
|
||||
**Bug Fixes**
|
||||
- Far::PatchTableFactory now supports PatchTable construction with ENDCAP_BILINEAR_BASIS specified
|
||||
|
||||
Release 3.3.1
|
||||
=============
|
||||
|
||||
@ -38,8 +51,8 @@ Release 3.3.1 is a minor bug-fix release
|
||||
|
||||
**Bug Fixes**
|
||||
- Fixed GLSL/HLSL/Metal patch shader code to resolve degenerate normals (GitHub Issue #947)
|
||||
- Fixed problems with face-varying patches in uniform PatchTables
|
||||
- Fixed integer overflow bugs for large meshes in PatchTable factories
|
||||
- Fixed problems with face-varying patches in uniform PatchTables (GitHub Issue #946)
|
||||
- Fixed integer overflow bugs for large meshes in PatchTable factories (GitHub Issue #957)
|
||||
- Fixed computation of PatchParam for triangle refinement (GitHub Issue #962)
|
||||
|
||||
**Changes**
|
||||
|
@ -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
|
||||
)
|
||||
|
||||
|
93
opensubdiv/far/bilinearPatchBuilder.cpp
Normal file
93
opensubdiv/far/bilinearPatchBuilder.cpp
Normal 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
|
65
opensubdiv/far/bilinearPatchBuilder.h
Normal file
65
opensubdiv/far/bilinearPatchBuilder.h
Normal 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 */
|
1951
opensubdiv/far/catmarkPatchBuilder.cpp
Normal file
1951
opensubdiv/far/catmarkPatchBuilder.cpp
Normal file
File diff suppressed because it is too large
Load Diff
68
opensubdiv/far/catmarkPatchBuilder.h
Normal file
68
opensubdiv/far/catmarkPatchBuilder.h
Normal 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 */
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
||||
|
@ -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
|
@ -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
|
@ -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 */
|
92
opensubdiv/far/loopPatchBuilder.cpp
Normal file
92
opensubdiv/far/loopPatchBuilder.cpp
Normal 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
|
65
opensubdiv/far/loopPatchBuilder.h
Normal file
65
opensubdiv/far/loopPatchBuilder.h
Normal 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 */
|
1141
opensubdiv/far/patchBuilder.cpp
Normal file
1141
opensubdiv/far/patchBuilder.cpp
Normal file
File diff suppressed because it is too large
Load Diff
321
opensubdiv/far/patchBuilder.h
Normal file
321
opensubdiv/far/patchBuilder.h
Normal 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 */
|
@ -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
@ -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
|
||||
|
183
opensubdiv/far/sparseMatrix.h
Normal file
183
opensubdiv/far/sparseMatrix.h
Normal 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), _numElements(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.size();
|
||||
}
|
||||
|
||||
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 */
|
@ -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
|
||||
|
||||
|
@ -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"
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -25,13 +25,13 @@
|
||||
#ifndef OPENSUBDIV3_VERSION_H
|
||||
#define OPENSUBDIV3_VERSION_H
|
||||
|
||||
#define OPENSUBDIV_VERSION v3_3_1
|
||||
#define OPENSUBDIV_VERSION v3_3_2
|
||||
|
||||
#define OPENSUBDIV_VERSION_NUMBER 30301
|
||||
#define OPENSUBDIV_VERSION_NUMBER 30302
|
||||
|
||||
#define OPENSUBDIV_VERSION_MAJOR 3
|
||||
#define OPENSUBDIV_VERSION_MINOR 3
|
||||
#define OPENSUBDIV_VERSION_PATCH 1
|
||||
#define OPENSUBDIV_VERSION_PATCH 2
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user