From e27fe41b012b612ee5fe1f4cc9317a61917cc973 Mon Sep 17 00:00:00 2001 From: Barry Fowler Date: Tue, 2 Aug 2022 20:41:44 -0700 Subject: [PATCH] Addition of Bfr interface (3 of 4): regression/bfr_evaluate --- regression/CMakeLists.txt | 2 + regression/bfr_evaluate/CMakeLists.txt | 54 + .../bfr_evaluate/bfrSurfaceEvaluator.cpp | 208 ++++ regression/bfr_evaluate/bfrSurfaceEvaluator.h | 82 ++ regression/bfr_evaluate/farPatchEvaluator.cpp | 291 ++++++ regression/bfr_evaluate/farPatchEvaluator.h | 83 ++ regression/bfr_evaluate/init_shapes.h | 99 ++ regression/bfr_evaluate/init_shapes_all.h | 149 +++ regression/bfr_evaluate/main.cpp | 954 ++++++++++++++++++ regression/bfr_evaluate/types.h | 313 ++++++ regression/shapes/all.h | 4 + regression/shapes/catmark_val2_back2back.h | 98 ++ regression/shapes/catmark_val2_foldover.h | 207 ++++ regression/shapes/catmark_val2_interior.h | 284 +++--- regression/shapes/catmark_val2_nonman.h | 125 +++ regression/shapes/loop_val2_interior.h | 98 ++ 16 files changed, 2929 insertions(+), 122 deletions(-) create mode 100644 regression/bfr_evaluate/CMakeLists.txt create mode 100644 regression/bfr_evaluate/bfrSurfaceEvaluator.cpp create mode 100644 regression/bfr_evaluate/bfrSurfaceEvaluator.h create mode 100644 regression/bfr_evaluate/farPatchEvaluator.cpp create mode 100644 regression/bfr_evaluate/farPatchEvaluator.h create mode 100644 regression/bfr_evaluate/init_shapes.h create mode 100644 regression/bfr_evaluate/init_shapes_all.h create mode 100644 regression/bfr_evaluate/main.cpp create mode 100644 regression/bfr_evaluate/types.h create mode 100644 regression/shapes/catmark_val2_back2back.h create mode 100644 regression/shapes/catmark_val2_foldover.h create mode 100644 regression/shapes/catmark_val2_nonman.h create mode 100644 regression/shapes/loop_val2_interior.h diff --git a/regression/CMakeLists.txt b/regression/CMakeLists.txt index 16e58d92..7aa22748 100644 --- a/regression/CMakeLists.txt +++ b/regression/CMakeLists.txt @@ -26,6 +26,8 @@ add_subdirectory(common) if (NOT NO_REGRESSION) + add_subdirectory(bfr_evaluate) + add_subdirectory(hbr_regression) add_subdirectory(far_regression) diff --git a/regression/bfr_evaluate/CMakeLists.txt b/regression/bfr_evaluate/CMakeLists.txt new file mode 100644 index 00000000..01a8906d --- /dev/null +++ b/regression/bfr_evaluate/CMakeLists.txt @@ -0,0 +1,54 @@ +# +# Copyright 2021 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. +# + +include_directories("${OPENSUBDIV_INCLUDE_DIR}") + +set(SOURCE_FILES + main.cpp + bfrSurfaceEvaluator.cpp + farPatchEvaluator.cpp +) + +set(PLATFORM_LIBRARIES + "${OSD_LINK_TARGET}" +) + +osd_add_executable(bfr_evaluate "regression" + ${SOURCE_FILES} + $ + $ + $ + $ + $ +) + +install(TARGETS bfr_evaluate DESTINATION "${CMAKE_BINDIR_BASE}") + +add_test(bfr_evaluate_pos ${EXECUTABLE_OUTPUT_PATH}/bfr_evaluate + -all -silent -l 3 -pass 2 -d1) +add_test(bfr_evaluate_uv1 ${EXECUTABLE_OUTPUT_PATH}/bfr_evaluate + -all -silent -l 3 -pass 0 -skippos -uv -uvint 1) +add_test(bfr_evaluate_uv5 ${EXECUTABLE_OUTPUT_PATH}/bfr_evaluate + -all -silent -l 3 -pass 0 -skippos -uv -uvint 5) + diff --git a/regression/bfr_evaluate/bfrSurfaceEvaluator.cpp b/regression/bfr_evaluate/bfrSurfaceEvaluator.cpp new file mode 100644 index 00000000..02619652 --- /dev/null +++ b/regression/bfr_evaluate/bfrSurfaceEvaluator.cpp @@ -0,0 +1,208 @@ +// +// Copyright 2021 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. +// + +#include "bfrSurfaceEvaluator.h" + + +template +BfrSurfaceEvaluator::BfrSurfaceEvaluator( + Far::TopologyRefiner const & baseMesh, + Vec3Vector const & basePos, + Vec3Vector const & baseUVs, + FactoryOptions const & factoryOptions) : + _baseMesh(baseMesh), + _baseMeshPos(basePos), + _baseMeshUVs(baseUVs), + _factory(baseMesh, factoryOptions) { + +} + +template +bool +BfrSurfaceEvaluator::FaceHasLimit(IndexType baseFace) const { + + return _factory.FaceHasLimitSurface(baseFace); +} + +template +void +BfrSurfaceEvaluator::Evaluate(IndexType baseFace, + TessCoordVector const & tessCoords, + EvalResults & results) const { + + // Allocate vectors for the properties to be evaluated: + int numCoords = (int) tessCoords.size() / 2; + + results.Resize(numCoords); + + // Create the Surfaces for position and UV (optional) and assert if + // not valid, since a limit surface is expected here. (Note we may + // create the position surface but not actually evaluate it.) + SurfaceType pSurface; + SurfaceType uvSurface; + + // Figure out how to get a command line arg here to run both + bool initSeparate = false; + if (initSeparate || !results.evalUV) { + _factory.InitVertexSurface(baseFace, &pSurface); + if (results.evalUV) { + _factory.InitFaceVaryingSurface(baseFace, &uvSurface); + } + } else { + _factory.InitSurfaces(baseFace, &pSurface, &uvSurface); + } + + assert(pSurface.IsValid()); + assert(uvSurface.IsValid() == results.evalUV); + + // Evaluate directly or using stencils: + if (results.useStencils) { + evaluateByStencils(pSurface, uvSurface, tessCoords, results); + } else { + evaluateDirectly(pSurface, uvSurface, tessCoords, results); + } +} + +template +void +BfrSurfaceEvaluator::evaluateDirectly( + SurfaceType const & pSurface, SurfaceType const & uvSurface, + TessCoordVector const & tessCoords, EvalResults & results) const { + + int numCoords = (int) tessCoords.size() / 2; + + if (results.evalPosition) { + Vec3Vector baseFacePos(pSurface.GetNumPatchPoints()); + + REAL const * meshPoints = &_baseMeshPos[0][0]; + REAL * patchPoints = &baseFacePos[0][0]; + + pSurface.PreparePatchPoints(meshPoints, 3, patchPoints, 3); + + REAL const * st = &tessCoords[0]; + for (int i = 0; i < numCoords; ++i, st += 2) { + if (!results.eval1stDeriv) { + pSurface.Evaluate(st, patchPoints, 3, &results.p[i][0]); + } else if (!results.eval2ndDeriv) { + pSurface.Evaluate(st, patchPoints, 3, + &results.p[i][0], &results.du[i][0], &results.dv[i][0]); + } else { + pSurface.Evaluate(st, patchPoints, 3, + &results.p[i][0], &results.du[i][0], &results.dv[i][0], + &results.duu[i][0], &results.duv[i][0], &results.dvv[i][0]); + } + } + } + if (results.evalUV) { + Vec3Vector baseFaceUVs(uvSurface.GetNumPatchPoints()); + + REAL const * meshPoints = &_baseMeshUVs[0][0]; + REAL * patchPoints = &baseFaceUVs[0][0]; + + uvSurface.PreparePatchPoints(meshPoints, 3, patchPoints, 3); + + REAL const * st = &tessCoords[0]; + for (int i = 0; i < numCoords; ++i, st += 2) { + uvSurface.Evaluate(st, patchPoints, 3, &results.uv[i][0]); + } + } +} + +template +void +BfrSurfaceEvaluator::evaluateByStencils( + SurfaceType const & pSurface, SurfaceType const & uvSurface, + TessCoordVector const & tessCoords, EvalResults & results) const { + + std::vector stencilWeights; + + int numCoords = (int) tessCoords.size() / 2; + + if (results.evalPosition) { + stencilWeights.resize(6 * pSurface.GetNumControlPoints()); + + REAL * sP = &stencilWeights[0]; + REAL * sDu = sP + pSurface.GetNumControlPoints(); + REAL * sDv = sDu + pSurface.GetNumControlPoints(); + REAL * sDuu = sDv + pSurface.GetNumControlPoints(); + REAL * sDuv = sDuu + pSurface.GetNumControlPoints(); + REAL * sDvv = sDuv + pSurface.GetNumControlPoints(); + + REAL const * st = &tessCoords[0]; + for (int i = 0; i < numCoords; ++i, st += 2) { + REAL const * meshPos = &_baseMeshPos[0][0]; + + if (!results.eval1stDeriv) { + pSurface.EvaluateStencil(st, &sP[0]); + } else if (!results.eval2ndDeriv) { + pSurface.EvaluateStencil(st, &sP[0], &sDu[0], &sDv[0]); + } else { + pSurface.EvaluateStencil(st, &sP[0], &sDu[0], &sDv[0], + &sDuu[0], &sDuv[0], &sDvv[0]); + } + + if (results.evalPosition) { + pSurface.ApplyStencilFromMesh(&sP[0], meshPos, 3, + &results.p[i][0]); + } + if (results.eval1stDeriv) { + pSurface.ApplyStencilFromMesh(&sDu[0], meshPos, 3, + &results.du[i][0]); + pSurface.ApplyStencilFromMesh(&sDv[0], meshPos, 3, + &results.dv[i][0]); + } + if (results.eval2ndDeriv) { + pSurface.ApplyStencilFromMesh(&sDuu[0], meshPos, 3, + &results.duu[i][0]); + pSurface.ApplyStencilFromMesh(&sDuv[0], meshPos, 3, + &results.duv[i][0]); + pSurface.ApplyStencilFromMesh(&sDvv[0], meshPos, 3, + &results.dvv[i][0]); + } + } + } + if (results.evalUV) { + REAL const * meshUVs = &_baseMeshUVs[0][0]; + + stencilWeights.resize(uvSurface.GetNumControlPoints()); + + REAL * sUV = &stencilWeights[0]; + + REAL const * st = &tessCoords[0]; + for (int i = 0; i < numCoords; ++i, st += 2) { + uvSurface.EvaluateStencil(st, &sUV[0]); + + uvSurface.ApplyStencilFromMesh(&sUV[0], meshUVs, 3, + &results.uv[i][0]); + } + } +} + + +// +// Explicit instantiation for float and double: +// +template class BfrSurfaceEvaluator; +template class BfrSurfaceEvaluator; + diff --git a/regression/bfr_evaluate/bfrSurfaceEvaluator.h b/regression/bfr_evaluate/bfrSurfaceEvaluator.h new file mode 100644 index 00000000..87db5cb7 --- /dev/null +++ b/regression/bfr_evaluate/bfrSurfaceEvaluator.h @@ -0,0 +1,82 @@ +// +// Copyright 2021 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. +// + +#include "./types.h" + +#include + +#include +#include + + +using namespace OpenSubdiv; +using namespace OpenSubdiv::OPENSUBDIV_VERSION; + + + +template +class BfrSurfaceEvaluator { +public: + typedef Bfr::Surface SurfaceType; + + typedef Bfr::RefinerSurfaceFactory<> SurfaceFactory; + typedef Bfr::SurfaceFactory::Options FactoryOptions; + typedef Bfr::SurfaceFactory::Index IndexType; + + typedef std::vector TessCoordVector; + + typedef std::vector< Vec3 > Vec3Vector; + +public: + BfrSurfaceEvaluator(Far::TopologyRefiner const & baseMesh, + Vec3Vector const & basePos, + Vec3Vector const & baseUVs, + FactoryOptions const & factoryOptions); + ~BfrSurfaceEvaluator() { } + +public: + bool FaceHasLimit(IndexType baseFace) const; + + void Evaluate(IndexType baseface, + TessCoordVector const & tessCoords, + EvalResults & results) const; + +private: + void evaluateDirectly(SurfaceType const & posSurface, + SurfaceType const & uvSurface, + TessCoordVector const & tessCoords, + EvalResults & results) const; + + void evaluateByStencils(SurfaceType const & posSurface, + SurfaceType const & uvSurface, + TessCoordVector const & tessCoords, + EvalResults & results) const; + +private: + Far::TopologyRefiner const & _baseMesh; + Vec3Vector const & _baseMeshPos; + Vec3Vector const & _baseMeshUVs; + + SurfaceFactory _factory; +}; diff --git a/regression/bfr_evaluate/farPatchEvaluator.cpp b/regression/bfr_evaluate/farPatchEvaluator.cpp new file mode 100644 index 00000000..646aebc6 --- /dev/null +++ b/regression/bfr_evaluate/farPatchEvaluator.cpp @@ -0,0 +1,291 @@ +// +// Copyright 2021 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. +// + +#include "farPatchEvaluator.h" + +#include +#include +#include +#include + + +template +FarPatchEvaluator::FarPatchEvaluator( + Far::TopologyRefiner const & baseMesh, + Vec3RealVector const & basePos, + Vec3RealVector const & baseUVs, + BfrSurfaceOptions const & bfrSurfaceOptions) : + _baseMesh(baseMesh), + _baseMeshPos(basePos), + _baseMeshUVs(baseUVs) { + + // + // Initialize simple members first: + // + _regFaceSize = Sdc::SchemeTypeTraits::GetRegularFaceSize( + baseMesh.GetSchemeType()); + + // + // Declare options to use in construction of PatchTable et al: + // + int primaryLevel = bfrSurfaceOptions.GetApproxLevelSharp(); + int secondaryLevel = bfrSurfaceOptions.GetApproxLevelSmooth(); + + Far::PatchTableFactory::Options patchOptions(primaryLevel); + patchOptions.SetPatchPrecision(); + patchOptions.SetFVarPatchPrecision(); + patchOptions.useInfSharpPatch = true; + patchOptions.generateLegacySharpCornerPatches = false; + patchOptions.shareEndCapPatchPoints = false; + patchOptions.endCapType = + Far::PatchTableFactory::Options::ENDCAP_GREGORY_BASIS; + + bool hasUVs = !baseUVs.empty(); + int fvarChannel = 0; + + patchOptions.generateFVarTables = hasUVs; + patchOptions.numFVarChannels = hasUVs ? 1 : 0; + patchOptions.fvarChannelIndices = &fvarChannel; + patchOptions.generateFVarLegacyLinearPatches = false; + + patchOptions.generateVaryingTables = false; + + Far::TopologyRefiner::AdaptiveOptions refineOptions = + patchOptions.GetRefineAdaptiveOptions(); + refineOptions.isolationLevel = primaryLevel; + refineOptions.secondaryLevel = secondaryLevel; + + // + // Create a TopologyRefiner (sharing the base) to adaptively refine + // and create the associated PatchTable: + // + Far::TopologyRefiner *patchRefiner = + Far::TopologyRefinerFactory::Create( + baseMesh); + + patchRefiner->RefineAdaptive(refineOptions); + + _patchTable = Far::PatchTableFactory::Create(*patchRefiner, patchOptions); + + _patchFaces = new Far::PtexIndices(baseMesh); + + _patchMap = new Far::PatchMap(*_patchTable); + + + // + // Declare buffers/vectors for refined/patch points: + // + Far::TopologyLevel const & baseLevel = baseMesh.GetLevel(0); + + int numBasePoints = baseLevel.GetNumVertices(); + int numRefinedPoints = patchRefiner->GetNumVerticesTotal() - numBasePoints; + int numLocalPoints = _patchTable->GetNumLocalPoints(); + + _patchPos.resize(numBasePoints + numRefinedPoints + numLocalPoints); + + std::memcpy(&_patchPos[0], &basePos[0], numBasePoints * sizeof(Vec3Real)); + + // + // Similarly declare buffers/vectors for refined/patch UVs: + // + int numBaseUVs = 0; + int numRefinedUVs = 0; + int numLocalUVs = 0; + + if (hasUVs) { + numBaseUVs = baseLevel.GetNumFVarValues(); + numRefinedUVs = patchRefiner->GetNumFVarValuesTotal() - numBaseUVs; + numLocalUVs = _patchTable->GetNumLocalPointsFaceVarying(); + + _patchUVs.resize(numBaseUVs + numRefinedUVs + numLocalUVs); + + std::memcpy(&_patchUVs[0], &baseUVs[0], numBaseUVs * sizeof(Vec3Real)); + } + + // + // Compute refined and local patch points and UVs: + // + if (numRefinedPoints) { + Far::PrimvarRefinerReal primvarRefiner(*patchRefiner); + + Vec3Real const * srcP = &_patchPos[0]; + Vec3Real * dstP = &_patchPos[numBasePoints]; + + Vec3Real const * srcUV = hasUVs ? &_patchUVs[0] : 0; + Vec3Real * dstUV = hasUVs ? &_patchUVs[numBaseUVs] : 0; + + for (int level = 1; level < patchRefiner->GetNumLevels(); ++level) { + primvarRefiner.Interpolate(level, srcP, dstP); + srcP = dstP; + dstP += patchRefiner->GetLevel(level).GetNumVertices(); + + if (hasUVs) { + primvarRefiner.InterpolateFaceVarying(level, srcUV, dstUV); + srcUV = dstUV; + dstUV += patchRefiner->GetLevel(level).GetNumFVarValues(); + } + } + } + if (numLocalPoints) { + _patchTable->GetLocalPointStencilTable()->UpdateValues( + &_patchPos[0], &_patchPos[numBasePoints + numRefinedPoints]); + } + if (hasUVs && numLocalUVs) { + _patchTable->GetLocalPointFaceVaryingStencilTable()->UpdateValues( + &_patchUVs[0], &_patchUVs[numBaseUVs + numRefinedUVs]); + } + + delete patchRefiner; +} + +template +bool +FarPatchEvaluator::FaceHasLimit(Far::Index baseFace) const { + + return ! _baseMesh.GetLevel(0).IsFaceHole(baseFace); +} + +template +void +FarPatchEvaluator::Evaluate(Far::Index baseFace, + TessCoordVector const & tessCoords, + EvalResults & results) const { + + assert(FaceHasLimit(baseFace)); + + int numCoords = (int) tessCoords.size() / 2; + + // Allocate vectors for the properties to be evaluated: + results.Resize(numCoords); + + // + // Identify the patch face and see if it needs to be re-parameterized: + // + int patchFace = _patchFaces->GetFaceId(baseFace); + + int faceSize = _baseMesh.GetLevel(0).GetFaceVertices(baseFace).size(); + + Bfr::Parameterization faceParam(_baseMesh.GetSchemeType(), faceSize); + + bool reparameterize = faceParam.HasSubFaces(); + + // + // Evaluate at each of the given coordinates: + // + REAL const * stPair = &tessCoords[0]; + for (int i = 0; i < numCoords; ++i, stPair += 2) { + REAL st[2] = { stPair[0], stPair[1] }; + + int patchIndex = patchFace; + if (reparameterize) { + patchIndex += faceParam.ConvertCoordToNormalizedSubFace(st, st); + } + + REAL s = st[0]; + REAL t = st[1]; + + Far::PatchTable::PatchHandle const * patchHandle = + _patchMap->FindPatch(patchIndex, s, t); + assert(patchHandle); + + // Evaluate position and derivatives: + if (results.evalPosition) { + REAL wP[20], wDu[20], wDv[20], wDuu[20], wDuv[20], wDvv[20]; + + if (!results.eval1stDeriv) { + _patchTable->EvaluateBasis(*patchHandle, s, t, wP); + } else if (!results.eval2ndDeriv) { + _patchTable->EvaluateBasis(*patchHandle, s, t, wP, + wDu, wDv); + } else { + _patchTable->EvaluateBasis(*patchHandle, s, t, wP, + wDu, wDv, wDuu, wDuv, wDvv); + } + + Vec3Real * P = results.evalPosition ? &results.p[i] : 0; + Vec3Real * Du = results.eval1stDeriv ? &results.du[i] : 0; + Vec3Real * Dv = results.eval1stDeriv ? &results.dv[i] : 0; + Vec3Real * Duu = results.eval2ndDeriv ? &results.duu[i] : 0; + Vec3Real * Duv = results.eval2ndDeriv ? &results.duv[i] : 0; + Vec3Real * Dvv = results.eval2ndDeriv ? &results.dvv[i] : 0; + + Far::ConstIndexArray cvIndices = + _patchTable->GetPatchVertices(*patchHandle); + + P->Clear(); + if (results.eval1stDeriv) { + Du->Clear(); + Dv->Clear(); + if (results.eval2ndDeriv) { + Duu->Clear(); + Duv->Clear(); + Dvv->Clear(); + } + } + + for (int cv = 0; cv < cvIndices.size(); ++cv) { + P->AddWithWeight(_patchPos[cvIndices[cv]], wP[cv]); + if (results.eval1stDeriv) { + Du->AddWithWeight(_patchPos[cvIndices[cv]], wDu[cv]); + Dv->AddWithWeight(_patchPos[cvIndices[cv]], wDv[cv]); + if (results.eval2ndDeriv) { + Duu->AddWithWeight(_patchPos[cvIndices[cv]], wDuu[cv]); + Duv->AddWithWeight(_patchPos[cvIndices[cv]], wDuv[cv]); + Dvv->AddWithWeight(_patchPos[cvIndices[cv]], wDvv[cv]); + } + } + } + } + if (results.evalUV) { + REAL wUV[20]; + _patchTable->EvaluateBasisFaceVarying(*patchHandle, s, t, wUV); + + Vec3Real & UV = results.uv[i]; + + UV.Clear(); + + Far::ConstIndexArray cvIndices = + _patchTable->GetPatchFVarValues(*patchHandle); + + for (int cv = 0; cv < cvIndices.size(); ++cv) { + UV.AddWithWeight(_patchUVs[cvIndices[cv]], wUV[cv]); + } + } + } +} + +template +FarPatchEvaluator::~FarPatchEvaluator() { + + delete _patchTable; + delete _patchFaces; + delete _patchMap; +} + +// +// Explicit instantiation for float and double: +// +template class FarPatchEvaluator; +template class FarPatchEvaluator; + diff --git a/regression/bfr_evaluate/farPatchEvaluator.h b/regression/bfr_evaluate/farPatchEvaluator.h new file mode 100644 index 00000000..c7814f12 --- /dev/null +++ b/regression/bfr_evaluate/farPatchEvaluator.h @@ -0,0 +1,83 @@ +// +// Copyright 2021 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. +// + +#include "./types.h" + +#include +#include +#include +#include +#include + +#include +#include + +using namespace OpenSubdiv; +using namespace OpenSubdiv::OPENSUBDIV_VERSION; + + +// +// FarPatchEvaluator bundles the Far::PatchTable and its ecosystem of +// related class to provide an evaluation interface targeted towards +// evaluation of the base faces of a mesh. +// +template +class FarPatchEvaluator { +public: + typedef Far::PatchTableFactory PatchFactory; + typedef Bfr::SurfaceFactory::Options BfrSurfaceOptions; + + typedef std::vector TessCoordVector; + + typedef Vec3 Vec3Real; + typedef std::vector Vec3RealVector; + +public: + FarPatchEvaluator(Far::TopologyRefiner const & baseMesh, + Vec3RealVector const & basePos, + Vec3RealVector const & baseUVs, + BfrSurfaceOptions const & bfrSurfaceOptions); + ~FarPatchEvaluator(); + +public: + bool FaceHasLimit(Far::Index baseFace) const; + + void Evaluate(Far::Index baseface, + TessCoordVector const & tessCoords, + EvalResults & results) const; + +private: + Far::TopologyRefiner const & _baseMesh; + Vec3RealVector const & _baseMeshPos; + Vec3RealVector const & _baseMeshUVs; + + Far::PatchTable * _patchTable; + Far::PatchMap * _patchMap; + Far::PtexIndices * _patchFaces; + + Vec3RealVector _patchPos; + Vec3RealVector _patchUVs; + + int _regFaceSize; +}; diff --git a/regression/bfr_evaluate/init_shapes.h b/regression/bfr_evaluate/init_shapes.h new file mode 100644 index 00000000..c196a690 --- /dev/null +++ b/regression/bfr_evaluate/init_shapes.h @@ -0,0 +1,99 @@ +// +// Copyright 2021 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. +// + +#include +#include + + +//------------------------------------------------------------------------------ +static void +initShapes(std::vector & shapes) { + + shapes.push_back(ShapeDesc("catmark_toroidal_tet", catmark_toroidal_tet, kCatmark)); + shapes.push_back(ShapeDesc("catmark_cube", catmark_cube, kCatmark)); + shapes.push_back(ShapeDesc("catmark_cubes_semisharp", catmark_cubes_semisharp, kCatmark)); + shapes.push_back(ShapeDesc("catmark_cubes_infsharp", catmark_cubes_infsharp, kCatmark)); + shapes.push_back(ShapeDesc("catmark_pyramid", catmark_pyramid, kCatmark)); + shapes.push_back(ShapeDesc("catmark_pyramid_creases0", catmark_pyramid_creases0, kCatmark)); + shapes.push_back(ShapeDesc("catmark_pyramid_creases1", catmark_pyramid_creases1, kCatmark)); + shapes.push_back(ShapeDesc("catmark_torus", catmark_torus, kCatmark)); + shapes.push_back(ShapeDesc("catmark_torus_creases0", catmark_torus_creases0, kCatmark)); + shapes.push_back(ShapeDesc("catmark_torus_creases1", catmark_torus_creases1, kCatmark)); + shapes.push_back(ShapeDesc("catmark_edgecorner", catmark_edgecorner, kCatmark)); + shapes.push_back(ShapeDesc("catmark_edgeonly", catmark_edgeonly, kCatmark)); + shapes.push_back(ShapeDesc("catmark_edgenone", catmark_edgenone, kCatmark)); + shapes.push_back(ShapeDesc("catmark_quadstrips", catmark_quadstrips, kCatmark)); + shapes.push_back(ShapeDesc("catmark_xord_interior", catmark_xord_interior, kCatmark)); + shapes.push_back(ShapeDesc("catmark_xord_boundary", catmark_xord_boundary, kCatmark)); + shapes.push_back(ShapeDesc("catmark_val2_interior", catmark_val2_interior, kCatmark)); + shapes.push_back(ShapeDesc("catmark_nonquads", catmark_nonquads, kCatmark)); + shapes.push_back(ShapeDesc("catmark_single_crease", catmark_single_crease, kCatmark)); + shapes.push_back(ShapeDesc("catmark_inf_crease0", catmark_inf_crease0, kCatmark)); + shapes.push_back(ShapeDesc("catmark_inf_crease1", catmark_inf_crease1, kCatmark)); + shapes.push_back(ShapeDesc("catmark_nonman_verts", catmark_nonman_verts, kCatmark)); + shapes.push_back(ShapeDesc("catmark_nonman_edges", catmark_nonman_edges, kCatmark)); + shapes.push_back(ShapeDesc("catmark_hole_test1", catmark_hole_test1, kCatmark)); + shapes.push_back(ShapeDesc("catmark_hole_test2", catmark_hole_test2, kCatmark)); + shapes.push_back(ShapeDesc("catmark_hole_test3", catmark_hole_test3, kCatmark)); + shapes.push_back(ShapeDesc("catmark_hole_test4", catmark_hole_test4, kCatmark)); + shapes.push_back(ShapeDesc("catmark_chaikin0", catmark_chaikin0, kCatmark)); + shapes.push_back(ShapeDesc("catmark_chaikin1", catmark_chaikin1, kCatmark)); + shapes.push_back(ShapeDesc("catmark_chaikin2", catmark_chaikin2, kCatmark)); + shapes.push_back(ShapeDesc("catmark_smoothtris0", catmark_smoothtris0, kCatmark)); + shapes.push_back(ShapeDesc("catmark_smoothtris1", catmark_smoothtris1, kCatmark)); + shapes.push_back(ShapeDesc("catmark_pole8", catmark_pole8, kCatmark)); +// shapes.push_back(ShapeDesc("catmark_pole64", catmark_pole64, kCatmark)); + shapes.push_back(ShapeDesc("catmark_nonman_quadpole64",catmark_nonman_quadpole64,kCatmark)); + shapes.push_back(ShapeDesc("catmark_nonman_edge100", catmark_nonman_edge100, kCatmark)); + shapes.push_back(ShapeDesc("catmark_helmet", catmark_helmet, kCatmark)); + shapes.push_back(ShapeDesc("catmark_bishop", catmark_bishop, kCatmark)); + shapes.push_back(ShapeDesc("catmark_pawn", catmark_pawn, kCatmark)); +// shapes.push_back(ShapeDesc("catmark_rook", catmark_rook, kCatmark)); + shapes.push_back(ShapeDesc("catmark_car", catmark_car, kCatmark)); + + shapes.push_back(ShapeDesc("loop_toroidal_tet", loop_toroidal_tet, kLoop)); + shapes.push_back(ShapeDesc("loop_tetrahedron", loop_tetrahedron, kLoop)); + shapes.push_back(ShapeDesc("loop_cube", loop_cube, kLoop)); + shapes.push_back(ShapeDesc("loop_cubes_semisharp", loop_cubes_semisharp, kLoop)); + shapes.push_back(ShapeDesc("loop_cubes_infsharp", loop_cubes_infsharp, kLoop)); + shapes.push_back(ShapeDesc("loop_cube_asymmetric", loop_cube_asymmetric, kLoop)); + shapes.push_back(ShapeDesc("loop_icosahedron", loop_icosahedron, kLoop)); + shapes.push_back(ShapeDesc("loop_icos_semisharp", loop_icos_semisharp, kLoop)); + shapes.push_back(ShapeDesc("loop_icos_infsharp", loop_icos_infsharp, kLoop)); + shapes.push_back(ShapeDesc("loop_triangle_edgecorner", loop_triangle_edgecorner, kLoop)); + shapes.push_back(ShapeDesc("loop_triangle_edgeonly", loop_triangle_edgeonly, kLoop)); + shapes.push_back(ShapeDesc("loop_triangle_edgenone", loop_triangle_edgenone, kLoop)); + shapes.push_back(ShapeDesc("loop_xord_interior", loop_xord_interior, kLoop)); + shapes.push_back(ShapeDesc("loop_xord_boundary", loop_xord_boundary, kLoop)); + shapes.push_back(ShapeDesc("loop_nonman_verts", loop_nonman_verts, kLoop)); + shapes.push_back(ShapeDesc("loop_nonman_edges", loop_nonman_edges, kLoop)); +// shapes.push_back(ShapeDesc("loop_pole64", loop_pole64, kLoop)); + shapes.push_back(ShapeDesc("loop_nonman_edge100", loop_nonman_edge100, kLoop)); + + shapes.push_back(ShapeDesc("bilinear_cube", bilinear_cube, kBilinear)); + shapes.push_back(ShapeDesc("bilinear_nonplanar", bilinear_nonplanar, kBilinear)); + shapes.push_back(ShapeDesc("bilinear_nonquads0", bilinear_nonquads0, kBilinear)); + shapes.push_back(ShapeDesc("bilinear_nonquads1", bilinear_nonquads1, kBilinear)); +} +//------------------------------------------------------------------------------ diff --git a/regression/bfr_evaluate/init_shapes_all.h b/regression/bfr_evaluate/init_shapes_all.h new file mode 100644 index 00000000..0401d8f2 --- /dev/null +++ b/regression/bfr_evaluate/init_shapes_all.h @@ -0,0 +1,149 @@ +// +// Copyright 2021 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. +// + +#include +#include + +static void +initShapesAll(std::vector & shapes) { + + shapes.push_back(ShapeDesc("catmark_cube", catmark_cube, kCatmark)); + shapes.push_back(ShapeDesc("catmark_cube_corner0", catmark_cube_corner0, kCatmark)); + shapes.push_back(ShapeDesc("catmark_cube_corner1", catmark_cube_corner1, kCatmark)); + shapes.push_back(ShapeDesc("catmark_cube_corner2", catmark_cube_corner2, kCatmark)); + shapes.push_back(ShapeDesc("catmark_cube_corner3", catmark_cube_corner3, kCatmark)); + shapes.push_back(ShapeDesc("catmark_cube_corner4", catmark_cube_corner4, kCatmark)); + shapes.push_back(ShapeDesc("catmark_cube_creases0", catmark_cube_creases0, kCatmark)); + shapes.push_back(ShapeDesc("catmark_cube_creases1", catmark_cube_creases1, kCatmark)); + shapes.push_back(ShapeDesc("catmark_cube_creases2", catmark_cube_creases2, kCatmark)); + shapes.push_back(ShapeDesc("catmark_cubes_infsharp", catmark_cubes_infsharp, kCatmark)); + shapes.push_back(ShapeDesc("catmark_cubes_semisharp", catmark_cubes_semisharp, kCatmark)); + shapes.push_back(ShapeDesc("catmark_chaikin0", catmark_chaikin0, kCatmark)); + shapes.push_back(ShapeDesc("catmark_chaikin1", catmark_chaikin1, kCatmark)); + shapes.push_back(ShapeDesc("catmark_chaikin2", catmark_chaikin2, kCatmark)); + shapes.push_back(ShapeDesc("catmark_dart_edgecorner", catmark_dart_edgecorner, kCatmark)); + shapes.push_back(ShapeDesc("catmark_dart_edgeonly", catmark_dart_edgeonly, kCatmark)); + shapes.push_back(ShapeDesc("catmark_edgecorner", catmark_edgecorner, kCatmark)); + shapes.push_back(ShapeDesc("catmark_edgeonly", catmark_edgeonly, kCatmark)); + shapes.push_back(ShapeDesc("catmark_edgenone", catmark_edgenone, kCatmark)); + shapes.push_back(ShapeDesc("catmark_fan", catmark_fan, kCatmark)); + shapes.push_back(ShapeDesc("catmark_flap", catmark_flap, kCatmark)); + shapes.push_back(ShapeDesc("catmark_flap2", catmark_flap2, kCatmark)); + shapes.push_back(ShapeDesc("catmark_fvar_bound0", catmark_fvar_bound0, kCatmark)); + shapes.push_back(ShapeDesc("catmark_fvar_bound1", catmark_fvar_bound1, kCatmark)); + shapes.push_back(ShapeDesc("catmark_fvar_bound2", catmark_fvar_bound2, kCatmark)); + shapes.push_back(ShapeDesc("catmark_fvar_bound3", catmark_fvar_bound3, kCatmark)); + shapes.push_back(ShapeDesc("catmark_fvar_bound4", catmark_fvar_bound4, kCatmark)); + shapes.push_back(ShapeDesc("catmark_fvar_project0", catmark_fvar_project0, kCatmark)); + shapes.push_back(ShapeDesc("catmark_gregory_test0", catmark_gregory_test0, kCatmark)); + shapes.push_back(ShapeDesc("catmark_gregory_test1", catmark_gregory_test1, kCatmark)); + shapes.push_back(ShapeDesc("catmark_gregory_test2", catmark_gregory_test2, kCatmark)); + shapes.push_back(ShapeDesc("catmark_gregory_test3", catmark_gregory_test3, kCatmark)); + shapes.push_back(ShapeDesc("catmark_gregory_test4", catmark_gregory_test4, kCatmark)); + shapes.push_back(ShapeDesc("catmark_gregory_test5", catmark_gregory_test5, kCatmark)); + shapes.push_back(ShapeDesc("catmark_gregory_test6", catmark_gregory_test6, kCatmark)); + shapes.push_back(ShapeDesc("catmark_gregory_test7", catmark_gregory_test7, kCatmark)); + shapes.push_back(ShapeDesc("catmark_gregory_test8", catmark_gregory_test8, kCatmark)); + shapes.push_back(ShapeDesc("catmark_helmet", catmark_helmet, kCatmark)); + shapes.push_back(ShapeDesc("catmark_hole_test1", catmark_hole_test1, kCatmark)); + shapes.push_back(ShapeDesc("catmark_hole_test2", catmark_hole_test2, kCatmark)); + shapes.push_back(ShapeDesc("catmark_hole_test3", catmark_hole_test3, kCatmark)); + shapes.push_back(ShapeDesc("catmark_hole_test4", catmark_hole_test4, kCatmark)); + shapes.push_back(ShapeDesc("catmark_lefthanded", catmark_lefthanded, kCatmark)); + shapes.push_back(ShapeDesc("catmark_righthanded", catmark_righthanded, kCatmark)); + shapes.push_back(ShapeDesc("catmark_nonman_edges", catmark_nonman_edges, kCatmark)); + shapes.push_back(ShapeDesc("catmark_nonman_edge100", catmark_nonman_edge100, kCatmark)); + shapes.push_back(ShapeDesc("catmark_nonman_verts", catmark_nonman_verts, kCatmark)); + shapes.push_back(ShapeDesc("catmark_nonman_quadpole8", catmark_nonman_quadpole8, kCatmark)); + shapes.push_back(ShapeDesc("catmark_nonman_quadpole64", catmark_nonman_quadpole64, kCatmark)); + shapes.push_back(ShapeDesc("catmark_nonman_quadpole360", catmark_nonman_quadpole360, kCatmark)); + shapes.push_back(ShapeDesc("catmark_nonman_bareverts", catmark_nonman_bareverts, kCatmark)); + shapes.push_back(ShapeDesc("catmark_nonquads", catmark_nonquads, kCatmark)); + shapes.push_back(ShapeDesc("catmark_pawn", catmark_pawn, kCatmark)); + shapes.push_back(ShapeDesc("catmark_pole8", catmark_pole8, kCatmark)); + shapes.push_back(ShapeDesc("catmark_pole64", catmark_pole64, kCatmark)); + shapes.push_back(ShapeDesc("catmark_pyramid_creases0", catmark_pyramid_creases0, kCatmark)); + shapes.push_back(ShapeDesc("catmark_pyramid_creases1", catmark_pyramid_creases1, kCatmark)); + shapes.push_back(ShapeDesc("catmark_pyramid_creases2", catmark_pyramid_creases2, kCatmark)); + shapes.push_back(ShapeDesc("catmark_pyramid", catmark_pyramid, kCatmark)); + shapes.push_back(ShapeDesc("catmark_quadstrips", catmark_quadstrips, kCatmark)); + shapes.push_back(ShapeDesc("catmark_single_crease", catmark_single_crease, kCatmark)); + shapes.push_back(ShapeDesc("catmark_inf_crease0", catmark_inf_crease0, kCatmark)); + shapes.push_back(ShapeDesc("catmark_inf_crease1", catmark_inf_crease1, kCatmark)); + shapes.push_back(ShapeDesc("catmark_smoothtris0", catmark_smoothtris0, kCatmark)); + shapes.push_back(ShapeDesc("catmark_smoothtris1", catmark_smoothtris1, kCatmark)); + shapes.push_back(ShapeDesc("catmark_tent_creases0", catmark_tent_creases0, kCatmark)); + shapes.push_back(ShapeDesc("catmark_tent_creases1", catmark_tent_creases1, kCatmark)); + shapes.push_back(ShapeDesc("catmark_tent", catmark_tent, kCatmark)); + shapes.push_back(ShapeDesc("catmark_toroidal_tet", catmark_toroidal_tet, kCatmark)); + shapes.push_back(ShapeDesc("catmark_torus", catmark_torus, kCatmark)); + shapes.push_back(ShapeDesc("catmark_torus_creases0", catmark_torus_creases0, kCatmark)); + shapes.push_back(ShapeDesc("catmark_torus_creases1", catmark_torus_creases1, kCatmark)); + shapes.push_back(ShapeDesc("catmark_val2_interior", catmark_val2_interior, kCatmark)); + shapes.push_back(ShapeDesc("catmark_val2_back2back", catmark_val2_back2back, kCatmark)); + shapes.push_back(ShapeDesc("catmark_val2_foldover", catmark_val2_foldover, kCatmark)); + shapes.push_back(ShapeDesc("catmark_val2_nonman", catmark_val2_nonman, kCatmark)); + shapes.push_back(ShapeDesc("catmark_xord_interior", catmark_xord_interior, kCatmark)); + shapes.push_back(ShapeDesc("catmark_xord_boundary", catmark_xord_boundary, kCatmark)); + shapes.push_back(ShapeDesc("bilinear_cube", bilinear_cube, kBilinear)); + shapes.push_back(ShapeDesc("bilinear_nonplanar", bilinear_nonplanar, kBilinear)); + shapes.push_back(ShapeDesc("bilinear_nonquads0", bilinear_nonquads0, kBilinear)); + shapes.push_back(ShapeDesc("bilinear_nonquads1", bilinear_nonquads1, kBilinear)); + shapes.push_back(ShapeDesc("loop_chaikin0", loop_chaikin0, kLoop)); + shapes.push_back(ShapeDesc("loop_chaikin1", loop_chaikin1, kLoop)); + shapes.push_back(ShapeDesc("loop_cube", loop_cube, kLoop)); + shapes.push_back(ShapeDesc("loop_cube_asymmetric", loop_cube_asymmetric, kLoop)); + shapes.push_back(ShapeDesc("loop_cube_creases0", loop_cube_creases0, kLoop)); + shapes.push_back(ShapeDesc("loop_cube_creases1", loop_cube_creases1, kLoop)); + shapes.push_back(ShapeDesc("loop_cubes_infsharp", loop_cubes_infsharp, kLoop)); + shapes.push_back(ShapeDesc("loop_cubes_semisharp", loop_cubes_semisharp, kLoop)); + shapes.push_back(ShapeDesc("loop_fvar_bound0", loop_fvar_bound0, kLoop)); + shapes.push_back(ShapeDesc("loop_fvar_bound1", loop_fvar_bound1, kLoop)); + shapes.push_back(ShapeDesc("loop_fvar_bound2", loop_fvar_bound2, kLoop)); + shapes.push_back(ShapeDesc("loop_fvar_bound3", loop_fvar_bound3, kLoop)); + shapes.push_back(ShapeDesc("loop_icosahedron", loop_icosahedron, kLoop)); + shapes.push_back(ShapeDesc("loop_icos_infsharp", loop_icos_infsharp, kLoop)); + shapes.push_back(ShapeDesc("loop_icos_semisharp", loop_icos_semisharp, kLoop)); + shapes.push_back(ShapeDesc("loop_nonman_edges", loop_nonman_edges, kLoop)); + shapes.push_back(ShapeDesc("loop_nonman_edge100", loop_nonman_edge100, kLoop)); + shapes.push_back(ShapeDesc("loop_nonman_verts", loop_nonman_verts, kLoop)); + shapes.push_back(ShapeDesc("loop_pole8", loop_pole8, kLoop)); + shapes.push_back(ShapeDesc("loop_pole64", loop_pole64, kLoop)); + shapes.push_back(ShapeDesc("loop_saddle_edgecorner", loop_saddle_edgecorner, kLoop)); + shapes.push_back(ShapeDesc("loop_saddle_edgeonly", loop_saddle_edgeonly, kLoop)); + shapes.push_back(ShapeDesc("loop_tetrahedron", loop_tetrahedron, kLoop)); + shapes.push_back(ShapeDesc("loop_toroidal_tet", loop_toroidal_tet, kLoop)); + shapes.push_back(ShapeDesc("loop_triangle_edgecorner", loop_triangle_edgecorner, kLoop)); + shapes.push_back(ShapeDesc("loop_triangle_edgeonly", loop_triangle_edgeonly, kLoop)); + shapes.push_back(ShapeDesc("loop_xord_boundary", loop_xord_boundary, kLoop)); + shapes.push_back(ShapeDesc("loop_xord_interior", loop_xord_interior, kLoop)); + shapes.push_back(ShapeDesc("loop_val2_interior", loop_val2_interior, kLoop)); + + // More complicated shapes with longer execution times: + shapes.push_back(ShapeDesc("catmark_car", catmark_car, kCatmark)); + shapes.push_back(ShapeDesc("catmark_rook", catmark_rook, kCatmark)); + shapes.push_back(ShapeDesc("catmark_bishop", catmark_bishop, kCatmark)); +// shapes.push_back(ShapeDesc("catmark_pole360", catmark_pole360, kCatmark)); +// shapes.push_back(ShapeDesc("loop_pole360", loop_pole360, kLoop)); +} diff --git a/regression/bfr_evaluate/main.cpp b/regression/bfr_evaluate/main.cpp new file mode 100644 index 00000000..77574108 --- /dev/null +++ b/regression/bfr_evaluate/main.cpp @@ -0,0 +1,954 @@ +// +// Copyright 2021 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. +// + +#include "./types.h" +#include "./bfrSurfaceEvaluator.h" +#include "./farPatchEvaluator.h" + +#include "../../regression/common/far_utils.h" + +#include "init_shapes.h" +#include "init_shapes_all.h" + +#include +#include +#include +#include +#include + +using namespace OpenSubdiv; +using namespace OpenSubdiv::OPENSUBDIV_VERSION; + +// +// Global set of shapes -- populated by variants of initShapes() that +// include explicit lists: +// +std::vector g_shapes; + + +// +// Command line arguments and their parsing: +// +class Args { +public: + // options related to testing and reporting: + unsigned int posEvaluate : 1; + unsigned int d1Evaluate : 1; + unsigned int d2Evaluate : 1; + unsigned int uvEvaluate : 1; + unsigned int posIgnore : 1; + unsigned int d1Ignore : 1; + unsigned int d2Ignore : 1; + unsigned int uvIgnore : 1; + unsigned int printArgs : 1; + unsigned int printProgress : 1; + unsigned int printFaceDiffs : 1; + unsigned int printSummary : 1; + unsigned int printWarnings : 1; + unsigned int ptexConvert : 1; + + // options affecting configuration and execution: + unsigned int evalByStencils : 1; + unsigned int doublePrecision : 1; + unsigned int noCacheFlag : 1; + + // options affecting the shape of the limit surface: + int depthSharp; + int depthSmooth; + int bndInterp; + int uvInterp; + + // options related to tessellation and comparison: + int uniformRes; + float relTolerance; + float absTolerance; + float uvTolerance; + + // options affecting the list of shapes to be tested: + int shapeCount; + Scheme shapeScheme; + bool shapesCat2Loop; + bool shapesAll; + + std::vector shapes; + + // options determining overall success/failure: + int passCount; + +public: + Args(int argc, char **argv) : + posEvaluate(true), + d1Evaluate(false), + d2Evaluate(false), + uvEvaluate(false), + posIgnore(false), + d1Ignore(false), + d2Ignore(false), + uvIgnore(false), + printArgs(true), + printProgress(true), + printFaceDiffs(false), + printSummary(true), + printWarnings(true), + ptexConvert(false), + evalByStencils(false), + doublePrecision(false), + noCacheFlag(false), + depthSharp(-1), + depthSmooth(-1), + bndInterp(-1), + uvInterp(-1), + uniformRes(3), + relTolerance(0.00005f), + absTolerance(0.0f), + uvTolerance(0.0001f), + shapeCount(0), + shapeScheme(kCatmark), + shapesCat2Loop(false), + shapesAll(false), + shapes(), + passCount(0) { + + std::string fileString; + + std::vector shapeNames; + + for (int i = 1; i < argc; ++i) { + char * arg = argv[i]; + + // Options related to input .obj files: + if (strstr(arg, ".obj")) { + if (readString(arg, fileString)) { + // Use the scheme declared at the time so that multiple + // shape/scheme pairs can be specified + shapes.push_back( + ShapeDesc(arg, fileString.c_str(), shapeScheme)); + } else { + fprintf(stderr, + "Error: Unable to open/read .obj file '%s'\n", arg); + exit(0); + } + + // Options affecting the limit surface shapes: + } else if (!strcmp(arg, "-l")) { + if (++i < argc) { + int maxLevel = atoi(argv[i]); + depthSharp = maxLevel; + depthSmooth = maxLevel; + } + } else if (!strcmp(arg, "-lsharp")) { + if (++i < argc) depthSharp = atoi(argv[i]); + } else if (!strcmp(arg, "-lsmooth")) { + if (++i < argc) depthSmooth = atoi(argv[i]); + } else if (!strcmp(argv[i], "-bint")) { + if (++i < argc) bndInterp = atoi(argv[i]); + } else if (!strcmp(argv[i], "-uvint")) { + if (++i < argc) uvInterp = atoi(argv[i]); + + // Options affecting what gets evaluated: + } else if (!strcmp(arg, "-res")) { + if (++i < argc) uniformRes = atoi(argv[i]); + } else if (!strcmp(arg, "-pos")) { + posEvaluate = true; + } else if (!strcmp(arg, "-nopos")) { + posEvaluate = false; + } else if (!strcmp(arg, "-d1")) { + d1Evaluate = true; + } else if (!strcmp(arg, "-nod1")) { + d1Evaluate = false; + } else if (!strcmp(arg, "-d2")) { + d2Evaluate = true; + } else if (!strcmp(arg, "-nod2")) { + d2Evaluate = false; + } else if (!strcmp(arg, "-uv")) { + uvEvaluate = true; + } else if (!strcmp(arg, "-nouv")) { + uvEvaluate = false; + } else if (!strcmp(arg, "-ptex")) { + ptexConvert = true; + } else if (!strcmp(arg, "-noptex")) { + ptexConvert = false; + + // Options affecting what gets compared and reported: + } else if (!strcmp(arg, "-skippos")) { + posIgnore = true; + } else if (!strcmp(arg, "-skipd1")) { + d1Ignore = true; + } else if (!strcmp(arg, "-skipd2")) { + d2Ignore = true; + } else if (!strcmp(arg, "-skipuv")) { + uvIgnore = true; + } else if (!strcmp(arg, "-faces")) { + printFaceDiffs = true; + + // Options affecting comparison tolerances: + } else if (!strcmp(argv[i], "-reltol")) { + if (++i < argc) relTolerance = (float)atof(argv[i]); + } else if (!strcmp(argv[i], "-abstol")) { + if (++i < argc) absTolerance = (float)atof(argv[i]); + } else if (!strcmp(argv[i], "-uvtol")) { + if (++i < argc) uvTolerance = (float)atof(argv[i]); + + // Options controlling other internal processing: + } else if (!strcmp(arg, "-stencils")) { + evalByStencils = true; + } else if (!strcmp(arg, "-double")) { + doublePrecision = true; + } else if (!strcmp(arg, "-nocache")) { + noCacheFlag = true; + + // Options affecting the shapes to be included: + } else if (!strcmp(arg, "-bilinear")) { + shapeScheme = kBilinear; + } else if (!strcmp(arg, "-catmark")) { + shapeScheme = kCatmark; + } else if (!strcmp(arg, "-loop")) { + shapeScheme = kLoop; + } else if (!strcmp(arg, "-cat2loop")) { + shapesCat2Loop = true; + } else if (!strcmp(arg, "-count")) { + if (++i < argc) shapeCount = atoi(argv[i]); + } else if (!strcmp(arg, "-shape")) { + if (++i < argc) { + shapeNames.push_back(std::string(argv[i])); + } + } else if (!strcmp(arg, "-all")) { + shapesAll = true; + + // Printing and reporting: + } else if (!strcmp(arg, "-args")) { + printArgs = true; + } else if (!strcmp(arg, "-noargs")) { + printArgs = false; + } else if (!strcmp(arg, "-prog")) { + printProgress = true; + } else if (!strcmp(arg, "-noprog")) { + printProgress = false; + } else if (!strcmp(arg, "-sum")) { + printSummary = true; + } else if (!strcmp(arg, "-nosum")) { + printSummary = false; + } else if (!strcmp(arg, "-quiet")) { + printWarnings = false; + } else if (!strcmp(arg, "-silent")) { + printArgs = false; + printProgress = false; + printSummary = false; + printWarnings = false; + + // Success/failure of the entire test: + } else if (!strcmp(argv[i], "-pass")) { + if (++i < argc) passCount = atoi(argv[i]); + + // Unrecognized... + } else { + fprintf(stderr, "Error: Unrecognized argument '%s'\n", arg); + exit(0); + } + } + + // Validation -- possible conflicting options, values, etc. + if (bndInterp > 2) { + fprintf(stderr, "Warning: Ignoring bad value to -bint (%d)\n", + bndInterp); + bndInterp = -1; + } + if (uvInterp > 5) { + fprintf(stderr, "Warning: Ignoring bad value to -uvint (%d)\n", + uvInterp); + uvInterp = -1; + } + + if (d2Evaluate) { + if (!d1Evaluate) { + fprintf(stderr, "Warning: 2nd deriv evaluation forces 1st.\n"); + d1Evaluate = true; + } + if (!posEvaluate) { + fprintf(stderr, "Warning: 2nd deriv evaluation forces pos.\n"); + posEvaluate = true; + } + } else if (d1Evaluate) { + if (!posEvaluate) { + fprintf(stderr, "Warning: 1st deriv evaluation forces pos.\n"); + posEvaluate = true; + } + } + if (!posEvaluate && !uvEvaluate) { + fprintf(stderr, "Error: All pos and UV evaluation disabled.\n"); + exit(0); + } + if (posIgnore && d1Ignore && d2Ignore && uvIgnore) { + fprintf(stderr, "Error: All pos and UV comparisons disabled.\n"); + exit(0); + } + + if ((depthSmooth == 0) || (depthSharp == 0)) { + fprintf(stderr, + "Warning: Far evaluation unstable with refinement level 0.\n"); + } + + // Managing the list of shapes: + assert(g_shapes.empty()); + if (!shapeNames.empty()) { + if (shapesAll) { + initShapesAll(g_shapes); + } else { + initShapes(g_shapes); + } + // Maybe worth building a map -- for this and more... + for (size_t i = 0; i < shapeNames.size(); ++i) { + std::string & shapeName = shapeNames[i]; + bool found = false; + for (size_t j = 0; !found && (j < g_shapes.size()); ++j) { + if (g_shapes[j].name == shapeName) { + shapes.push_back(g_shapes[j]); + found = true; + break; + } + } + if (!found) { + fprintf(stderr, + "Error: Specified shape '%s' not found.\n", + shapeName.c_str()); + exit(0); + } + } + } + } + ~Args() { } + + void + Print() const { + + char const * boolStrings[2] = { "false", "true" }; + char const * bIntStrings[3] = { "BOUNDARY_NONE", + "BOUNDARY_EDGE_ONLY", + "BOUNDARY_EDGE_AND_CORNER" }; + char const * fvIntStrings[6] = { "LINEAR_NONE", + "LINEAR_CORNERS_ONLY", + "LINEAR_CORNERS_PLUS1", + "LINEAR_CORNERS_PLUS2", + "LINEAR_BOUNDARIES", + "LINEAR_ALL" }; + + printf("\n"); + printf("Shape options:\n"); + if (depthSharp >= 0) { + printf(" - max level sharp = %d\n", depthSharp); + } else { + printf(" - max level sharp = %d (dflt)\n", + (Bfr::SurfaceFactory::Options()).GetApproxLevelSharp()); + } + if (depthSmooth >= 0) { + printf(" - max level smooth = %d\n", depthSmooth); + } else { + printf(" - max level smooth = %d (dflt)\n", + (Bfr::SurfaceFactory::Options()).GetApproxLevelSmooth()); + } + if (bndInterp < 0) { + printf(" - boundary interp = (as assigned)\n"); + } else { + printf(" - boundary interp = %s\n", bIntStrings[bndInterp]); + } + if (uvEvaluate) { + if (uvInterp < 0) { + printf(" - UV linear interp = (as assigned)\n"); + } else { + printf(" - UV linear interp = %s\n", fvIntStrings[uvInterp]); + } + } + + printf("Evaluation options:\n"); + printf(" - tessellation res = %d\n", uniformRes); + printf(" - position = %s\n", boolStrings[posEvaluate]); + printf(" - 1st derivative = %s\n", boolStrings[d1Evaluate]); + printf(" - 2nd derivative = %s\n", boolStrings[d2Evaluate]); + printf(" - UV = %s\n", boolStrings[uvEvaluate]); + + printf("Comparison options:\n"); + if (absTolerance > 0.0f) { + printf(" - tolerance (abs) = %g\n", absTolerance); + } else { + printf(" - tolerance (rel) = %g\n", relTolerance); + } + if (uvEvaluate) { + printf(" - tolerance UV = %g\n", uvTolerance); + } + if (posEvaluate && posIgnore) { + printf(" - ignore pos = %s\n", boolStrings[posIgnore]); + } + if (d1Evaluate && d1Ignore) { + printf(" - ignore 1st deriv = %s\n", boolStrings[d1Ignore]); + } + if (d2Evaluate && d2Ignore) { + printf(" - ignore 2nd deriv = %s\n", boolStrings[d2Ignore]); + } + if (uvEvaluate && uvIgnore) { + printf(" - ignore UV = %s\n", boolStrings[uvIgnore]); + } + printf("\n"); + } + +private: + Args() { } + + bool + readString(const char *fileName, std::string& fileString) { + std::ifstream ifs(fileName); + if (ifs) { + std::stringstream ss; + ss << ifs.rdbuf(); + ifs.close(); + + fileString = ss.str(); + return true; + } + return false; + } +}; + + +// +// Create a TopologyRefiner from a Shape: +// +template +Far::TopologyRefiner * +createTopologyRefiner(ShapeDesc const & shapeDesc, + std::vector< Vec3 > & shapePos, + std::vector< Vec3 > & shapeUVs, + Args const & args) { + + typedef Vec3 Vec3Real; + + // + // Load the Shape -- skip with a warning on failure: + // + Shape * shape = Shape::parseObj(shapeDesc.data.c_str(), + shapeDesc.scheme, + shapeDesc.isLeftHanded); + if (shape == 0) { + if (args.printWarnings) { + fprintf(stderr, "Warning: Failed to parse shape '%s'\n", + shapeDesc.name.c_str()); + } + return 0; + } + + // Verify UVs before continuing: + if (args.uvEvaluate) { + if (shape->uvs.empty() != shape->faceuvs.empty()) { + if (args.printWarnings) { + fprintf(stderr, + "Warning: Incomplete UVs assigned to Shape '%s'\n", + shapeDesc.name.c_str()); + } + delete shape; + return 0; + } + } + + // + // Create a TopologyRefiner and load position and UVs: + // + Sdc::SchemeType sdcType = GetSdcType(*shape); + + if (args.shapesCat2Loop && (sdcType == Sdc::SCHEME_LOOP)) { + if (args.printWarnings) { + fprintf(stderr, + "\t\tWarning: Applying Catmark to Loop shape '%s'\n", + shapeDesc.name.c_str()); + } + sdcType = Sdc::SCHEME_CATMARK; + } + + Sdc::Options sdcOptions = GetSdcOptions(*shape); + if (args.bndInterp >= 0) { + sdcOptions.SetVtxBoundaryInterpolation( + (Sdc::Options::VtxBoundaryInterpolation) args.bndInterp); + } + if (args.uvInterp >= 0) { + sdcOptions.SetFVarLinearInterpolation( + (Sdc::Options::FVarLinearInterpolation) args.uvInterp); + } + + Far::TopologyRefiner * refiner = + Far::TopologyRefinerFactory::Create(*shape, + Far::TopologyRefinerFactory::Options(sdcType, sdcOptions)); + + if (refiner == 0) { + if (args.printWarnings) { + fprintf(stderr, "Warning: Unable to interpret Shape '%s'\n", + shapeDesc.name.c_str()); + } + delete shape; + return 0; + } + + int numVertices = refiner->GetNumVerticesTotal(); + shapePos.resize(numVertices); + for (int i = 0; i < numVertices; ++i) { + shapePos[i] = Vec3Real(shape->verts[i*3], + shape->verts[i*3+1], + shape->verts[i*3+2]); + } + + shapeUVs.resize(0); + if (args.uvEvaluate) { + if (refiner->GetNumFVarChannels()) { + int numUVs = refiner->GetNumFVarValuesTotal(0); + shapeUVs.resize(numUVs); + for (int i = 0; i < numUVs; ++i) { + shapeUVs[i] = Vec3Real(shape->uvs[i*2], + shape->uvs[i*2+1], + 0.0f); + } + } + } + + delete shape; + return refiner; +} + + +// +// Compute the bounding box of a Vec3 vector and a relative tolerance: +// +template +REAL +GetRelativeTolerance(std::vector< Vec3 > const & p, REAL fraction) { + + Vec3 pMin = p[0]; + Vec3 pMax = p[0]; + + for (size_t i = 1; i < p.size(); ++i) { + Vec3 const & pi = p[i]; + + pMin[0] = std::min(pMin[0], pi[0]); + pMin[1] = std::min(pMin[1], pi[1]); + pMin[2] = std::min(pMin[2], pi[2]); + + pMax[0] = std::max(pMax[0], pi[0]); + pMax[1] = std::max(pMax[1], pi[1]); + pMax[2] = std::max(pMax[2], pi[2]); + } + + Vec3 pDelta = pMax - pMin; + + REAL maxSize = std::max(std::abs(pDelta[0]), std::abs(pDelta[1])); + maxSize = std::max(maxSize, std::abs(pDelta[2])); + + return fraction * maxSize; +} + + +// +// An independent test from limit surface evaluation: comparing the +// conversion of (u,v) coordinates for Bfr::Parameterization to Ptex +// and back (subject to a given tolerance): +// +template +void +ValidatePtexConversion(Bfr::Parameterization const & param, + REAL const givenCoord[2], REAL tol = 0.0001f) { + + if (!param.HasSubFaces()) return; + + // + // Convert the given (u,v) coordinate to Ptex and back and + // compare the final result to the original: + // + REAL ptexCoord[2]; + REAL finalCoord[2]; + + int ptexFace = param.ConvertCoordToNormalizedSubFace(givenCoord, ptexCoord); + param.ConvertNormalizedSubFaceToCoord(ptexFace, ptexCoord, finalCoord); + + bool subFaceDiff = (ptexFace != param.GetSubFace(givenCoord)); + bool uCoordDiff = (std::abs(finalCoord[0] - givenCoord[0]) > tol); + bool vCoordDiff = (std::abs(finalCoord[1] - givenCoord[1]) > tol); + + if (subFaceDiff || uCoordDiff || vCoordDiff) { + fprintf(stderr, + "Warning: Mismatch in sub-face Parameterization conversion:\n"); + if (subFaceDiff ) { + fprintf(stderr, + " converted sub-face (%d) != original (%d)\n", + ptexFace, param.GetSubFace(givenCoord)); + } + if (uCoordDiff || vCoordDiff) { + fprintf(stderr, + " converted coord (%f,%f) != original (%f,%f)\n", + finalCoord[0], finalCoord[1], givenCoord[0], givenCoord[1]); + } + } +} + + +// +// Compare two meshes using Bfr::Surfaces and a Far::PatchTable: +// +template +int +testMesh(Far::TopologyRefiner const & mesh, + std::string const & meshName, + std::vector< Vec3 > const & meshPos, + std::vector< Vec3 > const & meshUVs, + Args const & args) { + + // + // Determine what to evaluate/compare based on args and mesh content + // (remember that these are not completely independent -- position + // evaluation will have been set if evaluating any derivatives): + // + bool evalPos = args.posEvaluate; + bool evalD1 = args.d1Evaluate; + bool evalD2 = args.d2Evaluate; + bool evalUV = args.uvEvaluate && (meshUVs.size() > 0); + + bool comparePos = evalPos && !args.posIgnore; + bool compareD1 = evalD1 && !args.d1Ignore; + bool compareD2 = evalD2 && !args.d2Ignore; + bool compareUV = evalUV && !args.uvIgnore; + + // If nothing to compare, return 0 failures: + if ((comparePos + compareD1 + compareD2 + compareUV) == 0) { + return 0; + } + + // Declare/allocate output evaluation buffers for both Bfr and Far: + std::vector evalCoords; + + EvalResults bfrResults; + bfrResults.evalPosition = evalPos; + bfrResults.eval1stDeriv = evalD1; + bfrResults.eval2ndDeriv = evalD2; + bfrResults.evalUV = evalUV; + bfrResults.useStencils = args.evalByStencils; + + EvalResults farResults; + farResults.evalPosition = evalPos; + farResults.eval1stDeriv = evalD1; + farResults.eval2ndDeriv = evalD2; + farResults.evalUV = evalUV; + + // + // Create evaluators for Bfr and Far -- using the same set of Bfr + // options to ensure consistency (the Far evaluator needs to interpret + // them appropriate to Far::PatchTable and associated refinement) + // + Bfr::SurfaceFactory::Options surfaceOptions; + + // Leave approximation defaults in place unless explicitly overridden: + if (args.depthSharp >= 0) { + surfaceOptions.SetApproxLevelSharp(args.depthSharp); + } + if (args.depthSmooth >= 0) { + surfaceOptions.SetApproxLevelSmooth(args.depthSmooth); + } + surfaceOptions.SetDefaultFVarID(0); + surfaceOptions.EnableCaching(!args.noCacheFlag); + + BfrSurfaceEvaluator bfrEval(mesh, meshPos, meshUVs, surfaceOptions); + FarPatchEvaluator farEval(mesh, meshPos, meshUVs, surfaceOptions); + + // + // Initialize tolerances and variables to track differences: + // + REAL pTol = (args.absTolerance > 0.0f) ? args.absTolerance : + GetRelativeTolerance(meshPos, args.relTolerance); + REAL d1Tol = pTol * 5.0f; + REAL d2Tol = d1Tol * 5.0f; + REAL uvTol = args.uvTolerance; + + VectorDelta pDelta(pTol); + VectorDelta duDelta(d1Tol); + VectorDelta dvDelta(d1Tol); + VectorDelta duuDelta(d2Tol); + VectorDelta duvDelta(d2Tol); + VectorDelta dvvDelta(d2Tol); + VectorDelta uvDelta(uvTol); + + FaceDelta faceDelta; + + MeshDelta meshDelta; + + bool meshHasBeenLabeled = false; + + int numFaces = mesh.GetNumFacesTotal(); + for (int faceIndex = 0; faceIndex < numFaces; ++faceIndex) { + // + // Make sure both match in terms of identifying a limit surface: + // + assert(bfrEval.FaceHasLimit(faceIndex) == + farEval.FaceHasLimit(faceIndex)); + + if (!farEval.FaceHasLimit(faceIndex)) continue; + + // + // Declare/define a Tessellation to generate a consistent set of + // (u,v) locations to compare and evaluate: + // + int faceSize = mesh.GetLevel(0).GetFaceVertices(faceIndex).size(); + + Bfr::Parameterization faceParam(mesh.GetSchemeType(), faceSize); + assert(faceParam.IsValid()); + + Bfr::Tessellation faceTess(faceParam, args.uniformRes); + assert(faceTess.IsValid()); + + evalCoords.resize(2 * faceTess.GetNumCoords()); + faceTess.GetCoords(&evalCoords[0]); + + // + // Before evaluating and comparing, run the test to convert the + // parametric coords to Ptex and back: + // + if (args.ptexConvert) { + for (int i = 0; i < faceTess.GetNumCoords(); ++i) { + ValidatePtexConversion(faceParam, &evalCoords[2*i]); + } + } + + // + // Evaluate and capture results of comparisons between results: + // + bfrEval.Evaluate(faceIndex, evalCoords, bfrResults); + farEval.Evaluate(faceIndex, evalCoords, farResults); + + if (comparePos) { + pDelta.Compare(bfrResults.p, farResults.p); + } + if (compareD1) { + duDelta.Compare(bfrResults.du, farResults.du); + dvDelta.Compare(bfrResults.dv, farResults.dv); + } + if (compareD2) { + duuDelta.Compare(bfrResults.duu, farResults.duu); + duvDelta.Compare(bfrResults.duv, farResults.duv); + dvvDelta.Compare(bfrResults.dvv, farResults.dvv); + } + if (compareUV) { + uvDelta.Compare(bfrResults.uv, farResults.uv); + } + + // + // Note collective differences for this face and report: + // + faceDelta.Clear(); + faceDelta.AddPDelta(pDelta); + faceDelta.AddDuDelta(duDelta); + faceDelta.AddDvDelta(dvDelta); + faceDelta.AddDuuDelta(duuDelta); + faceDelta.AddDuvDelta(duvDelta); + faceDelta.AddDvvDelta(dvvDelta); + faceDelta.AddUVDelta(uvDelta); + + if (args.printFaceDiffs && faceDelta.hasDeltas) { + if (!meshHasBeenLabeled) { + meshHasBeenLabeled = true; + printf("'%s':\n", meshName.c_str()); + } + printf("\t Face %d:\n", faceIndex); + + if (comparePos && faceDelta.numPDeltas) { + printf("\t\t POS:%6d diffs, max delta P = %g\n", + faceDelta.numPDeltas, (float) faceDelta.maxPDelta); + } + if (compareD1 && faceDelta.numD1Deltas) { + printf("\t\t D1:%6d diffs, max delta D1 = %g\n", + faceDelta.numD1Deltas, (float) faceDelta.maxD1Delta); + } + if (compareD2 && faceDelta.numD2Deltas) { + printf("\t\t D2:%6d diffs, max delta D2 = %g\n", + faceDelta.numD2Deltas, (float) faceDelta.maxD2Delta); + } + if (compareUV && faceDelta.hasUVDeltas) { + printf("\t\t UV:%6d diffs, max delta UV = %g\n", + uvDelta.numDeltas, (float) uvDelta.maxDelta); + } + } + + // Add the results for this face to the collective mesh delta: + meshDelta.AddFace(faceDelta); + } + + // + // Report the differences for this mesh: + // + if (meshDelta.numFacesWithDeltas) { + if (args.printFaceDiffs) { + printf("\t Total:\n"); + } else { + printf("'%s':\n", meshName.c_str()); + } + } + + if (comparePos && meshDelta.numFacesWithPDeltas) { + printf("\t\tPOS diffs:%6d faces, max delta P = %g\n", + meshDelta.numFacesWithPDeltas, (float) meshDelta.maxPDelta); + } + if (compareD1 && meshDelta.numFacesWithD1Deltas) { + printf("\t\t D1 diffs:%6d faces, max delta D1 = %g\n", + meshDelta.numFacesWithD1Deltas, (float) meshDelta.maxD1Delta); + } + if (compareD2 && meshDelta.numFacesWithD2Deltas) { + printf("\t\t D2 diffs:%6d faces, max delta D2 = %g\n", + meshDelta.numFacesWithD2Deltas, (float) meshDelta.maxD2Delta); + } + if (compareUV && meshDelta.numFacesWithUVDeltas) { + printf("\t\t UV diffs:%6d faces, max delta UV = %g\n", + meshDelta.numFacesWithUVDeltas, (float) meshDelta.maxUVDelta); + } + return meshDelta.numFacesWithDeltas; +} + + +// +// Run the comparison for a given Shape in single or double precision: +// +template +int +testShape(ShapeDesc const & shapeDesc, Args const & args) { + + // + // Get the TopologyRefiner, positions and UVs for the Shape, report + // failure to generate the shape, and run the test: + // + std::string const & meshName = shapeDesc.name; + + std::vector< Vec3 > basePos; + std::vector< Vec3 > baseUV; + + Far::TopologyRefiner * refiner = + createTopologyRefiner(shapeDesc, basePos, baseUV, args); + + if (refiner == 0) { + if (args.printWarnings) { + fprintf(stderr, + "Warning: Shape '%s' ignored (unable to construct refiner)\n", + meshName.c_str()); + } + return -1; + } + + int nFailures = testMesh(*refiner, meshName, basePos, baseUV, args); + + delete refiner; + + return nFailures; +} + + +// +// Run comparison tests on a list of shapes using command line options: +// +int +main(int argc, char **argv) { + + Args args(argc, argv); + + // Capture relevant command line options used here: + if (args.printArgs) { + args.Print(); + } + + // + // Initialize the list of shapes and test each (or only the first): + // + // - currently the internal list can be overridden on the command + // line (so use of wildcards is possible) + // + // - still exploring additional command line options, e.g. hoping + // to specify a list of shape names from the internal list... + // + // So a bit more to be done here... + // + std::vector& shapeList = g_shapes; + + if (!args.shapes.empty()) { + shapeList.swap(args.shapes); + } + if (shapeList.empty()) { + if (args.shapesAll) { + initShapesAll(shapeList); + } else { + initShapes(shapeList); + } + } + + int shapesToTest = (int) shapeList.size(); + int shapesIgnored = 0; + if ((args.shapeCount > 0) && (args.shapeCount < shapesToTest)) { + shapesIgnored = shapesToTest - args.shapeCount; + shapesToTest = args.shapeCount; + } + + if (args.printProgress) { + printf("Testing %d shapes", shapesToTest); + if (shapesIgnored) { + printf(" (%d ignored)", shapesIgnored); + } + printf(":\n"); + } + + // + // Run the comparison test for each shape (ShapeDesc) in the + // specified precision and report results: + // + int shapesFailed = 0; + + for (int shapeIndex = 0; shapeIndex < shapesToTest; ++shapeIndex) { + ShapeDesc & shapeDesc = shapeList[shapeIndex]; + + if (args.printProgress) { + printf("%4d of %d: '%s'\n", 1 + shapeIndex, shapesToTest, + shapeDesc.name.c_str()); + } + + int nFailures = args.doublePrecision ? + testShape(shapeDesc, args) : + testShape(shapeDesc, args); + + if (nFailures < 0) { + // Possible error/warning...? + ++ shapesFailed; + } + if (nFailures > 0) { + ++ shapesFailed; + } + } + + if (args.printSummary) { + printf("\n"); + if (shapesFailed == 0) { + printf("All tests passed for %d shapes\n", shapesToTest); + } else { + printf("Total failures: %d of %d shapes\n", shapesFailed, + shapesToTest); + } + } + + return (shapesFailed == args.passCount) ? EXIT_SUCCESS : EXIT_FAILURE; +} diff --git a/regression/bfr_evaluate/types.h b/regression/bfr_evaluate/types.h new file mode 100644 index 00000000..63fb5c29 --- /dev/null +++ b/regression/bfr_evaluate/types.h @@ -0,0 +1,313 @@ +// +// Copyright 2021 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. +// +#ifndef OPENSUBDIV3_REGRESSION_BFR_EVALUATE_TYPES_H +#define OPENSUBDIV3_REGRESSION_BFR_EVALUATE_TYPES_H + +#include +#include +#include +#include +#include + +// +// Simple interpolatable struct for (x,y,z) positions and normals: +// +template +struct Vec3 { + Vec3() { } + Vec3(REAL x, REAL y, REAL z) { p[0] = x, p[1] = y, p[2] = z; } + + // Clear() and AddWithWeight() required for interpolation: + void Clear( void * =0 ) { p[0] = p[1] = p[2] = 0.0f; } + + void AddWithWeight(Vec3 const & src, REAL weight) { + p[0] += weight * src.p[0]; + p[1] += weight * src.p[1]; + p[2] += weight * src.p[2]; + } + + // Element access via []: + REAL const & operator[](int i) const { return p[i]; } + REAL & operator[](int i) { return p[i]; } + + // Element access via []: + REAL const * Coords() const { return p; } + REAL * Coords() { return p; } + + // Additional useful mathematical operations: + Vec3 operator-(Vec3 const & x) const { + return Vec3(p[0] - x.p[0], p[1] - x.p[1], p[2] - x.p[2]); + } + Vec3 operator+(Vec3 const & x) const { + return Vec3(p[0] + x.p[0], p[1] + x.p[1], p[2] + x.p[2]); + } + Vec3 operator*(REAL s) const { + return Vec3(p[0] * s, p[1] * s, p[2] * s); + } + Vec3 Cross(Vec3 const & x) const { + return Vec3(p[1]*x.p[2] - p[2]*x.p[1], + p[2]*x.p[0] - p[0]*x.p[2], + p[0]*x.p[1] - p[1]*x.p[0]); + } + REAL Dot(Vec3 const & x) const { + return p[0]*x.p[0] + p[1]*x.p[1] + p[2]*x.p[2]; + } + REAL Length() const { + return std::sqrt(this->Dot(*this)); + } + + // Static method to compute normal vector: + static + Vec3 ComputeNormal(Vec3 const & Du, Vec3 const & Dv, + REAL eps = 0.0f) { + Vec3 N = Du.Cross(Dv); + REAL lenSqrd = N.Dot(N); + if (lenSqrd <= eps) return Vec3(0.0f, 0.0f, 0.0f); + return N * (1.0f / std::sqrt(lenSqrd)); + } + + // Member variables (XYZ coordinates): + REAL p[3]; +}; + +typedef Vec3 Vec3f; +typedef Vec3 Vec3d; + + +// +// Simple struct to hold the results of a face evaluation: +// +template +struct EvalResults { + EvalResults() : evalPosition(true), + eval1stDeriv(true), + eval2ndDeriv(false), + evalUV(false), + useStencils(false) { } + + bool evalPosition; + bool eval1stDeriv; + bool eval2ndDeriv; + bool evalUV; + bool useStencils; + + std::vector< Vec3 > p; + std::vector< Vec3 > du; + std::vector< Vec3 > dv; + std::vector< Vec3 > duu; + std::vector< Vec3 > duv; + std::vector< Vec3 > dvv; + + std::vector< Vec3 > uv; + + void Resize(int size) { + if (evalPosition) { + p.resize(size); + if (eval1stDeriv) { + du.resize(size); + dv.resize(size); + if (eval2ndDeriv) { + duu.resize(size); + duv.resize(size); + dvv.resize(size); + } + } + } + if (evalUV) { + uv.resize(size); + } + } +}; + + +// +// Simple struct to hold the differences between two vectors: +// +template +class VectorDelta { +public: + typedef std::vector< Vec3 > VectorVec3; + +public: + // Member variables: + std::vector< Vec3 > const * vectorA; + std::vector< Vec3 > const * vectorB; + + int numDeltas; + REAL maxDelta; + REAL tolerance; + +public: + VectorDelta(REAL epsilon = 0.0f) : + vectorA(0), vectorB(0), + numDeltas(0), maxDelta(0.0f), + tolerance(epsilon) { } + + void + Compare(VectorVec3 const & a, VectorVec3 const & b) { + + assert(a.size() == b.size()); + + vectorA = &a; + vectorB = &b; + + numDeltas = 0; + maxDelta = 0.0f; + + for (size_t i = 0; i < a.size(); ++i) { + REAL const * ai = a[i].Coords(); + REAL const * bi = b[i].Coords(); + + REAL dx = std::abs(ai[0] - bi[0]); + REAL dy = std::abs(ai[1] - bi[1]); + REAL dz = std::abs(ai[2] - bi[2]); + if ((dx > tolerance) || (dy > tolerance) || (dz > tolerance)) { + ++ numDeltas; + + if (maxDelta < dx) maxDelta = dx; + if (maxDelta < dy) maxDelta = dy; + if (maxDelta < dz) maxDelta = dz; + } + } + } +}; + +template +class FaceDelta { +public: + // Member variables: + bool hasDeltas; + bool hasGeomDeltas; + bool hasUVDeltas; + + int numPDeltas; + int numD1Deltas; + int numD2Deltas; + int numUVDeltas; + + REAL maxPDelta; + REAL maxD1Delta; + REAL maxD2Delta; + REAL maxUVDelta; + +public: + FaceDelta() { Clear(); } + + void Clear() { + std::memset(this, 0, sizeof(*this)); + } + + void AddPDelta(VectorDelta const & pDelta) { + if (pDelta.numDeltas) { + numPDeltas = pDelta.numDeltas; + maxPDelta = pDelta.maxDelta; + hasDeltas = hasGeomDeltas = true; + } + } + void AddDuDelta(VectorDelta const & duDelta) { + if (duDelta.numDeltas) { + numD1Deltas += duDelta.numDeltas; + maxD1Delta = std::max(maxD1Delta, duDelta.maxDelta); + hasDeltas = hasGeomDeltas = true; + } + } + void AddDvDelta(VectorDelta const & dvDelta) { + if (dvDelta.numDeltas) { + numD1Deltas += dvDelta.numDeltas; + maxD1Delta = std::max(maxD1Delta, dvDelta.maxDelta); + hasDeltas = hasGeomDeltas = true; + } + } + void AddDuuDelta(VectorDelta const & duuDelta) { + if (duuDelta.numDeltas) { + numD2Deltas += duuDelta.numDeltas; + maxD2Delta = std::max(maxD2Delta, duuDelta.maxDelta); + hasDeltas = hasGeomDeltas = true; + } + } + void AddDuvDelta(VectorDelta const & duvDelta) { + if (duvDelta.numDeltas) { + numD2Deltas += duvDelta.numDeltas; + maxD2Delta = std::max(maxD2Delta, duvDelta.maxDelta); + hasDeltas = hasGeomDeltas = true; + } + } + void AddDvvDelta(VectorDelta const & dvvDelta) { + if (dvvDelta.numDeltas) { + numD2Deltas += dvvDelta.numDeltas; + maxD2Delta = std::max(maxD2Delta, dvvDelta.maxDelta); + hasDeltas = hasGeomDeltas = true; + } + } + void AddUVDelta(VectorDelta const & uvDelta) { + if (uvDelta.numDeltas) { + numUVDeltas = uvDelta.numDeltas; + maxUVDelta = uvDelta.maxDelta; + hasDeltas = hasUVDeltas = true; + } + } +}; + +template +class MeshDelta { +public: + // Member variables: + int numFacesWithDeltas; + int numFacesWithGeomDeltas; + int numFacesWithUVDeltas; + + int numFacesWithPDeltas; + int numFacesWithD1Deltas; + int numFacesWithD2Deltas; + + REAL maxPDelta; + REAL maxD1Delta; + REAL maxD2Delta; + REAL maxUVDelta; + +public: + MeshDelta() { Clear(); } + + void Clear() { + std::memset(this, 0, sizeof(*this)); + } + + void AddFace(FaceDelta const & faceDelta) { + + numFacesWithDeltas += faceDelta.hasDeltas; + numFacesWithGeomDeltas += faceDelta.hasGeomDeltas; + numFacesWithUVDeltas += faceDelta.hasUVDeltas; + + numFacesWithPDeltas += (faceDelta.numPDeltas > 0); + numFacesWithD1Deltas += (faceDelta.numD1Deltas > 0); + numFacesWithD2Deltas += (faceDelta.numD2Deltas > 0); + + maxPDelta = std::max(maxPDelta, faceDelta.maxPDelta); + maxD1Delta = std::max(maxD1Delta, faceDelta.maxD1Delta); + maxD2Delta = std::max(maxD2Delta, faceDelta.maxD2Delta); + maxUVDelta = std::max(maxUVDelta, faceDelta.maxUVDelta); + } +}; + +#endif /* OPENSUBDIV3_REGRESSION_BFR_EVALUATE_TYPES_H */ diff --git a/regression/shapes/all.h b/regression/shapes/all.h index 2161cb79..89c69b3c 100644 --- a/regression/shapes/all.h +++ b/regression/shapes/all.h @@ -106,6 +106,9 @@ #include "catmark_torus_creases0.h" #include "catmark_torus_creases1.h" #include "catmark_val2_interior.h" +#include "catmark_val2_back2back.h" +#include "catmark_val2_foldover.h" +#include "catmark_val2_nonman.h" #include "catmark_xord_interior.h" #include "catmark_xord_boundary.h" @@ -144,5 +147,6 @@ #include "loop_triangle_edgeonly.h" #include "loop_xord_boundary.h" #include "loop_xord_interior.h" +#include "loop_val2_interior.h" #endif // OPENSUBDIV_REGRESSION_SHAPES_ALL_H diff --git a/regression/shapes/catmark_val2_back2back.h b/regression/shapes/catmark_val2_back2back.h new file mode 100644 index 00000000..74810713 --- /dev/null +++ b/regression/shapes/catmark_val2_back2back.h @@ -0,0 +1,98 @@ +// +// Copyright 2022 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. +// + +static const std::string catmark_val2_back2back = +"#\n" +"# Four shapes ordered left->right and top->bottom in the XZ plane\n" +"#\n" +"# Shape 1: top-left\n" +"#\n" +"v -0.90 0 0.10\n" +"v -0.10 0 0.10\n" +"v -0.50 0 0.90\n" +"\n" +"vt -0.90 0.10\n" +"vt -0.10 0.10\n" +"vt -0.50 0.90\n" +"\n" +"f 1/1 2/2 3/3\n" +"f 3/3 2/2 1/1\n" +"\n" +"#\n" +"# Shape 2: top-right\n" +"#\n" +"v 0.10 0 0.10\n" +"v 0.90 0 0.10\n" +"v 0.90 0 0.90\n" +"v 0.10 0 0.90\n" +"\n" +"vt 0.10 0.10\n" +"vt 0.90 0.10\n" +"vt 0.90 0.90\n" +"vt 0.10 0.90\n" +"\n" +"f 4/4 5/5 6/6 7/7\n" +"f 7/7 6/6 5/5 4/4\n" +"\n" +"#\n" +"# Shape 3: bottom-left\n" +"#\n" +"v -0.70 0 -0.90\n" +"v -0.30 0 -0.90\n" +"v -0.10 0 -0.50\n" +"v -0.50 0 -0.10\n" +"v -0.90 0 -0.50\n" +"\n" +"vt -0.70 -0.90\n" +"vt -0.30 -0.90\n" +"vt -0.10 -0.50\n" +"vt -0.50 -0.10\n" +"vt -0.90 -0.50\n" +"\n" +"f 8/8 9/9 10/10 11/11 12/12\n" +"f 12/12 11/11 10/10 9/9 8/8\n" +"\n" +"#\n" +"# Shape 4: bottom-right\n" +"#\n" +"v 0.30 0 -0.90\n" +"v 0.70 0 -0.90\n" +"v 0.90 0 -0.50\n" +"v 0.70 0 -0.10\n" +"v 0.30 0 -0.10\n" +"v 0.10 0 -0.50\n" +"\n" +"vt 0.30 -0.90\n" +"vt 0.70 -0.90\n" +"vt 0.90 -0.50\n" +"vt 0.70 -0.10\n" +"vt 0.30 -0.10\n" +"vt 0.10 -0.50\n" +"\n" +"f 13/13 14/14 15/15 16/16 17/17 18/18\n" +"f 18/18 17/17 16/16 15/15 14/14 13/13\n" +"\n" +"t interpolateboundary 1/0/0 1\n" +"\n" +; diff --git a/regression/shapes/catmark_val2_foldover.h b/regression/shapes/catmark_val2_foldover.h new file mode 100644 index 00000000..f531ed94 --- /dev/null +++ b/regression/shapes/catmark_val2_foldover.h @@ -0,0 +1,207 @@ +// +// Copyright 2022 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. +// + +static const std::string catmark_val2_foldover = +"#\n" +"# Nine shapes ordered left->right and top->bottom in the XZ plane\n" +"#\n" +"# Shape 1: top-left\n" +"#\n" +"v -1.4 0.0 0.6\n" +"v -0.6 0.0 0.6\n" +"v -0.6 0.0 1.4\n" +"v -1.4 0.0 1.4\n" +"\n" +"vt -1.4 0.6\n" +"vt -0.6 0.6\n" +"vt -0.6 1.4\n" +"vt -1.4 1.4\n" +"\n" +"f 1/1 2/2 3/3 4/4\n" +"f 1/1 4/4 3/3\n" +"f 1/1 3/3 2/2\n" +"\n" +"#\n" +"# Shape 2: top-middle\n" +"#\n" +"v -0.4 0.0 0.6\n" +"v 0.4 0.0 0.6\n" +"v 0.4 0.0 1.4\n" +"v -0.4 0.0 1.4\n" +"\n" +"vt -0.4 0.6\n" +"vt 0.4 0.6\n" +"vt 0.4 1.4\n" +"vt -0.4 1.4\n" +"\n" +"f 5/5 6/6 7/7 8/8\n" +"f 5/5 8/8 7/7\n" +"\n" +"#\n" +"# Shape 3: top-right\n" +"#\n" +"v 0.8 0.0 0.6\n" +"v 1.2 0.0 0.6\n" +"v 1.4 0.0 1.0\n" +"v 1.0 0.0 1.4\n" +"v 0.6 0.0 1.0\n" +"\n" +"vt 0.8 0.6\n" +"vt 1.2 0.6\n" +"vt 1.4 1.0\n" +"vt 1.0 1.4\n" +"vt 0.6 1.0\n" +"\n" +"f 9/9 10/10 11/11 12/12 13/13\n" +"f 12/12 11/11 10/10 9/9 \n" +"f 12/12 9/9 13/13\n" +"\n" +"#\n" +"# Shape 4: center-left\n" +"#\n" +"v -1.2 0.0 -0.4\n" +"v -0.8 0.0 -0.4\n" +"v -0.6 0.0 0.0\n" +"v -1.0 0.0 0.4\n" +"v -1.4 0.0 0.0\n" +"\n" +"vt -1.2 -0.4\n" +"vt -0.8 -0.4\n" +"vt -0.6 0.0\n" +"vt -1.0 0.4\n" +"vt -1.4 0.0\n" +"\n" +"f 14/14 15/15 16/16 17/17 18/18\n" +"f 17/17 16/16 15/15\n" +"f 17/17 15/15 14/14\n" +"f 17/17 14/14 18/18\n" +"\n" +"#\n" +"# Shape 5: center-middle\n" +"#\n" +"v -0.2 0.0 -0.4\n" +"v 0.2 0.0 -0.4\n" +"v 0.4 0.0 0.0\n" +"v 0.0 0.0 0.4\n" +"v -0.4 0.0 0.0\n" +"\n" +"vt -0.2 -0.4\n" +"vt 0.2 -0.4\n" +"vt 0.4 0.0\n" +"vt 0.0 0.4\n" +"vt -0.4 0.0\n" +"\n" +"f 19/19 20/20 21/21 22/22 23/23\n" +"f 22/22 19/19 23/23\n" +"\n" +"#\n" +"# Shape 6: center-right\n" +"#\n" +"v 0.8 0.0 -0.4\n" +"v 1.2 0.0 -0.4\n" +"v 1.4 0.0 0.0\n" +"v 1.2 0.0 0.4\n" +"v 0.8 0.0 0.4\n" +"v 0.6 0.0 0.0\n" +"\n" +"vt 0.8 -0.4\n" +"vt 1.2 -0.4\n" +"vt 1.4 0.0\n" +"vt 1.2 0.4\n" +"vt 0.8 0.4\n" +"vt 0.6 0.0\n" +"\n" +"f 24/24 25/25 26/26 27/27 28/28 29/29\n" +"f 29/29 28/28 27/27 26/26\n" +"f 29/29 26/26 25/25 24/24\n" +"\n" +"#\n" +"# Shape 7: bottom-left\n" +"#\n" +"v -1.2 0.0 -1.4\n" +"v -0.8 0.0 -1.4\n" +"v -0.6 0.0 -1.0\n" +"v -0.8 0.0 -0.6\n" +"v -1.2 0.0 -0.6\n" +"v -1.4 0.0 -1.0\n" +"\n" +"vt -1.2 -1.4\n" +"vt -0.8 -1.4\n" +"vt -0.6 -1.0\n" +"vt -0.8 -0.6\n" +"vt -1.2 -0.6\n" +"vt -1.4 -1.0\n" +"\n" +"f 30/30 31/31 32/32 33/33 34/34 35/35\n" +"f 35/35 34/34 33/33\n" +"f 35/35 33/33 32/32\n" +"f 35/35 32/32 31/31\n" +"f 35/35 31/31 30/30\n" +"\n" +"#\n" +"# Shape 8: bottom-middle\n" +"#\n" +"v -0.2 0.0 -1.4\n" +"v 0.2 0.0 -1.4\n" +"v 0.4 0.0 -1.0\n" +"v 0.2 0.0 -0.6\n" +"v -0.2 0.0 -0.6\n" +"v -0.4 0.0 -1.0\n" +"\n" +"vt -0.2 -1.4\n" +"vt 0.2 -1.4\n" +"vt 0.4 -1.0\n" +"vt 0.2 -0.6\n" +"vt -0.2 -0.6\n" +"vt -0.4 -1.0\n" +"\n" +"f 36/36 37/37 38/38 39/39 40/40 41/41\n" +"f 41/41 40/40 39/39\n" +"f 41/41 37/37 36/36\n" +"\n" +"#\n" +"# Shape 9: bottom-right\n" +"#\n" +"v 0.8 0.0 -1.4\n" +"v 1.2 0.0 -1.4\n" +"v 1.4 0.0 -1.0\n" +"v 1.2 0.0 -0.6\n" +"v 0.8 0.0 -0.6\n" +"v 0.6 0.0 -1.0\n" +"\n" +"vt 0.8 -1.4\n" +"vt 1.2 -1.4\n" +"vt 1.4 -1.0\n" +"vt 1.2 -0.6\n" +"vt 0.8 -0.6\n" +"vt 0.6 -1.0\n" +"\n" +"f 42/42 43/43 44/44 45/45 46/46 47/47\n" +"f 47/47 46/46 45/45\n" +"f 47/47 45/45 44/44 43/43\n" +"f 47/47 43/43 42/42\n" +"\n" +"t interpolateboundary 1/0/0 1\n" +"\n" +; diff --git a/regression/shapes/catmark_val2_interior.h b/regression/shapes/catmark_val2_interior.h index 23ac276f..cabe680f 100644 --- a/regression/shapes/catmark_val2_interior.h +++ b/regression/shapes/catmark_val2_interior.h @@ -46,23 +46,23 @@ static const std::string catmark_val2_interior = "v -1.42 0.0 1.42\n" "v -1.25 -0.5 1.25\n" "\n" -"vt -0.5 -0.5\n" -"vt -0.17 -0.5\n" -"vt 0.17 -0.5\n" -"vt 0.5 -0.5\n" -"vt 0.5 -0.17\n" -"vt 0.5 0.17\n" -"vt 0.5 0.5\n" -"vt 0.17 0.5\n" -"vt -0.17 0.5\n" -"vt -0.5 0.5\n" -"vt -0.5 0.17\n" -"vt -0.5 -0.17\n" -"vt -0.17 -0.17\n" -"vt 0.17 -0.17\n" -"vt 0.17 0.17\n" -"vt -0.17 0.17\n" -"vt 0.0 0.0 \n" +"vt -1.75 0.75\n" +"vt -1.42 0.75\n" +"vt -1.08 0.75\n" +"vt -0.75 0.75\n" +"vt -0.75 1.08\n" +"vt -0.75 1.42\n" +"vt -0.75 1.75\n" +"vt -1.08 1.75\n" +"vt -1.42 1.75\n" +"vt -1.75 1.75\n" +"vt -1.75 1.42\n" +"vt -1.75 1.08\n" +"vt -1.42 1.08\n" +"vt -1.08 1.08\n" +"vt -1.08 1.42\n" +"vt -1.42 1.42\n" +"vt -1.25 1.25\n" "\n" "f 1/1 2/2 13/13 12/12\n" "f 2/2 3/3 14/14 13/13\n" @@ -92,19 +92,19 @@ static const std::string catmark_val2_interior = "v 0.5 0.0 0.75\n" "v 0.5 0.0 1.0\n" "\n" -"vt 0 0\n" -"vt 0.25 0.25\n" -"vt -0.25 0.25\n" -"vt -0.25 -0.25\n" -"vt 0.25 -0.25\n" -"vt 0.5 0.5\n" -"vt -0.25 0.5\n" -"vt -0.5 0.5\n" -"vt -0.5 0.25\n" -"vt -0.5 -0.5\n" -"vt 0.25 -0.5\n" -"vt 0.5 -0.5\n" -"vt 0.5 -0.25\n" +"vt 0.0 1.25\n" +"vt 0.25 1.5\n" +"vt -0.25 1.5\n" +"vt -0.25 1.0\n" +"vt 0.25 1.0\n" +"vt 0.5 1.75\n" +"vt -0.25 1.75\n" +"vt -0.5 1.75\n" +"vt -0.5 1.5\n" +"vt -0.5 0.75\n" +"vt 0.25 0.75\n" +"vt 0.5 0.75\n" +"vt 0.5 1.0\n" "\n" "f 18/18 19/19 20/20 21/21\n" "f 18/18 21/21 22/22 19/19\n" @@ -132,19 +132,19 @@ static const std::string catmark_val2_interior = "v 1.75 0.0 0.75\n" "v 1.75 0.0 1.0 \n" "\n" -"vt 0 0\n" -"vt 0.25 0.25\n" -"vt -0.25 0.25\n" -"vt -0.25 -0.25\n" -"vt 0.25 -0.25\n" -"vt 0.5 0.5\n" -"vt -0.25 0.5\n" -"vt -0.5 0.5\n" -"vt -0.5 0.25\n" -"vt -0.5 -0.5\n" -"vt 0.25 -0.5\n" -"vt 0.5 -0.5\n" -"vt 0.5 -0.25\n" +"vt 1.25 1.25\n" +"vt 1.50 1.5 \n" +"vt 1.0 1.5 \n" +"vt 1.0 1.0 \n" +"vt 1.5 1.0 \n" +"vt 1.75 1.75\n" +"vt 1.0 1.75\n" +"vt 0.75 1.75\n" +"vt 0.75 1.5 \n" +"vt 0.75 0.75\n" +"vt 1.5 0.75\n" +"vt 1.75 0.75\n" +"vt 1.75 1.0 \n" "\n" "f 31/31 32/32 33/33 34/34\n" "f 31/31 34/34 35/35 32/32\n" @@ -164,74 +164,112 @@ static const std::string catmark_val2_interior = "# Shape 4: center-left\n" "#\n" "v -1.75 0.0 -0.5\n" +"v -1.42 0.0 -0.5\n" "v -1.08 0.0 -0.5\n" "v -0.75 0.0 -0.5\n" +"v -1.75 0.0 -0.17\n" "v -1.42 -0.5 -0.17\n" +"v -1.08 -0.5 -0.17\n" +"v -0.75 0.0 -0.17\n" "v -1.75 0.0 0.17\n" -"v -1.08 0.0 0.17\n" +"v -1.42 -0.5 0.17\n" +"v -1.08 -0.5 0.17\n" +"v -0.75 0.0 0.17\n" "v -1.75 0.0 0.5\n" +"v -1.42 0.0 0.5\n" +"v -1.08 0.0 0.5\n" "v -0.75 0.0 0.5\n" +"v -1.31 -0.5 -0.06\n" +"v -1.19 -0.5 0.06\n" "\n" "vt -1.75 -0.5\n" +"vt -1.42 -0.5\n" "vt -1.08 -0.5\n" "vt -0.75 -0.5\n" +"vt -1.75 -0.17\n" "vt -1.42 -0.17\n" +"vt -1.08 -0.17\n" +"vt -0.75 -0.17\n" "vt -1.75 0.17\n" +"vt -1.42 0.17\n" "vt -1.08 0.17\n" +"vt -0.75 0.17\n" "vt -1.75 0.5\n" +"vt -1.42 0.5\n" +"vt -1.08 0.5\n" "vt -0.75 0.5\n" +"vt -1.31 -0.06\n" +"vt -1.19 0.06\n" "\n" -"f 44/44 45/45 49/49 47/47\n" -"f 45/45 46/46 51/51 49/49\n" -"f 44/44 47/47 49/49 48/48\n" -"f 48/48 49/49 51/51 50/50\n" +"f 44/44 45/45 49/49 48/48\n" +"f 45/45 46/46 50/50 49/49\n" +"f 46/46 47/47 51/51 50/50\n" +"f 48/48 49/49 53/53 52/52\n" +"f 50/50 60/60 53/53 49/49\n" +"f 50/50 54/54 53/53 61/61\n" +"f 50/50 61/61 53/53 60/60\n" +"f 50/50 51/51 55/55 54/54\n" +"f 52/52 53/53 57/57 56/56\n" +"f 53/53 54/54 58/58 57/57\n" +"f 54/54 55/55 59/59 58/58\n" "\n" "#\n" "# Shape 5: center-middle\n" "#\n" -"v -0.5 0.0 -0.5\n" -"v 0.0 0.0 -0.5\n" -"v 0.5 0.0 -0.5\n" -"v -0.5 0.0 0.0\n" -"v 0.0 0.0 0.0\n" -"v 0.5 0.0 0.0\n" -"v -0.5 0.0 0.5\n" -"v 0.0 0.0 0.5\n" -"v 0.5 0.0 0.5\n" -"v -0.1 0.1 -0.1\n" +"v -0.5 0.0 -0.5\n" +"v 0.17 0.0 -0.5\n" +"v 0.5 0.0 -0.5\n" +"v -0.17 -0.5 -0.17\n" +"v -0.5 0.0 0.17\n" +"v 0.17 0.0 0.17\n" +"v -0.5 0.0 0.5\n" +"v 0.5 0.0 0.5\n" "\n" -"vt -0.5 -0.5\n" -"vt 0.0 -0.5\n" -"vt 0.5 -0.5\n" -"vt -0.5 0.0\n" -"vt 0.0 0.0\n" -"vt 0.5 0.0\n" -"vt -0.5 0.5\n" -"vt 0.0 0.5\n" -"vt 0.5 0.5\n" -"vt -0.1 -0.1\n" +"vt -0.5 -0.5\n" +"vt 0.17 -0.5\n" +"vt 0.5 -0.5\n" +"vt -0.17 -0.17\n" +"vt -0.5 0.17\n" +"vt 0.17 0.17\n" +"vt -0.5 0.5\n" +"vt 0.5 0.5\n" "\n" -"f 52/52 53/53 56/56 55/55\n" -"f 53/53 54/54 57/57 56/56\n" -"f 55/55 56/56 59/59 58/58\n" -"f 56/56 57/57 60/60 59/59\n" -"f 53/53 52/52 55/55 61/61\n" +"f 62/62 63/63 67/67 65/65\n" +"f 63/63 64/64 69/69 67/67\n" +"f 62/62 65/65 67/67 66/66\n" +"f 66/66 67/67 69/69 68/68\n" "\n" "#\n" "# Shape 6: center-right\n" "#\n" +"# - starts at vertex 52\n" "v 0.75 0.0 -0.5\n" +"v 1.25 0.0 -0.5\n" "v 1.75 0.0 -0.5\n" -"v 1.75 0.0 0.5\n" +"v 0.75 0.0 0.0\n" +"v 1.25 0.0 0.0\n" +"v 1.75 0.0 0.0\n" "v 0.75 0.0 0.5\n" +"v 1.25 0.0 0.5\n" +"v 1.75 0.0 0.5\n" +"v 0.75 -0.5 -0.5\n" "\n" -"vt 0.75 -0.5\n" -"vt 1.75 -0.5\n" -"vt 1.75 0.5\n" -"vt 0.75 0.5\n" +"vt 0.75 -0.5\n" +"vt 1.25 -0.5\n" +"vt 1.75 -0.5\n" +"vt 0.75 0.0\n" +"vt 1.25 0.0\n" +"vt 1.75 0.0\n" +"vt 0.75 0.5\n" +"vt 1.25 0.5\n" +"vt 1.75 0.5\n" +"vt 0.75 -0.5\n" "\n" -"f 62/62 63/63 64/64 65/65\n" -"f 62/62 65/65 64/64 63/63\n" +"f 70/70 71/71 74/74 73/73\n" +"f 71/71 72/72 75/75 74/74\n" +"f 73/73 74/74 77/77 76/76\n" +"f 74/74 75/75 78/78 77/77\n" +"f 71/71 70/70 73/73 79/79\n" "\n" "#\n" "# Shape 7: bottom-left\n" @@ -244,16 +282,16 @@ static const std::string catmark_val2_interior = "v -1.25 0.0 -0.75\n" "v -0.75 0.0 -0.75\n" "\n" -"vt -0.5 -0.5\n" -"vt 0.0 -0.5\n" -"vt 0.5 -0.5\n" -"vt 0.0 0.0\n" -"vt -0.5 0.5\n" -"vt 0.0 0.5\n" -"vt 0.5 0.5\n" +"vt -1.75 -1.75\n" +"vt -1.25 -1.75\n" +"vt -0.75 -1.75\n" +"vt -1.25 -1.25\n" +"vt -1.75 -0.75\n" +"vt -1.25 -0.75\n" +"vt -0.75 -0.75\n" "\n" -"f 66/66 67/67 69/69 71/71 70/70\n" -"f 67/67 68/68 72/72 71/71 69/69\n" +"f 80/80 81/81 83/83 85/85 84/84\n" +"f 81/81 82/82 86/86 85/85 83/83\n" "\n" "#\n" "# Shape 8: bottom-middle\n" @@ -267,17 +305,17 @@ static const std::string catmark_val2_interior = "v 0.0 -0.5 -0.75\n" "v 0.5 0.0 -0.75\n" "\n" -"vt -0.5 -0.5\n" -"vt 0.0 -0.5\n" -"vt 0.0 -0.5\n" -"vt 0.5 -0.5\n" -"vt -0.5 0.5\n" -"vt 0.0 0.5\n" -"vt 0.0 0.5\n" -"vt 0.5 0.5\n" +"vt -0.5 -1.75\n" +"vt 0.0 -1.75\n" +"vt 0.0 -1.75\n" +"vt 0.5 -1.75\n" +"vt -0.5 -0.75\n" +"vt 0.0 -0.75\n" +"vt 0.0 -0.75\n" +"vt 0.5 -0.75\n" "\n" -"f 73/73 74/74 75/75 79/79 78/78 77/77\n" -"f 80/80 78/78 79/79 75/75 74/74 76/76\n" +"f 87/87 88/88 89/89 93/93 92/92 91/91\n" +"f 94/94 92/92 93/93 89/89 88/88 90/90\n" "\n" "#\n" "# Shape 9: bottom-right\n" @@ -292,30 +330,32 @@ static const std::string catmark_val2_interior = "v 1.75 0.5 -0.75\n" "v 0.75 0.5 -0.75\n" "\n" -"vt 0.375 0.000\n" -"vt 0.500 0.000\n" -"vt 0.625 0.000\n" -"vt 0.375 0.250\n" -"vt 0.625 0.250\n" -"vt 0.375 0.500\n" -"vt 0.625 0.500\n" -"vt 0.375 0.750\n" -"vt 0.500 0.750\n" -"vt 0.625 0.750\n" -"vt 0.375 1.000\n" -"vt 0.500 1.000\n" -"vt 0.625 1.000\n" -"vt 0.875 0.000\n" -"vt 0.875 0.250\n" -"vt 0.125 0.000\n" -"vt 0.125 0.250\n" +"vt 1.15 -1.65\n" +"vt 1.35 -1.65\n" +"vt 1.15 -1.45\n" +"vt 1.35 -1.45\n" +"vt 1.05 -1.25\n" +"vt 1.25 -1.25\n" +"vt 1.45 -1.25\n" +"vt 1.15 -1.05\n" +"vt 1.35 -1.05\n" +"vt 1.15 -0.85\n" +"vt 1.35 -0.85\n" +"vt 1.00 -1.15\n" +"vt 0.80 -1.15\n" +"vt 0.80 -1.35\n" +"vt 1.00 -1.35\n" +"vt 1.70 -1.15\n" +"vt 1.50 -1.15\n" +"vt 1.50 -1.35\n" +"vt 1.70 -1.35\n" "\n" -"f 84/84 81/81 82/82 83/83 85/85\n" -"f 86/86 84/84 85/85 87/87\n" -"f 88/88 86/86 87/87 89/89\n" -"f 82/92 81/91 88/88 89/89 83/93\n" -"f 83/83 89/94 87/95 85/85\n" -"f 88/96 81/81 84/84 86/97\n" +"f 98/98 95/101 96/100 97/99 99/97\n" +"f 100/96 98/98 99/97 101/95\n" +"f 102/103 100/105 101/104 103/102\n" +"f 95/101 102/103 103/102 97/99 96/100\n" +"f 97/106 103/107 101/108 99/109\n" +"f 102/110 95/111 98/112 100/113\n" "\n" "t interpolateboundary 1/0/0 1\n" "\n" diff --git a/regression/shapes/catmark_val2_nonman.h b/regression/shapes/catmark_val2_nonman.h new file mode 100644 index 00000000..b07350c0 --- /dev/null +++ b/regression/shapes/catmark_val2_nonman.h @@ -0,0 +1,125 @@ +// +// Copyright 2022 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. +// + +static const std::string catmark_val2_nonman = +"#\n" +"# Four shapes ordered left->right and top->bottom in the XZ plane\n" +"#\n" +"# Shape 1: top-left\n" +"#\n" +"v -0.70 0 0.30\n" +"v -0.30 0 0.30\n" +"v -0.30 0 0.70\n" +"v -0.70 0 0.70\n" +"v -0.70 0.2 0.10\n" +"v -0.30 0.2 0.10\n" +"v -0.70 -0.2 0.10\n" +"v -0.30 -0.2 0.10\n" +"\n" +"vt -0.70 0.30\n" +"vt -0.30 0.30\n" +"vt -0.30 0.70\n" +"vt -0.70 0.70\n" +"vt -0.70 0.10\n" +"vt -0.30 0.10\n" +"vt -0.70 0.10\n" +"vt -0.30 0.10\n" +"\n" +"f 1/1 2/2 3/3 4/4\n" +"f 4/4 3/3 2/2 1/1\n" +"f 1/1 2/2 6/6 5/5\n" +"f 2/2 1/1 7/7 8/8\n" +"\n" +"#\n" +"# Shape 2: top-right\n" +"#\n" +"v 0.30 0 0.30\n" +"v 0.70 0 0.30\n" +"v 0.50 0 0.70\n" +"v 0.50 0 0.70\n" +"v 0.30 0.2 0.10\n" +"v 0.70 0.2 0.10\n" +"v 0.30 -0.2 0.10\n" +"v 0.70 -0.2 0.10\n" +"\n" +"vt 0.30 0.30\n" +"vt 0.70 0.30\n" +"vt 0.50 0.70\n" +"vt 0.50 0.70\n" +"vt 0.30 0.10\n" +"vt 0.70 0.10\n" +"vt 0.30 0.10\n" +"vt 0.70 0.10\n" +"\n" +"f 9/9 10/10 11/11\n" +"f 11/11 10/10 9/9\n" +"f 9/9 10/10 14/14 13/13\n" +"f 10/10 9/9 15/15 16/16\n" +"\n" +"#\n" +"# Shape 3: bottom-left\n" +"#\n" +"v -0.70 0 -0.70\n" +"v -0.30 0 -0.70\n" +"v -0.30 0 -0.30\n" +"v -0.70 0 -0.30\n" +"v -0.70 -0.2 -0.90\n" +"v -0.30 -0.2 -0.90\n" +"\n" +"vt -0.70 -0.70\n" +"vt -0.30 -0.70\n" +"vt -0.30 -0.30\n" +"vt -0.70 -0.30\n" +"vt -0.70 -0.90\n" +"vt -0.30 -0.90\n" +"\n" +"f 17/17 18/18 19/19 20/20\n" +"f 20/20 19/19 18/18 17/17\n" +"f 21/21 22/22 17/17\n" +"\n" +"#\n" +"# Shape 4: bottom-right\n" +"#\n" +"v 0.30 0 -0.70\n" +"v 0.70 0 -0.70\n" +"v 0.70 0 -0.30\n" +"v 0.30 0 -0.30\n" +"v 0.30 -0.2 -0.90\n" +"v 0.70 -0.2 -0.90\n" +"\n" +"vt 0.30 -0.70\n" +"vt 0.70 -0.70\n" +"vt 0.70 -0.30\n" +"vt 0.30 -0.30\n" +"vt 0.30 -0.90\n" +"vt 0.70 -0.90\n" +"\n" +"f 23/23 24/24 25/25 26/26\n" +"f 26/26 25/25 24/24 23/23\n" +"f 27/27 28/28 23/23\n" +"f 27/27 28/28 24/24\n" +"\n" +"t interpolateboundary 1/0/0 1\n" +"\n" +; diff --git a/regression/shapes/loop_val2_interior.h b/regression/shapes/loop_val2_interior.h new file mode 100644 index 00000000..cf46fdbe --- /dev/null +++ b/regression/shapes/loop_val2_interior.h @@ -0,0 +1,98 @@ +// +// Copyright 2022 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. +// + +static const std::string loop_val2_interior = +"#\n" +"# Shape 1:\n" +"#\n" +"v -1.75 0.0 0.0\n" +"v -0.75 0.0 0.0\n" +"v -1.25 0.0 0.866\n" +"v -1.75 -0.75 0.866\n" +"v -0.75 -0.75 0.866\n" +"v -1.75 0.75 0.866\n" +"v -0.75 0.75 0.866\n" +"\n" +"vt 0.05 0.10\n" +"vt 0.45 0.10\n" +"vt 0.25 0.40\n" +"vt 0.55 0.10\n" +"vt 0.95 0.10\n" +"vt 0.75 0.40\n" +"vt 0.20 0.90\n" +"vt 0.20 0.50\n" +"vt 0.50 0.70\n" +"vt 0.80 0.50\n" +"vt 0.80 0.90\n" +"\n" +"f 1/1 2/2 3/3\n" +"f 2/4 1/5 3/6\n" +"f 3/9 4/7 5/8\n" +"f 3/9 7/10 6/11\n" +"\n" +"#\n" +"# Shape 2:\n" +"#\n" +"v -0.5 0.0 0.0\n" +"v 0.5 0.0 0.0\n" +"v 0.0 0.0 0.866\n" +"\n" +"vt 1.05 0.30\n" +"vt 1.45 0.30\n" +"vt 1.25 0.60\n" +"vt 1.55 0.30\n" +"vt 1.95 0.30\n" +"vt 1.75 0.60\n" +"\n" +"f 8/12 9/13 10/14\n" +"f 9/15 8/16 10/17\n" +"\n" +"#\n" +"# Shape 3:\n" +"#\n" +"v 0.75 0.0 0.0\n" +"v 1.75 0.0 0.0\n" +"v 1.25 0.0 0.866\n" +"v 1.25 -0.75 0.0\n" +"v 1.25 0.75 0.0\n" +"\n" +"vt 2.05 0.60\n" +"vt 2.45 0.60\n" +"vt 2.25 0.90\n" +"vt 2.55 0.60\n" +"vt 2.95 0.60\n" +"vt 2.75 0.90\n" +"vt 2.10 0.30\n" +"vt 2.90 0.30\n" +"vt 2.50 0.10\n" +"vt 2.50 0.50\n" +"\n" +"f 11/18 12/19 13/20\n" +"f 12/21 11/22 13/23\n" +"f 14/24 12/26 11/27\n" +"f 15/25 11/27 12/26\n" +"\n" +"t interpolateboundary 1/0/0 1\n" +"\n" +;