diff --git a/regression/common/far_utils.h b/regression/common/far_utils.h index 3e843fd0..9fc2680c 100644 --- a/regression/common/far_utils.h +++ b/regression/common/far_utils.h @@ -137,19 +137,16 @@ InterpolateFVarData(OpenSubdiv::Far::TopologyRefiner & refiner, template OpenSubdiv::Far::TopologyRefiner * -InterpolateFarVertexData(const char *shapeStr, Scheme scheme, int maxlevel, - std::vector &data) { +InterpolateFarVertexData(Shape const & shape, int maxlevel, std::vector &data) { typedef OpenSubdiv::Far::TopologyRefiner FarTopologyRefiner; typedef OpenSubdiv::Far::TopologyRefinerFactory FarTopologyRefinerFactory; // Far interpolation - Shape * shape = Shape::parseObj(shapeStr, scheme); - FarTopologyRefiner * refiner = - FarTopologyRefinerFactory::Create(*shape, + FarTopologyRefinerFactory::Create(shape, FarTopologyRefinerFactory::Options( - GetSdcType(*shape), GetSdcOptions(*shape))); + GetSdcType(shape), GetSdcOptions(shape))); assert(refiner); FarTopologyRefiner::UniformOptions options(maxlevel); @@ -159,9 +156,9 @@ InterpolateFarVertexData(const char *shapeStr, Scheme scheme, int maxlevel, // populate coarse mesh positions data.resize(refiner->GetNumVerticesTotal()); for (int i=0; iGetLevel(0).GetNumVertices(); i++) { - data[i].SetPosition(shape->verts[i*3+0], - shape->verts[i*3+1], - shape->verts[i*3+2]); + data[i].SetPosition(shape.verts[i*3+0], + shape.verts[i*3+1], + shape.verts[i*3+2]); } T * srcVerts = &data[0]; @@ -173,6 +170,18 @@ InterpolateFarVertexData(const char *shapeStr, Scheme scheme, int maxlevel, srcVerts = dstVerts; dstVerts += refiner->GetLevel(i).GetNumVertices(); } + return refiner; +} + +template +OpenSubdiv::Far::TopologyRefiner * +InterpolateFarVertexData(const char *shapeStr, Scheme scheme, int maxlevel, + std::vector &data) { + + Shape const * shape = Shape::parseObj(shapeStr, scheme); + + OpenSubdiv::Far::TopologyRefiner * refiner = + InterpolateFarVertexData(*shape, maxlevel, data); delete shape; return refiner; diff --git a/regression/common/hbr_utils.h b/regression/common/hbr_utils.h index c56a0f5a..e75fb038 100644 --- a/regression/common/hbr_utils.h +++ b/regression/common/hbr_utils.h @@ -578,61 +578,74 @@ createFaceVaryingUV( Shape const * sh, OpenSubdiv::HbrMesh * mesh) { //------------------------------------------------------------------------------ template OpenSubdiv::HbrMesh * -simpleHbr(char const * Shapestr, Scheme scheme, std::vector * verts=0, bool fvar=false) { - - Shape * sh = Shape::parseObj( Shapestr, scheme ); +simpleHbr(Shape const * sh, std::vector * verts=0, bool fvar=false) { int fvarwidth = fvar and sh->HasUV() ? 2 : 0; - OpenSubdiv::HbrMesh * mesh = createMesh(scheme, fvarwidth); + OpenSubdiv::HbrMesh * mesh = createMesh(sh->scheme, fvarwidth); createVerticesWithPositions(sh, mesh); - createTopology(sh, mesh, scheme); + createTopology(sh, mesh, sh->scheme); if (fvar) createFaceVaryingUV(sh, mesh); if (verts) - copyVertexPositions(sh,mesh,*verts); + copyVertexPositions(sh, mesh, *verts); + + return mesh; +} + +template OpenSubdiv::HbrMesh * +simpleHbr(char const * Shapestr, Scheme scheme, std::vector * verts=0, bool fvar=false) { + + Shape const * sh = Shape::parseObj( Shapestr, scheme ); + + OpenSubdiv::HbrMesh * mesh = simpleHbr(sh, verts, fvar); delete sh; - return mesh; } //------------------------------------------------------------------------------ template OpenSubdiv::HbrMesh * -simpleHbr(char const * Shapestr, Scheme scheme, std::vector & verts, bool fvar=false) { - - Shape * sh = Shape::parseObj( Shapestr, scheme ); +simpleHbr(Shape const * sh, std::vector & verts, bool fvar=false) { int fvarwidth = fvar and sh->HasUV() ? 2 : 0; - OpenSubdiv::HbrMesh * mesh = createMesh(scheme, fvarwidth); + OpenSubdiv::HbrMesh * mesh = createMesh(sh->scheme, fvarwidth); createVertices(sh, mesh); - createTopology(sh, mesh, scheme); + createTopology(sh, mesh, sh->scheme); if (fvar) createFaceVaryingUV(sh, mesh); - copyVertexPositions(sh,mesh,verts); + copyVertexPositions(sh, mesh, verts); + + return mesh; +} + +template OpenSubdiv::HbrMesh * +simpleHbr(char const * Shapestr, Scheme scheme, std::vector & verts, bool fvar=false) { + + Shape const * sh = Shape::parseObj( Shapestr, scheme ); + + OpenSubdiv::HbrMesh *mesh = simpleHbr(sh, verts, fvar); delete sh; - return mesh; } //------------------------------------------------------------------------------ template OpenSubdiv::HbrMesh * -interpolateHbrVertexData(char const * Shapestr, Scheme scheme, int maxlevel) { +interpolateHbrVertexData(Shape const * sh, int maxlevel) { // Hbr interpolation - OpenSubdiv::HbrMesh *hmesh = simpleHbr(Shapestr, scheme, - /* verts vector */ 0, /* fvar */ false); + OpenSubdiv::HbrMesh *hmesh = simpleHbr(sh, /* verts vector */ 0, /* fvar */ false); assert(hmesh); for (int level=0, firstface=0; level +OpenSubdiv::HbrMesh * +interpolateHbrVertexData(char const * Shapestr, Scheme scheme, int maxlevel) { + + Shape const * sh = Shape::parseObj( Shapestr, scheme ); + + OpenSubdiv::HbrMesh *mesh = interpolateHbrVertexData(sh, maxlevel); + + delete sh; + return mesh; } //------------------------------------------------------------------------------ diff --git a/regression/far_regression/far_regression.cpp b/regression/far_regression/far_regression.cpp index f483e984..9d0b7439 100644 --- a/regression/far_regression/far_regression.cpp +++ b/regression/far_regression/far_regression.cpp @@ -115,6 +115,8 @@ private: typedef OpenSubdiv::HbrMesh Hmesh; //------------------------------------------------------------------------------ +typedef OpenSubdiv::Sdc::Options SdcOptions; +typedef OpenSubdiv::Far::TopologyLevel FarTopologyLevel; typedef OpenSubdiv::Far::TopologyRefiner FarTopologyRefiner; typedef OpenSubdiv::Far::TopologyRefinerFactory FarTopologyRefinerFactory; @@ -138,34 +140,18 @@ printVertexData(std::vector const & hbrBuffer, std::vector const & //------------------------------------------------------------------------------ static int -checkMesh(ShapeDesc const & desc, int maxlevel) { - - static char const * schemes[] = { "Bilinear", "Catmark", "Loop" }; - printf("- %-25s ( %-8s ): \n", desc.name.c_str(), schemes[desc.scheme]); +compareVertexData(std::vector const& farVertexData, std::vector const& hbrVertexData) { int count=0; float deltaAvg[3] = {0.0f, 0.0f, 0.0f}, deltaCnt[3] = {0.0f, 0.0f, 0.0f}; - std::vector hbrVertexData, - farVertexData; - - Hmesh * hmesh = interpolateHbrVertexData( - desc.data.c_str(), desc.scheme, maxlevel); - - FarTopologyRefiner * refiner = - InterpolateFarVertexData( - desc.data.c_str(), desc.scheme, maxlevel, farVertexData); - - // copy Hbr vertex data into a re-ordered buffer (for easier comparison) - GetReorderedHbrVertexData(*refiner, *hmesh, &hbrVertexData); - int nverts = (int)farVertexData.size(); for (int i=0; i const& farVertexData) { + + std::vector hbrVertexData; + + Hmesh * hmesh = interpolateHbrVertexData(&shape, refiner.GetMaxLevel()); + + // copy Hbr vertex data into a re-ordered buffer (for easier comparison) + GetReorderedHbrVertexData(refiner, *hmesh, &hbrVertexData); + + // compare and report differences in vertex positions + return compareVertexData(farVertexData, hbrVertexData); +} + +static bool +isBaseMeshNonManifold(FarTopologyRefiner const & refiner) { + + // Some simpler inspection methods of the RefinerLevel would help here... + // - vertices and edges are internally tagged as manifold or not + + FarTopologyLevel const & level = refiner.GetLevel(0); + + int nVerts = level.GetNumVertices(); + for (int i = 0; i < nVerts; ++i) { + int nVertFaces = level.GetVertexFaces(i).size(); + int nVertEdges = level.GetVertexEdges(i).size(); + int nEdgesMinusFaces = nVertEdges - nVertFaces; + if ((nEdgesMinusFaces > 1) || (nEdgesMinusFaces < 0)) { + return true; + } + } + + int nEdges = level.GetNumEdges(); + for (int i = 0; i < nEdges; ++i) { + int nEdgeFaces = level.GetEdgeFaces(i).size(); + if ((nEdgeFaces < 1) || (nEdgeFaces > 2)) { + return true; + } + if (level.GetEdgeVertices(i)[0] == level.GetEdgeVertices(i)[1]) { + return true; + } + } + return false; +} + +static bool +shapeHasHierarchicalEditTags(Shape const & shape) { + + for (int i = 0; i < (int)shape.tags.size(); ++i) { + Shape::tag const & tag = *shape.tags[i]; + + if ((tag.name == "vertexedit") || (tag.name == "edgeedit") || (tag.name == "faceedit")) { + return true; + } + } + return false; +} + +static bool +areVerticesCompatibleWithHbr(Shape const & shape, FarTopologyRefiner const & refiner, + std::string * incompatibleString = 0) +{ + // + // Known incompatibilities with Hbr: + // - non-manifold features -- Hbr does not support them + // - very high-valence vertex -- accumulation of Hbr inaccuracies becomes considerable + // - Chaikin creasing -- Hbr known to be incorrect + // - hierarchical edits -- not supported by FarTopologyRefiner + // - Shape will include tags "vertexedit", "edgeedit" and "faceedit" + // + if (isBaseMeshNonManifold(refiner)) { + if (incompatibleString) { + *incompatibleString = std::string("mesh is non-manifold"); + } + return false; + } + if (refiner.GetMaxValence() > 64) { + if (incompatibleString) { + *incompatibleString = std::string("vertices of excessively high valence present"); + } + return false; + } + if (refiner.GetSchemeOptions().GetCreasingMethod() == SdcOptions::CREASE_CHAIKIN) { + if (incompatibleString) { + *incompatibleString = std::string("assigned crease method is Chaikin"); + } + return false; + } + if (shapeHasHierarchicalEditTags(shape)) { + if (incompatibleString) { + *incompatibleString = std::string("hierarchical edits no longer supported"); + } + return false; + } + return true; +} + +//------------------------------------------------------------------------------ +static int +checkMesh(Shape const & shape, std::string const& name, int maxlevel) { + + std::string warningDetail; + + static char const * schemes[] = { "Bilinear", "Catmark", "Loop" }; + printf("- %-25s ( %-8s ): \n", name.c_str(), schemes[shape.scheme]); + + // Refine and interpolate vertex data for every shape: + std::vector farVertexData; + + FarTopologyRefiner * refiner = InterpolateFarVertexData(shape, maxlevel, farVertexData); + + // Perform relevant tests and accumulate failures: + int failureCount = 0; + + if (areVerticesCompatibleWithHbr(shape, *refiner, &warningDetail)) { + failureCount = compareVerticesWithHbr(shape, *refiner, farVertexData); + } else { + printf(" warning : vertex data not compared with Hbr (%s)\n", warningDetail.c_str()); + } + + return failureCount; +} + //------------------------------------------------------------------------------ int main(int /* argc */, char ** /* argv */) { @@ -233,8 +343,17 @@ int main(int /* argc */, char ** /* argv */) { printf("[ "); else printf("precision : %f\n",PRECISION); + for (int i=0; i<(int)g_shapes.size(); ++i) { - total+=checkMesh(g_shapes[i], levels); + ShapeDesc const & desc = g_shapes[i]; + + Shape * shape = Shape::parseObj(desc.data.c_str(), desc.scheme); + if (shape) { + // May want to inspect and/or modify the shape before proceeding... + + total+=checkMesh(*shape, desc.name, levels); + } + delete shape; } if (g_debugmode) diff --git a/regression/far_regression/init_shapes.h b/regression/far_regression/init_shapes.h index 8cd42bca..9bda1c6e 100644 --- a/regression/far_regression/init_shapes.h +++ b/regression/far_regression/init_shapes.h @@ -23,6 +23,7 @@ // #include "../common/shape_utils.h" +#include "../shapes/all.h" struct ShapeDesc { @@ -38,69 +39,14 @@ struct ShapeDesc { static std::vector g_shapes; -#include "../shapes/bilinear_cube.h" - -#include "../shapes/catmark_chaikin0.h" -#include "../shapes/catmark_chaikin1.h" -#include "../shapes/catmark_cube_corner0.h" -#include "../shapes/catmark_cube_corner1.h" -#include "../shapes/catmark_cube_corner2.h" -#include "../shapes/catmark_cube_corner3.h" -#include "../shapes/catmark_cube_corner4.h" -#include "../shapes/catmark_cube_creases0.h" -#include "../shapes/catmark_cube_creases1.h" -#include "../shapes/catmark_cube.h" -#include "../shapes/catmark_dart_edgecorner.h" -#include "../shapes/catmark_dart_edgeonly.h" -#include "../shapes/catmark_edgecorner.h" -#include "../shapes/catmark_edgeonly.h" -#include "../shapes/catmark_fan.h" -#include "../shapes/catmark_flap.h" -#include "../shapes/catmark_flap2.h" -#include "../shapes/catmark_gregory_test1.h" -#include "../shapes/catmark_gregory_test2.h" -#include "../shapes/catmark_gregory_test3.h" -#include "../shapes/catmark_gregory_test4.h" -#include "../shapes/catmark_gregory_test5.h" -#include "../shapes/catmark_helmet.h" -#include "../shapes/catmark_lefthanded.h" -#include "../shapes/catmark_pole8.h" -#include "../shapes/catmark_pole64.h" -#include "../shapes/catmark_pole360.h" -#include "../shapes/catmark_pyramid_creases0.h" -#include "../shapes/catmark_pyramid_creases1.h" -#include "../shapes/catmark_pyramid.h" -#include "../shapes/catmark_square_hedit0.h" -#include "../shapes/catmark_square_hedit1.h" -#include "../shapes/catmark_square_hedit2.h" -#include "../shapes/catmark_square_hedit3.h" -#include "../shapes/catmark_tent_creases0.h" -#include "../shapes/catmark_tent_creases1.h" -#include "../shapes/catmark_tent.h" -#include "../shapes/catmark_torus.h" -#include "../shapes/catmark_torus_creases0.h" - -#include "../shapes/loop_cube_creases0.h" -#include "../shapes/loop_cube_creases1.h" -#include "../shapes/loop_cube.h" -#include "../shapes/loop_icosahedron.h" -#include "../shapes/loop_pole8.h" -#include "../shapes/loop_pole64.h" -#include "../shapes/loop_pole360.h" -#include "../shapes/loop_saddle_edgecorner.h" -#include "../shapes/loop_saddle_edgeonly.h" -#include "../shapes/loop_triangle_edgecorner.h" -#include "../shapes/loop_triangle_edgeonly.h" -#include "../shapes/loop_chaikin0.h" -#include "../shapes/loop_chaikin1.h" - //------------------------------------------------------------------------------ static void initShapes() { -// g_shapes.push_back( ShapeDesc("bilinear_cube", bilinear_cube, kBilinear) ); + g_shapes.push_back( ShapeDesc("bilinear_cube", bilinear_cube, kBilinear) ); g_shapes.push_back( ShapeDesc("catmark_cube_corner0", catmark_cube_corner0, kCatmark ) ); g_shapes.push_back( ShapeDesc("catmark_cube_corner1", catmark_cube_corner1, kCatmark ) ); g_shapes.push_back( ShapeDesc("catmark_cube_corner2", catmark_cube_corner2, kCatmark ) ); + g_shapes.push_back( ShapeDesc("catmark_cube_corner3", catmark_cube_corner3, kCatmark ) ); g_shapes.push_back( ShapeDesc("catmark_cube_corner4", catmark_cube_corner4, kCatmark ) ); g_shapes.push_back( ShapeDesc("catmark_cube_creases0", catmark_cube_creases0, kCatmark ) ); @@ -110,26 +56,28 @@ static void initShapes() { g_shapes.push_back( ShapeDesc("catmark_dart_edgeonly", catmark_dart_edgeonly, kCatmark ) ); g_shapes.push_back( ShapeDesc("catmark_edgecorner", catmark_edgecorner, kCatmark ) ); g_shapes.push_back( ShapeDesc("catmark_edgeonly", catmark_edgeonly, kCatmark ) ); -// g_shapes.push_back( ShapeDesc("catmark_chaikin0", catmark_chaikin0, kCatmark ) ); -// g_shapes.push_back( ShapeDesc("catmark_chaikin1", catmark_chaikin1, kCatmark ) ); -// g_shapes.push_back( ShapeDesc("catmark_fan", catmark_fan, kCatmark ) ); + g_shapes.push_back( ShapeDesc("catmark_chaikin0", catmark_chaikin0, kCatmark ) ); + g_shapes.push_back( ShapeDesc("catmark_chaikin1", catmark_chaikin1, kCatmark ) ); + g_shapes.push_back( ShapeDesc("catmark_chaikin2", catmark_chaikin2, kCatmark ) ); + + g_shapes.push_back( ShapeDesc("catmark_fan", catmark_fan, kCatmark ) ); g_shapes.push_back( ShapeDesc("catmark_flap", catmark_flap, kCatmark ) ); g_shapes.push_back( ShapeDesc("catmark_flap2", catmark_flap2, 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 ) ); -// g_shapes.push_back( ShapeDesc("catmark_gregory_test4", catmark_gregory_test4, kCatmark ) ); + g_shapes.push_back( ShapeDesc("catmark_gregory_test4", catmark_gregory_test4, kCatmark ) ); g_shapes.push_back( ShapeDesc("catmark_gregory_test5", catmark_gregory_test5, kCatmark ) ); g_shapes.push_back( ShapeDesc("catmark_pole8", catmark_pole8, kCatmark ) ); g_shapes.push_back( ShapeDesc("catmark_pole64", catmark_pole64, kCatmark ) ); -// g_shapes.push_back( ShapeDesc("catmark_pole360", catmark_pole360, kCatmark ) ); + g_shapes.push_back( ShapeDesc("catmark_pole360", catmark_pole360, kCatmark ) ); g_shapes.push_back( ShapeDesc("catmark_pyramid_creases0", catmark_pyramid_creases0, kCatmark ) ); g_shapes.push_back( ShapeDesc("catmark_pyramid_creases1", catmark_pyramid_creases1, kCatmark ) ); g_shapes.push_back( ShapeDesc("catmark_pyramid", catmark_pyramid, kCatmark ) ); -// g_shapes.push_back( ShapeDesc("catmark_square_hedit0", catmark_square_hedit0, kCatmark ) ); -// g_shapes.push_back( ShapeDesc("catmark_square_hedit1", catmark_square_hedit1, kCatmark ) ); -// g_shapes.push_back( ShapeDesc("catmark_square_hedit2", catmark_square_hedit2, kCatmark ) ); -// g_shapes.push_back( ShapeDesc("catmark_square_hedit3", catmark_square_hedit3, kCatmark ) ); + g_shapes.push_back( ShapeDesc("catmark_square_hedit0", catmark_square_hedit0, kCatmark ) ); + g_shapes.push_back( ShapeDesc("catmark_square_hedit1", catmark_square_hedit1, kCatmark ) ); + g_shapes.push_back( ShapeDesc("catmark_square_hedit2", catmark_square_hedit2, kCatmark ) ); + g_shapes.push_back( ShapeDesc("catmark_square_hedit3", catmark_square_hedit3, kCatmark ) ); g_shapes.push_back( ShapeDesc("catmark_tent_creases0", catmark_tent_creases0, kCatmark ) ); g_shapes.push_back( ShapeDesc("catmark_tent_creases1", catmark_tent_creases1 , kCatmark ) ); g_shapes.push_back( ShapeDesc("catmark_tent", catmark_tent, kCatmark ) ); @@ -144,12 +92,12 @@ static void initShapes() { g_shapes.push_back( ShapeDesc("loop_icosahedron", loop_icosahedron, kLoop ) ); g_shapes.push_back( ShapeDesc("loop_pole8", loop_pole8, kLoop ) ); g_shapes.push_back( ShapeDesc("loop_pole64", loop_pole64, kLoop ) ); -// g_shapes.push_back( ShapeDesc("loop_pole360", loop_pole360, kLoop ) ); + g_shapes.push_back( ShapeDesc("loop_pole360", loop_pole360, kLoop ) ); g_shapes.push_back( ShapeDesc("loop_saddle_edgecorner", loop_saddle_edgecorner, kLoop ) ); g_shapes.push_back( ShapeDesc("loop_saddle_edgeonly", loop_saddle_edgeonly, kLoop ) ); g_shapes.push_back( ShapeDesc("loop_triangle_edgecorner", loop_triangle_edgecorner, kLoop ) ); g_shapes.push_back( ShapeDesc("loop_triangle_edgeonly", loop_triangle_edgeonly, kLoop ) ); -// g_shapes.push_back( ShapeDesc("loop_chaikin0", loop_chaikin0, kLoop ) ); -// g_shapes.push_back( ShapeDesc("loop_chaikin1", loop_chaikin1, kLoop ) ); + g_shapes.push_back( ShapeDesc("loop_chaikin0", loop_chaikin0, kLoop ) ); + g_shapes.push_back( ShapeDesc("loop_chaikin1", loop_chaikin1, kLoop ) ); } //------------------------------------------------------------------------------