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:
manuelk 2013-10-28 10:40:24 -07:00
parent a68bad450d
commit 9e9fd5c021
6 changed files with 226 additions and 149 deletions

View File

@ -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));

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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);

View File

@ -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);

View 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";