From 24f9dc154b38882eda82ae91c0c99eeddc0ff7a9 Mon Sep 17 00:00:00 2001 From: Takahito Tejima Date: Tue, 7 Apr 2015 18:34:05 -0700 Subject: [PATCH] Enable GregoryBasis patch. PatchTablesFactory fills 20 indices topology into patchtable, and use it for eval and draw. note: currently screen-space adaptive tessellation of gregory basis patches is broken and cracks appear around them. --- examples/common/patchColors.cpp | 2 +- examples/glEvalLimit/glEvalLimit.cpp | 44 +++- examples/glEvalLimit/init_shapes.h | 2 + examples/glPtexViewer/glPtexViewer.cpp | 1 + examples/glViewer/glViewer.cpp | 5 +- examples/glViewer/init_shapes.h | 2 + examples/glViewer/shader.glsl | 1 + examples/vtrViewer/fontShader.glsl | 14 +- examples/vtrViewer/init_shapes.h | 6 + examples/vtrViewer/vtrViewer.cpp | 101 +++++--- opensubdiv/far/gregoryBasis.cpp | 77 ++++-- opensubdiv/far/gregoryBasis.h | 26 +- opensubdiv/far/patchTables.cpp | 34 +-- opensubdiv/far/patchTables.h | 16 +- opensubdiv/far/patchTablesFactory.cpp | 112 +++++---- opensubdiv/far/patchTablesFactory.h | 5 +- opensubdiv/far/stencilTablesFactory.cpp | 41 +-- opensubdiv/osd/CMakeLists.txt | 1 + opensubdiv/osd/cpuEvalLimitController.cpp | 19 +- opensubdiv/osd/cpuEvalLimitKernel.cpp | 123 +++------ opensubdiv/osd/cpuEvalLimitKernel.h | 6 +- opensubdiv/osd/glDrawRegistry.cpp | 14 ++ opensubdiv/osd/glMesh.h | 230 +++++++++++------ opensubdiv/osd/glslPatchCommon.glsl | 2 + opensubdiv/osd/glslPatchGregoryBasis.glsl | 294 ++++++++++++++++++++++ opensubdiv/osd/mesh.h | 3 +- regression/shapes/catmark_gregory_test0.h | 21 ++ 27 files changed, 858 insertions(+), 344 deletions(-) create mode 100644 opensubdiv/osd/glslPatchGregoryBasis.glsl create mode 100644 regression/shapes/catmark_gregory_test0.h diff --git a/examples/common/patchColors.cpp b/examples/common/patchColors.cpp index 322084cc..2cdb3dd8 100644 --- a/examples/common/patchColors.cpp +++ b/examples/common/patchColors.cpp @@ -30,7 +30,7 @@ static float _colors[5][7][4] = {{{1.0f, 1.0f, 1.0f, 1.0f}, // regular {0.0f, 1.0f, 0.0f, 1.0f}, // corner {1.0f, 1.0f, 0.0f, 1.0f}, // gregory {1.0f, 0.5f, 0.0f, 1.0f}, // gregory boundary - {1.0f, 1.0f, 0.0f, 1.0f}}, // gregory basis + {1.0f, 0.7f, 0.3f, 1.0f}}, // gregory basis {{0.0f, 1.0f, 1.0f, 1.0f}, // regular pattern 0 {0.0f, 0.5f, 1.0f, 1.0f}, // regular pattern 1 diff --git a/examples/glEvalLimit/glEvalLimit.cpp b/examples/glEvalLimit/glEvalLimit.cpp index c617d2df..d6ad53a0 100644 --- a/examples/glEvalLimit/glEvalLimit.cpp +++ b/examples/glEvalLimit/glEvalLimit.cpp @@ -376,26 +376,50 @@ createOsdMesh(ShapeDesc const & shapeDesc, int level) { Far::StencilTables const * varyingStencils = Far::StencilTablesFactory::Create(*g_topologyRefiner, soptions); - g_kernelBatches.clear(); - g_kernelBatches.push_back(Far::StencilTablesFactory::Create(*vertexStencils)); - - // Create an Osd Compute context, used to "pose" the vertices with - // the stencils tables - delete g_computeCtx; - g_computeCtx = Osd::CpuComputeContext::Create(vertexStencils, varyingStencils); - - // Generate bi-cubic patch tables for the limit surface Far::PatchTablesFactory::Options poptions; // optional : pass the vertex stencils so that the factory can generate gregory basis // stencils (faster evaluation) - poptions.adaptiveStencilTables = vertexStencils; + poptions.adaptiveStencilTables = vertexStencils; + poptions.adaptiveVaryingStencilTables = varyingStencils; + Far::PatchTables const * patchTables = Far::PatchTablesFactory::Create(*g_topologyRefiner, poptions); + Far::StencilTables const *inStencils[] = { + vertexStencils, patchTables->GetEndCapVertexStencilTables() + }; + Far::StencilTables const *concatStencils = + Far::StencilTablesFactory::Create(2, inStencils); + + // add gregory basis vertices FIXME: + if (patchTables->GetEndCapVertexStencilTables()) { + nverts += patchTables->GetEndCapVertexStencilTables()->GetNumStencils(); + } + + + Far::StencilTables const *concatVaryingStencils = varyingStencils; + if (varyingStencils and patchTables->GetEndCapVaryingStencilTables()) { + Far::StencilTables const *inVaryingStencils[] = { + varyingStencils, patchTables->GetEndCapVaryingStencilTables() + }; + concatVaryingStencils = + Far::StencilTablesFactory::Create(2, inVaryingStencils); + } + + // Create an Osd Compute context, used to "pose" the vertices with + // the stencils tables + delete g_computeCtx; + g_computeCtx = Osd::CpuComputeContext::Create(concatStencils, concatVaryingStencils); + + // Create a limit Eval context with the patch tables delete g_evalCtx; g_evalCtx = Osd::CpuEvalLimitContext::Create(*patchTables); + + g_kernelBatches.clear(); + g_kernelBatches.push_back(Far::StencilTablesFactory::Create(*concatStencils)); + } { // Create vertex primvar buffer for the CVs diff --git a/examples/glEvalLimit/init_shapes.h b/examples/glEvalLimit/init_shapes.h index b4349dfa..9fbd8d74 100644 --- a/examples/glEvalLimit/init_shapes.h +++ b/examples/glEvalLimit/init_shapes.h @@ -56,6 +56,7 @@ static std::vector g_defaultShapes; #include #include #include +#include #include #include #include @@ -103,6 +104,7 @@ 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_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/glPtexViewer/glPtexViewer.cpp b/examples/glPtexViewer/glPtexViewer.cpp index 21c9fd6b..855c4915 100644 --- a/examples/glPtexViewer/glPtexViewer.cpp +++ b/examples/glPtexViewer/glPtexViewer.cpp @@ -1033,6 +1033,7 @@ createOsdMesh(int level, int kernel) { OpenSubdiv::Osd::MeshBitset bits; bits.set(OpenSubdiv::Osd::MeshAdaptive, doAdaptive); bits.set(OpenSubdiv::Osd::MeshPtexData, true); + bits.set(OpenSubdiv::Osd::MeshUseGregoryBasis, true); int numVertexElements = g_adaptive ? 3 : 6; int numVaryingElements = 0; diff --git a/examples/glViewer/glViewer.cpp b/examples/glViewer/glViewer.cpp index 2b3171c5..18cee8e5 100644 --- a/examples/glViewer/glViewer.cpp +++ b/examples/glViewer/glViewer.cpp @@ -535,6 +535,7 @@ createOsdMesh(ShapeDesc const & shapeDesc, int level, int kernel, Scheme scheme= bits.set(OpenSubdiv::Osd::MeshUseSingleCreasePatch, doSingleCreasePatch); bits.set(OpenSubdiv::Osd::MeshInterleaveVarying, interleaveVarying); bits.set(OpenSubdiv::Osd::MeshFVarData, g_displayStyle == kFaceVaryingColor); + bits.set(OpenSubdiv::Osd::MeshUseGregoryBasis, true); int numVertexElements = 3; int numVaryingElements = @@ -1157,7 +1158,7 @@ display() { g_mesh->GetDrawContext()->GetPatchArrays(); // patch drawing - int patchCount[12][6][4]; // [Type][Pattern][Rotation] (see far/patchTables.h) + int patchCount[13][6][4]; // [Type][Pattern][Rotation] (see far/patchTables.h) int numTotalPatches = 0; int numDrawCalls = 0; memset(patchCount, 0, sizeof(patchCount)); @@ -1300,6 +1301,8 @@ display() { patchCount[Descriptor::GREGORY][0][0]); y+= 20; g_hud.DrawString(x, y, "Boundary Gregory : %d", patchCount[Descriptor::GREGORY_BOUNDARY][0][0]); y+= 20; + g_hud.DrawString(x, y, "Gregory Basis : %d", + patchCount[Descriptor::GREGORY_BASIS][0][0]); y+= 20; g_hud.DrawString(x, y, "Trans. Regular : %d %d %d %d %d", patchCount[Descriptor::REGULAR][Descriptor::PATTERN0][0], patchCount[Descriptor::REGULAR][Descriptor::PATTERN1][0], diff --git a/examples/glViewer/init_shapes.h b/examples/glViewer/init_shapes.h index 960d4bf9..c68ae79d 100644 --- a/examples/glViewer/init_shapes.h +++ b/examples/glViewer/init_shapes.h @@ -60,6 +60,7 @@ static std::vector g_defaultShapes; #include #include #include +#include #include #include #include @@ -126,6 +127,7 @@ static void initShapes() { 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_test0", catmark_gregory_test0, 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/glViewer/shader.glsl b/examples/glViewer/shader.glsl index 1b7ee206..32afe870 100644 --- a/examples/glViewer/shader.glsl +++ b/examples/glViewer/shader.glsl @@ -160,6 +160,7 @@ out block { void emit(int index, vec3 normal) { outpt.v.position = inpt[index].v.position; + outpt.v.patchCoord = inpt[index].v.patchCoord; #ifdef SMOOTH_NORMALS outpt.v.normal = inpt[index].v.normal; #else diff --git a/examples/vtrViewer/fontShader.glsl b/examples/vtrViewer/fontShader.glsl index e5659d59..be0c44e2 100644 --- a/examples/vtrViewer/fontShader.glsl +++ b/examples/vtrViewer/fontShader.glsl @@ -103,7 +103,7 @@ vec2 computeUV( int c ) } -uniform float scale=0.025; +uniform float scale=0.01; void main() { @@ -116,10 +116,14 @@ void main() vec2 ofs = inpt[0].data.xy; - emit(0, scale * (vec2( 1.0, -2.0)+ofs), uv + dim); - emit(1, scale * (vec2( 1.0, 2.0)+ofs), vec2(uv.x+dim.x, uv.y)); - emit(2, scale * (vec2(-1.0, -2.0)+ofs), vec2(uv.x, uv.y+dim.y)); - emit(3, scale * (vec2(-1.0, 2.0)+ofs), uv); + vec4 clipPos = ProjectionMatrix * inpt[0].position; + + float s = scale * clipPos.w; + + emit(0, s * (vec2( 1.0, -2.0)+ofs), uv + dim); + emit(1, s * (vec2( 1.0, 2.0)+ofs), vec2(uv.x+dim.x, uv.y)); + emit(2, s * (vec2(-1.0, -2.0)+ofs), vec2(uv.x, uv.y+dim.y)); + emit(3, s * (vec2(-1.0, 2.0)+ofs), uv); EndPrimitive(); } diff --git a/examples/vtrViewer/init_shapes.h b/examples/vtrViewer/init_shapes.h index 4e037948..e5a1afe6 100644 --- a/examples/vtrViewer/init_shapes.h +++ b/examples/vtrViewer/init_shapes.h @@ -59,6 +59,7 @@ static std::vector g_shapes; #include #include #include +#include #include #include #include @@ -76,6 +77,8 @@ static std::vector g_shapes; #include #include #include +#include +#include #include #include @@ -113,6 +116,7 @@ static void initShapes() { g_shapes.push_back( ShapeDesc("catmark_fvar_bound0", catmark_fvar_bound0, kCatmark ) ); g_shapes.push_back( ShapeDesc("catmark_fvar_bound1", catmark_fvar_bound1, kCatmark ) ); g_shapes.push_back( ShapeDesc("catmark_fvar_bound2", catmark_fvar_bound2, kCatmark ) ); + g_shapes.push_back( ShapeDesc("catmark_gregory_test0", catmark_gregory_test0, kCatmark ) ); g_shapes.push_back( ShapeDesc("catmark_gregory_test1", catmark_gregory_test1, kCatmark ) ); g_shapes.push_back( ShapeDesc("catmark_gregory_test2", catmark_gregory_test2, kCatmark ) ); g_shapes.push_back( ShapeDesc("catmark_gregory_test3", catmark_gregory_test3, kCatmark ) ); @@ -131,6 +135,8 @@ static void initShapes() { g_shapes.push_back( ShapeDesc("catmark_tent", catmark_tent, kCatmark ) ); g_shapes.push_back( ShapeDesc("catmark_torus", catmark_torus, kCatmark ) ); g_shapes.push_back( ShapeDesc("catmark_torus_creases0", catmark_torus_creases0, kCatmark ) ); + g_shapes.push_back( ShapeDesc("catmark_smoothtris0", catmark_smoothtris0, kCatmark ) ); + g_shapes.push_back( ShapeDesc("catmark_smoothtris1", catmark_smoothtris1, kCatmark ) ); g_shapes.push_back( ShapeDesc("catmark_car", catmark_car, kCatmark ) ); g_shapes.push_back( ShapeDesc("catmark_bishop", catmark_bishop, kCatmark ) ); diff --git a/examples/vtrViewer/vtrViewer.cpp b/examples/vtrViewer/vtrViewer.cpp index e85e0fbd..3763d4cb 100644 --- a/examples/vtrViewer/vtrViewer.cpp +++ b/examples/vtrViewer/vtrViewer.cpp @@ -635,23 +635,18 @@ createGregoryBasis(OpenSubdiv::Far::PatchTables const & patchTables, typedef OpenSubdiv::Far::PatchDescriptor PatchDescriptor; int npatches = 0; + int patchArray = 0; for (int array=0; array<(int)patchTables.GetNumPatchArrays(); ++array) { if (patchTables.GetPatchArrayDescriptor(array).GetType()== PatchDescriptor::GREGORY_BASIS) { npatches = patchTables.GetNumPatches(array); + patchArray = array; break; } } int nedges = npatches * 20; std::vector vertsperedge(nedges), edgeindices(nedges*2); - std::vector edgeverts(npatches*20); - - OpenSubdiv::Far::StencilTables const * gstencils = - patchTables.GetEndCapStencilTables(); - assert(gstencils); - - gstencils->UpdateValues(&vertexBuffer[0], &edgeverts[0]); for (int patch=0; patchPrint3D(verts[vid].GetPos(), buf, 3); - snprintf(buf, 16, " Ep%d", i); - g_font->Print3D(verts[vid+1].GetPos(), buf, 3); - snprintf(buf, 16, " Em%d", i); - g_font->Print3D(verts[vid+2].GetPos(), buf, 3); - snprintf(buf, 16, " Fp%d", i); - g_font->Print3D(verts[vid+3].GetPos(), buf, 3); - snprintf(buf, 16, " Fm%d", i); - g_font->Print3D(verts[vid+4].GetPos(), buf, 3); + int vid = patch * 20 + i * 5; + + const float *P = vertexBuffer[cvs[i*5+0]].GetPos(); + const float *Ep = vertexBuffer[cvs[i*5+1]].GetPos(); + const float *Em = vertexBuffer[cvs[i*5+2]].GetPos(); + const float *Fp = vertexBuffer[cvs[i*5+3]].GetPos(); + const float *Fm = vertexBuffer[cvs[i*5+4]].GetPos(); + + snprintf(buf, 16, " P%d (%d)", i, vid); + g_font->Print3D(P, buf, 3); + snprintf(buf, 16, " Ep%d (%d)", i, vid+1); + g_font->Print3D(Ep, buf, 3); + snprintf(buf, 16, " Em%d (%d)", i, vid+2); + g_font->Print3D(Em, buf, 3); + snprintf(buf, 16, " Fp%d (%d)", i, vid+3); + g_font->Print3D(Fp, buf, 3); + snprintf(buf, 16, " Fm%d (%d)", i, vid+4); + g_font->Print3D(Fm, buf, 3); } } GLMesh::Options options; - gregoryWire.Initialize(options, (int)edgeverts.size(), (int)vertsperedge.size(), - &vertsperedge[0], &edgeindices[0], (float const * )&edgeverts[0]); - + gregoryWire.Initialize(options, (int)vertexBuffer.size(), (int)vertsperedge.size(), + &vertsperedge[0], &edgeindices[0], (float const *)&vertexBuffer[0]); } //------------------------------------------------------------------------------ @@ -770,17 +775,6 @@ createVtrMesh(Shape * shape, int maxlevel) { // Stencils // - // create vertex primvar data buffer - std::vector vertexBuffer(refiner->GetNumVerticesTotal()); - Vertex * verts = &vertexBuffer[0]; - - // copy coarse vertices positions - int ncoarseverts = shape->GetNumVertices(); - for (int i=0; iverts[i*3]; - verts[i].SetPosition(ptr[0], ptr[1], ptr[2]); - } - //#define no_stencils #ifdef no_stencils { @@ -800,8 +794,6 @@ createVtrMesh(Shape * shape, int maxlevel) { stencilTables = OpenSubdiv::Far::StencilTablesFactory::Create(*refiner, options); - - stencilTables->UpdateValues(verts, verts + ncoarseverts); } #endif @@ -848,6 +840,39 @@ createVtrMesh(Shape * shape, int maxlevel) { refiner->InterpolateFaceVarying(values, values + nCoarseValues); } } + // note: gregoryBasisStencilTables is owned by patchTables. + OpenSubdiv::Far::StencilTables const * gregoryBasisStencilTables = + patchTables->GetEndCapVertexStencilTables(); + + if (gregoryBasisStencilTables) { + OpenSubdiv::Far::StencilTables const *inStencilTables[] = { + stencilTables, gregoryBasisStencilTables + }; + OpenSubdiv::Far::StencilTables const *concatStencilTables = + concatStencilTables = OpenSubdiv::Far::StencilTablesFactory::Create( + 2, inStencilTables); + delete stencilTables; + stencilTables = concatStencilTables; + } + + int numTotalVerts = shape->GetNumVertices() + stencilTables->GetNumStencils(); + + // create vertex primvar data buffer + std::vector vertexBuffer(numTotalVerts); + Vertex * verts = &vertexBuffer[0]; + + // copy coarse vertices positions + int ncoarseverts = shape->GetNumVertices(); + for (int i=0; iverts[i*3]; + verts[i].SetPosition(ptr[0], ptr[1], ptr[2]); + } + + // + // apply stencils + // + stencilTables->UpdateValues(verts, verts + ncoarseverts); + s.Stop(); // @@ -1391,7 +1416,7 @@ initHUD() { g_hud.AddCheckBox("Adaptive (`)", g_Adaptive!=0, 10, 350, callbackAdaptive, 0, '`'); - g_hud.AddSlider("Font Scale", 0.0f, 0.1f, 0.025f, + g_hud.AddSlider("Font Scale", 0.0f, 0.1f, 0.01f, -900, -50, 100, false, callbackScale, 0); for (int i = 1; i < 11; ++i) { diff --git a/opensubdiv/far/gregoryBasis.cpp b/opensubdiv/far/gregoryBasis.cpp index 069aed96..b7b5acb9 100644 --- a/opensubdiv/far/gregoryBasis.cpp +++ b/opensubdiv/far/gregoryBasis.cpp @@ -89,7 +89,8 @@ getQuadOffsets(Vtr::Level const & level, Vtr::Index fIndex, 16 + maxvalence - 3 // limit valence of 30 because we use a pre-computed closed-form 'ef' table -static const int MAX_VALENCE=30, +// XXXtakahito: revisit here to determine appropriate size +static const int MAX_VALENCE=(30*2), MAX_ELEMS = GetNumMaxElems(MAX_VALENCE); namespace Far { @@ -271,6 +272,9 @@ struct ProtoBasis { // Point P[4], Ep[4], Em[4], Fp[4], Fm[4]; + + // for varying interpolation + Point V[4]; }; int @@ -293,6 +297,7 @@ ProtoBasis::OffsetIndices(Index offset) { Em[vid].OffsetIndices(offset); Fp[vid].OffsetIndices(offset); Fm[vid].OffsetIndices(offset); + V[vid].OffsetIndices(offset); } } void @@ -349,6 +354,8 @@ ProtoBasis::ProtoBasis(Vtr::Level const & level, Index faceIndex, int fvarChanne for (int vid=0; vid<4; ++vid) { org[vid] = facePoints[vid]; + // save for varying stencils + V[vid] = facePoints[vid]; int ringSize = level.gatherQuadRegularRingAroundVertex( @@ -595,6 +602,8 @@ GregoryBasisFactory::Create(TopologyRefiner const & refiner, basis.Copy(result->_sizes, &result->_indices[0], &result->_weights[0]); + // note: this function doesn't create varying stencils. + for (int i=0, offset=0; i<20; ++i) { result->_offsets[i] = offset; offset += result->_sizes[i]; @@ -607,15 +616,19 @@ GregoryBasisFactory::Create(TopologyRefiner const & refiner, // GregoryBasisFactory for Vertex StencilTables // GregoryBasisFactory::GregoryBasisFactory(TopologyRefiner const & refiner, - StencilTables const & stencils, - int numpatches, int maxvalence) : + StencilTables const *stencils, + StencilTables const *varyingStencils, + int numpatches, int maxvalence) : _currentStencil(0), _refiner(refiner), - _stencils(stencils), _alloc(GetNumMaxElems(maxvalence)) { + _stencils(stencils), _varyingStencils(varyingStencils), + _alloc(GetNumMaxElems(maxvalence)), + _varyingAlloc(GetNumMaxElems(maxvalence)) { // Sanity check: the mesh must be adaptively refined assert(not _refiner.IsUniform()); _alloc.Resize(numpatches * 20); + _varyingAlloc.Resize(numpatches * 20); // Gregory limit stencils have indices that are relative to the level // (maxlevel) of subdivision. These indices need to be offset to match @@ -624,9 +637,10 @@ GregoryBasisFactory::GregoryBasisFactory(TopologyRefiner const & refiner, // (single weight of 1.0f) as place-holders for coarse mesh vertices, // which also needs to be accounted for. _stencilsOffset=-1; - { int maxlevel = _refiner.GetMaxLevel(), + { + int maxlevel = _refiner.GetMaxLevel(), nverts = _refiner.GetNumVerticesTotal(), - nstencils = _stencils.GetNumStencils(); + nstencils = _stencils->GetNumStencils(); if (nstencils==nverts) { // the table contain stencils for the control vertices @@ -645,17 +659,20 @@ GregoryBasisFactory::GregoryBasisFactory(TopologyRefiner const & refiner, } } static inline void -factorizeBasisVertex(StencilTables const & stencils, Point const & p, ProtoStencil dst) { +factorizeBasisVertex(StencilTables const * stencils, Point const & p, ProtoStencil dst) { // Use the Allocator to factorize the Gregory patch influence CVs with the // supporting CVs from the stencil tables. + if (!stencils) return; + dst.Clear(); for (int j=0; j _endcapTopology; -#endif + StencilTables const * _endcapVertexStencilTables; + StencilTables const * _endcapVaryingStencilTables; QuadOffsetsTable _quadOffsetsTable; // Quad offsets (for Gregory patches) VertexValenceTable _vertexValenceTable; // Vertex valence table (for Gregory patches) @@ -494,10 +490,10 @@ PatchTables::Evaluate(PatchHandle const & handle, float s, float t, } } else if (ptype==PatchDescriptor::GREGORY_BASIS) { - assert(_endcapStencilTables); + assert(_endcapVertexStencilTables); GetBezierWeights(bits, s, t, Q, Qd1, Qd2); - InterpolateGregoryPatch(_endcapStencilTables, handle.vertIndex, + InterpolateGregoryPatch(_endcapVertexStencilTables, handle.vertIndex, s, t, Q, Qd1, Qd2, src, dst); } else if (ptype==PatchDescriptor::QUADS) { diff --git a/opensubdiv/far/patchTablesFactory.cpp b/opensubdiv/far/patchTablesFactory.cpp index 018ac15e..527e1879 100644 --- a/opensubdiv/far/patchTablesFactory.cpp +++ b/opensubdiv/far/patchTablesFactory.cpp @@ -904,7 +904,6 @@ PatchTablesFactory::computePatchParam(TopologyRefiner const & refiner, return ++coord; } -#ifdef ENDCAP_TOPOPOLGY // XXXX manuelk work in progress for end-cap topology gathering // // Populates the topology table used by Gregory-basis patches @@ -913,17 +912,21 @@ PatchTablesFactory::computePatchParam(TopologyRefiner const & refiner, // Note 2: this code attempts to identify basis vertices shared along // gregory patch edges static int -gatherGregoryBasisTopology(Vtr::Level const& level, Index faceIndex, int numVertices, - PatchFaceTag const * levelPatchTags, - bool skip[0], std::vector & basisIndices, PatchTables::PTable & topology) { +gatherGregoryBasisTopology(Vtr::Level const& level, Index faceIndex, + int numGregoryBasisPatches, + int numGregoryBasisVertices, + PatchFaceTag const * levelPatchTags, + std::vector & basisIndices, + PatchTables::PatchVertsTable & topology, + bool newVerticesMask[4][5]) { assert(not topology.empty()); - Index * dest = &topology[basisIndices.size()*20]; + Index * dest = &topology[numGregoryBasisPatches*20]; assert(Vtr::INDEX_INVALID==0xFFFFFFFF); memset(dest, 0xFF, 20*sizeof(Index)); - IndexArray fedges = level.getFaceEdges(faceIndex); + ConstIndexArray fedges = level.getFaceEdges(faceIndex); assert(fedges.size()==4); for (int i=0; i<4; ++i) { @@ -931,7 +934,7 @@ gatherGregoryBasisTopology(Vtr::Level const& level, Index faceIndex, int numVert adjface = 0; { // Gather adjacent faces - IndexArray adjfaces = level.getEdgeFaces(edge); + ConstIndexArray adjfaces = level.getEdgeFaces(edge); for (int i=0; i=0 and srcBasisIdx<(int)basisIndices.size()); // Copy the indices of CVs from the face on the other side of the @@ -973,23 +981,26 @@ gatherGregoryBasisTopology(Vtr::Level const& level, Index faceIndex, int numVert {15, 16, 2, 0} }; Index * src = &topology[srcBasisIdx*20]; for (int j=0; j<4; ++j) { - dest[i*4+j] = src[gregoryEdgeVerts[aedge][j]]; + // invert direction + dest[gregoryEdgeVerts[i][3-j]] = src[gregoryEdgeVerts[aedge][j]]; } - - skip[i] = true; - } else { - skip[i] = false; } } - for (int i=0; i<20; ++i) { - if (dest[i]==Vtr::INDEX_INVALID) { - dest[i] = numVertices++; + for (int i = 0; i < 4; ++i) { + for (int j = 0; j < 5; ++j) { + if (dest[i*5+j]==Vtr::INDEX_INVALID) { + // assign new vertex + dest[i*5+j] = numGregoryBasisVertices++; + newVerticesMask[i][j] = true; + } else { + // share vertex + newVerticesMask[i][j] = false; + } } } basisIndices.push_back(faceIndex); - return numVertices; + return numGregoryBasisVertices; } -#endif // // Indexing sharpnesses @@ -1602,27 +1613,37 @@ PatchTablesFactory::populateAdaptivePatches(AdaptiveContext & context) { bool hasGregoryPatches = context.RequiresLegacyGregoryPatches() or context.RequiresGregoryBasisPatches(); GregoryBasisFactory * gregoryStencilsFactory = 0; -#ifdef ENDCAP_TOPOPOLGY int numGregoryBasisVertices=0; + int numGregoryBasisPatches=0; std::vector gregoryBasisIndices; -#endif + std::vector endcapTopology; if (hasGregoryPatches) { - StencilTables const * adaptiveStencils = context.options.adaptiveStencilTables; - if (adaptiveStencils and context.RequiresGregoryBasisPatches()) { + StencilTables const * adaptiveVertexStencils = + context.options.adaptiveStencilTables; + StencilTables const * adaptiveVaryingStencils = + context.options.adaptiveVaryingStencilTables; + + if (adaptiveVertexStencils and + context.RequiresGregoryBasisPatches()) { assert(not context.RequiresLegacyGregoryPatches()); int maxvalence = refiner.GetMaxValence(), npatches = context.patchInventory.GP; - gregoryStencilsFactory = - new GregoryBasisFactory(refiner, *adaptiveStencils, npatches, maxvalence); -#ifdef ENDCAP_TOPOPOLGY + gregoryStencilsFactory = + new GregoryBasisFactory(refiner, + adaptiveVertexStencils, + adaptiveVaryingStencils, + npatches, maxvalence); + + // XXX reconsider these variable names: + // gregoryBasisIndices holds patch indices, + // endcapTopology contains vert indices. gregoryBasisIndices.reserve(npatches); - tables->_endcapTopology.resize(npatches*20); -#endif + endcapTopology.resize(npatches*20); } gregoryVertexFlags.resize(refiner.GetNumVerticesTotal(), false); } @@ -1739,19 +1760,24 @@ PatchTablesFactory::populateAdaptivePatches(AdaptiveContext & context) { // Gregory basis end-cap (20 CVs - no quad-offsets / valence tables) assert(i==refiner.GetMaxLevel()); // Gregory Boundary Patch (4 CVs 0-ring for varying interpolation) - Vtr::ConstIndexArray faceVerts = level->getFaceVertices(faceIndex); - for (int j = 0; j < 4; ++j) { - iptrs.GP[j] = faceVerts[j] + levelVertOffset; - gregoryVertexFlags[iptrs.GP[j]] = true; - } - iptrs.GP += 4; + bool newVerticesMask[4][5]; + numGregoryBasisVertices = gatherGregoryBasisTopology(*level, faceIndex, + numGregoryBasisPatches, + numGregoryBasisVertices, + levelPatchTags, + gregoryBasisIndices, + endcapTopology, + newVerticesMask); + gregoryStencilsFactory->AddPatchBasis(faceIndex, newVerticesMask); -#ifdef ENDCAP_TOPOPOLGY - bool edgeSkip[4]; - numGregoryBasisVertices = gatherGregoryBasisTopology(*level, faceIndex, numGregoryBasisVertices, - levelPatchTags, edgeSkip, gregoryBasisIndices, tables->_endcapTopology); -#endif - gregoryStencilsFactory->AddPatchBasis(faceIndex); + // populate 20 indices with offset + for (int j = 0; j < 20; ++j) { + iptrs.GP[j] = endcapTopology[numGregoryBasisPatches*20+j] + + refiner.GetNumVerticesTotal(); + } + iptrs.GP += 20; + + ++numGregoryBasisPatches; pptrs.GP = computePatchParam(refiner, i, faceIndex, 0, pptrs.GP); @@ -1807,8 +1833,10 @@ PatchTablesFactory::populateAdaptivePatches(AdaptiveContext & context) { } if (gregoryStencilsFactory) { - tables->_endcapStencilTables = - gregoryStencilsFactory->CreateStencilTables(); + tables->_endcapVertexStencilTables = + gregoryStencilsFactory->CreateVertexStencilTables(); + tables->_endcapVaryingStencilTables = + gregoryStencilsFactory->CreateVaryingStencilTables(); delete gregoryStencilsFactory; } diff --git a/opensubdiv/far/patchTablesFactory.h b/opensubdiv/far/patchTablesFactory.h index f67dc8f7..6205b963 100644 --- a/opensubdiv/far/patchTablesFactory.h +++ b/opensubdiv/far/patchTablesFactory.h @@ -62,7 +62,9 @@ public: useFVarQuadEndCaps(true), // XXXX change to false when FVar Gregory is ready numFVarChannels(-1), fvarChannelIndices(0), - adaptiveStencilTables(0) { } + adaptiveStencilTables(0), + adaptiveVaryingStencilTables(0) + { } unsigned int generateAllLevels : 1, ///< Include levels from 'firstLevel' to 'maxLevel' (Uniform mode only) triangulateQuads : 1, ///< Triangulate 'QUADS' primitives (Uniform mode only) @@ -79,6 +81,7 @@ public: StencilTables const * adaptiveStencilTables; ///< Passing a valid stencil table allows the factory to generate ///< stencils for gregory patches and replace them with a much ///< more efficient basis. + StencilTables const * adaptiveVaryingStencilTables; }; /// \brief Factory constructor for PatchTables diff --git a/opensubdiv/far/stencilTablesFactory.cpp b/opensubdiv/far/stencilTablesFactory.cpp index 51b7caad..299bb3b8 100644 --- a/opensubdiv/far/stencilTablesFactory.cpp +++ b/opensubdiv/far/stencilTablesFactory.cpp @@ -190,40 +190,53 @@ StencilTablesFactory::Create(TopologyRefiner const & refiner, StencilTables const * StencilTablesFactory::Create(int numTables, StencilTables const ** tables) { - StencilTables * result = new StencilTables; + // XXXtakahito: + // This function returns NULL for empty inputs or erroneous condition. + // It's convenient for skipping varying stencils etc, however, + // other Create() API returns an empty stencil instead of NULL. + // They need to be consistent. if ( (numTables<=0) or (not tables)) { - return result; + return NULL; } - int ncvs = tables[0]->GetNumControlVertices(), + int ncvs = -1, nstencils = 0, nelems = 0; for (int i=0; i= 0 and st->GetNumControlVertices() != ncvs) { + return NULL; } - nstencils += st.GetNumStencils(); - nelems += (int)st.GetControlIndices().size(); + ncvs = st->GetNumControlVertices(); + nstencils += st->GetNumStencils(); + nelems += (int)st->GetControlIndices().size(); } + if (ncvs == -1) { + return NULL; + } + + StencilTables * result = new StencilTables; result->resize(nstencils, nelems); unsigned char * sizes = &result->_sizes[0]; Index * indices = &result->_indices[0]; float * weights = &result->_weights[0]; for (int i=0; iGetNumStencils(), + st_nelems = (int)st->_indices.size(); + memcpy(sizes, &st->_sizes[0], st_nstencils*sizeof(unsigned char)); + memcpy(indices, &st->_indices[0], st_nelems*sizeof(Index)); + memcpy(weights, &st->_weights[0], st_nelems*sizeof(float)); sizes += st_nstencils; indices += st_nelems; diff --git a/opensubdiv/osd/CMakeLists.txt b/opensubdiv/osd/CMakeLists.txt index dc3bb4d3..58665879 100644 --- a/opensubdiv/osd/CMakeLists.txt +++ b/opensubdiv/osd/CMakeLists.txt @@ -200,6 +200,7 @@ if( OPENGL_FOUND OR OPENGLES_FOUND ) glslPatchCommon.glsl glslPatchBSpline.glsl glslPatchGregory.glsl + glslPatchGregoryBasis.glsl glslPatchTransition.glsl glslPtexCommon.glsl ) diff --git a/opensubdiv/osd/cpuEvalLimitController.cpp b/opensubdiv/osd/cpuEvalLimitController.cpp index ad4bb2b5..5e1e2eed 100644 --- a/opensubdiv/osd/cpuEvalLimitController.cpp +++ b/opensubdiv/osd/cpuEvalLimitController.cpp @@ -105,12 +105,8 @@ CpuEvalLimitController::EvalLimitSample( LimitLocation const & coord, outQ, outDQU, outDQV ); break; case Desc::GREGORY_BASIS : { - Far::StencilTables const * stencils = - ptables.GetEndCapStencilTables(); - assert(stencils and stencils->GetNumStencils()>0); evalGregoryBasis( pparam.bitField, s, t, - *stencils, - ptables.GetEndCapStencilIndex(*handle), + cvs.begin(), vertexData.inDesc, vertexData.in, vertexData.outDesc, @@ -206,12 +202,8 @@ CpuEvalLimitController::_EvalLimitSample( LimitLocation const & coords, out, outDu, outDv ); break; case Desc::GREGORY_BASIS : { - Far::StencilTables const * stencils = - ptables.GetEndCapStencilTables(); - assert(stencils and stencils->GetNumStencils()>0); evalGregoryBasis( pparam.bitField, s, t, - *stencils, - ptables.GetEndCapStencilIndex(*handle), + cvs.begin(), vertexData.inDesc, vertexData.in, vertexData.outDesc, @@ -236,7 +228,8 @@ CpuEvalLimitController::_EvalLimitSample( LimitLocation const & coords, static int const zeroRings[6][4] = { {5, 6,10, 9}, // regular {1, 2, 6, 5}, // boundary / single-crease {1, 2, 5, 4}, // corner - {0, 1, 2, 3} }; // no permutation + {0, 1, 2, 3}, // no permutation + {0, 5, 10, 15} }; // gregory basis int const * permute = 0; switch (desc.GetType()) { @@ -245,8 +238,8 @@ CpuEvalLimitController::_EvalLimitSample( LimitLocation const & coords, case Desc::BOUNDARY : permute = zeroRings[1]; break; case Desc::CORNER : permute = zeroRings[2]; break; case Desc::GREGORY : - case Desc::GREGORY_BOUNDARY : - case Desc::GREGORY_BASIS : permute = zeroRings[3]; break; + case Desc::GREGORY_BOUNDARY : permute = zeroRings[3]; break; + case Desc::GREGORY_BASIS : permute = zeroRings[4]; break; default: assert(0); }; diff --git a/opensubdiv/osd/cpuEvalLimitKernel.cpp b/opensubdiv/osd/cpuEvalLimitKernel.cpp index 1853fbf2..b15a5ce9 100644 --- a/opensubdiv/osd/cpuEvalLimitKernel.cpp +++ b/opensubdiv/osd/cpuEvalLimitKernel.cpp @@ -372,8 +372,7 @@ evalCorner(Far::PatchParam::BitField bits, void evalGregoryBasis(Far::PatchParam::BitField bits, float u, float v, - Far::StencilTables const & basisStencils, - int stencilIndex, + Far::Index const * vertexIndices, VertexBufferDescriptor const & inDesc, float const * inQ, VertexBufferDescriptor const & outDesc, @@ -390,10 +389,10 @@ evalGregoryBasis(Far::PatchParam::BitField bits, float u, float v, float const *inOffset = inQ + inDesc.offset; - float * Q = outQ + outDesc.offset; + outQ += outDesc.offset; // clear result - memset(Q, 0, length*sizeof(float)); + memset(outQ, 0, length*sizeof(float)); if (outDQU) { memset(outDQU, 0, length*sizeof(float)); } @@ -404,22 +403,17 @@ evalGregoryBasis(Far::PatchParam::BitField bits, float u, float v, float uu = 1-u, vv = 1-v; // remark #1572: floating-point equality and inequality comparisons are unreliable -#ifdef __INvEL_COMPILER -#pragma warning diuable 1572 +#ifdef __INTEL_COMPILER +#pragma warning disable 1572 #endif float d11 = u+v; if(u+v==0.0f) d11 = 1.0f; float d12 = uu+v; if(uu+v==0.0f) d12 = 1.0f; float d21 = u+vv; if(u+vv==0.0f) d21 = 1.0f; float d22 = uu+vv; if(uu+vv==0.0f) d22 = 1.0f; -#ifdef __INvEL_COMPILER +#ifdef __INTEL_COMPILER #pragma warning enable 1572 #endif - float weights[4][2] = { { u/d11, v/d11 }, - { uu/d12, v/d12 }, - { u/d21, vv/d21 }, - { uu/d22, vv/d22 } }; - // // P3 e3- e2+ P2 // O--------O--------O--------O @@ -441,89 +435,44 @@ evalGregoryBasis(Far::PatchParam::BitField bits, float u, float v, // P0 e0+ e1- P1 // + float const *v3 = inOffset + vertexIndices[3]*inDesc.stride, + *v4 = inOffset + vertexIndices[4]*inDesc.stride, + *v8 = inOffset + vertexIndices[8]*inDesc.stride, + *v9 = inOffset + vertexIndices[9]*inDesc.stride, + *v13 = inOffset + vertexIndices[13]*inDesc.stride, + *v14 = inOffset + vertexIndices[14]*inDesc.stride, + *v18 = inOffset + vertexIndices[18]*inDesc.stride, + *v19 = inOffset + vertexIndices[19]*inDesc.stride; + + float *CP = (float*)alloca(inDesc.length*4*sizeof(float)); + + for (int k=0; ktessEvalShader.AddDefine("OSD_PATCH_TESS_EVAL_GREGORY_SHADER"); sconfig->tessEvalShader.AddDefine("OSD_PATCH_GREGORY_BOUNDARY"); break; + case Far::PatchDescriptor::GREGORY_BASIS: + sconfig->vertexShader.source = gregoryBasisShaderSource; + sconfig->vertexShader.version = "#version 410\n"; + sconfig->vertexShader.AddDefine("OSD_PATCH_VERTEX_GREGORY_BASIS_SHADER"); + sconfig->tessControlShader.source = gregoryBasisShaderSource; + sconfig->tessControlShader.version = "#version 410\n"; + sconfig->tessControlShader.AddDefine("OSD_PATCH_TESS_CONTROL_GREGORY_BASIS_SHADER"); + sconfig->tessEvalShader.source = gregoryBasisShaderSource; + sconfig->tessEvalShader.version = "#version 410\n"; + sconfig->tessEvalShader.AddDefine("OSD_PATCH_TESS_EVAL_GREGORY_BASIS_SHADER"); + break; default: // POINTS, LINES, QUADS, TRIANGLES // do nothing break; diff --git a/opensubdiv/osd/glMesh.h b/opensubdiv/osd/glMesh.h index ac54df70..2f3f3934 100644 --- a/opensubdiv/osd/glMesh.h +++ b/opensubdiv/osd/glMesh.h @@ -68,14 +68,31 @@ public: _drawContext(0) { - GLMeshInterface::refineMesh(*_refiner, level, bits.test(MeshAdaptive), bits.test(MeshUseSingleCreasePatch)); + GLMeshInterface::refineMesh(*_refiner, level, + bits.test(MeshAdaptive), + bits.test(MeshUseSingleCreasePatch)); - int numElements = - initializeVertexBuffers(numVertexElements, numVaryingElements, bits); + int numVertexElementsInterleaved = numVertexElements + + (bits.test(MeshInterleaveVarying) ? numVaryingElements : 0); + int numVaryingElementsNonInterleaved = + (bits.test(MeshInterleaveVarying) ? 0 : numVaryingElements); - initializeComputeContext(numVertexElements, numVaryingElements); + initializeContext(numVertexElements, numVaryingElements, + numVertexElementsInterleaved, level, bits); - initializeDrawContext(numElements, level, bits); + int numVertices = GLMeshInterface::getNumVertices(*_refiner); + + // FIXME: need a better API for numTotalVertices. + if (_patchTables->GetEndCapVertexStencilTables()) { + numVertices += _patchTables->GetEndCapVertexStencilTables()->GetNumStencils(); + } + + initializeVertexBuffers(numVertices, + numVertexElementsInterleaved, + numVaryingElementsNonInterleaved); + + // will retire soon + _drawContext->UpdateVertexTexture(_vertexBuffer); } Mesh(ComputeController * computeController, @@ -170,8 +187,9 @@ public: private: - void initializeComputeContext(int numVertexElements, - int numVaryingElements ) { + void initializeContext(int numVertexElements, + int numVaryingElements, + int numElements, int level, MeshBitset bits) { assert(_refiner); @@ -185,7 +203,6 @@ private: vertexStencils = Far::StencilTablesFactory::Create(*_refiner, options); - _kernelBatches.push_back(Far::StencilTablesFactory::Create(*vertexStencils)); } if (numVaryingElements>0) { @@ -195,44 +212,69 @@ private: varyingStencils = Far::StencilTablesFactory::Create(*_refiner, options); } - _computeContext = ComputeContext::Create(vertexStencils, varyingStencils); + assert(_refiner); + Far::PatchTablesFactory::Options poptions(level); + poptions.generateFVarTables = bits.test(MeshFVarData); + poptions.useSingleCreasePatch = bits.test(MeshUseSingleCreasePatch); + + if (bits.test(MeshUseGregoryBasis)) { + poptions.adaptiveStencilTables = vertexStencils; + poptions.adaptiveVaryingStencilTables = varyingStencils; + } + + _patchTables = Far::PatchTablesFactory::Create(*_refiner, poptions); + + _drawContext = DrawContext::Create(_patchTables, numElements); + + // XXX: factory API fix needed + // merge greogry basis stencils + Far::StencilTables const * endCapVertexStencils = + _patchTables->GetEndCapVertexStencilTables(); + + if (endCapVertexStencils) { + Far::StencilTables const * endCapVaryingStencils = + _patchTables->GetEndCapVaryingStencilTables(); + + // concatinate vertexStencils and endCapStencils. + // note that endCapStensils is owned by patchTable. + Far::StencilTables const *inStencils[] = { + vertexStencils, endCapVertexStencils + }; + Far::StencilTables const *concatStencils = + Far::StencilTablesFactory::Create(2, inStencils); + + Far::StencilTables const *inVaryingStencils[] = { + varyingStencils, endCapVaryingStencils + }; + Far::StencilTables const *concatVaryingStencils = + Far::StencilTablesFactory::Create(2, inVaryingStencils); + + delete vertexStencils; + vertexStencils = concatStencils; + delete varyingStencils; + varyingStencils = concatVaryingStencils; + } + + _kernelBatches.push_back(Far::StencilTablesFactory::Create(*vertexStencils)); + + _computeContext = ComputeContext::Create(vertexStencils, + varyingStencils); delete vertexStencils; delete varyingStencils; } - void initializeDrawContext(int numElements, int level, MeshBitset bits) { - - assert(_refiner and _vertexBuffer); - - Far::PatchTablesFactory::Options options(level); - options.generateFVarTables = bits.test(MeshFVarData); - options.useSingleCreasePatch = bits.test(MeshUseSingleCreasePatch); - - _patchTables = Far::PatchTablesFactory::Create(*_refiner, options); - - _drawContext = DrawContext::Create(_patchTables, numElements); - - _drawContext->UpdateVertexTexture(_vertexBuffer); - } - - int initializeVertexBuffers(int numVertexElements, - int numVaryingElements, MeshBitset bits) { - - int numVertices = GLMeshInterface::getNumVertices(*_refiner); - - int numElements = numVertexElements + - (bits.test(MeshInterleaveVarying) ? numVaryingElements : 0); + void initializeVertexBuffers(int numVertices, + int numVertexElements, + int numVaryingElements) { if (numVertexElements) { - - _vertexBuffer = VertexBuffer::Create(numElements, numVertices); + _vertexBuffer = VertexBuffer::Create(numVertexElements, numVertices); } - if (numVaryingElements>0 and (not bits.test(MeshInterleaveVarying))) { + if (numVaryingElements) { _varyingBuffer = VertexBuffer::Create(numVaryingElements, numVertices); } - return numElements; } Far::TopologyRefiner * _refiner; @@ -280,14 +322,32 @@ public: { assert(_refiner); - GLMeshInterface::refineMesh(*_refiner, level, bits.test(MeshAdaptive), bits.test(MeshUseSingleCreasePatch)); + GLMeshInterface::refineMesh(*_refiner, level, + bits.test(MeshAdaptive), + bits.test(MeshUseSingleCreasePatch)); - int numElements = - initializeVertexBuffers(numVertexElements, numVaryingElements, bits); - initializeComputeContext(numVertexElements, numVaryingElements); + int numVertexElementsInterleaved = numVertexElements + + (bits.test(MeshInterleaveVarying) ? numVaryingElements : 0); + int numVaryingElementsNonInterleaved = + (bits.test(MeshInterleaveVarying) ? 0 : numVaryingElements); - initializeDrawContext(numElements, level, bits); + initializeContext(numVertexElements, numVaryingElements, + numVertexElementsInterleaved, level, bits); + + int numVertices = GLMeshInterface::getNumVertices(*_refiner); + + // FIXME: need better API for total number of vertices. + if (_patchTables->GetEndCapVertexStencilTables()) { + numVertices += _patchTables->GetEndCapVertexStencilTables()->GetNumStencils(); + } + + initializeVertexBuffers(numVertices, + numVertexElementsInterleaved, + numVaryingElementsNonInterleaved); + + // will retire + _drawContext->UpdateVertexTexture(_vertexBuffer); } Mesh(ComputeController * computeController, @@ -382,9 +442,9 @@ public: private: - void initializeComputeContext(int numVertexElements, - int numVaryingElements ) { - + void initializeContext(int numVertexElements, + int numVaryingElements, + int numElements, int level, MeshBitset bits) { assert(_refiner); Far::StencilTablesFactory::Options options; @@ -396,8 +456,6 @@ private: if (numVertexElements>0) { vertexStencils = Far::StencilTablesFactory::Create(*_refiner, options); - - _kernelBatches.push_back(Far::StencilTablesFactory::Create(*vertexStencils)); } if (numVaryingElements>0) { @@ -409,41 +467,73 @@ private: _computeContext = ComputeContext::Create(_clContext, vertexStencils, varyingStencils); + assert(_refiner); + + Far::PatchTablesFactory::Options poptions(level); + poptions.generateFVarTables = bits.test(MeshFVarData); + poptions.useSingleCreasePatch = bits.test(MeshUseSingleCreasePatch); + + // use gregory stencils + if (bits.test(MeshUseGregoryBasis)) { + poptions.adaptiveStencilTables = vertexStencils; + poptions.adaptiveVaryingStencilTables = varyingStencils; + } + + _patchTables = Far::PatchTablesFactory::Create(*_refiner, poptions); + + _drawContext = DrawContext::Create(_patchTables, numElements); + + Far::StencilTables const *endCapVertexStencils = + _patchTables->GetEndCapVertexStencilTables(); + + if (endCapVertexStencils) { + Far::StencilTables const *endCapVaryingStencils = + _patchTables->GetEndCapVaryingStencilTables(); + + // concatinate vertexStencils and endCapStencils. + // note that endCapStensils is owned by patchTable. + Far::StencilTables const *inStencils[] = { + vertexStencils, endCapVertexStencils + }; + + Far::StencilTables const *concatStencils = + Far::StencilTablesFactory::Create(2, inStencils); + + _kernelBatches.push_back(Far::StencilTablesFactory::Create(*concatStencils)); + + Far::StencilTables const *inVaryingStencils[] = { + varyingStencils, endCapVaryingStencils + }; + + Far::StencilTables const *concatVaryingStencils = + Far::StencilTablesFactory::Create(2, inVaryingStencils); + + delete vertexStencils; + vertexStencils = concatStencils; + delete varyingStencils; + varyingStencils = concatVaryingStencils; + } + _kernelBatches.push_back(Far::StencilTablesFactory::Create(*vertexStencils)); + + _computeContext = ComputeContext::Create(_clContext, + vertexStencils, + varyingStencils); + delete vertexStencils; delete varyingStencils; } - void initializeDrawContext(int numElements, int level, MeshBitset bits) { - - assert(_refiner and _vertexBuffer); - - Far::PatchTablesFactory::Options options(level); - options.generateFVarTables = bits.test(MeshFVarData); - - _patchTables = Far::PatchTablesFactory::Create(*_refiner); - - _drawContext = DrawContext::Create(_patchTables, numElements); - - _drawContext->UpdateVertexTexture(_vertexBuffer); - } - - int initializeVertexBuffers(int numVertexElements, - int numVaryingElements, MeshBitset bits) { - - int numVertices = GLMeshInterface::getNumVertices(*_refiner); - - int numElements = numVertexElements + - (bits.test(MeshInterleaveVarying) ? numVaryingElements : 0); + void initializeVertexBuffers(int numVertices, + int numVertexElements, + int numVaryingElements) { if (numVertexElements) { - - _vertexBuffer = VertexBuffer::Create(numElements, numVertices, _clContext); + _vertexBuffer = VertexBuffer::Create(numVertexElements, numVertices, _clContext); } - if (numVaryingElements>0 and (not bits.test(MeshInterleaveVarying))) { + if (numVaryingElements) { _varyingBuffer = VertexBuffer::Create(numVaryingElements, numVertices, _clContext); } - return numElements; } Far::TopologyRefiner * _refiner; diff --git a/opensubdiv/osd/glslPatchCommon.glsl b/opensubdiv/osd/glslPatchCommon.glsl index 79a25ffe..7c38ea35 100644 --- a/opensubdiv/osd/glslPatchCommon.glsl +++ b/opensubdiv/osd/glslPatchCommon.glsl @@ -93,7 +93,9 @@ struct ControlVertex { vec4 position; centroid vec4 patchCoord; // u, v, level, faceID ivec4 ptexInfo; // U offset, V offset, 2^ptexlevel', rotation +#ifdef OSD_ENABLE_PATCH_CULL ivec3 clipFlag; +#endif }; struct OutputVertex { diff --git a/opensubdiv/osd/glslPatchGregoryBasis.glsl b/opensubdiv/osd/glslPatchGregoryBasis.glsl new file mode 100644 index 00000000..7ac3a6b9 --- /dev/null +++ b/opensubdiv/osd/glslPatchGregoryBasis.glsl @@ -0,0 +1,294 @@ +// +// Copyright 2015 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. +// + +//---------------------------------------------------------- +// Patches.VertexGregoryBasis +//---------------------------------------------------------- +#ifdef OSD_PATCH_VERTEX_GREGORY_BASIS_SHADER + +layout(location = 0) in vec4 position; +OSD_USER_VARYING_ATTRIBUTE_DECLARE + +out block { + ControlVertex v; + OSD_USER_VARYING_DECLARE +} outpt; + +void main() +{ + outpt.v.position = OsdModelViewMatrix() * position; + outpt.v.patchCoord = vec4(0); + outpt.v.ptexInfo = ivec4(0); + OSD_PATCH_CULL_COMPUTE_CLIPFLAGS(position); + OSD_USER_VARYING_PER_VERTEX(); +} + +#endif + +//---------------------------------------------------------- +// Patches.TessControlGregoryBasis +//---------------------------------------------------------- +#ifdef OSD_PATCH_TESS_CONTROL_GREGORY_BASIS_SHADER + +layout(vertices = 20) out; + +in block { + ControlVertex v; + OSD_USER_VARYING_DECLARE +} inpt[]; + +out block { + ControlVertex v; + OSD_USER_VARYING_DECLARE +} outpt[]; + +#define ID gl_InvocationID + +void main() +{ + outpt[ID].v = inpt[ID].v; + OSD_USER_VARYING_PER_CONTROL_POINT(ID, ID); + + int patchLevel = GetPatchLevel(); + + // +0.5 to avoid interpolation error of integer value + outpt[ID].v.patchCoord = vec4(0, 0, + patchLevel+0.5, + GetPrimitiveID()+0.5); + OSD_COMPUTE_PTEX_COORD_TESSCONTROL_SHADER; + + if (ID == 0) { + OSD_PATCH_CULL(OSD_PATCH_INPUT_SIZE); + + // XXX: this metric is not consistent. + // we will 1) compute the cage length as before + // or 2) compute limit length for all patches. + #ifdef OSD_ENABLE_SCREENSPACE_TESSELLATION + gl_TessLevelOuter[0] = + TessAdaptive(inpt[0].v.position.xyz, inpt[5].v.position.xyz); + gl_TessLevelOuter[1] = + TessAdaptive(inpt[0].v.position.xyz, inpt[15].v.position.xyz); + gl_TessLevelOuter[2] = + TessAdaptive(inpt[10].v.position.xyz, inpt[15].v.position.xyz); + gl_TessLevelOuter[3] = + TessAdaptive(inpt[5].v.position.xyz, inpt[10].v.position.xyz); + + gl_TessLevelInner[0] = + max(gl_TessLevelOuter[1], gl_TessLevelOuter[3]); + gl_TessLevelInner[1] = + max(gl_TessLevelOuter[0], gl_TessLevelOuter[2]); + #else + gl_TessLevelInner[0] = GetTessLevel(patchLevel); + gl_TessLevelInner[1] = GetTessLevel(patchLevel); + gl_TessLevelOuter[0] = GetTessLevel(patchLevel); + gl_TessLevelOuter[1] = GetTessLevel(patchLevel); + gl_TessLevelOuter[2] = GetTessLevel(patchLevel); + gl_TessLevelOuter[3] = GetTessLevel(patchLevel); + #endif + } +} + +#endif + +//---------------------------------------------------------- +// Patches.TessEvalGregory +//---------------------------------------------------------- +#ifdef OSD_PATCH_TESS_EVAL_GREGORY_BASIS_SHADER + +layout(quads) in; +layout(cw) in; + +#if defined OSD_FRACTIONAL_ODD_SPACING + layout(fractional_odd_spacing) in; +#elif defined OSD_FRACTIONAL_EVEN_SPACING + layout(fractional_even_spacing) in; +#endif + +in block { + ControlVertex v; + OSD_USER_VARYING_DECLARE +} inpt[]; + +out block { + OutputVertex v; + OSD_USER_VARYING_DECLARE +} outpt; + +void main() +{ + float u = gl_TessCoord.x, + v = gl_TessCoord.y; + + vec3 p[20]; + + for (int i = 0; i < 20; ++i) { + p[i] = inpt[i].v.position.xyz; + } + vec3 q[16]; + + float U = 1-u, V=1-v; + + float d11 = u+v; if(u+v==0.0f) d11 = 1.0f; + float d12 = U+v; if(U+v==0.0f) d12 = 1.0f; + float d21 = u+V; if(u+V==0.0f) d21 = 1.0f; + float d22 = U+V; if(U+V==0.0f) d22 = 1.0f; + +#if 1 + q[ 5] = (u*p[3] + v*p[4])/d11; + q[ 6] = (U*p[9] + v*p[8])/d12; + q[ 9] = (u*p[19] + V*p[18])/d21; + q[10] = (U*p[13] + V*p[14])/d22; +#else + q[ 5] = (p[3] + p[4])/2.0; + q[ 6] = (p[9] + p[8])/2.0; + q[ 9] = (p[19] + p[18])/2.0; + q[10] = (p[13] + p[14])/2.0; +#endif + + q[ 0] = p[0]; + q[ 1] = p[1]; + q[ 2] = p[7]; + q[ 3] = p[5]; + q[ 4] = p[2]; + q[ 7] = p[6]; + q[ 8] = p[16]; + q[11] = p[12]; + q[12] = p[15]; + q[13] = p[17]; + q[14] = p[11]; + q[15] = p[10]; + + vec3 WorldPos = vec3(0, 0, 0); + vec3 Tangent = vec3(0, 0, 0); + vec3 BiTangent = vec3(0, 0, 0); + +#ifdef OSD_COMPUTE_NORMAL_DERIVATIVES + float B[4], D[4], C[4]; + vec3 BUCP[4] = vec3[4](vec3(0,0,0), vec3(0,0,0), vec3(0,0,0), vec3(0,0,0)), + DUCP[4] = vec3[4](vec3(0,0,0), vec3(0,0,0), vec3(0,0,0), vec3(0,0,0)), + CUCP[4] = vec3[4](vec3(0,0,0), vec3(0,0,0), vec3(0,0,0), vec3(0,0,0)); + vec3 dUU = vec3(0); + vec3 dVV = vec3(0); + vec3 dUV = vec3(0); + + Univar4x4(u, B, D, C); + + for (int i=0; i<4; ++i) { + for (uint j=0; j<4; ++j) { + // reverse face front + vec3 A = q[i + 4*j]; + + BUCP[i] += A * B[j]; + DUCP[i] += A * D[j]; + CUCP[i] += A * C[j]; + } + } + + Univar4x4(v, B, D, C); + + for (int i=0; i<4; ++i) { + WorldPos += B[i] * BUCP[i]; + Tangent += B[i] * DUCP[i]; + BiTangent += D[i] * BUCP[i]; + dUU += B[i] * CUCP[i]; + dVV += C[i] * BUCP[i]; + dUV += D[i] * DUCP[i]; + } + + int level = int(inpt[0].v.ptexInfo.z); + BiTangent *= 3 * level; + Tangent *= 3 * level; + dUU *= 6 * level; + dVV *= 6 * level; + dUV *= 9 * level; + + vec3 n = cross(BiTangent, Tangent); + vec3 normal = normalize(n); + + float E = dot(Tangent, Tangent); + float F = dot(Tangent, BiTangent); + float G = dot(BiTangent, BiTangent); + float e = dot(normal, dUU); + float f = dot(normal, dUV); + float g = dot(normal, dVV); + + vec3 Nu = (f*F-e*G)/(E*G-F*F) * Tangent + (e*F-f*E)/(E*G-F*F) * BiTangent; + vec3 Nv = (g*F-f*G)/(E*G-F*F) * Tangent + (f*F-g*E)/(E*G-F*F) * BiTangent; + + Nu = Nu/length(n) - n * (dot(Nu,n)/pow(dot(n,n), 1.5)); + Nv = Nv/length(n) - n * (dot(Nv,n)/pow(dot(n,n), 1.5)); + + outpt.v.Nu = Nu; + outpt.v.Nv = Nv; + +#else + float B[4], D[4]; + vec3 BUCP[4] = vec3[4](vec3(0,0,0), vec3(0,0,0), vec3(0,0,0), vec3(0,0,0)), + DUCP[4] = vec3[4](vec3(0,0,0), vec3(0,0,0), vec3(0,0,0), vec3(0,0,0)); + + Univar4x4(u, B, D); + + for (int i=0; i<4; ++i) { + for (uint j=0; j<4; ++j) { + // reverse face front + vec3 A = q[i + 4*j]; + + BUCP[i] += A * B[j]; + DUCP[i] += A * D[j]; + } + } + + Univar4x4(v, B, D); + + for (int i=0; i<4; ++i) { + WorldPos += B[i] * BUCP[i]; + Tangent += B[i] * DUCP[i]; + BiTangent += D[i] * BUCP[i]; + } + int level = int(inpt[0].v.ptexInfo.z); + BiTangent *= 3 * level; + Tangent *= 3 * level; + + vec3 normal = normalize(cross(BiTangent, Tangent)); + +#endif + outpt.v.position = vec4(WorldPos, 1.0f); + outpt.v.normal = normal; + outpt.v.tangent = BiTangent; + outpt.v.bitangent = Tangent; + + //OSD_USER_VARYING_PER_EVAL_POINT(vec2(u,v), 0, 3, 1, 2); + OSD_USER_VARYING_PER_EVAL_POINT(vec2(u,v), 0, 15, 5, 10); + + outpt.v.patchCoord = inpt[0].v.patchCoord; + outpt.v.patchCoord.xy = vec2(v, u); + + OSD_COMPUTE_PTEX_COORD_TESSEVAL_SHADER; + + OSD_DISPLACEMENT_CALLBACK; + + gl_Position = OsdProjectionMatrix() * outpt.v.position; +} + +#endif diff --git a/opensubdiv/osd/mesh.h b/opensubdiv/osd/mesh.h index a3baba14..7ae49026 100644 --- a/opensubdiv/osd/mesh.h +++ b/opensubdiv/osd/mesh.h @@ -51,7 +51,8 @@ enum MeshBits { MeshPtexData = 2, MeshFVarData = 3, MeshUseSingleCreasePatch = 4, - NUM_MESH_BITS = 5, + MeshUseGregoryBasis = 5, + NUM_MESH_BITS = 6, }; typedef std::bitset MeshBitset; diff --git a/regression/shapes/catmark_gregory_test0.h b/regression/shapes/catmark_gregory_test0.h new file mode 100644 index 00000000..6a916ce8 --- /dev/null +++ b/regression/shapes/catmark_gregory_test0.h @@ -0,0 +1,21 @@ +static const std::string catmark_gregory_test0 = std::string( +"# This file uses centimeters as units for non-parametric coordinates.\n" +"v -0.500000 0.204097 -0.500000\n" +"v 0.000000 0.117710 -0.500000\n" +"v -0.500000 0.142210 -0.000000\n" +"v 0.000000 0.000000 0.000000\n" +"v -0.500000 0.204097 0.500000\n" +"v 0.000000 0.117710 0.500000\n" +"v 0.500000 0.348563 -0.003642\n" +"vt -0.500000 -0.500000\n" +"vt 0.000000 -0.500000\n" +"vt -0.500000 -0.000000\n" +"vt 0.000000 0.000000\n" +"vt -0.500000 0.500000\n" +"vt 0.000000 0.500000\n" +"vt 0.500000 -0.003642\n" +"s 1\n" +"f 1/1/1 2/2/2 4/4/4 3/3/3\n" +"f 3/3/3 4/4/4 6/6/6 5/5/5\n" +"f 2/2/2 7/7/7 6/6/6 4/4/4\n" +);