Modify Far remapping of singular vertices to point to their source vertex.

- Add a vector of index pairs to HbrMesh to track the index of a split
  vertex and its origin vertex
- Correct the Far remap tables in FarSubdivisionTablesFactory to point split
  vertices to their origin instead of themselves
- Fix regression/common/shape_utils.h to use the new HbrMesh::GetSplitVertices()
  method.
- Fix the osdPolySmooth example to use the new HbrMesh::GetSplitVertices()
  method.
- Add a paragraph to the documentation

fixes #241
This commit is contained in:
manuelk 2013-11-21 16:05:31 -08:00
parent 25f6565238
commit c3cb17fa99
7 changed files with 127 additions and 137 deletions

View File

@ -593,3 +593,32 @@ vertices (use HbrVertex::GetValence() for proper valence counts)
v->ApplyOperatorSurroundingVertices( op );
----
Managing Singular Vertices
==========================
Certain topological configurations would force vertices to share multiple
half-edge cycles. Because Hbr is a half-edge representation, these "singular"
vertices have to be duplicated as part of the HbrMesh::Finish() phase of the
instantiation.
These duplicated vertices can cause problems for client-code that tries to
populate buffers of vertex or varying data. The following sample code shows
how to match the vertex data to singular vertex splits:
.. code:: c++
// Populating an OsdCpuVertexBuffer with vertex data (positions,...)
float const * vtxData = inMeshFn.getRawPoints(&returnStatus);
OpenSubdiv::OsdCpuVertexBuffer *vertexBuffer =
OpenSubdiv::OsdCpuVertexBuffer::Create(numVertexElements, numFarVerts);
vertexBuffer->UpdateData(vtxData, 0, numVertices );
// Duplicate the vertex data into the split singular vertices
std::vector<std::pair<int, int> > const splits = hbrMesh->GetSplitVertices();
for (int i=0; i<(int)splits.size(); ++i) {
vertexBuffer->UpdateData(vtxData+splits[i].second*numVertexElements, splits[i].first, 1);
}

View File

@ -785,8 +785,6 @@ MStatus OsdPolySmooth::compute( const MPlug& plug, MDataBlock& data ) {
// NOTE: This HAS to be called after all HBR parameters are set
hbrMesh->Finish();
int ncoarseverts = hbrMesh->GetNumVertices();
// Create a FarMesh from the HBR mesh and pass into
// It will be owned by the OsdMesh and deleted in the ~OsdMesh()
FMeshFactory meshFactory(hbrMesh, subdivisionLevel, false);
@ -817,31 +815,9 @@ MStatus OsdPolySmooth::compute( const MPlug& plug, MDataBlock& data ) {
// Hbr dupes singular vertices during Mesh::Finish() - we need
// to duplicate their positions in the vertex buffer.
if (ncoarseverts > numVertices) {
MIntArray polyverts;
for (int i=numVertices; i<ncoarseverts; ++i) {
HVertex const * v = hbrMesh->GetVertex(i);
HFace const * f = v->GetIncidentEdge()->GetFace();
int vidx = -1;
for (int j=0; j<f->GetNumVertices(); ++j) {
if (f->GetVertex(j)==v) {
vidx = j;
break;
}
}
assert(vidx>-1);
inMeshFn.getPolygonVertices(f->GetID(), polyverts);
int vert = polyverts[vidx];
vertexBuffer->UpdateData(&vertex3fArray[0]+vert*numVertexElements, i, 1);
}
std::vector<std::pair<int, int> > const splits = hbrMesh->GetSplitVertices();
for (int i=0; i<(int)splits.size(); ++i) {
vertexBuffer->UpdateData(&vertex3fArray[0]+splits[i].second*numVertexElements, splits[i].first, 1);
}
// == Delete HBR

View File

@ -285,8 +285,6 @@ FarMeshFactory<T,U>::refine( HbrMesh<T> * mesh, int maxlevel ) {
// faces that have already been refined.
firstface = nfaces;
}
mesh->SetSubdivisionMethod(HbrMesh<T>::k_SubdivisionMethodUniform);
}
// Scan the faces of a mesh and compute the max level of subdivision required
@ -578,9 +576,6 @@ FarMeshFactory<T,U>::refineAdaptive( HbrMesh<T> * mesh, int maxIsolate ) {
}
}
}
mesh->SetSubdivisionMethod(HbrMesh<T>::k_SubdivisionMethodFeatureAdaptive);
return maxlevel-1;
}

View File

@ -236,7 +236,11 @@ FarSubdivisionTablesFactory<T,U>::FarSubdivisionTablesFactory( HbrMesh<T> const
for (size_t i=0; i<_vertVertsList[l].size(); ++i)
remapTable[ _vertVertsList[l][i]->GetID() ]=_vertVertIdx[l]+(int)i;
// Remap singular vertices to their origin vertices
std::vector<std::pair<int, int> > const & singulars = mesh->GetSplitVertices();
for (int i=0; i<(int)singulars.size(); ++i) {
remapTable[singulars[i].first]=singulars[i].second;
}
}

View File

@ -427,16 +427,19 @@ private:
#ifdef HBR_ADAPTIVE
public:
enum SubdivisionMethod {
k_SubdivisionMethodNone,
k_SubdivisionMethodUniform,
k_SubdivisionMethodFeatureAdaptive
};
void SetSubdivisionMethod(SubdivisionMethod method) { _subdivisionMethod=method; }
SubdivisionMethod GetSubdivisionMethod() const { return _subdivisionMethod; }
std::vector<std::pair<int, int> > const & GetSplitVertices() const {
return m_splitVertices;
}
protected:
friend class HbrVertex<T>;
void addSplitVertex(int splitIdx, int orgIdx) {
m_splitVertices.push_back(std::pair<int,int>(splitIdx, orgIdx));
}
private:
SubdivisionMethod _subdivisionMethod;
std::vector<std::pair<int, int> > m_splitVertices;
#endif
};

View File

@ -412,11 +412,10 @@ private:
#ifdef HBR_ADAPTIVE
public:
struct adaptiveFlags {
unsigned subdivisions:4;
unsigned isTagged:1;
unsigned wasTagged:1;
adaptiveFlags() : subdivisions(0), isTagged(0), wasTagged(0) { }
adaptiveFlags() : isTagged(0), wasTagged(0) { }
};
adaptiveFlags _adaptiveFlags;
@ -1524,6 +1523,9 @@ HbrVertex<T>::splitSingular() {
}
}
w->Finish();
#ifdef HBR_ADAPTIVE
mesh->addSplitVertex(w->GetID(), this->GetID());
#endif
}
e = incidentEdges[0];

View File

@ -25,6 +25,10 @@
#ifndef SHAPE_UTILS_H
#define SHAPE_UTILS_H
#ifndef HBR_ADAPTIVE
#define HBR_ADAPTIVE
#endif
#include <hbr/mesh.h>
#include <hbr/bilinear.h>
#include <hbr/loop.h>
@ -775,32 +779,9 @@ copyVertexPositions( shape const * sh, OpenSubdiv::HbrMesh<T> * mesh, std::vecto
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) {
vidx = j;
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];
}
std::vector<std::pair<int, int> > const splits = mesh->GetSplitVertices();
for (int i=0; i<(int)splits.size(); ++i) {
memcpy(&verts[splits[i].first*3], &sh->verts[splits[i].second*3], 3*sizeof(float));
}
}