From 92ca9958eac6efe26a851b1f6b8a233f1607b991 Mon Sep 17 00:00:00 2001 From: sunyab Date: Tue, 7 Jul 2020 10:04:21 -0700 Subject: [PATCH] Add option to enable interpolation for missing clip values to UsdUtilsStitchClips and UsdUtilsStitchClipsTemplate as well as usdstitchclips utility. (Internal change: 2082024) --- pxr/usd/bin/usdstitchclips/usdstitchclips.py | 6 +++++ pxr/usd/usdUtils/stitchClips.cpp | 13 +++++++++++ pxr/usd/usdUtils/stitchClips.h | 18 ++++++++++++++- .../testenv/testUsdUtilsStitchClips.py | 13 +++++++---- pxr/usd/usdUtils/wrapStitchClips.cpp | 23 +++++++++++++------ 5 files changed, 61 insertions(+), 12 deletions(-) diff --git a/pxr/usd/bin/usdstitchclips/usdstitchclips.py b/pxr/usd/bin/usdstitchclips/usdstitchclips.py index e89c36ad28..e96eeb3ce3 100644 --- a/pxr/usd/bin/usdstitchclips/usdstitchclips.py +++ b/pxr/usd/bin/usdstitchclips/usdstitchclips.py @@ -59,6 +59,10 @@ help='specify a named clipSet in which to author clip metadata, so that multiple sets of clips can be applied on the same prim.') parser.add_argument('--activeOffset', action='store', required=False, help='specify an offset for template-based clips, offsetting the frame number of each clip file.') +parser.add_argument('--interpolateMissingClipValues', action='store_true', + help=('specify whether values for clips without authored ' + 'samples are interpolated from surrounding clips ' + 'if no default value is authored in any clip.')) # useful for debugging with diffs parser.add_argument('-n', '--noComment', action='store_true', help='do not write a comment specifying how the usd file was generated') @@ -120,6 +124,7 @@ def _checkMissingTemplateArg(argName, argValue): results.endTimeCode, results.stride, results.activeOffset, + results.interpolateMissingClipValues, results.clipSet) else: if results.templatePath: @@ -134,6 +139,7 @@ def _checkMissingTemplateArg(argName, argValue): UsdUtils.StitchClips(outLayer, results.usdFiles, results.clipPath, results.startTimeCode, results.endTimeCode, + results.interpolateMissingClipValues, results.clipSet) diff --git a/pxr/usd/usdUtils/stitchClips.cpp b/pxr/usd/usdUtils/stitchClips.cpp index 84ecc82bd0..4f09a6e3d3 100644 --- a/pxr/usd/usdUtils/stitchClips.cpp +++ b/pxr/usd/usdUtils/stitchClips.cpp @@ -727,6 +727,7 @@ namespace { const SdfPath& clipPath, const double startTimeCode, const double endTimeCode, + const bool interpolateMissingClipValues, const TfToken& clipSet) { TfErrorMark errorMark; @@ -736,6 +737,12 @@ namespace { _SetTimeCodeRange(resultLayer, clipPath, startTimeCode, endTimeCode, clipSet); + if (interpolateMissingClipValues) { + _SetValue(resultLayer, clipPath, + UsdClipsAPIInfoKeys->interpolateMissingClipValues, + interpolateMissingClipValues, clipSet); + } + return errorMark.IsClean(); } @@ -831,6 +838,7 @@ UsdUtilsStitchClips(const SdfLayerHandle& resultLayer, const SdfPath& clipPath, const double startTimeCode, const double endTimeCode, + const bool interpolateMissingClipValues, const TfToken& clipSet) { // XXX: See comment in UsdUtilsStitchClipsTopology above. @@ -868,6 +876,7 @@ UsdUtilsStitchClips(const SdfLayerHandle& resultLayer, || !_UsdUtilsStitchClipsImpl(resultLayer, topologyLayer, clipLayers, clipPath, startTimeCode, endTimeCode, + interpolateMissingClipValues, clipSet)) { if (!topologyPreExisting) { TfDeleteFile(topologyLayer->GetIdentifier()); @@ -906,6 +915,7 @@ UsdUtilsStitchClipsTemplate(const SdfLayerHandle& resultLayer, const double endTime, const double stride, const double activeOffset, + const bool interpolateMissingClipValues, const TfToken& clipSet) { // XXX: See comment in UsdUtilsStitchClipsTopology above. @@ -940,6 +950,9 @@ UsdUtilsStitchClipsTemplate(const SdfLayerHandle& resultLayer, if (activeOffset != std::numeric_limits::max()) { clipSetDict[UsdClipsAPIInfoKeys->templateActiveOffset] = activeOffset; } + if (interpolateMissingClipValues) { + clipSetDict[UsdClipsAPIInfoKeys->interpolateMissingClipValues] = true; + } VtDictionary clips; clips[clipSet] = clipSetDict; diff --git a/pxr/usd/usdUtils/stitchClips.h b/pxr/usd/usdUtils/stitchClips.h index 52b2f17119..1055a29601 100644 --- a/pxr/usd/usdUtils/stitchClips.h +++ b/pxr/usd/usdUtils/stitchClips.h @@ -67,7 +67,13 @@ SDF_DECLARE_HANDLES(SdfLayer); /// highest endTimeCode authored from the /// \p clipLayers. /// -/// \p clipSet The name of the clipSet in which the +/// \p interpolateMissingClipValues +/// Whether values for clips without samples are +/// interpolated from surrounding clips. See +/// UsdClipsAPI::GetInterpolateMissingClipValues +/// for more details. +/// +/// \p clipSet The name of the clipSet in which the /// aforementioned metadata will be authored. /// \note If this parameter is omitted, the default /// clipSet name will be authored. @@ -114,6 +120,8 @@ UsdUtilsStitchClips(const SdfLayerHandle& resultLayer, = std::numeric_limits::max(), const double endTimeCode = std::numeric_limits::max(), + const bool interpolateMissingClipValues + = false, const TfToken& clipSet = UsdClipsAPISetNames->default_); @@ -164,6 +172,12 @@ UsdUtilsStitchClipsTopology(const SdfLayerHandle& topologyLayer, /// \note If this parameter is omitted, no value /// will be authored as the metadata is optional. /// +/// \p interpolateMissingClipValues +/// Whether values for clips without samples are +/// interpolated from surrounding clips. See +/// UsdClipsAPI::GetInterpolateMissingClipValues +/// for more details. +/// /// \p clipSet The name of the clipSet in which the /// aforementioned metadata will be authored. /// \note If this parameter is omitted, the default @@ -182,6 +196,8 @@ UsdUtilsStitchClipsTemplate(const SdfLayerHandle& resultLayer, const double stride, const double activeOffset = std::numeric_limits::max(), + const bool interpolateMissingClipValues + = false, const TfToken& clipSet = UsdClipsAPISetNames->default_); diff --git a/pxr/usd/usdUtils/testenv/testUsdUtilsStitchClips.py b/pxr/usd/usdUtils/testenv/testUsdUtilsStitchClips.py index f94f0e4f66..2cdae7ca38 100644 --- a/pxr/usd/usdUtils/testenv/testUsdUtilsStitchClips.py +++ b/pxr/usd/usdUtils/testenv/testUsdUtilsStitchClips.py @@ -70,7 +70,8 @@ def setUp(self): rootLayer = Sdf.Layer.FindOrOpen(self.baseName) self.rootLayer = rootLayer if rootLayer else Sdf.Layer.CreateNew(self.baseName) UsdUtils.StitchClips(self.rootLayer, self.layerFileNames[0:7], - self.clipPath, self.startTimeCode, self.endTimeCode) + self.clipPath, self.startTimeCode, self.endTimeCode, + interpolateMissingClipValues=True) self.setupComplete = True @@ -83,7 +84,8 @@ def test_ValidClipMetadata(self): set(['default'])) self.assertEqual(set(clipPrim.GetInfo('clips')['default'].keys()), set(['times', 'assetPaths', 'primPath', - 'manifestAssetPath', 'active'])) + 'manifestAssetPath', 'active', + 'interpolateMissingClipValues'])) def test_ValidUsdLayerGeneration(self): self.assertTrue(self.rootLayer) @@ -192,7 +194,9 @@ def test_CustomSetName(self): resultLayer = Sdf.Layer.CreateNew('customSetName.usd') topLayer = Sdf.Layer.CreateNew('customSetName.topology.usd') UsdUtils.StitchClipsTemplate(resultLayer, topLayer, self.clipPath, - 'asset.#.usd', 101, 120, 1, 0.3, 'bob') + 'asset.#.usd', 101, 120, 1, 0.3, + interpolateMissingClipValues=True, + clipSet='bob') self.assertEqual(list(resultLayer.subLayerPaths), ['./customSetName.topology.usd']) self.assertEqual(resultLayer.endTimeCode, 120) @@ -205,7 +209,8 @@ def test_CustomSetName(self): 'templateActiveOffset': 0.3, 'primPath': '/World/fx/Particles_Splash', 'templateAssetPath': 'asset.#.usd', - 'templateEndTime': 120.0} + 'templateEndTime': 120.0, + 'interpolateMissingClipValues': True} # Ensure that our custom set name applied actualValues = prim.GetInfo('clips')['bob'] diff --git a/pxr/usd/usdUtils/wrapStitchClips.cpp b/pxr/usd/usdUtils/wrapStitchClips.cpp index f11e4722d0..7b6a3772a5 100644 --- a/pxr/usd/usdUtils/wrapStitchClips.cpp +++ b/pxr/usd/usdUtils/wrapStitchClips.cpp @@ -55,15 +55,18 @@ _ConvertStitchClips(const SdfLayerHandle& resultLayer, const SdfPath& clipPath, const object pyStartFrame, const object pyEndFrame, + const object pyInterpolateMissingClipValues, const object pyClipSet) { const auto clipSet = _ConvertWithDefault(pyClipSet, UsdClipsAPISetNames->default_); constexpr double dmax = std::numeric_limits::max(); - return UsdUtilsStitchClips(resultLayer, clipLayerFiles, clipPath, - _ConvertWithDefault(pyStartFrame, dmax), - _ConvertWithDefault(pyEndFrame, dmax), - clipSet); + return UsdUtilsStitchClips( + resultLayer, clipLayerFiles, clipPath, + _ConvertWithDefault(pyStartFrame, dmax), + _ConvertWithDefault(pyEndFrame, dmax), + _ConvertWithDefault(pyInterpolateMissingClipValues, false), + clipSet); } bool @@ -88,6 +91,7 @@ _ConvertStitchClipTemplate(const SdfLayerHandle& resultLayer, const double endFrame, const double stride, const object pyActiveOffset, + const object pyInterpolateMissingClipValues, const object pyClipSet) { const auto clipSet @@ -95,9 +99,12 @@ _ConvertStitchClipTemplate(const SdfLayerHandle& resultLayer, const auto activeOffset = _ConvertWithDefault(pyActiveOffset, std::numeric_limits::max()); - return UsdUtilsStitchClipsTemplate(resultLayer, topologyLayer, - clipPath, templatePath, startFrame, - endFrame, stride, activeOffset, clipSet); + const auto interpolateMissingClipValues + = _ConvertWithDefault(pyInterpolateMissingClipValues, false); + return UsdUtilsStitchClipsTemplate( + resultLayer, topologyLayer, + clipPath, templatePath, startFrame, + endFrame, stride, activeOffset, interpolateMissingClipValues, clipSet); } } // anonymous namespace @@ -111,6 +118,7 @@ void wrapStitchClips() arg("clipPath"), arg("startFrame")=object(), arg("endFrame")=object(), + arg("interpolateMissingClipValues")=object(), arg("clipSet")=object())); def("StitchClipsTopology", @@ -128,6 +136,7 @@ void wrapStitchClips() arg("endTimeCode"), arg("stride"), arg("activeOffset")=object(), + arg("interpolateMissingClipValues")=object(), arg("clipSet")=object())); def("GenerateClipTopologyName",