mirror of
https://github.com/PixarAnimationStudios/OpenSubdiv
synced 2024-11-24 04:20:21 +00:00
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:
parent
25f6565238
commit
c3cb17fa99
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -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
|
||||
};
|
||||
|
||||
|
@ -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];
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user