From 42f5090290b10907d4a998176ce5216c30649f2f Mon Sep 17 00:00:00 2001 From: "David G. Yu" Date: Thu, 29 Sep 2016 10:00:19 -0700 Subject: [PATCH] Updated glFVarViewer and glEvalLimit examples These have both been updated to test the refinement and evaluation of face-varying patch data. --- examples/dxViewer/dxviewer.cpp | 2 + examples/glEvalLimit/CMakeLists.txt | 1 + examples/glEvalLimit/glEvalLimit.cpp | 165 +++++++++++++++++++------ examples/glEvalLimit/init_shapes.h | 4 +- examples/glFVarViewer/glFVarViewer.cpp | 114 +++++++++++++++-- examples/glFVarViewer/init_shapes.h | 3 + examples/glFVarViewer/shader.glsl | 54 +++++++- examples/glViewer/glViewer.cpp | 2 + 8 files changed, 294 insertions(+), 51 deletions(-) diff --git a/examples/dxViewer/dxviewer.cpp b/examples/dxViewer/dxviewer.cpp index 44364723..a4f6165d 100644 --- a/examples/dxViewer/dxviewer.cpp +++ b/examples/dxViewer/dxviewer.cpp @@ -564,6 +564,8 @@ public: } // include osd PatchCommon + ss << "#define OSD_PATCH_BASIS_HLSL\n"; + ss << Osd::HLSLPatchShaderSource::GetPatchBasisShaderSource(); ss << Osd::HLSLPatchShaderSource::GetCommonShaderSource(); std::string common = ss.str(); ss.str(""); diff --git a/examples/glEvalLimit/CMakeLists.txt b/examples/glEvalLimit/CMakeLists.txt index 467ac419..223f3736 100644 --- a/examples/glEvalLimit/CMakeLists.txt +++ b/examples/glEvalLimit/CMakeLists.txt @@ -56,6 +56,7 @@ _add_glfw_executable(glEvalLimit "examples" particles.h "${INC_FILES}" $ + $ $ ) diff --git a/examples/glEvalLimit/glEvalLimit.cpp b/examples/glEvalLimit/glEvalLimit.cpp index a05d7fad..ecf6eefb 100644 --- a/examples/glEvalLimit/glEvalLimit.cpp +++ b/examples/glEvalLimit/glEvalLimit.cpp @@ -160,6 +160,9 @@ struct Transform { float ModelViewProjectionMatrix[16]; } g_transformData; +OpenSubdiv::Sdc::Options::FVarLinearInterpolation g_fvarBoundary = + //OpenSubdiv::Sdc::Options::FVAR_LINEAR_ALL; + OpenSubdiv::Sdc::Options::FVAR_LINEAR_CORNERS_ONLY; // performance float g_evalTime = 0; @@ -190,6 +193,7 @@ struct Program { GLuint attrTangentU; GLuint attrTangentV; GLuint attrPatchCoord; + GLuint attrFVarData; } g_defaultProgram; //------------------------------------------------------------------------------ @@ -216,13 +220,16 @@ public: virtual GLuint BindSourceData() const = 0; virtual GLuint BindVertexData() const = 0; virtual GLuint BindDerivatives() const = 0; + virtual GLuint BindFaceVaryingData() const = 0; virtual GLuint BindPatchCoords() const = 0; virtual void UpdateData(const float *src, int startVertex, int numVertices) = 0; virtual void UpdateVaryingData(const float *src, int startVertex, int numVertices) = 0; + virtual void UpdateFaceVaryingData(const float *src, int startVertex, int numVertices) = 0; virtual void Refine() = 0; virtual void EvalPatches() = 0; virtual void EvalPatchesWithDerivatives() = 0; virtual void EvalPatchesVarying() = 0; + virtual void EvalPatchesFaceVarying() = 0; virtual void UpdatePatchCoords( std::vector const &patchCoords) = 0; }; @@ -241,39 +248,52 @@ public: EvalOutput(Far::StencilTable const *vertexStencils, Far::StencilTable const *varyingStencils, - int numCoarseVerts, int numTotalVerts, int numParticles, - Far::PatchTable const *patchTable, + Far::StencilTable const *faceVaryingStencils, + int numCoarseVerts, int numTotalVerts, + int numCoarseFVarVerts, int numTotalFVarVerts, + int numParticles, Far::PatchTable const *patchTable, EvaluatorCache *evaluatorCache = NULL, DEVICE_CONTEXT *deviceContext = NULL) : _srcDesc( /*offset*/ 0, /*length*/ 3, /*stride*/ 3), _srcVaryingDesc(/*offset*/ 0, /*length*/ 3, /*stride*/ 3), + _srcFVarDesc( /*offset*/ 0, /*length*/ 2, /*stride*/ 2), _vertexDesc( /*offset*/ 0, /*legnth*/ 3, /*stride*/ 6), _varyingDesc( /*offset*/ 3, /*legnth*/ 3, /*stride*/ 6), + _fvarDesc( /*offset*/ 0, /*legnth*/ 2, /*stride*/ 2), _duDesc( /*offset*/ 0, /*legnth*/ 3, /*stride*/ 6), _dvDesc( /*offset*/ 3, /*legnth*/ 3, /*stride*/ 6), _deviceContext(deviceContext) { _srcData = SRC_VERTEX_BUFFER::Create(3, numTotalVerts, _deviceContext); _srcVaryingData = SRC_VERTEX_BUFFER::Create(3, numTotalVerts, _deviceContext); + _srcFVarData = EVAL_VERTEX_BUFFER::Create(2, numTotalFVarVerts, _deviceContext); _vertexData = EVAL_VERTEX_BUFFER::Create(6, numParticles, _deviceContext); _derivatives = EVAL_VERTEX_BUFFER::Create(6, numParticles, _deviceContext); + _fvarData = EVAL_VERTEX_BUFFER::Create(2, numParticles, _deviceContext); _patchTable = PATCH_TABLE::Create(patchTable, _deviceContext); _patchCoords = NULL; _numCoarseVerts = numCoarseVerts; + _numCoarseFVarVerts = numCoarseFVarVerts; _vertexStencils = Osd::convertToCompatibleStencilTable(vertexStencils, _deviceContext); _varyingStencils = Osd::convertToCompatibleStencilTable(varyingStencils, _deviceContext); + _faceVaryingStencils = (faceVaryingStencils) + ? Osd::convertToCompatibleStencilTable(faceVaryingStencils, _deviceContext) + : NULL; _evaluatorCache = evaluatorCache; } ~EvalOutput() { delete _srcData; delete _srcVaryingData; + delete _srcFVarData; delete _vertexData; delete _derivatives; + delete _fvarData; delete _patchTable; delete _patchCoords; delete _vertexStencils; delete _varyingStencils; + delete _faceVaryingStencils; } virtual GLuint BindSourceData() const { return _srcData->BindVBO(); @@ -284,6 +304,9 @@ public: virtual GLuint BindDerivatives() const { return _derivatives->BindVBO(); } + virtual GLuint BindFaceVaryingData() const { + return _fvarData->BindVBO(); + } virtual GLuint BindPatchCoords() const { return _patchCoords->BindVBO(); } @@ -293,6 +316,9 @@ public: virtual void UpdateVaryingData(const float *src, int startVertex, int numVertices) { _srcVaryingData->UpdateData(src, startVertex, numVertices, _deviceContext); } + virtual void UpdateFaceVaryingData(const float *src, int startVertex, int numVertices) { + _srcFVarData->UpdateData(src, startVertex, numVertices, _deviceContext); + } virtual void Refine() { Osd::BufferDescriptor dstDesc = _srcDesc; dstDesc.offset += _numCoarseVerts * _srcDesc.stride; @@ -316,6 +342,21 @@ public: _varyingStencils, evalInstance, _deviceContext); + + if (_faceVaryingStencils) { + int const fvarWidth = 2; + Osd::BufferDescriptor dstFVarDesc(_numCoarseFVarVerts*fvarWidth, + fvarWidth, fvarWidth); + evalInstance = OpenSubdiv::Osd::GetEvaluator( + _evaluatorCache, _srcFVarDesc, dstFVarDesc, _deviceContext); + + EVALUATOR::EvalStencils(_srcFVarData, _srcFVarDesc, + _srcFVarData, dstFVarDesc, + _faceVaryingStencils, + evalInstance, + _deviceContext); + } + } virtual void EvalPatches() { EVALUATOR const *evalInstance = OpenSubdiv::Osd::GetEvaluator( @@ -344,7 +385,7 @@ public: EVALUATOR const *evalInstance = OpenSubdiv::Osd::GetEvaluator( _evaluatorCache, _srcVaryingDesc, _varyingDesc, _deviceContext); - EVALUATOR::EvalPatches( + EVALUATOR::EvalPatchesVarying( _srcVaryingData, _srcVaryingDesc, // varyingdata is interleved in vertexData. _vertexData, _varyingDesc, @@ -352,6 +393,17 @@ public: _patchCoords, _patchTable, evalInstance, _deviceContext); } + virtual void EvalPatchesFaceVarying() { + EVALUATOR const *evalInstance = OpenSubdiv::Osd::GetEvaluator( + _evaluatorCache, _srcFVarDesc, _fvarDesc, _deviceContext); + + EVALUATOR::EvalPatchesFaceVarying( + _srcFVarData, _srcFVarDesc, + _fvarData, _fvarDesc, + _patchCoords->GetNumVertices(), + _patchCoords, + _patchTable, /*fvarChannel=*/0, evalInstance, _deviceContext); + } virtual void UpdatePatchCoords( std::vector const &patchCoords) { if (_patchCoords && @@ -369,21 +421,26 @@ public: private: SRC_VERTEX_BUFFER *_srcData; SRC_VERTEX_BUFFER *_srcVaryingData; + EVAL_VERTEX_BUFFER *_srcFVarData; EVAL_VERTEX_BUFFER *_vertexData; EVAL_VERTEX_BUFFER *_derivatives; - EVAL_VERTEX_BUFFER *_varyingData; + EVAL_VERTEX_BUFFER *_fvarData; EVAL_VERTEX_BUFFER *_patchCoords; PATCH_TABLE *_patchTable; Osd::BufferDescriptor _srcDesc; Osd::BufferDescriptor _srcVaryingDesc; + Osd::BufferDescriptor _srcFVarDesc; Osd::BufferDescriptor _vertexDesc; Osd::BufferDescriptor _varyingDesc; + Osd::BufferDescriptor _fvarDesc; Osd::BufferDescriptor _duDesc; Osd::BufferDescriptor _dvDesc; int _numCoarseVerts; + int _numCoarseFVarVerts; STENCIL_TABLE const *_vertexStencils; STENCIL_TABLE const *_varyingStencils; + STENCIL_TABLE const *_faceVaryingStencils; EvaluatorCache *_evaluatorCache; DEVICE_CONTEXT *_deviceContext; @@ -459,8 +516,9 @@ updateGeom() { // color if (g_drawMode == kVARYING) { - // XXX: is this really varying? g_evalOutput->EvalPatchesVarying(); + } else if (g_drawMode == kFACEVARYING) { + g_evalOutput->EvalPatchesFaceVarying(); } s.Stop(); @@ -478,6 +536,8 @@ createOsdMesh(ShapeDesc const & shapeDesc, int level) { OpenSubdiv::Sdc::SchemeType sdctype = GetSdcType(*shape); OpenSubdiv::Sdc::Options sdcoptions = GetSdcOptions(*shape); + sdcoptions.SetFVarLinearInterpolation(g_fvarBoundary); + Far::TopologyRefiner *topologyRefiner = OpenSubdiv::Far::TopologyRefinerFactory::Create(*shape, OpenSubdiv::Far::TopologyRefinerFactory::Options(sdctype, sdcoptions)); @@ -485,8 +545,6 @@ createOsdMesh(ShapeDesc const & shapeDesc, int level) { g_orgPositions=shape->verts; g_positions.resize(g_orgPositions.size(), 0.0f); - delete shape; - float speed = g_particles ? g_particles->GetSpeed() : 0.2f; // save coarse topology (used for coarse mesh drawing) @@ -501,7 +559,9 @@ createOsdMesh(ShapeDesc const & shapeDesc, int level) { Far::StencilTable const * vertexStencils = NULL; Far::StencilTable const * varyingStencils = NULL; - int nverts=0; + Far::StencilTable const * faceVaryingStencils = NULL; + std::vector fvarData; + int nverts=0, nTotalfvarVerts=0; { bool adaptive = (sdctype == OpenSubdiv::Sdc::SCHEME_CATMARK); @@ -509,6 +569,7 @@ createOsdMesh(ShapeDesc const & shapeDesc, int level) { // Apply feature adaptive refinement to the mesh so that we can use the // limit evaluation API features. Far::TopologyRefiner::AdaptiveOptions options(level); + options.considerFVarChannels = true; topologyRefiner->RefineAdaptive(options); } else { Far::TopologyRefiner::UniformOptions options(level); @@ -531,7 +592,7 @@ createOsdMesh(ShapeDesc const & shapeDesc, int level) { Far::StencilTableFactory::Create(*topologyRefiner, soptions); // Generate bi-cubic patch table for the limit surface - Far::PatchTableFactory::Options poptions; + Far::PatchTableFactory::Options poptions(level); if (g_endCap == kEndCapBSplineBasis) { poptions.SetEndCapType( Far::PatchTableFactory::Options::ENDCAP_BSPLINE_BASIS); @@ -539,6 +600,8 @@ createOsdMesh(ShapeDesc const & shapeDesc, int level) { poptions.SetEndCapType( Far::PatchTableFactory::Options::ENDCAP_GREGORY_BASIS); } + poptions.generateFVarTables = true; + poptions.generateFVarLegacyLinearPatches = false; Far::PatchTable const * patchTable = Far::PatchTableFactory::Create(*topologyRefiner, poptions); @@ -561,17 +624,29 @@ createOsdMesh(ShapeDesc const & shapeDesc, int level) { delete varyingStencils; varyingStencils = table; } + if (Far::StencilTable const *localPointFaceVaryingStencilTable = + patchTable->GetLocalPointFaceVaryingStencilTable()) { + faceVaryingStencils = localPointFaceVaryingStencilTable; + } // total number of vertices = coarse verts + refined verts + gregory basis verts nverts = vertexStencils->GetNumControlVertices() + vertexStencils->GetNumStencils(); + nTotalfvarVerts = topologyRefiner->GetNumFVarValuesTotal(0) + + patchTable->GetNumLocalPointsFaceVarying(0); + + InterpolateFVarData(*topologyRefiner, *shape, fvarData); + if (g_patchTable) delete g_patchTable; g_patchTable = patchTable; } + delete shape; + // note that for patch eval we need coarse+refined combined buffer. int nCoarseVertices = topologyRefiner->GetLevel(0).GetNumVertices(); + int nCoarseFVarVertices = (int)fvarData.size()/2; // In following template instantiations, same type of vertex buffers are // used for both source and destination (first and second template @@ -587,8 +662,10 @@ createOsdMesh(ShapeDesc const & shapeDesc, int level) { Far::StencilTable, Osd::CpuPatchTable, Osd::CpuEvaluator> - (vertexStencils, varyingStencils, - nCoarseVertices, nverts, g_nParticles, g_patchTable); + (vertexStencils, varyingStencils, faceVaryingStencils, + nCoarseVertices, nverts, + nCoarseFVarVertices, nTotalfvarVerts, + g_nParticles, g_patchTable); #ifdef OPENSUBDIV_HAS_OPENMP } else if (g_kernel == kOPENMP) { g_evalOutput = new EvalOutput - (vertexStencils, varyingStencils, - nCoarseVertices, nverts, g_nParticles, g_patchTable); + (vertexStencils, varyingStencils, faceVaryingStencils, + nCoarseVertices, nverts, + nCoarseFVarVertices, nTotalfvarVerts, + g_nParticles, g_patchTable); #endif #ifdef OPENSUBDIV_HAS_TBB } else if (g_kernel == kTBB) { @@ -606,8 +685,10 @@ createOsdMesh(ShapeDesc const & shapeDesc, int level) { Far::StencilTable, Osd::CpuPatchTable, Osd::TbbEvaluator> - (vertexStencils, varyingStencils, - nCoarseVertices, nverts, g_nParticles, g_patchTable); + (vertexStencils, varyingStencils, faceVaryingStencils, + nCoarseVertices, nverts, + nCoarseFVarVertices, nTotalfvarVerts, + g_nParticles, g_patchTable); #endif #ifdef OPENSUBDIV_HAS_CUDA } else if (g_kernel == kCUDA) { @@ -616,8 +697,10 @@ createOsdMesh(ShapeDesc const & shapeDesc, int level) { Osd::CudaStencilTable, Osd::CudaPatchTable, Osd::CudaEvaluator> - (vertexStencils, varyingStencils, - nCoarseVertices, nverts, g_nParticles, g_patchTable); + (vertexStencils, varyingStencils, faceVaryingStencils, + nCoarseVertices, nverts, + nCoarseFVarVertices, nTotalfvarVerts, + g_nParticles, g_patchTable); #endif #ifdef OPENSUBDIV_HAS_OPENCL } else if (g_kernel == kCL) { @@ -628,8 +711,10 @@ createOsdMesh(ShapeDesc const & shapeDesc, int level) { Osd::CLPatchTable, Osd::CLEvaluator, CLDeviceContext> - (vertexStencils, varyingStencils, - nCoarseVertices, nverts, g_nParticles, g_patchTable, + (vertexStencils, varyingStencils, faceVaryingStencils, + nCoarseVertices, nverts, + nCoarseFVarVertices, nTotalfvarVerts, + g_nParticles, g_patchTable, &clEvaluatorCache, &g_clDeviceContext); #endif #ifdef OPENSUBDIV_HAS_GLSL_TRANSFORM_FEEDBACK @@ -640,8 +725,10 @@ createOsdMesh(ShapeDesc const & shapeDesc, int level) { Osd::GLStencilTableTBO, Osd::GLPatchTable, Osd::GLXFBEvaluator> - (vertexStencils, varyingStencils, - nCoarseVertices, nverts, g_nParticles, g_patchTable, + (vertexStencils, varyingStencils, faceVaryingStencils, + nCoarseVertices, nverts, + nCoarseFVarVertices, nTotalfvarVerts, + g_nParticles, g_patchTable, &glXFBEvaluatorCache); #endif #ifdef OPENSUBDIV_HAS_GLSL_COMPUTE @@ -652,12 +739,16 @@ createOsdMesh(ShapeDesc const & shapeDesc, int level) { Osd::GLStencilTableSSBO, Osd::GLPatchTable, Osd::GLComputeEvaluator> - (vertexStencils, varyingStencils, - nCoarseVertices, nverts, g_nParticles, g_patchTable, + (vertexStencils, varyingStencils, faceVaryingStencils, + nCoarseVertices, nverts, + nCoarseFVarVertices, nTotalfvarVerts, + g_nParticles, g_patchTable, &glComputeEvaluatorCache); #endif } + g_evalOutput->UpdateFaceVaryingData(&fvarData[0], 0, (int)fvarData.size()/2); + // Create the 'uv particles' manager - this class manages the limit // location samples (ptex face index, (s,t) and updates them between frames. // Note: the number of limit locations can be entirely arbitrary @@ -692,6 +783,7 @@ linkDefaultProgram() { "in vec3 tangentU;\n" "in vec3 tangentV;\n" "in vec2 patchCoord;\n" + "in vec2 fvarData;\n" "out vec4 fragColor;\n" "uniform mat4 ModelViewMatrix;\n" "uniform mat4 ProjectionMatrix;\n" @@ -708,7 +800,9 @@ linkDefaultProgram() { " } else if (DrawMode == 3) {\n" " fragColor = vec4(vec3(1)*dot(normal, vec3(0,0,1)), 1);\n" " } else if (DrawMode == 4) {\n" // face varying - " fragColor = vec4(1);\n" + " // generating a checkerboard pattern\n" + " int checker = int(floor(20*fvarData.r)+floor(20*fvarData.g))&1;\n" + " fragColor = vec4(fvarData.rg*checker, 1-checker, 1);\n" " } else {\n" // varying " fragColor = vec4(color, 1);\n" " }\n" @@ -734,6 +828,7 @@ linkDefaultProgram() { glBindAttribLocation(program, 2, "tangentU"); glBindAttribLocation(program, 3, "tangentV"); glBindAttribLocation(program, 4, "patchCoord"); + glBindAttribLocation(program, 5, "fvarData"); glBindFragDataLocation(program, 0, "color"); glLinkProgram(program); @@ -762,6 +857,7 @@ linkDefaultProgram() { g_defaultProgram.attrTangentU = glGetAttribLocation(program, "tangentU"); g_defaultProgram.attrTangentV = glGetAttribLocation(program, "tangentV"); g_defaultProgram.attrPatchCoord = glGetAttribLocation(program, "patchCoord"); + g_defaultProgram.attrFVarData = glGetAttribLocation(program, "fvarData"); return true; } @@ -783,6 +879,8 @@ drawSamples() { glEnableVertexAttribArray(g_defaultProgram.attrColor); glEnableVertexAttribArray(g_defaultProgram.attrTangentU); glEnableVertexAttribArray(g_defaultProgram.attrTangentV); + glEnableVertexAttribArray(g_defaultProgram.attrPatchCoord); + glEnableVertexAttribArray(g_defaultProgram.attrFVarData); glBindBuffer(GL_ARRAY_BUFFER, g_evalOutput->BindVertexData()); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof (GLfloat) * 6, 0); @@ -795,11 +893,15 @@ drawSamples() { glBindBuffer(GL_ARRAY_BUFFER, g_evalOutput->BindPatchCoords()); glVertexAttribPointer(4, 2, GL_FLOAT, GL_FALSE, sizeof (GLfloat) * 5, (float*)12); + glBindBuffer(GL_ARRAY_BUFFER, g_evalOutput->BindFaceVaryingData()); + glVertexAttribPointer(5, 2, GL_FLOAT, GL_FALSE, sizeof (GLfloat) * 2, 0); + glEnableVertexAttribArray(g_defaultProgram.attrPosition); glEnableVertexAttribArray(g_defaultProgram.attrColor); glEnableVertexAttribArray(g_defaultProgram.attrTangentU); glEnableVertexAttribArray(g_defaultProgram.attrTangentV); glEnableVertexAttribArray(g_defaultProgram.attrPatchCoord); + glEnableVertexAttribArray(g_defaultProgram.attrFVarData); glPointSize(2.0f); int nPatchCoords = (int)g_particles->GetPatchCoords().size(); @@ -811,6 +913,7 @@ drawSamples() { glDisableVertexAttribArray(g_defaultProgram.attrTangentU); glDisableVertexAttribArray(g_defaultProgram.attrTangentV); glDisableVertexAttribArray(g_defaultProgram.attrPatchCoord); + glDisableVertexAttribArray(g_defaultProgram.attrFVarData); glBindVertexArray(0); @@ -875,20 +978,6 @@ display() { g_hud.DrawString(10, -40, "CPU Draw : %.3f ms", drawCpuTime); g_hud.DrawString(10, -20, "FPS : %3.1f", fps); - if (g_drawMode==kFACEVARYING) { - static char msg[] = - "ERROR: Face-varying interpolation hasn't been supported yet."; - g_hud.DrawString(g_width/4, g_height/4, 1, 0, 0, msg); - } - - if (g_endCap != kEndCapBSplineBasis && - (g_kernel != kCPU && g_kernel != kOPENMP && g_kernel != kTBB)) { - static char msg[] = - "ERROR: This kernel only supports BSpline basis patches."; - g_hud.DrawString(g_width/4, g_height/4+20, 1, 0, 0, msg); - } - - g_hud.Flush(); } diff --git a/examples/glEvalLimit/init_shapes.h b/examples/glEvalLimit/init_shapes.h index 689604e2..c7cb0dd1 100644 --- a/examples/glEvalLimit/init_shapes.h +++ b/examples/glEvalLimit/init_shapes.h @@ -58,7 +58,9 @@ static void initShapes() { g_defaultShapes.push_back( ShapeDesc("catmark_fan", catmark_fan, kCatmark ) ); g_defaultShapes.push_back( ShapeDesc("catmark_flap", catmark_flap, kCatmark ) ); g_defaultShapes.push_back( ShapeDesc("catmark_flap2", catmark_flap2, kCatmark ) ); - g_defaultShapes.push_back( ShapeDesc("catmark_gregory_test0", catmark_gregory_test0, kCatmark ) ); + g_defaultShapes.push_back( ShapeDesc("catmark_fvar_bound0", catmark_fvar_bound0, kCatmark ) ); + g_defaultShapes.push_back( ShapeDesc("catmark_fvar_bound1", catmark_fvar_bound1, kCatmark ) ); + g_defaultShapes.push_back( ShapeDesc("catmark_fvar_bound2", catmark_fvar_bound2, kCatmark ) ); g_defaultShapes.push_back( ShapeDesc("catmark_gregory_test1", catmark_gregory_test1, kCatmark ) ); g_defaultShapes.push_back( ShapeDesc("catmark_gregory_test2", catmark_gregory_test2, kCatmark ) ); g_defaultShapes.push_back( ShapeDesc("catmark_gregory_test3", catmark_gregory_test3, kCatmark ) ); diff --git a/examples/glFVarViewer/glFVarViewer.cpp b/examples/glFVarViewer/glFVarViewer.cpp index 6f651a32..56483e54 100644 --- a/examples/glFVarViewer/glFVarViewer.cpp +++ b/examples/glFVarViewer/glFVarViewer.cpp @@ -30,6 +30,7 @@ GLFWmonitor* g_primary = 0; #include #include +#include #include #include OpenSubdiv::Osd::GLMeshInterface *g_mesh = NULL; @@ -62,6 +63,9 @@ enum DisplayStyle { kWire = 0, kShaded, kWireShaded }; +enum EndCap { kEndCapBSplineBasis, + kEndCapGregoryBasis }; + int g_currentShape = 0; int g_frame = 0, @@ -105,6 +109,7 @@ std::vector g_orgPositions, Scheme g_scheme; +int g_endCap = kEndCapBSplineBasis; int g_level = 2; int g_tessLevel = 1; int g_tessLevelMin = 1; @@ -138,7 +143,7 @@ struct Program { struct FVarData { FVarData() : - textureBuffer(0) { + textureBuffer(0), textureParamBuffer(0) { } ~FVarData() { Release(); @@ -147,11 +152,38 @@ struct FVarData if (textureBuffer) glDeleteTextures(1, &textureBuffer); textureBuffer = 0; + if (textureParamBuffer) + glDeleteTextures(1, &textureParamBuffer); + textureParamBuffer = 0; } void Create(OpenSubdiv::Far::PatchTable const *patchTable, int fvarWidth, std::vector const & fvarSrcData) { + + using namespace OpenSubdiv; + Release(); - OpenSubdiv::Far::ConstIndexArray indices = patchTable->GetFVarValues(); + Far::ConstIndexArray indices = patchTable->GetFVarValues(); + + const float * fvarSrcDataPtr = &fvarSrcData[0]; + Osd::CpuVertexBuffer *fvarBuffer = NULL; + + int numLocalFVarPoints = patchTable->GetNumLocalPointsFaceVarying(); + if (numLocalFVarPoints > 0) { + int numSrcFVarPoints = (int)fvarSrcData.size() / fvarWidth; + fvarBuffer = Osd::CpuVertexBuffer::Create( + fvarWidth, numSrcFVarPoints + numLocalFVarPoints); + fvarBuffer->UpdateData(&fvarSrcData[0], 0, numSrcFVarPoints); + + Osd::BufferDescriptor srcDesc(0, fvarWidth, fvarWidth); + Osd::BufferDescriptor dstDesc(numSrcFVarPoints*fvarWidth, + fvarWidth, fvarWidth); + + Osd::CpuEvaluator::EvalStencils(fvarBuffer, srcDesc, + fvarBuffer, dstDesc, + patchTable->GetLocalPointFaceVaryingStencilTable()); + + fvarSrcDataPtr = fvarBuffer->BindCpuBuffer(); + } // expand fvardata to per-patch array std::vector data; @@ -160,7 +192,7 @@ struct FVarData for (int fvert = 0; fvert < (int)indices.size(); ++fvert) { int index = indices[fvert] * fvarWidth; for (int i = 0; i < fvarWidth; ++i) { - data.push_back(fvarSrcData[index++]); + data.push_back(fvarSrcDataPtr[index++]); } } GLuint buffer; @@ -169,6 +201,10 @@ struct FVarData glBufferData(GL_ARRAY_BUFFER, data.size()*sizeof(float), &data[0], GL_STATIC_DRAW); + if (fvarBuffer) { + delete fvarBuffer; + } + glGenTextures(1, &textureBuffer); glBindTexture(GL_TEXTURE_BUFFER, textureBuffer); glTexBuffer(GL_TEXTURE_BUFFER, GL_R32F, buffer); @@ -176,8 +212,23 @@ struct FVarData glBindTexture(GL_ARRAY_BUFFER, 0); glDeleteBuffers(1, &buffer); + + Far::ConstPatchParamArray fvarParam = patchTable->GetFVarPatchParam(); + + glGenBuffers(1, &buffer); + glBindBuffer(GL_ARRAY_BUFFER, buffer); + glBufferData(GL_ARRAY_BUFFER, fvarParam.size()*sizeof(Far::PatchParam), + &fvarParam[0], GL_STATIC_DRAW); + + glGenTextures(1, &textureParamBuffer); + glBindTexture(GL_TEXTURE_BUFFER, textureParamBuffer); + glTexBuffer(GL_TEXTURE_BUFFER, GL_RG32I, buffer); + glBindTexture(GL_TEXTURE_BUFFER, 0); + glBindTexture(GL_ARRAY_BUFFER, 0); + + glDeleteBuffers(1, &buffer); } - GLuint textureBuffer; + GLuint textureBuffer, textureParamBuffer; } g_fvarData; //------------------------------------------------------------------------------ @@ -366,6 +417,10 @@ rebuildMesh() { OpenSubdiv::Osd::MeshBitset bits; bits.set(OpenSubdiv::Osd::MeshAdaptive, doAdaptive); bits.set(OpenSubdiv::Osd::MeshFVarData, 1); + bits.set(OpenSubdiv::Osd::MeshFVarAdaptive, 1); + bits.set(OpenSubdiv::Osd::MeshEndCapBSplineBasis, g_endCap == kEndCapBSplineBasis); + bits.set(OpenSubdiv::Osd::MeshEndCapGregoryBasis, g_endCap == kEndCapGregoryBasis); + int numVertexElements = 3; int numVaryingElements = 0; @@ -461,10 +516,13 @@ GetEffect(bool uvDraw = false) { struct EffectDesc { EffectDesc(OpenSubdiv::Far::PatchDescriptor desc, - Effect effect) : desc(desc), effect(effect), + OpenSubdiv::Far::PatchDescriptor fvarDesc, + Effect effect) : desc(desc), fvarDesc(fvarDesc), + effect(effect), maxValence(0), numElements(0) { } OpenSubdiv::Far::PatchDescriptor desc; + OpenSubdiv::Far::PatchDescriptor fvarDesc; Effect effect; int maxValence; int numElements; @@ -472,9 +530,10 @@ struct EffectDesc { bool operator < (const EffectDesc &e) const { return (desc < e.desc || ((desc == e.desc && + (fvarDesc < e.fvarDesc || ((fvarDesc == e.fvarDesc && (maxValence < e.maxValence || ((maxValence == e.maxValence) && (numElements < e.numElements || ((numElements == e.numElements) && - (effect < e.effect)))))))); + (effect < e.effect))))))))))); } }; @@ -536,7 +595,17 @@ public: ss << "#define SHADING_FACEVARYING_UNIFORM_SUBDIVISION\n"; } + if (effectDesc.desc.IsAdaptive()) { + if (effectDesc.fvarDesc.GetType() == Far::PatchDescriptor::REGULAR) { + ss << "#define SHADING_FACEVARYING_SMOOTH_BSPLINE_BASIS\n"; + } else if (effectDesc.fvarDesc.GetType() == Far::PatchDescriptor::GREGORY_BASIS) { + ss << "#define SHADING_FACEVARYING_SMOOTH_GREGORY_BASIS\n"; + } + } + // include osd PatchCommon + ss << "#define OSD_PATCH_BASIS_GLSL\n"; + ss << Osd::GLSLPatchShaderSource::GetPatchBasisShaderSource(); ss << Osd::GLSLPatchShaderSource::GetCommonShaderSource(); std::string common = ss.str(); ss.str(""); @@ -607,6 +676,9 @@ public: if ((loc = glGetUniformLocation(program, "OsdFVarDataBuffer")) != -1) { glUniform1i(loc, 1); // GL_TEXTURE1 } + if ((loc = glGetUniformLocation(program, "OsdFVarParamBuffer")) != -1) { + glUniform1i(loc, 2); // GL_TEXTURE2 + } return config; @@ -661,14 +733,18 @@ bindTextures() { } glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_BUFFER, g_fvarData.textureBuffer); + glActiveTexture(GL_TEXTURE2); + glBindTexture(GL_TEXTURE_BUFFER, g_fvarData.textureParamBuffer); glActiveTexture(GL_TEXTURE0); } static GLenum -bindProgram(Effect effect, OpenSubdiv::Osd::PatchArray const & patch) { +bindProgram(Effect effect, + OpenSubdiv::Osd::PatchArray const & patch, + OpenSubdiv::Far::PatchDescriptor const & fvarDesc) { - EffectDesc effectDesc(patch.GetDescriptor(), effect); + EffectDesc effectDesc(patch.GetDescriptor(), fvarDesc, effect); typedef OpenSubdiv::Far::PatchDescriptor Descriptor; @@ -745,6 +821,9 @@ display() { glBindVertexArray(g_vao); + OpenSubdiv::Far::PatchDescriptor fvarDesc = + g_mesh->GetFarPatchTable()->GetFVarChannelPatchDescriptor(0); + OpenSubdiv::Osd::PatchArrayVector const & patches = g_mesh->GetPatchTable()->GetPatchArrays(); @@ -758,7 +837,7 @@ display() { for (int i = 0; i < (int)patches.size(); ++i) { OpenSubdiv::Osd::PatchArray const & patch = patches[i]; - GLenum primType = bindProgram(GetEffect(), patch); + GLenum primType = bindProgram(GetEffect(), patch, fvarDesc); glDrawElements( primType, @@ -789,7 +868,7 @@ display() { for (int i = 0; i < (int)patches.size(); ++i) { OpenSubdiv::Osd::PatchArray const & patch = patches[i]; - GLenum primType = bindProgram(GetEffect(/*uvDraw=*/ true), patch); + GLenum primType = bindProgram(GetEffect(/*uvDraw=*/ true), patch, fvarDesc); glDrawElements( primType, @@ -927,6 +1006,12 @@ callbackDisplayStyle(int b) { g_displayStyle = b; } +static void +callbackEndCap(int endCap) { + g_endCap = endCap; + rebuildMesh(); +} + static void callbackLevel(int l) { @@ -996,6 +1081,15 @@ initHUD() { g_hud.AddPullDownButton(shading_pulldown, "Shaded", kShaded, g_displayStyle==kShaded); g_hud.AddPullDownButton(shading_pulldown, "Wire+Shaded", kWireShaded, g_displayStyle==kWireShaded); + int endcap_pulldown = g_hud.AddPullDown("End cap (E)", 10, 140, 200, + callbackEndCap, 'e'); + g_hud.AddPullDownButton(endcap_pulldown, "BSpline", + kEndCapBSplineBasis, + g_endCap == kEndCapBSplineBasis); + g_hud.AddPullDownButton(endcap_pulldown, "GregoryBasis", + kEndCapGregoryBasis, + g_endCap == kEndCapGregoryBasis); + if (GLUtils::SupportsAdaptiveTessellation()) g_hud.AddCheckBox("Adaptive (`)", g_adaptive != 0, 10, 250, callbackAdaptive, 0, '`'); diff --git a/examples/glFVarViewer/init_shapes.h b/examples/glFVarViewer/init_shapes.h index 9f97846d..07f94da2 100644 --- a/examples/glFVarViewer/init_shapes.h +++ b/examples/glFVarViewer/init_shapes.h @@ -64,6 +64,9 @@ static void initShapes() { g_defaultShapes.push_back( ShapeDesc("catmark_gregory_test2", catmark_gregory_test2, kCatmark ) ); g_defaultShapes.push_back( ShapeDesc("catmark_gregory_test3", catmark_gregory_test3, kCatmark ) ); g_defaultShapes.push_back( ShapeDesc("catmark_gregory_test4", catmark_gregory_test4, kCatmark ) ); + g_defaultShapes.push_back( ShapeDesc("catmark_gregory_test5", catmark_gregory_test5, kCatmark ) ); + g_defaultShapes.push_back( ShapeDesc("catmark_gregory_test6", catmark_gregory_test6, kCatmark ) ); + g_defaultShapes.push_back( ShapeDesc("catmark_gregory_test7", catmark_gregory_test7, kCatmark ) ); g_defaultShapes.push_back( ShapeDesc("catmark_hole_test1", catmark_hole_test1, kCatmark ) ); g_defaultShapes.push_back( ShapeDesc("catmark_hole_test2", catmark_hole_test2, kCatmark ) ); g_defaultShapes.push_back( ShapeDesc("catmark_pyramid_creases0", catmark_pyramid_creases0, kCatmark ) ); diff --git a/examples/glFVarViewer/shader.glsl b/examples/glFVarViewer/shader.glsl index e47beabc..d012dd46 100644 --- a/examples/glFVarViewer/shader.glsl +++ b/examples/glFVarViewer/shader.glsl @@ -166,6 +166,57 @@ out block { OSD_USER_VARYING_DECLARE } outpt; +uniform isamplerBuffer OsdFVarParamBuffer; + +vec2 +interpolateFaceVarying(vec2 uv, int fvarOffset) +{ + int patchIndex = OsdGetPatchIndex(gl_PrimitiveID); + +#if defined(SHADING_FACEVARYING_SMOOTH_BSPLINE_BASIS) + float wP[16], wDs[16], wDt[16], wDss[16], wDst[16], wDtt[16]; + int patchCVs = 16; + int patchStride = patchCVs; + int boundaryMask = (int(texelFetch(OsdFVarParamBuffer, patchIndex).y) >> 8) & 0xf; + OsdGetBSplinePatchWeights(uv.s, uv.t, 1.0f, boundaryMask, wP, wDs, wDt, wDss, wDst, wDtt); + +#elif defined(SHADING_FACEVARYING_SMOOTH_GREGORY_BASIS) + float wP[20], wDs[20], wDt[20], wDss[20], wDst[20], wDtt[20]; + int patchCVs = 20; + int patchStride = patchCVs; + bool isRegular = ((int(texelFetch(OsdFVarParamBuffer, patchIndex).y) >> 5) & 0x1) != 0; + if (isRegular) { + float wP16[16], wDs16[16], wDt16[16], wDss16[16], wDst16[16], wDtt16[16]; + patchCVs = 16; + int boundaryMask = (int(texelFetch(OsdFVarParamBuffer, patchIndex).y) >> 8) & 0xf; + OsdGetBSplinePatchWeights(uv.s, uv.t, 1.0f, boundaryMask, wP16, wDs16, wDt16, wDss16, wDst16, wDtt16); + for (int i=0; i