first pass at face-varying interpolation for CpuEvalLimit - still

a couple of kinks to be worked out...
This commit is contained in:
manuelk 2013-06-06 18:07:46 -07:00
parent f0be0b5799
commit c18cf5bff2
7 changed files with 295 additions and 121 deletions

View File

@ -139,7 +139,8 @@ std::vector<float> g_coarseEdgeSharpness;
std::vector<float> g_coarseVertexSharpness; std::vector<float> g_coarseVertexSharpness;
enum DrawMode { kUV=0, enum DrawMode { kUV=0,
kVARYING=1 }; kVARYING=1,
kFACEVARYING=2 };
int g_running = 1, int g_running = 1,
g_width = 1024, g_width = 1024,
@ -387,7 +388,9 @@ OsdCpuEvalLimitController g_evalCtrl;
OsdVertexBufferDescriptor g_idesc( /*offset*/ 0, /*legnth*/ 3, /*stride*/ 3 ), OsdVertexBufferDescriptor g_idesc( /*offset*/ 0, /*legnth*/ 3, /*stride*/ 3 ),
g_odesc( /*offset*/ 0, /*legnth*/ 3, /*stride*/ 6 ), g_odesc( /*offset*/ 0, /*legnth*/ 3, /*stride*/ 6 ),
g_vdesc( /*offset*/ 3, /*legnth*/ 3, /*stride*/ 6 ); g_vdesc( /*offset*/ 3, /*legnth*/ 3, /*stride*/ 6 ),
g_fvidesc( /*offset*/ 0, /*legnth*/ 2, /*stride*/ 2 ),
g_fvodesc( /*offset*/ 3, /*legnth*/ 2, /*stride*/ 6 );
std::vector<OsdEvalCoords> g_coords; std::vector<OsdEvalCoords> g_coords;
@ -444,9 +447,15 @@ updateGeom() {
// The varying data ends-up interleaved in the same g_Q output buffer because // The varying data ends-up interleaved in the same g_Q output buffer because
// g_Q has a stride of 6 and g_vdesc sets the offset to 3, while g_odesc sets // g_Q has a stride of 6 and g_vdesc sets the offset to 3, while g_odesc sets
// the offset to 0 // the offset to 0
if (g_drawMode==kVARYING) { switch (g_drawMode) {
g_evalCtx->BindVaryingBuffers( g_idesc, g_varyingData, g_vdesc, g_Q ); case kVARYING : g_evalCtx->BindVaryingBuffers( g_idesc, g_varyingData, g_vdesc, g_Q ); break;
}
case kFACEVARYING : g_evalCtx->BindFaceVaryingBuffers( g_fvidesc, g_fvodesc, g_Q );
case kUV :
default : g_evalCtx->UnbindVaryingBuffers(); break;
}
#define USE_OPENMP #define USE_OPENMP
#if defined(OPENSUBDIV_HAS_OPENMP) and defined(USE_OPENMP) #if defined(OPENSUBDIV_HAS_OPENMP) and defined(USE_OPENMP)
@ -457,16 +466,19 @@ updateGeom() {
int n = g_evalCtrl.EvalLimitSample<OsdCpuVertexBuffer,OsdCpuGLVertexBuffer>( g_coords[i], g_evalCtx, i ); int n = g_evalCtrl.EvalLimitSample<OsdCpuVertexBuffer,OsdCpuGLVertexBuffer>( g_coords[i], g_evalCtx, i );
if (n) { if (n) {
// point colors
switch (g_drawMode) {
case kUV : { float * color = g_Q->BindCpuBuffer() + i * 6 + 3;
color[0] = g_coords[i].u;
color[1] = 0.0f;
color[2] = g_coords[i].v; } break;
// point colors case kVARYING : break;
switch (g_drawMode) {
case kUV : { float * color = g_Q->BindCpuBuffer() + i * 6 + 3; case kFACEVARYING : { g_Q->BindCpuBuffer()[i*6 + 5] = 0.1f;
color[0] = g_coords[i].u; } break;
color[1] = 0.0f; default : break;
color[2] = g_coords[i].v; } break; }
case kVARYING :
default : break;
}
#if defined(OPENSUBDIV_HAS_OPENMP) and defined(USE_OPENMP) #if defined(OPENSUBDIV_HAS_OPENMP) and defined(USE_OPENMP)
#pragma omp atomic #pragma omp atomic
#endif #endif
@ -488,7 +500,7 @@ static void
createOsdMesh( const std::string &shape, int level, Scheme scheme=kCatmark ) { createOsdMesh( const std::string &shape, int level, Scheme scheme=kCatmark ) {
// Create HBR mesh // Create HBR mesh
OsdHbrMesh * hmesh = simpleHbr<OsdVertex>(shape.c_str(), scheme, g_orgPositions); OsdHbrMesh * hmesh = simpleHbr<OsdVertex>(shape.c_str(), scheme, g_orgPositions, true);
g_positions.resize(g_orgPositions.size(),0.0f); g_positions.resize(g_orgPositions.size(),0.0f);
@ -504,7 +516,7 @@ createOsdMesh( const std::string &shape, int level, Scheme scheme=kCatmark ) {
OsdFarMeshFactory factory( hmesh, level, /*adaptive*/ true); OsdFarMeshFactory factory( hmesh, level, /*adaptive*/ true);
delete g_fmesh; delete g_fmesh;
g_fmesh = factory.Create(/*fvar*/ false); g_fmesh = factory.Create(/*fvar*/ true);
int nverts = g_fmesh->GetNumVertices(); int nverts = g_fmesh->GetNumVertices();
@ -514,17 +526,13 @@ createOsdMesh( const std::string &shape, int level, Scheme scheme=kCatmark ) {
delete g_vertexData; delete g_vertexData;
g_vertexData = OsdCpuVertexBuffer::Create(3, nverts); g_vertexData = OsdCpuVertexBuffer::Create(3, nverts);
// Create v-buffer & populate w/ colors // Create primvar v-buffer & populate w/ colors or (u,v) data
delete g_varyingData; delete g_varyingData; g_varyingData = 0;
if (g_drawMode==kVARYING) { if (g_drawMode==kVARYING) {
g_varyingData = OsdCpuVertexBuffer::Create(3, nverts); g_varyingData = OsdCpuVertexBuffer::Create(3, nverts);
g_varyingData->UpdateData( &g_varyingColors[0], 0, nverts); g_varyingData->UpdateData( &g_varyingColors[0], 0, nverts);
} else {
g_varyingData = 0;
} }
// Create a Compute context, used to "pose" the vertices // Create a Compute context, used to "pose" the vertices
delete g_computeCtx; delete g_computeCtx;
g_computeCtx = OsdCpuComputeContext::Create(g_fmesh); g_computeCtx = OsdCpuComputeContext::Create(g_fmesh);
@ -535,7 +543,7 @@ createOsdMesh( const std::string &shape, int level, Scheme scheme=kCatmark ) {
// Create eval context & data buffers // Create eval context & data buffers
delete g_evalCtx; delete g_evalCtx;
g_evalCtx = OsdCpuEvalLimitContext::Create(g_fmesh); g_evalCtx = OsdCpuEvalLimitContext::Create(g_fmesh, /*requireFVarData*/ true);
delete g_Q; delete g_Q;
g_Q = OsdCpuGLVertexBuffer::Create(6,nsamples); g_Q = OsdCpuGLVertexBuffer::Create(6,nsamples);
@ -780,7 +788,7 @@ drawSamples() {
glBindVertexArray(g_samplesVAO); glBindVertexArray(g_samplesVAO);
glPointSize(1.0f); glPointSize(1.0f);
glDrawArrays( GL_POINTS, 0, (int)g_coords.size() ); glDrawArrays( GL_POINTS, 0, g_nsamplesFound);
glPointSize(1.0f); glPointSize(1.0f);
glBindVertexArray(0); glBindVertexArray(0);
@ -1044,6 +1052,7 @@ initHUD()
g_hud.AddRadioButton(0, "(u,v)", true, 200, 10, callbackDisplayVaryingColors, kUV, 'k'); g_hud.AddRadioButton(0, "(u,v)", true, 200, 10, callbackDisplayVaryingColors, kUV, 'k');
g_hud.AddRadioButton(0, "varying", false, 200, 30, callbackDisplayVaryingColors, kVARYING, 'k'); g_hud.AddRadioButton(0, "varying", false, 200, 30, callbackDisplayVaryingColors, kVARYING, 'k');
g_hud.AddRadioButton(0, "face-varying", false, 200, 50, callbackDisplayVaryingColors, kFACEVARYING, 'k');
for (int i = 1; i < 11; ++i) { for (int i = 1; i < 11; ++i) {
char level[16]; char level[16];

View File

@ -67,7 +67,7 @@ namespace OpenSubdiv {
namespace OPENSUBDIV_VERSION { namespace OPENSUBDIV_VERSION {
OsdCpuEvalLimitContext * OsdCpuEvalLimitContext *
OsdCpuEvalLimitContext::Create(FarMesh<OsdVertex> const * farmesh) { OsdCpuEvalLimitContext::Create(FarMesh<OsdVertex> const * farmesh, bool requireFVarData) {
assert(farmesh); assert(farmesh);
@ -75,7 +75,7 @@ OsdCpuEvalLimitContext::Create(FarMesh<OsdVertex> const * farmesh) {
if (not farmesh->GetPatchTables()) if (not farmesh->GetPatchTables())
return NULL; return NULL;
return new OsdCpuEvalLimitContext(farmesh); return new OsdCpuEvalLimitContext(farmesh, requireFVarData);
} }
void void
@ -85,7 +85,15 @@ OsdCpuEvalLimitContext::EvalData::Unbind() {
_inQ=0; _inQ=0;
_outDesc.Reset(); _outDesc.Reset();
_outQ = _outdQu = _outdQv = 0; _outQ = 0;
}
void
OsdCpuEvalLimitContext::EvalVertexData::Unbind() {
EvalData::Unbind();
_outdQu = _outdQv = 0;
} }
void void
@ -98,7 +106,12 @@ OsdCpuEvalLimitContext::UnbindVaryingBuffers() {
_varyingData.Unbind(); _varyingData.Unbind();
} }
OsdCpuEvalLimitContext::OsdCpuEvalLimitContext(FarMesh<OsdVertex> const * farmesh) : void
OsdCpuEvalLimitContext::UnbindFaceVaryingBuffers() {
_faceVaryingData.Unbind();
}
OsdCpuEvalLimitContext::OsdCpuEvalLimitContext(FarMesh<OsdVertex> const * farmesh, bool requireFVarData) :
OsdEvalLimitContext(farmesh) { OsdEvalLimitContext(farmesh) {
FarPatchTables const * patchTables = farmesh->GetPatchTables(); FarPatchTables const * patchTables = farmesh->GetPatchTables();
@ -137,6 +150,12 @@ OsdCpuEvalLimitContext::OsdCpuEvalLimitContext(FarMesh<OsdVertex> const * farmes
} }
} }
if (requireFVarData) {
_fvarwidth = farmesh->GetTotalFVarWidth();
if (_fvarwidth>0) {
_fvarData = patchTables->GetFVarDataTable();
}
}
_patchMap = new FarPatchTables::PatchMap( *patchTables ); _patchMap = new FarPatchTables::PatchMap( *patchTables );
} }

View File

@ -71,11 +71,18 @@ namespace OPENSUBDIV_VERSION {
class OsdCpuEvalLimitContext : public OsdEvalLimitContext { class OsdCpuEvalLimitContext : public OsdEvalLimitContext {
public: public:
/// \brief Factory /// \brief Factory
/// Returns an EvalLimitContext from the given farmesh. /// Returns an EvalLimitContext from the given farmesh.
/// Note : the farmesh is expected to be feature-adaptive and have ptex /// Note : the farmesh is expected to be feature-adaptive and have ptex
/// coordinates tables. /// coordinates tables.
static OsdCpuEvalLimitContext * Create(FarMesh<OsdVertex> const * farmesh); ///
/// @param farmesh a pointer to an initialized farmesh
///
/// @param requireFVarData flag for generating face-varying data
///
static OsdCpuEvalLimitContext * Create(FarMesh<OsdVertex> const * farmesh,
bool requireFVarData=false);
/// Destructor /// Destructor
virtual ~OsdCpuEvalLimitContext(); virtual ~OsdCpuEvalLimitContext();
@ -99,12 +106,14 @@ public:
return _outQ + index * _outDesc.stride; return _outQ + index * _outDesc.stride;
} }
float const * GetOutputDU(int index=0) const { template <class BUFFER>
return _outdQu + index * _outDesc.stride; void BindInputData( BUFFER * inQ ) {
_inQ = inQ ? inQ->BindCpuBuffer() : 0;
} }
float const * GetOutputDV(int index=0) const { template <class BUFFER>
return _outdQv + index * _outDesc.stride; void BindOutputData( BUFFER * outQ ) {
_outQ = outQ ? outQ->BindCpuBuffer() : 0;
} }
bool IsBound() const { bool IsBound() const {
@ -114,46 +123,47 @@ public:
private: private:
friend class OsdCpuEvalLimitContext; friend class OsdCpuEvalLimitContext;
EvalData() : _inQ(0), _outQ(0) { }
OsdVertexBufferDescriptor _inDesc; // input data OsdVertexBufferDescriptor _inDesc; // input data
float * _inQ; float * _inQ;
OsdVertexBufferDescriptor _outDesc; // output data OsdVertexBufferDescriptor _outDesc; // output data
float * _outQ, float * _outQ;
* _outdQu, // U derivative of output data
* _outdQv; // V derivative of output data
/// Binds the data buffers.
///
/// @param inDesc vertex / varying data descriptor shared by all input data buffers
///
/// @param inQ input subidivision data
///
/// @param outDesc vertex buffer data descriptor shared by all output data buffers
///
/// @param outQ output vertex data
///
/// @param outdQu optional output derivative along "u" of the vertex data
///
/// @param outdQv optional output derivative along "v" of the vertex data
///
template<class INPUT_BUFFER, class OUTPUT_BUFFER>
void Bind( OsdVertexBufferDescriptor const & inDesc, INPUT_BUFFER *inQ,
OsdVertexBufferDescriptor const & outDesc, OUTPUT_BUFFER *outQ,
OUTPUT_BUFFER *outdQu=0,
OUTPUT_BUFFER *outdQv=0);
/// Resets the descriptors & pointers /// Resets the descriptors & pointers
void Unbind(); void Unbind();
}; };
EvalData const & GetVertexData() const { /// Limit evaluation data descriptor with derivatives
return _vertexData; class EvalVertexData : public EvalData {
} public:
float const * GetOutputDU(int index=0) const {
return _outdQu + index * _outDesc.stride;
}
EvalData const & GetVaryingData() const { float const * GetOutputDV(int index=0) const {
return _varyingData; return _outdQv + index * _outDesc.stride;
} }
template <class BUFFER>
void BindOutputDerivData( BUFFER * outdQu, BUFFER * outdQv ) {
_outdQu = outdQu ? outdQu->BindCpuBuffer() : 0;
_outdQv = outdQv ? outdQv->BindCpuBuffer() : 0;
}
private:
friend class OsdCpuEvalLimitContext;
EvalVertexData() : _outdQu(0), _outdQv(0) { }
/// Resets the descriptors & pointers
void Unbind();
float * _outdQu, // U derivative of output data
* _outdQv; // V derivative of output data
};
/// Binds the vertex-interpolated data buffers. /// Binds the vertex-interpolated data buffers.
/// ///
@ -174,12 +184,24 @@ public:
OsdVertexBufferDescriptor const & outDesc, OUTPUT_BUFFER *outQ, OsdVertexBufferDescriptor const & outDesc, OUTPUT_BUFFER *outQ,
OUTPUT_BUFFER *outdQu=0, OUTPUT_BUFFER *outdQu=0,
OUTPUT_BUFFER *outdQv=0) { OUTPUT_BUFFER *outdQv=0) {
_vertexData.Bind( inDesc, inQ, outDesc, outQ, outdQu, outdQv ); _vertexData._inDesc = inDesc;
_vertexData.BindInputData( inQ );
_vertexData._outDesc = outDesc;
_vertexData.BindOutputData( outQ );
_vertexData.BindOutputDerivData( outdQu, outdQv );
} }
/// Unbind the vertex data buffers /// Unbind the vertex data buffers
void UnbindVertexBuffers(); void UnbindVertexBuffers();
/// Returns an Eval data descriptor of the vertex-interpolated data currently
/// bound to this EvalLimitContext.
EvalVertexData const & GetVertexData() const {
return _vertexData;
}
/// Binds the varying-interpolated data buffers. /// Binds the varying-interpolated data buffers.
/// ///
/// @param inDesc varying buffer data descriptor shared by all input data buffers /// @param inDesc varying buffer data descriptor shared by all input data buffers
@ -190,19 +212,59 @@ public:
/// ///
/// @param outQ output varying data /// @param outQ output varying data
/// ///
/// @param outdQu optional output derivative along "u" of the varying data
///
/// @param outdQv optional output derivative along "v" of the varying data
///
template<class VARYING_BUFFER, class OUTPUT_BUFFER> template<class VARYING_BUFFER, class OUTPUT_BUFFER>
void BindVaryingBuffers( OsdVertexBufferDescriptor const & inDesc, VARYING_BUFFER *inQ, void BindVaryingBuffers( OsdVertexBufferDescriptor const & inDesc, VARYING_BUFFER *inQ,
OsdVertexBufferDescriptor const & outDesc, OUTPUT_BUFFER *outQ) { OsdVertexBufferDescriptor const & outDesc, OUTPUT_BUFFER *outQ) {
_varyingData.Bind( inDesc, inQ, outDesc, outQ ); _varyingData._inDesc = inDesc;
_varyingData.BindInputData( inQ );
_varyingData._outDesc = outDesc;
_varyingData.BindOutputData( outQ );
} }
/// Unbind the varying data buffers /// Unbind the varying data buffers
void UnbindVaryingBuffers(); void UnbindVaryingBuffers();
/// Returns an Eval data descriptor of the varying-interpolated data currently
/// bound to this EvalLimitContext.
EvalData const & GetVaryingData() const {
return _varyingData;
}
/// Binds the face-varying-interpolated data buffers.
///
/// Note : currently we only support bilinear boundary interpolation rules
/// for face-varying data. Although Hbr supports 3 addition smooth rule sets,
/// the feature-adaptive patch interpolation code currently does not support
/// them, and neither does this EvalContext
///
/// @param inDesc varying buffer data descriptor shared by all input data buffers
///
/// @param inQ input varying data
///
/// @param outDesc varying buffer data descriptor shared by all output data buffers
///
/// @param outQ output varying data
///
template<class OUTPUT_BUFFER>
void BindFaceVaryingBuffers( OsdVertexBufferDescriptor const & inDesc,
OsdVertexBufferDescriptor const & outDesc, OUTPUT_BUFFER *outQ) {
_faceVaryingData._inDesc = inDesc;
_faceVaryingData._outDesc = outDesc;
_faceVaryingData.BindOutputData( outQ );
}
/// Unbind the varying data buffers
void UnbindFaceVaryingBuffers();
/// Returns an Eval data descriptor of the face-varying-interpolated data
/// currently bound to this EvalLimitContext.
EvalData const & GetFaceVaryingData() const {
return _faceVaryingData;
}
/// Returns the vector of patch arrays /// Returns the vector of patch arrays
const FarPatchTables::PatchArrayVector & GetPatchArrayVector() const { const FarPatchTables::PatchArrayVector & GetPatchArrayVector() const {
@ -228,6 +290,16 @@ public:
const unsigned int *GetQuadOffsetBuffer() const { const unsigned int *GetQuadOffsetBuffer() const {
return &_quadOffsetBuffer[0]; return &_quadOffsetBuffer[0];
} }
/// Returns the face-varying data patch table
FarPatchTables::FVarDataTable const & GetFVarData() const {
return _fvarData;
}
/// Returns the number of floats in a datum of the face-varying data table
int GetFVarWidth() const {
return _fvarwidth;
}
/// Returns a map object that can connect a faceId to a list of children patches /// Returns a map object that can connect a faceId to a list of children patches
const FarPatchTables::PatchMap * GetPatchesMap() const { const FarPatchTables::PatchMap * GetPatchesMap() const {
@ -240,7 +312,7 @@ public:
} }
protected: protected:
explicit OsdCpuEvalLimitContext(FarMesh<OsdVertex> const * farmesh); explicit OsdCpuEvalLimitContext(FarMesh<OsdVertex> const * farmesh, bool requireFVarData);
private: private:
@ -252,32 +324,18 @@ private:
FarPatchTables::VertexValenceTable _vertexValenceBuffer; // extra Gregory patch data buffers FarPatchTables::VertexValenceTable _vertexValenceBuffer; // extra Gregory patch data buffers
FarPatchTables::QuadOffsetTable _quadOffsetBuffer; FarPatchTables::QuadOffsetTable _quadOffsetBuffer;
FarPatchTables::FVarDataTable _fvarData;
FarPatchTables::PatchMap * _patchMap; // map of the sub-patches given a face index FarPatchTables::PatchMap * _patchMap; // map of the sub-patches given a face index
EvalData _vertexData, EvalVertexData _vertexData; // vertex-interpolated data descriptor
_varyingData; EvalData _varyingData, // varying-interpolated data descriptor
_faceVaryingData; // face-varying-interpolated data descriptor
int _maxValence; int _maxValence,
_fvarwidth;
}; };
template<class INPUT_BUFFER, class OUTPUT_BUFFER> void
OsdCpuEvalLimitContext::EvalData::Bind( OsdVertexBufferDescriptor const & inDesc,
INPUT_BUFFER *inQ,
OsdVertexBufferDescriptor const & outDesc,
OUTPUT_BUFFER *outQ,
OUTPUT_BUFFER *outdQu,
OUTPUT_BUFFER *outdQv) {
_inDesc = inDesc;
_inQ = inQ ? inQ->BindCpuBuffer() : 0;
_outDesc = outDesc;
_outQ = outQ ? outQ->BindCpuBuffer() : 0 ;
_outdQu = outdQu ? outdQu->BindCpuBuffer() : 0 ;
_outdQv = outdQv ? outdQv->BindCpuBuffer() : 0 ;
}
} // end namespace OPENSUBDIV_VERSION } // end namespace OPENSUBDIV_VERSION
using namespace OPENSUBDIV_VERSION; using namespace OPENSUBDIV_VERSION;

View File

@ -104,9 +104,8 @@ OsdCpuEvalLimitController::_EvalLimitSample( OpenSubdiv::OsdEvalCoords const & c
unsigned int const * cvs = &context->GetControlVertices()[ parray.GetVertIndex() + handle.vertexOffset ]; unsigned int const * cvs = &context->GetControlVertices()[ parray.GetVertIndex() + handle.vertexOffset ];
OsdCpuEvalLimitContext::EvalData const & vertexData = context->GetVertexData(), OsdCpuEvalLimitContext::EvalVertexData const & vertexData = context->GetVertexData();
& varyingData = context->GetVaryingData();
// Position lookup pointers at the indexed vertex // Position lookup pointers at the indexed vertex
float const * inQ = vertexData.GetInputData(); float const * inQ = vertexData.GetInputData();
float * outQ = const_cast<float *>(vertexData.GetOutputData(index)); float * outQ = const_cast<float *>(vertexData.GetOutputData(index));
@ -167,6 +166,8 @@ OsdCpuEvalLimitController::_EvalLimitSample( OpenSubdiv::OsdEvalCoords const & c
default: default:
assert(0); assert(0);
} }
OsdCpuEvalLimitContext::EvalData const & varyingData = context->GetVaryingData();
if (varyingData.IsBound()) { if (varyingData.IsBound()) {
static int indices[5][4] = { {5, 6,10, 9}, // regular static int indices[5][4] = { {5, 6,10, 9}, // regular
@ -182,13 +183,37 @@ OsdCpuEvalLimitController::_EvalLimitSample( OpenSubdiv::OsdEvalCoords const & c
cvs[indices[type][2]], cvs[indices[type][2]],
cvs[indices[type][3]] }; cvs[indices[type][3]] };
evalVarying( v, u, zeroRing, evalBilinear( v, u, zeroRing,
varyingData.GetInputDesc(), varyingData.GetInputDesc(),
varyingData.GetInputData(), varyingData.GetInputData(),
varyingData.GetOutputDesc(), varyingData.GetOutputDesc(),
const_cast<float *>(varyingData.GetOutputData(index)) ); const_cast<float *>(varyingData.GetOutputData(index)) );
} }
// Note : currently we only support bilinear boundary interpolation rules
// for face-varying data. Although Hbr supports 3 addition smooth rule sets,
// the feature-adaptive patch interpolation code currently does not support
// them, and neither does this EvalContext
OsdCpuEvalLimitContext::EvalData const & faceVaryingData = context->GetFaceVaryingData();
if (faceVaryingData.GetOutputData()) {
FarPatchTables::FVarDataTable const & fvarData = context->GetFVarData();
if (not fvarData.empty()) {
float const * fvar = &fvarData[ handle.serialIndex * 4 * context->GetFVarWidth() ];
static unsigned int zeroRing[4] = {0,1,2,3};
evalBilinear( v, u, zeroRing,
faceVaryingData.GetInputDesc(),
fvar,
faceVaryingData.GetOutputDesc(),
const_cast<float *>(faceVaryingData.GetOutputData(index)) );
}
}
return 1; return 1;
} }

View File

@ -69,12 +69,12 @@ namespace OpenSubdiv {
namespace OPENSUBDIV_VERSION { namespace OPENSUBDIV_VERSION {
void void
evalVarying(float u, float v, evalBilinear(float u, float v,
unsigned int const * vertexIndices, unsigned int const * vertexIndices,
OsdVertexBufferDescriptor const & inDesc, OsdVertexBufferDescriptor const & inDesc,
float const * inQ, float const * inQ,
OsdVertexBufferDescriptor const & outDesc, OsdVertexBufferDescriptor const & outDesc,
float * outQ) { float * outQ) {
assert( inDesc.length <= (outDesc.stride-outDesc.offset) ); assert( inDesc.length <= (outDesc.stride-outDesc.offset) );

View File

@ -65,12 +65,12 @@ namespace OpenSubdiv {
namespace OPENSUBDIV_VERSION { namespace OPENSUBDIV_VERSION {
void void
evalVarying(float u, float v, evalBilinear(float u, float v,
unsigned int const * vertexIndices, unsigned int const * vertexIndices,
OsdVertexBufferDescriptor const & inDesc, OsdVertexBufferDescriptor const & inDesc,
float const * inQ, float const * inQ,
OsdVertexBufferDescriptor const & outDesc, OsdVertexBufferDescriptor const & outDesc,
float * outQ); float * outQ);
void void
evalBSpline(float u, float v, evalBSpline(float u, float v,

View File

@ -703,7 +703,7 @@ hbrToObj( OpenSubdiv::HbrMesh<T> * mesh ) {
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
template <class T> OpenSubdiv::HbrMesh<T> * template <class T> OpenSubdiv::HbrMesh<T> *
createMesh( Scheme scheme=kCatmark) { createMesh( Scheme scheme=kCatmark, int fvarwidth=0) {
OpenSubdiv::HbrMesh<T> * mesh = 0; OpenSubdiv::HbrMesh<T> * mesh = 0;
@ -711,10 +711,32 @@ createMesh( Scheme scheme=kCatmark) {
static OpenSubdiv::HbrLoopSubdivision<T> _loop; static OpenSubdiv::HbrLoopSubdivision<T> _loop;
static OpenSubdiv::HbrCatmarkSubdivision<T> _catmark; static OpenSubdiv::HbrCatmarkSubdivision<T> _catmark;
static int indices[1] = { 0 },
widths[1] = { 2 };
int const fvarcount = fvarwidth > 0 ? 1 : 0,
* fvarindices = fvarwidth > 0 ? indices : NULL,
* fvarwidths = fvarwidth > 0 ? widths : NULL;
switch (scheme) { switch (scheme) {
case kBilinear : mesh = new OpenSubdiv::HbrMesh<T>( &_bilinear ); break; case kBilinear : mesh = new OpenSubdiv::HbrMesh<T>( &_bilinear,
case kLoop : mesh = new OpenSubdiv::HbrMesh<T>( &_loop ); break; fvarcount,
case kCatmark : mesh = new OpenSubdiv::HbrMesh<T>( &_catmark ); break; fvarindices,
fvarwidths,
fvarwidth ); break;
case kLoop : mesh = new OpenSubdiv::HbrMesh<T>( &_loop,
fvarcount,
fvarindices,
fvarwidths,
fvarwidth ); break;
case kCatmark : mesh = new OpenSubdiv::HbrMesh<T>( &_catmark,
fvarcount,
fvarindices,
fvarwidths,
fvarwidth ); break;
} }
return mesh; return mesh;
@ -840,19 +862,55 @@ createTopology( shape const * sh, OpenSubdiv::HbrMesh<T> * mesh, Scheme scheme)
mesh->Finish(); mesh->Finish();
} }
//------------------------------------------------------------------------------
template <class T> void
createFaceVaryingUV( shape const * sh, OpenSubdiv::HbrMesh<T> * mesh) {
if (sh->uvs.empty() or sh->faceuvs.empty())
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++] ];
if (not fvt.IsInitialized()) {
fvt.SetAllData(2, fvdata);
} else if (not fvt.CompareAll(2, fvdata)) {
OpenSubdiv::HbrFVarData<T> & nfvt = e->GetOrgVertex()->NewFVarData(f);
nfvt.SetAllData(2, fvdata);
}
}
}
}
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
template <class T> OpenSubdiv::HbrMesh<T> * template <class T> OpenSubdiv::HbrMesh<T> *
simpleHbr(char const * shapestr, Scheme scheme, std::vector<float> * verts=0) { simpleHbr(char const * shapestr, Scheme scheme, std::vector<float> * verts=0, bool fvar=false) {
shape * sh = shape::parseShape( shapestr ); shape * sh = shape::parseShape( shapestr );
OpenSubdiv::HbrMesh<T> * mesh = createMesh<T>(scheme); int fvarwidth = fvar ? 2 : 0;
OpenSubdiv::HbrMesh<T> * mesh = createMesh<T>(scheme, fvarwidth);
createVertices<T>(sh, mesh, verts); createVertices<T>(sh, mesh, verts);
createTopology<T>(sh, mesh, scheme); createTopology<T>(sh, mesh, scheme);
if (fvar)
createFaceVaryingUV<T>(sh, mesh);
if(verts) if (verts)
copyVertexPositions<T>(sh,mesh,*verts); copyVertexPositions<T>(sh,mesh,*verts);
delete sh; delete sh;
@ -862,16 +920,21 @@ simpleHbr(char const * shapestr, Scheme scheme, std::vector<float> * verts=0) {
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
template <class T> OpenSubdiv::HbrMesh<T> * template <class T> OpenSubdiv::HbrMesh<T> *
simpleHbr(char const * shapestr, Scheme scheme, std::vector<float> & verts) { simpleHbr(char const * shapestr, Scheme scheme, std::vector<float> & verts, bool fvar=false) {
shape * sh = shape::parseShape( shapestr ); shape * sh = shape::parseShape( shapestr );
OpenSubdiv::HbrMesh<T> * mesh = createMesh<T>(scheme); int fvarwidth = fvar ? 2 : 0;
OpenSubdiv::HbrMesh<T> * mesh = createMesh<T>(scheme, fvarwidth);
createVertices<T>(sh, mesh, verts); createVertices<T>(sh, mesh, verts);
createTopology<T>(sh, mesh, scheme); createTopology<T>(sh, mesh, scheme);
if (fvar)
createFaceVaryingUV<T>(sh, mesh);
copyVertexPositions<T>(sh,mesh,verts); copyVertexPositions<T>(sh,mesh,verts);
delete sh; delete sh;