mirror of
https://github.com/PixarAnimationStudios/OpenSubdiv
synced 2025-01-12 01:20:07 +00:00
Fix Far to handle disconnected vertices in an Hbr mesh.
Also: - change our shape parser to skip non-manifold faces (print a warning) - add a 'fan' non-manifold test shape to the glViewer fixes #233
This commit is contained in:
parent
a68bad450d
commit
9e9fd5c021
@ -382,6 +382,9 @@ initializeShapes( ) {
|
||||
#include <shapes/catmark_edgeonly.h>
|
||||
g_defaultShapes.push_back(SimpleShape(catmark_edgeonly, "catmark_edgeonly", kCatmark));
|
||||
|
||||
#include <shapes/catmark_fan.h>
|
||||
g_defaultShapes.push_back(SimpleShape(catmark_fan, "catmark_fan", kCatmark));
|
||||
|
||||
#include <shapes/catmark_gregory_test1.h>
|
||||
g_defaultShapes.push_back(SimpleShape(catmark_gregory_test1, "catmark_gregory_test1", kCatmark));
|
||||
|
||||
|
@ -27,7 +27,7 @@
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
// Activate Hbr feature adaptive tagging : in order to process the HbrMesh
|
||||
// Activate Hbr feature adaptive tagging : in order to process the HbrMesh
|
||||
// adaptively, some tag data is added to HbrFace, HbrVertex and HbrHalfedge.
|
||||
// While small, these tags incur some performance costs and are by default
|
||||
// disabled.
|
||||
@ -54,7 +54,7 @@ namespace OPENSUBDIV_VERSION {
|
||||
|
||||
/// \brief Instantiates a FarMesh from an HbrMesh.
|
||||
///
|
||||
/// FarMeshFactory requires a 2 steps process :
|
||||
/// FarMeshFactory requires a 2 steps process :
|
||||
/// 1. Instantiate a FarMeshFactory object from an HbrMesh
|
||||
/// 2. Call "Create" to obtain the FarMesh instance
|
||||
///
|
||||
@ -68,7 +68,7 @@ template <class T, class U=T> class FarMeshFactory {
|
||||
public:
|
||||
|
||||
/// \brief Constructor for the factory.
|
||||
/// Analyzes the HbrMesh and stores transient data used to create the
|
||||
/// Analyzes the HbrMesh and stores transient data used to create the
|
||||
/// adaptive patch representation. Once the new rep has been instantiated
|
||||
/// with 'Create', this factory object can be deleted safely.
|
||||
///
|
||||
@ -76,7 +76,7 @@ public:
|
||||
/// modified by this factory).
|
||||
///
|
||||
/// @param maxlevel In uniform subdivision mode : number of levels of
|
||||
/// subdivision. In feature adaptive mode : maximum
|
||||
/// subdivision. In feature adaptive mode : maximum
|
||||
/// level of isolation around extraordinary topological
|
||||
/// features.
|
||||
///
|
||||
@ -98,12 +98,12 @@ public:
|
||||
FarMesh<U> * Create( bool requireFVarData=false );
|
||||
|
||||
/// \brief Computes the minimum number of adaptive feature isolation levels required
|
||||
/// in order for the limit surface to be an accurate representation of the
|
||||
/// in order for the limit surface to be an accurate representation of the
|
||||
/// shape given all the tags and edits.
|
||||
///
|
||||
/// @param mesh The HbrMesh describing the topology
|
||||
/// @param mesh The HbrMesh describing the topology
|
||||
///
|
||||
/// @param nfaces The number of faces in the HbrMesh
|
||||
/// @param nfaces The number of faces in the HbrMesh
|
||||
///
|
||||
/// @param cornerIsolate The level of isolation desired for patch corners
|
||||
///
|
||||
@ -134,7 +134,7 @@ public:
|
||||
return sumList<HbrFace<T> *>(_facesList, level);
|
||||
}
|
||||
|
||||
/// \brief Returns the corresponding index of the HbrVertex<T> in the new
|
||||
/// \brief Returns the corresponding index of the HbrVertex<T> in the new
|
||||
/// FarMesh
|
||||
///
|
||||
/// @param v the vertex
|
||||
@ -143,7 +143,7 @@ public:
|
||||
///
|
||||
int GetVertexID( HbrVertex<T> * v );
|
||||
|
||||
/// \brief Returns a the mapping between HbrVertex<T>->GetID() and Far
|
||||
/// \brief Returns a the mapping between HbrVertex<T>->GetID() and Far
|
||||
/// vertices indices
|
||||
///
|
||||
/// @return the table that maps HbrMesh to FarMesh vertex indices
|
||||
@ -161,10 +161,10 @@ private:
|
||||
template <class X> struct VertCompare {
|
||||
bool operator()(HbrVertex<X> const * v1, HbrVertex<X> const * v2 ) const {
|
||||
//return v1->GetID() < v2->GetID();
|
||||
return (void*)(v1) < (void*)(v2);
|
||||
return (void*)(v1) < (void*)(v2);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Non-copyable, so these are not implemented:
|
||||
FarMeshFactory( FarMeshFactory const & );
|
||||
FarMeshFactory<T,U> & operator=(FarMeshFactory<T,U> const &);
|
||||
@ -200,12 +200,12 @@ private:
|
||||
|
||||
// Adaptively refine the Hbr mesh
|
||||
int refineAdaptive( HbrMesh<T> * mesh, int maxIsolate );
|
||||
|
||||
|
||||
typedef std::vector<std::vector< HbrFace<T> *> > FacesList;
|
||||
|
||||
|
||||
// Returns sorted vectors of HbrFace<T> pointers sorted by level
|
||||
FacesList const & GetFaceList() const { return _facesList; }
|
||||
|
||||
|
||||
private:
|
||||
HbrMesh<T> * _hbrMesh;
|
||||
|
||||
@ -244,16 +244,16 @@ FarMeshFactory<T,U>::refine( HbrMesh<T> * mesh, int maxlevel ) {
|
||||
for (int level=0, firstface=0; level<maxlevel; ++level ) {
|
||||
|
||||
int nfaces = mesh->GetNumFaces();
|
||||
|
||||
|
||||
for (int i=firstface; i<nfaces; ++i) {
|
||||
|
||||
|
||||
HbrFace<T> * f = mesh->GetFace(i);
|
||||
|
||||
if (f->GetDepth()==level) {
|
||||
|
||||
if (not f->IsHole()) {
|
||||
f->Refine();
|
||||
} else {
|
||||
} else {
|
||||
|
||||
// Hole faces need to maintain the 1-ring of vertices so we
|
||||
// have to create an extra row of children faces around the
|
||||
@ -262,20 +262,20 @@ FarMeshFactory<T,U>::refine( HbrMesh<T> * mesh, int maxlevel ) {
|
||||
for (int i=0; i<f->GetNumVertices(); ++i) {
|
||||
assert(e);
|
||||
if (e->GetRightFace() and (not e->GetRightFace()->IsHole())) {
|
||||
|
||||
|
||||
// RefineFaceAtVertex only creates a single child face
|
||||
// centered on the passed vertex
|
||||
HbrSubdivision<T> * s = mesh->GetSubdivision();
|
||||
s->RefineFaceAtVertex(mesh,f,e->GetOrgVertex());
|
||||
s->RefineFaceAtVertex(mesh,f,e->GetDestVertex());
|
||||
}
|
||||
|
||||
|
||||
e = e->GetNext();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Hbr allocates faces sequentially, so there is no need to iterate over
|
||||
// faces that have already been refined.
|
||||
firstface = nfaces;
|
||||
@ -285,17 +285,17 @@ FarMeshFactory<T,U>::refine( HbrMesh<T> * mesh, int maxlevel ) {
|
||||
}
|
||||
|
||||
// Scan the faces of a mesh and compute the max level of subdivision required
|
||||
template <class T, class U> int
|
||||
template <class T, class U> int
|
||||
FarMeshFactory<T,U>::ComputeMinIsolation( HbrMesh<T> const * mesh, int nfaces, int cornerIsolate ) {
|
||||
|
||||
assert(mesh);
|
||||
|
||||
|
||||
int editmax=0;
|
||||
int editmax=0;
|
||||
float sharpmax=0.0f;
|
||||
|
||||
|
||||
float cornerSharp=0.0;
|
||||
|
||||
|
||||
float cornerSharp=0.0;
|
||||
if (mesh->GetInterpolateBoundaryMethod()<HbrMesh<T>::k_InterpolateBoundaryEdgeAndCorner)
|
||||
cornerSharp = (float) cornerIsolate;
|
||||
|
||||
@ -312,9 +312,9 @@ FarMeshFactory<T,U>::ComputeMinIsolation( HbrMesh<T> const * mesh, int nfaces, i
|
||||
|
||||
// Check edge sharpness and hierarchical edits
|
||||
for (int i=0 ; i<nfaces ; ++i) {
|
||||
|
||||
|
||||
HbrFace<T> * f = mesh->GetFace(i);
|
||||
|
||||
|
||||
// We don't need to check non-coarse faces
|
||||
if (not f->IsCoarse())
|
||||
continue;
|
||||
@ -332,7 +332,7 @@ FarMeshFactory<T,U>::ComputeMinIsolation( HbrMesh<T> const * mesh, int nfaces, i
|
||||
// Check for sharpness
|
||||
int nv = f->GetNumVertices();
|
||||
for (int j=0; j<nv; ++j) {
|
||||
|
||||
|
||||
HbrHalfedge<T> * e = f->GetEdge(j);
|
||||
if (not e->IsBoundary())
|
||||
sharpmax = std::max( sharpmax, f->GetEdge(j)->GetSharpness() );
|
||||
@ -340,34 +340,34 @@ FarMeshFactory<T,U>::ComputeMinIsolation( HbrMesh<T> const * mesh, int nfaces, i
|
||||
}
|
||||
|
||||
int result = std::max( (int)ceil(sharpmax)+1, editmax+1 );
|
||||
|
||||
|
||||
// Cap the result to "infinitely sharp" (10)
|
||||
return std::min( result, (int)HbrHalfedge<T>::k_InfinitelySharp );
|
||||
}
|
||||
|
||||
// True if a vertex is a regular boundary
|
||||
template <class T, class U> bool
|
||||
template <class T, class U> bool
|
||||
FarMeshFactory<T,U>::vertexIsRegularBoundary( HbrVertex<T> * v ) {
|
||||
int valence = v->GetValence();
|
||||
int valence = v->GetValence();
|
||||
return (v->OnBoundary() and (valence==2 or valence==3));
|
||||
}
|
||||
|
||||
// True if the vertex can be incorporated into a B-spline patch
|
||||
template <class T, class U> bool
|
||||
template <class T, class U> bool
|
||||
FarMeshFactory<T,U>::vertexIsBSpline( HbrVertex<T> * v, bool next ) {
|
||||
|
||||
int valence = v->GetValence();
|
||||
|
||||
int valence = v->GetValence();
|
||||
|
||||
bool isRegBoundary = v->OnBoundary() and (valence==3);
|
||||
|
||||
|
||||
// Extraordinary vertices that are not on a regular boundary
|
||||
if (v->IsExtraordinary() and not isRegBoundary )
|
||||
return false;
|
||||
|
||||
|
||||
// Irregular boundary vertices (high valence)
|
||||
if (v->OnBoundary() and (valence>3))
|
||||
return false;
|
||||
|
||||
|
||||
// Creased vertices that aren't corner / boundaries
|
||||
if (v->IsSharp(next) and not v->OnBoundary())
|
||||
return false;
|
||||
@ -376,9 +376,9 @@ FarMeshFactory<T,U>::vertexIsBSpline( HbrVertex<T> * v, bool next ) {
|
||||
}
|
||||
|
||||
// Calls Hbr to refines the neighbors of v
|
||||
template <class T, class U> void
|
||||
template <class T, class U> void
|
||||
FarMeshFactory<T,U>::refineVertexNeighbors(HbrVertex<T> * v) {
|
||||
|
||||
|
||||
assert(v);
|
||||
|
||||
HbrHalfedge<T> * start = v->GetIncidentEdge(),
|
||||
@ -388,23 +388,23 @@ FarMeshFactory<T,U>::refineVertexNeighbors(HbrVertex<T> * v) {
|
||||
HbrFace<T> * lft = next->GetLeftFace(),
|
||||
* rgt = next->GetRightFace();
|
||||
|
||||
if (not ((lft and lft->IsHole()) and
|
||||
if (not ((lft and lft->IsHole()) and
|
||||
(rgt and rgt->IsHole()) ) ) {
|
||||
|
||||
|
||||
if (rgt)
|
||||
rgt->_adaptiveFlags.isTagged=true;
|
||||
|
||||
if (lft)
|
||||
lft->_adaptiveFlags.isTagged=true;
|
||||
|
||||
HbrHalfedge<T> * istart = next,
|
||||
HbrHalfedge<T> * istart = next,
|
||||
* inext = istart;
|
||||
do {
|
||||
if (not inext->IsInsideHole() )
|
||||
inext->GetOrgVertex()->Refine();
|
||||
inext = inext->GetNext();
|
||||
} while (istart != inext);
|
||||
}
|
||||
}
|
||||
next = v->GetNextEdge( next );
|
||||
} while (next and next!=start);
|
||||
}
|
||||
@ -417,26 +417,31 @@ FarMeshFactory<T,U>::refineAdaptive( HbrMesh<T> * mesh, int maxIsolate ) {
|
||||
int ncoarsefaces = mesh->GetNumCoarseFaces(),
|
||||
ncoarseverts = mesh->GetNumVertices();
|
||||
|
||||
int maxlevel = maxIsolate+1;
|
||||
|
||||
int maxlevel = maxIsolate+1;
|
||||
|
||||
// First pass : tag coarse vertices & faces that need refinement
|
||||
|
||||
typedef std::set<HbrVertex<T> *,VertCompare<T> > VertSet;
|
||||
VertSet verts, nextverts;
|
||||
|
||||
|
||||
for (int i=0; i<ncoarseverts; ++i) {
|
||||
HbrVertex<T> * v = mesh->GetVertex(i);
|
||||
|
||||
|
||||
// Non manifold topology may leave un-connected vertices that need to be skipped
|
||||
if (not v->IsConnected()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Tag non-BSpline vertices for refinement
|
||||
if (not vertexIsBSpline(v, false)) {
|
||||
v->_adaptiveFlags.isTagged=true;
|
||||
nextverts.insert(v);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for (int i=0; i<ncoarsefaces; ++i) {
|
||||
HbrFace<T> * f = mesh->GetFace(i);
|
||||
|
||||
|
||||
if (f->IsHole())
|
||||
continue;
|
||||
|
||||
@ -444,7 +449,7 @@ FarMeshFactory<T,U>::refineAdaptive( HbrMesh<T> * mesh, int maxIsolate ) {
|
||||
|
||||
int nv = f->GetNumVertices();
|
||||
for (int j=0; j<nv; ++j) {
|
||||
|
||||
|
||||
HbrHalfedge<T> * e = f->GetEdge(j);
|
||||
assert(e);
|
||||
|
||||
@ -452,11 +457,11 @@ FarMeshFactory<T,U>::refineAdaptive( HbrMesh<T> * mesh, int maxIsolate ) {
|
||||
if (e->IsSharp(true) and (not e->IsBoundary())) {
|
||||
nextverts.insert(e->GetOrgVertex());
|
||||
nextverts.insert(e->GetDestVertex());
|
||||
|
||||
|
||||
e->GetOrgVertex()->_adaptiveFlags.isTagged=true;
|
||||
e->GetDestVertex()->_adaptiveFlags.isTagged=true;
|
||||
}
|
||||
|
||||
|
||||
// Tag extraordinary (non-quad) faces for refinement
|
||||
if (extraordinary or f->HasVertexEdits()) {
|
||||
HbrVertex<T> * v = f->GetVertex(j);
|
||||
@ -465,7 +470,7 @@ FarMeshFactory<T,U>::refineAdaptive( HbrMesh<T> * mesh, int maxIsolate ) {
|
||||
}
|
||||
|
||||
// Quad-faces with 2 non-consecutive boundaries need to be flagged
|
||||
// for refinement as boundary patches.
|
||||
// for refinement as boundary patches.
|
||||
//
|
||||
// o ........ o ........ o ........ o
|
||||
// . | | . ... b.undary edge
|
||||
@ -475,7 +480,7 @@ FarMeshFactory<T,U>::refineAdaptive( HbrMesh<T> * mesh, int maxIsolate ) {
|
||||
// o ........ o ........ o ........ o
|
||||
//
|
||||
if ( e->IsBoundary() and (not f->_adaptiveFlags.isTagged) and nv==4 ) {
|
||||
|
||||
|
||||
if (e->GetPrev() and (not e->GetPrev()->IsBoundary()) and
|
||||
e->GetNext() and (not e->GetNext()->IsBoundary()) and
|
||||
e->GetNext() and e->GetNext()->GetNext() and e->GetNext()->GetNext()->IsBoundary()) {
|
||||
@ -495,10 +500,10 @@ FarMeshFactory<T,U>::refineAdaptive( HbrMesh<T> * mesh, int maxIsolate ) {
|
||||
}
|
||||
_maxValence = std::max(_maxValence, nv);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Second pass : refine adaptively around singularities
|
||||
|
||||
|
||||
for (int level=0; level<maxlevel-1; ++level) {
|
||||
|
||||
verts = nextverts;
|
||||
@ -530,7 +535,7 @@ FarMeshFactory<T,U>::refineAdaptive( HbrMesh<T> * mesh, int maxIsolate ) {
|
||||
|
||||
// Skip edges that have already been processed (HasChild())
|
||||
if ((not e->HasChild()) and e->IsSharp(false) and (not e->IsBoundary())) {
|
||||
|
||||
|
||||
if (not e->IsInsideHole()) {
|
||||
nextverts.insert( e->Subdivide() );
|
||||
nextverts.insert( e->GetOrgVertex()->Subdivide() );
|
||||
@ -562,15 +567,15 @@ FarMeshFactory<T,U>::refineAdaptive( HbrMesh<T> * mesh, int maxIsolate ) {
|
||||
for (int i=0; i<ncoarsefaces; ++i) {
|
||||
HbrFace<T> * f = mesh->GetFace(i);
|
||||
assert (f->IsCoarse());
|
||||
|
||||
|
||||
if (mesh->GetSubdivision()->FaceIsExtraordinary(mesh,f))
|
||||
nextverts.insert( f->Subdivide() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
mesh->SetSubdivisionMethod(HbrMesh<T>::k_SubdivisionMethodFeatureAdaptive);
|
||||
|
||||
|
||||
return maxlevel-1;
|
||||
}
|
||||
|
||||
@ -592,20 +597,20 @@ FarMeshFactory<T,U>::FarMeshFactory( HbrMesh<T> * mesh, int maxlevel, bool adapt
|
||||
{
|
||||
_numCoarseVertices = mesh->GetNumVertices();
|
||||
_numPtexFaces = getNumPtexFaces(mesh);
|
||||
|
||||
|
||||
// Subdivide the Hbr mesh up to maxlevel.
|
||||
//
|
||||
// Note : using a placeholder vertex class 'T' can greatly speed up the
|
||||
// Note : using a placeholder vertex class 'T' can greatly speed up the
|
||||
// topological analysis if the interpolation results are not used.
|
||||
if (adaptive)
|
||||
_maxlevel=refineAdaptive( mesh, maxlevel );
|
||||
else
|
||||
refine( mesh, maxlevel);
|
||||
|
||||
|
||||
_numFaces = mesh->GetNumFaces();
|
||||
|
||||
_numVertices = mesh->GetNumVertices();
|
||||
|
||||
|
||||
if (not adaptive) {
|
||||
|
||||
// Populate the face lists
|
||||
@ -621,7 +626,7 @@ FarMeshFactory<T,U>::FarMeshFactory( HbrMesh<T> * mesh, int maxlevel, bool adapt
|
||||
_facesList[1].reserve(fsize);
|
||||
for (int l=2; l<=maxlevel; ++l)
|
||||
_facesList[l].reserve( _facesList[l-1].capacity()*4 );
|
||||
|
||||
|
||||
for (int i=0; i<_numFaces; ++i) {
|
||||
HbrFace<T> * f = mesh->GetFace(i);
|
||||
if (f->GetDepth()<=maxlevel and (not f->IsHole()))
|
||||
@ -763,7 +768,7 @@ FarMeshFactory<T,U>::Create( bool requireFVarData ) {
|
||||
return 0;
|
||||
|
||||
FarMesh<U> * result = new FarMesh<U>();
|
||||
|
||||
|
||||
if ( isBilinear( GetHbrMesh() ) ) {
|
||||
result->_subdivisionTables = FarBilinearSubdivisionTablesFactory<T,U>::Create(this, result, &result->_batches);
|
||||
} else if ( isCatmark( GetHbrMesh() ) ) {
|
||||
@ -796,7 +801,7 @@ FarMeshFactory<T,U>::Create( bool requireFVarData ) {
|
||||
assert( result->_patchTables );
|
||||
|
||||
result->_numPtexFaces = _numPtexFaces;
|
||||
|
||||
|
||||
if (requireFVarData) {
|
||||
result->_totalFVarWidth = _hbrMesh->GetTotalFVarWidth();
|
||||
} else {
|
||||
@ -808,7 +813,7 @@ FarMeshFactory<T,U>::Create( bool requireFVarData ) {
|
||||
result->_vertexEditTables = FarVertexEditTablesFactory<T,U>::Create( this, result, &result->_batches, GetMaxLevel() );
|
||||
assert(result->_vertexEditTables);
|
||||
}
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -868,7 +868,7 @@ FarPatchTablesFactory<T>::Create( int maxlevel, int maxvalence, bool requireFVar
|
||||
// feature adaptive refinement can generate un-connected face-vertices
|
||||
// that have a valence of 0
|
||||
if (not v->IsConnected()) {
|
||||
assert( v->GetParentFace() );
|
||||
//assert( v->GetParentFace() );
|
||||
table[offset] = 0;
|
||||
continue;
|
||||
}
|
||||
|
@ -53,7 +53,7 @@ protected:
|
||||
friend class FarLoopSubdivisionTablesFactory<T,U>;
|
||||
|
||||
template <class X, class Y> friend class FarMeshFactory;
|
||||
|
||||
|
||||
// This factory accumulates vertex topology data that will be shared among the
|
||||
// specialized subdivision scheme factories (Bilinear / Catmark / Loop).
|
||||
// It also populates the FarMeshFactory vertex remapping vector that ties the
|
||||
@ -61,8 +61,8 @@ protected:
|
||||
FarSubdivisionTablesFactory( HbrMesh<T> const * mesh, int maxlevel, std::vector<int> & remapTable );
|
||||
|
||||
// Returns the number of coarse vertices found in the mesh
|
||||
int GetNumCoarseVertices() const {
|
||||
return (int)(_vertVertsList[0].size());
|
||||
int GetNumCoarseVertices() const {
|
||||
return (int)(_vertVertsList[0].size());
|
||||
}
|
||||
|
||||
// Total number of face vertices up to 'level'
|
||||
@ -83,7 +83,7 @@ protected:
|
||||
// Valence summation up to 'level'
|
||||
int GetFaceVertsValenceSum() const { return _faceVertsValenceSum; }
|
||||
|
||||
// Valence summation for face vertices
|
||||
// Valence summation for face vertices
|
||||
int GetVertVertsValenceSum() const { return _vertVertsValenceSum; }
|
||||
|
||||
// Returns an integer based on the order in which the kernels are applied
|
||||
@ -96,7 +96,7 @@ protected:
|
||||
|
||||
// Mumber of indices required for the face-vert and vertex-vert
|
||||
// iteration tables at each level
|
||||
int _faceVertsValenceSum,
|
||||
int _faceVertsValenceSum,
|
||||
_vertVertsValenceSum;
|
||||
|
||||
// lists of vertices sorted by type and level
|
||||
@ -110,29 +110,29 @@ private:
|
||||
|
||||
template <class Type> static int sumList( std::vector<std::vector<Type> > const & list, int level );
|
||||
|
||||
// Sums the number of adjacent vertices required to interpolate a Vert-Vertex
|
||||
// Sums the number of adjacent vertices required to interpolate a Vert-Vertex
|
||||
static int sumVertVertexValence(HbrVertex<T> * vertex);
|
||||
|
||||
// Compares vertices based on their topological configuration
|
||||
// Compares vertices based on their topological configuration
|
||||
// (see subdivisionTables::GetMaskRanking for more details)
|
||||
static bool compareVertices( HbrVertex<T> const *x, HbrVertex<T> const *y );
|
||||
};
|
||||
|
||||
template <class T, class U>
|
||||
template <class T, class U>
|
||||
FarSubdivisionTablesFactory<T,U>::FarSubdivisionTablesFactory( HbrMesh<T> const * mesh, int maxlevel, std::vector<int> & remapTable ) :
|
||||
_faceVertIdx(maxlevel+1,0),
|
||||
_edgeVertIdx(maxlevel+1,0),
|
||||
_vertVertIdx(maxlevel+1,0),
|
||||
_faceVertsValenceSum(0),
|
||||
_faceVertsValenceSum(0),
|
||||
_vertVertsValenceSum(0),
|
||||
_faceVertsList(maxlevel+1),
|
||||
_edgeVertsList(maxlevel+1),
|
||||
_vertVertsList(maxlevel+1)
|
||||
{
|
||||
assert( mesh );
|
||||
|
||||
|
||||
int numVertices = mesh->GetNumVertices();
|
||||
|
||||
|
||||
std::vector<int> faceCounts(maxlevel+1,0),
|
||||
edgeCounts(maxlevel+1,0),
|
||||
vertCounts(maxlevel+1,0);
|
||||
@ -145,6 +145,10 @@ FarSubdivisionTablesFactory<T,U>::FarSubdivisionTablesFactory( HbrMesh<T> const
|
||||
HbrVertex<T> * v = mesh->GetVertex(i);
|
||||
assert(v);
|
||||
|
||||
if (not v->IsConnected()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int depth = getVertexDepth( v );
|
||||
|
||||
if (depth>maxlevel)
|
||||
@ -192,6 +196,11 @@ FarSubdivisionTablesFactory<T,U>::FarSubdivisionTablesFactory( HbrMesh<T> const
|
||||
HbrVertex<T> * v = mesh->GetVertex(i);
|
||||
assert(v);
|
||||
|
||||
if (not v->IsConnected()) {
|
||||
remapTable[ v->GetID() ] = v->GetID();
|
||||
continue;
|
||||
}
|
||||
|
||||
int depth = getVertexDepth( v );
|
||||
|
||||
if (depth>maxlevel)
|
||||
@ -231,7 +240,7 @@ FarSubdivisionTablesFactory<T,U>::FarSubdivisionTablesFactory( HbrMesh<T> const
|
||||
}
|
||||
|
||||
|
||||
template <class T, class U> int
|
||||
template <class T, class U> int
|
||||
FarSubdivisionTablesFactory<T,U>::getVertexDepth(HbrVertex<T> * v) {
|
||||
|
||||
if (v->IsConnected()) {
|
||||
@ -286,14 +295,14 @@ FarSubdivisionTablesFactory<T,U>::GetMaskRanking( unsigned char mask0, unsigned
|
||||
return masks[mask0][mask1];
|
||||
}
|
||||
|
||||
// Sums the number of adjacent vertices required to interpolate a Vert-Vertex
|
||||
template <class T, class U> int
|
||||
// Sums the number of adjacent vertices required to interpolate a Vert-Vertex
|
||||
template <class T, class U> int
|
||||
FarSubdivisionTablesFactory<T,U>::sumVertVertexValence(HbrVertex<T> * vertex) {
|
||||
int masks[2], npasses=1, result=0;
|
||||
|
||||
|
||||
HbrVertex<T> * pv = vertex->GetParentVertex();
|
||||
assert(pv);
|
||||
|
||||
|
||||
masks[0] = pv->GetMask(false);
|
||||
masks[1] = pv->GetMask(true);
|
||||
|
||||
|
@ -75,7 +75,7 @@ struct shape {
|
||||
struct tag {
|
||||
|
||||
static tag * parseTag( char const * stream );
|
||||
|
||||
|
||||
std::string genTag() const;
|
||||
|
||||
std::string name;
|
||||
@ -85,11 +85,11 @@ struct shape {
|
||||
};
|
||||
|
||||
static shape * parseShape(char const * shapestr, int axis=1);
|
||||
|
||||
|
||||
std::string genShape(char const * name) const;
|
||||
|
||||
std::string genObj(char const * name) const;
|
||||
|
||||
|
||||
std::string genRIB() const;
|
||||
|
||||
~shape();
|
||||
@ -97,7 +97,7 @@ struct shape {
|
||||
int getNverts() const { return (int)verts.size()/3; }
|
||||
|
||||
int getNfaces() const { return (int)nvertsPerFace.size(); }
|
||||
|
||||
|
||||
bool hasUV() const { return not (uvs.empty() or faceuvs.empty()); }
|
||||
|
||||
std::vector<float> verts;
|
||||
@ -174,7 +174,7 @@ std::string shape::tag::genTag() const {
|
||||
std::stringstream t;
|
||||
|
||||
t<<"\"t \""<<name<<"\" ";
|
||||
|
||||
|
||||
t<<intargs.size()<<"/"<<floatargs.size()<<"/"<<stringargs.size()<<" ";
|
||||
|
||||
std::copy(intargs.begin(), intargs.end(), std::ostream_iterator<int>(t));
|
||||
@ -185,16 +185,16 @@ std::string shape::tag::genTag() const {
|
||||
|
||||
std::copy(stringargs.begin(), stringargs.end(), std::ostream_iterator<std::string>(t));
|
||||
t<<"\\n\"\n";
|
||||
|
||||
|
||||
return t.str();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
std::string shape::genShape(char const * name) const {
|
||||
std::stringstream sh;
|
||||
|
||||
|
||||
sh<<"static char const * "<<name<<" = \n";
|
||||
|
||||
|
||||
for (int i=0; i<(int)verts.size(); i+=3)
|
||||
sh << "\"v " << verts[i] << " " << verts[i+1] << " " << verts[i+2] <<"\\n\"\n";
|
||||
|
||||
@ -220,16 +220,16 @@ std::string shape::genShape(char const * name) const {
|
||||
|
||||
for (int i=0; i<(int)tags.size(); ++i)
|
||||
sh << tags[i]->genTag();
|
||||
|
||||
|
||||
return sh.str();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
std::string shape::genObj(char const * name) const {
|
||||
std::stringstream sh;
|
||||
|
||||
|
||||
sh<<"# This file uses centimeters as units for non-parametric coordinates.\n\n";
|
||||
|
||||
|
||||
for (int i=0; i<(int)verts.size(); i+=3)
|
||||
sh << "v " << verts[i] << " " << verts[i+1] << " " << verts[i+2] <<"\n";
|
||||
|
||||
@ -253,16 +253,16 @@ std::string shape::genObj(char const * name) const {
|
||||
|
||||
for (int i=0; i<(int)tags.size(); ++i)
|
||||
sh << tags[i]->genTag();
|
||||
|
||||
|
||||
return sh.str();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
std::string shape::genRIB() const {
|
||||
std::stringstream rib;
|
||||
|
||||
|
||||
rib << "HierarchicalSubdivisionMesh \"catmull-clark\" ";
|
||||
|
||||
|
||||
rib << "[";
|
||||
std::copy(nvertsPerFace.begin(), nvertsPerFace.end(), std::ostream_iterator<int>(rib));
|
||||
rib << "] ";
|
||||
@ -270,21 +270,21 @@ std::string shape::genRIB() const {
|
||||
rib << "[";
|
||||
std::copy(faceverts.begin(), faceverts.end(), std::ostream_iterator<int>(rib));
|
||||
rib << "] ";
|
||||
|
||||
|
||||
std::stringstream names, nargs, intargs, floatargs, strargs;
|
||||
for (int i=0; i<(int)tags.size();) {
|
||||
tag * t = tags[i];
|
||||
|
||||
|
||||
names << t->name;
|
||||
|
||||
nargs << t->intargs.size() << " " << t->floatargs.size() << " " << t->stringargs.size();
|
||||
|
||||
|
||||
std::copy(t->intargs.begin(), t->intargs.end(), std::ostream_iterator<int>(intargs));
|
||||
|
||||
std::copy(t->floatargs.begin(), t->floatargs.end(), std::ostream_iterator<float>(floatargs));
|
||||
|
||||
std::copy(t->stringargs.begin(), t->stringargs.end(), std::ostream_iterator<std::string>(strargs));
|
||||
|
||||
|
||||
if (++i<(int)tags.size()) {
|
||||
names << " ";
|
||||
nargs << " ";
|
||||
@ -293,13 +293,13 @@ std::string shape::genRIB() const {
|
||||
strargs << " ";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
rib << "["<<names<<"] " << "["<<nargs<<"] " << "["<<intargs<<"] " << "["<<floatargs<<"] " << "["<<strargs<<"] ";
|
||||
|
||||
rib << "\"P\" [";
|
||||
std::copy(verts.begin(), verts.end(), std::ostream_iterator<float>(rib));
|
||||
rib << "] ";
|
||||
|
||||
|
||||
return rib.str();
|
||||
}
|
||||
|
||||
@ -324,7 +324,7 @@ shape * shape::parseShape(char const * shapestr, int axis ) {
|
||||
s->verts.push_back(y); break;
|
||||
case 1 : s->verts.push_back(y);
|
||||
s->verts.push_back(z); break;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case 't': if(sscanf(line, "vt %f %f", &u, &v) == 2) {
|
||||
s->uvs.push_back(u);
|
||||
@ -583,16 +583,16 @@ void applyTags( OpenSubdiv::HbrMesh<T> * mesh, shape const * sh ) {
|
||||
|
||||
} // End of subop processing loop
|
||||
} else if (t->name=="faceedit") {
|
||||
|
||||
|
||||
int nint = (int)t->intargs.size();
|
||||
for (int k=0; k<nint; ) {
|
||||
int pathlength = t->intargs[k];
|
||||
|
||||
|
||||
if (k+pathlength>=nint) {
|
||||
printf("Invalid path length for %s tag on SubdivisionMesh", t->name.c_str());
|
||||
goto nexttag;
|
||||
}
|
||||
|
||||
|
||||
int faceid = t->intargs[k+1];
|
||||
int nsubfaces = pathlength - 1;
|
||||
int *subfaces = &t->intargs[k+2];
|
||||
@ -601,7 +601,7 @@ void applyTags( OpenSubdiv::HbrMesh<T> * mesh, shape const * sh ) {
|
||||
printf("Invalid face %d specified for %s tag on SubdivisionMesh.\n", faceid, t->name.c_str());
|
||||
goto nexttag;
|
||||
}
|
||||
|
||||
|
||||
// Found the face. Do some preliminary error checking to make sure the path is
|
||||
// correct. First value in path depends on the number of vertices of the face
|
||||
// which we have in hand
|
||||
@ -609,7 +609,7 @@ void applyTags( OpenSubdiv::HbrMesh<T> * mesh, shape const * sh ) {
|
||||
printf("Invalid path component %d in %s tag on SubdivisionMesh.\n", subfaces[0], t->name.c_str());
|
||||
goto nexttag;
|
||||
}
|
||||
|
||||
|
||||
// All subsequent values must be less than 4 (FIXME or 3 in the loop case?)
|
||||
for (int l=1; l<nsubfaces; ++l) {
|
||||
if (subfaces[l] < 0 || subfaces[l] > 3) {
|
||||
@ -617,7 +617,7 @@ void applyTags( OpenSubdiv::HbrMesh<T> * mesh, shape const * sh ) {
|
||||
goto nexttag;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Now loop over string ops
|
||||
int nstring = (int)t->stringargs.size();
|
||||
for (int l = 0; l < nstring; ) {
|
||||
@ -642,7 +642,7 @@ void applyTags( OpenSubdiv::HbrMesh<T> * mesh, shape const * sh ) {
|
||||
// Advance to next path
|
||||
k += pathlength + 1;
|
||||
} // end face path loop
|
||||
|
||||
|
||||
} else {
|
||||
printf("Unknown tag : \"%s\" - skipping\n", t->name.c_str());
|
||||
}
|
||||
@ -651,26 +651,26 @@ nexttag: ;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template <class T> std::string
|
||||
template <class T> std::string
|
||||
hbrToObj( OpenSubdiv::HbrMesh<T> * mesh ) {
|
||||
|
||||
std::stringstream sh;
|
||||
|
||||
sh<<"# This file uses centimeters as units for non-parametric coordinates.\n\n";
|
||||
|
||||
|
||||
int nv = mesh->GetNumVertices();
|
||||
for (int i=0; i<nv; ++i) {
|
||||
const float * pos = mesh->GetVertex(i)->GetData().GetPos();
|
||||
sh << "v " << pos[0] << " " << pos[1] << " " << pos[2] <<"\n";
|
||||
}
|
||||
|
||||
|
||||
int nf = mesh->GetNumFaces();
|
||||
for (int i=0; i<nf; ++i) {
|
||||
|
||||
|
||||
sh << "f ";
|
||||
|
||||
|
||||
OpenSubdiv::HbrFace<T> * f = mesh->GetFace(i);
|
||||
|
||||
|
||||
for (int j=0; j<f->GetNumVertices(); ++j) {
|
||||
int vert = f->GetVertex(j)->GetID()+1;
|
||||
sh << vert << "/" << vert << "/" << vert << " ";
|
||||
@ -702,7 +702,7 @@ createMesh( Scheme scheme=kCatmark, int fvarwidth=0) {
|
||||
|
||||
|
||||
switch (scheme) {
|
||||
case kBilinear : mesh = new OpenSubdiv::HbrMesh<T>( &_bilinear,
|
||||
case kBilinear : mesh = new OpenSubdiv::HbrMesh<T>( &_bilinear,
|
||||
fvarcount,
|
||||
fvarindices,
|
||||
fvarwidths,
|
||||
@ -713,7 +713,7 @@ createMesh( Scheme scheme=kCatmark, int fvarwidth=0) {
|
||||
fvarindices,
|
||||
fvarwidths,
|
||||
fvarwidth ); break;
|
||||
|
||||
|
||||
case kCatmark : mesh = new OpenSubdiv::HbrMesh<T>( &_catmark,
|
||||
fvarcount,
|
||||
fvarindices,
|
||||
@ -749,20 +749,20 @@ template <class T> void
|
||||
copyVertexPositions( shape const * sh, OpenSubdiv::HbrMesh<T> * mesh, std::vector<float> & verts ) {
|
||||
|
||||
int nverts = mesh->GetNumVertices();
|
||||
|
||||
|
||||
verts.resize( nverts * 3 );
|
||||
|
||||
|
||||
std::copy(sh->verts.begin(), sh->verts.end(), verts.begin());
|
||||
|
||||
|
||||
// Sometimes Hbr dupes some vertices during Mesh::Finish()
|
||||
if (nverts > sh->getNverts()) {
|
||||
|
||||
|
||||
for (int i=sh->getNverts(); i<nverts; ++i) {
|
||||
|
||||
|
||||
OpenSubdiv::HbrVertex<T> * v = mesh->GetVertex(i);
|
||||
|
||||
|
||||
OpenSubdiv::HbrFace<T> * f = v->GetIncidentEdge()->GetFace();
|
||||
|
||||
|
||||
int vidx = -1;
|
||||
for (int j=0; j<f->GetNumVertices(); ++j)
|
||||
if (f->GetVertex(j)==v) {
|
||||
@ -770,13 +770,13 @@ copyVertexPositions( shape const * sh, OpenSubdiv::HbrMesh<T> * mesh, std::vecto
|
||||
break;
|
||||
}
|
||||
assert(vidx>-1);
|
||||
|
||||
|
||||
const int * shfaces = &sh->faceverts[0];
|
||||
for (int j=0; j<f->GetID(); ++j)
|
||||
shfaces += sh->nvertsPerFace[j];
|
||||
|
||||
|
||||
int shvert = shfaces[vidx];
|
||||
|
||||
|
||||
verts[i*3+0] = sh->verts[shvert*3+0];
|
||||
verts[i*3+1] = sh->verts[shvert*3+1];
|
||||
verts[i*3+2] = sh->verts[shvert*3+2];
|
||||
@ -798,6 +798,8 @@ createTopology( shape const * sh, OpenSubdiv::HbrMesh<T> * mesh, Scheme scheme)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
bool valid = true;
|
||||
|
||||
for(int j=0;j<nv;j++) {
|
||||
OpenSubdiv::HbrVertex<T> * origin = mesh->GetVertex( fv[j] );
|
||||
OpenSubdiv::HbrVertex<T> * destination = mesh->GetVertex( fv[(j+1)%nv] );
|
||||
@ -805,34 +807,42 @@ createTopology( shape const * sh, OpenSubdiv::HbrMesh<T> * mesh, Scheme scheme)
|
||||
|
||||
if(origin==NULL || destination==NULL) {
|
||||
printf(" An edge was specified that connected a nonexistent vertex\n");
|
||||
exit(1);
|
||||
valid=false;
|
||||
break;
|
||||
}
|
||||
|
||||
if(origin == destination) {
|
||||
printf(" An edge was specified that connected a vertex to itself\n");
|
||||
exit(1);
|
||||
valid=false;
|
||||
break;
|
||||
}
|
||||
|
||||
if(opposite && opposite->GetOpposite() ) {
|
||||
printf(" A non-manifold edge incident to more than 2 faces was found\n");
|
||||
exit(1);
|
||||
valid=false;
|
||||
break;
|
||||
}
|
||||
|
||||
if(origin->GetEdge(destination)) {
|
||||
printf(" An edge connecting two vertices was specified more than once."
|
||||
" It's likely that an incident face was flipped\n");
|
||||
exit(1);
|
||||
valid=false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
OpenSubdiv::HbrFace<T> * face = mesh->NewFace(nv, (int *)fv, 0);
|
||||
if (valid) {
|
||||
|
||||
face->SetPtexIndex(ptxidx);
|
||||
OpenSubdiv::HbrFace<T> * face = mesh->NewFace(nv, (int *)fv, 0);
|
||||
|
||||
if ( (scheme==kCatmark or scheme==kBilinear) and nv != 4 )
|
||||
ptxidx+=nv;
|
||||
else
|
||||
ptxidx++;
|
||||
face->SetPtexIndex(ptxidx);
|
||||
|
||||
if ( (scheme==kCatmark or scheme==kBilinear) and nv != 4 ) {
|
||||
ptxidx+=nv;
|
||||
} else {
|
||||
ptxidx++;
|
||||
}
|
||||
}
|
||||
|
||||
fv+=nv;
|
||||
}
|
||||
@ -842,11 +852,10 @@ createTopology( shape const * sh, OpenSubdiv::HbrMesh<T> * mesh, Scheme scheme)
|
||||
applyTags<T>( mesh, sh );
|
||||
|
||||
mesh->Finish();
|
||||
|
||||
|
||||
// check for disconnected vertices
|
||||
if (mesh->GetNumDisconnectedVertices()) {
|
||||
printf("The specified subdivmesh contains disconnected surface components.\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
@ -858,17 +867,17 @@ createFaceVaryingUV( shape const * sh, OpenSubdiv::HbrMesh<T> * mesh) {
|
||||
return;
|
||||
|
||||
for (int i=0, idx=0; i<sh->getNfaces(); ++i ) {
|
||||
|
||||
|
||||
OpenSubdiv::HbrFace<T> * f = mesh->GetFace(i);
|
||||
|
||||
|
||||
int nv = sh->nvertsPerFace[i];
|
||||
|
||||
|
||||
OpenSubdiv::HbrHalfedge<T> * e = f->GetFirstEdge();
|
||||
|
||||
|
||||
for (int j=0; j<nv; ++j, e=e->GetNext()) {
|
||||
|
||||
OpenSubdiv::HbrFVarData<T> & fvt = e->GetOrgVertex()->GetFVarData(f);
|
||||
|
||||
|
||||
float const * fvdata = &sh->uvs[ sh->faceuvs[idx++]*2 ];
|
||||
|
||||
if (not fvt.IsInitialized()) {
|
||||
@ -894,7 +903,7 @@ simpleHbr(char const * shapestr, Scheme scheme, std::vector<float> * verts=0, bo
|
||||
createVertices<T>(sh, mesh, verts);
|
||||
|
||||
createTopology<T>(sh, mesh, scheme);
|
||||
|
||||
|
||||
if (fvar)
|
||||
createFaceVaryingUV<T>(sh, mesh);
|
||||
|
||||
|
51
regression/shapes/catmark_fan.h
Normal file
51
regression/shapes/catmark_fan.h
Normal file
@ -0,0 +1,51 @@
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
static const std::string catmark_fan =
|
||||
"# This file uses centimeters as units for non-parametric coordinates.\n"
|
||||
"\n"
|
||||
"v -1.000000 0.000000 -1.000000\n"
|
||||
"v -1.000000 0.000000 0.000000\n"
|
||||
"v 0.000000 0.000000 0.000000\n"
|
||||
"v 0.000000 0.000000 -1.000000\n"
|
||||
"v 1.000000 0.000000 0.000000\n"
|
||||
"v 1.000000 0.000000 -1.000000\n"
|
||||
"v 0.000000 1.000000 0.000000\n"
|
||||
"v 0.000000 1.000000 -1.000000\n"
|
||||
"vt 0.000000 0.000000\n"
|
||||
"vt 1.000000 0.000000\n"
|
||||
"vt 1.000000 1.000000\n"
|
||||
"vt 0.000000 1.000000\n"
|
||||
"vt 0.000000 0.000000\n"
|
||||
"vt 1.000000 0.000000\n"
|
||||
"vt 1.000000 1.000000\n"
|
||||
"vt 0.000000 1.000000\n"
|
||||
"vt 0.000000 0.000000\n"
|
||||
"vt 1.000000 0.000000\n"
|
||||
"vt 1.000000 1.000000\n"
|
||||
"vt 0.000000 1.000000\n"
|
||||
"f 1/1 2/2 3/3 4/4\n"
|
||||
"f 4/5 3/6 5/7 6/8\n"
|
||||
"f 4/9 3/10 7/11 8/12\n"
|
||||
"\n";
|
Loading…
Reference in New Issue
Block a user