From dd5cf14393aa6c8711a2180bb52638e5765ca3bd Mon Sep 17 00:00:00 2001 From: debloip-adsk <145056365+debloip-adsk@users.noreply.github.com> Date: Thu, 18 Jan 2024 15:03:20 -0500 Subject: [PATCH] HYDRA-764 : Add prim instancing unit test (#33) * HYDRA-764 : Create minimalized version of ALab workbench scene * HYDRA-764 : Further simplify the USD scene * HYDRA-764 : Convert geometry usdc file to usda and remove some meshes * HYDRA-764 : Replace workbench with simple cube * HYDRA-764 : Have just the root Xform reference the cube in the scene file * HYDRA-674 : Rename Xform and mesh in cube.usda * HYDRA-764 : First working test * HYDRA-764 : Extract USD stage load from file logic into utils * HYDRA-764 : Add extra checks in scene hierarchy * HYDRA-764 : Comment scene file * HYDRA-764 : Cleanup unused imports and includes * HYDRA-764 : Rename root prim * HYDRA-764 : Move usdUtils import inside a function called after MayaUSD is loaded * HYDRA-764 : Remove incorrect comment in usda scene file * HYDRA-764 : Rename scene file --- .../mayaUsd/render/mayaToHydra/CMakeLists.txt | 1 + .../render/mayaToHydra/cpp/CMakeLists.txt | 1 + .../mayaToHydra/cpp/testPrimInstancing.cpp | 68 +++++++++++++++++++ .../mayaToHydra/cpp/testPrimInstancing.py | 42 ++++++++++++ test/testSamples/testPrimInstancing/cube.usda | 14 ++++ .../testPrimInstancing/instanceableCube.usda | 11 +++ test/testUtils/usdUtils.py | 16 +++++ 7 files changed, 153 insertions(+) create mode 100644 test/lib/mayaUsd/render/mayaToHydra/cpp/testPrimInstancing.cpp create mode 100644 test/lib/mayaUsd/render/mayaToHydra/cpp/testPrimInstancing.py create mode 100644 test/testSamples/testPrimInstancing/cube.usda create mode 100644 test/testSamples/testPrimInstancing/instanceableCube.usda diff --git a/test/lib/mayaUsd/render/mayaToHydra/CMakeLists.txt b/test/lib/mayaUsd/render/mayaToHydra/CMakeLists.txt index 94f297ff34..1e47a21e3e 100644 --- a/test/lib/mayaUsd/render/mayaToHydra/CMakeLists.txt +++ b/test/lib/mayaUsd/render/mayaToHydra/CMakeLists.txt @@ -25,6 +25,7 @@ set(TEST_SCRIPT_FILES cpp/testFlowViewportAPIAddPrims.py cpp/testUsdStageLayerMuting.py cpp/testFlowViewportAPIFilterPrims.py + cpp/testPrimInstancing.py ) # Test use of mesh adapter code for mesh support, using environment variable. diff --git a/test/lib/mayaUsd/render/mayaToHydra/cpp/CMakeLists.txt b/test/lib/mayaUsd/render/mayaToHydra/cpp/CMakeLists.txt index 538b22b175..8925fd0fe1 100644 --- a/test/lib/mayaUsd/render/mayaToHydra/cpp/CMakeLists.txt +++ b/test/lib/mayaUsd/render/mayaToHydra/cpp/CMakeLists.txt @@ -26,6 +26,7 @@ target_sources(${TARGET_NAME} testUsdStageLayerMuting.cpp testMeshAdapterTransform.cpp testFlowViewportAPIFilterPrims.cpp + testPrimInstancing.cpp ) # ----------------------------------------------------------------------------- diff --git a/test/lib/mayaUsd/render/mayaToHydra/cpp/testPrimInstancing.cpp b/test/lib/mayaUsd/render/mayaToHydra/cpp/testPrimInstancing.cpp new file mode 100644 index 0000000000..e5d3a0c7bd --- /dev/null +++ b/test/lib/mayaUsd/render/mayaToHydra/cpp/testPrimInstancing.cpp @@ -0,0 +1,68 @@ +// Copyright 2023 Autodesk +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#include "testUtils.h" + +#include + +#include + +PXR_NAMESPACE_USING_DIRECTIVE + +namespace { +FindPrimPredicate findInstanceableCubePredicate = PrimNamePredicate("instanceableCube"); +HdDataSourceLocator instancerLocator = HdDataSourceLocator(TfToken("instance"), TfToken("instancer")); +} // namespace + +TEST(PrimInstancing, testUsdPrimInstancing) +{ + // Get the terminal scene index + const auto& sceneIndices = GetTerminalSceneIndices(); + ASSERT_GT(sceneIndices.size(), 0u); + SceneIndexInspector inspector(sceneIndices.front()); + + // Find the instanceable cube prim + PrimEntriesVector instanceableCubePrims = inspector.FindPrims(findInstanceableCubePredicate); + ASSERT_EQ(instanceableCubePrims.size(), 1u); + HdSceneIndexPrim instanceableCubePrim = instanceableCubePrims.front().prim; + + // Retrieve the instancer data source + auto instancerDataSource = HdTypedSampledDataSource::Cast( + HdContainerDataSource::Get(instanceableCubePrim.dataSource, instancerLocator)); + ASSERT_TRUE(instancerDataSource); + + // Ensure the instancer prim exists and is populated + SdfPath instancerPath = instancerDataSource->GetTypedValue(0); + auto findInstancerPredicate + = [instancerPath](const HdSceneIndexBasePtr& sceneIndex, const SdfPath& primPath) -> bool { + return primPath == instancerPath; + }; + PrimEntriesVector instancerPrims = inspector.FindPrims(findInstancerPredicate); + ASSERT_EQ(instancerPrims.size(), 1u); + HdSceneIndexPrim instancerPrim = instancerPrims.front().prim; + ASSERT_EQ(instancerPrim.primType, HdPrimTypeTokens->instancer); + ASSERT_NE(instancerPrim.dataSource, nullptr); + + // Ensure the reference cube prim exists and is populated + auto findCubePredicate + = [instancerPath](const HdSceneIndexBasePtr& sceneIndex, const SdfPath& primPath) -> bool { + return primPath.HasPrefix(instancerPath) && primPath.GetName() == "cubeMesh"; + }; + PrimEntriesVector cubePrims = inspector.FindPrims(findCubePredicate); + ASSERT_EQ(cubePrims.size(), 1u); + HdSceneIndexPrim cubePrim = cubePrims.front().prim; + ASSERT_EQ(cubePrim.primType, HdPrimTypeTokens->mesh); + ASSERT_NE(cubePrim.dataSource, nullptr); +} diff --git a/test/lib/mayaUsd/render/mayaToHydra/cpp/testPrimInstancing.py b/test/lib/mayaUsd/render/mayaToHydra/cpp/testPrimInstancing.py new file mode 100644 index 0000000000..bee463f53f --- /dev/null +++ b/test/lib/mayaUsd/render/mayaToHydra/cpp/testPrimInstancing.py @@ -0,0 +1,42 @@ +# Copyright 2023 Autodesk +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +import maya.cmds as cmds + +import fixturesUtils +import mtohUtils +import unittest + +import testUtils +from testUtils import PluginLoaded + +class TestPrimInstancing(mtohUtils.MayaHydraBaseTestCase): + # MayaHydraBaseTestCase.setUpClass requirement. + _file = __file__ + + def loadUsdScene(self): + import usdUtils + usdScenePath = testUtils.getTestScene('testPrimInstancing', 'instanceableCube.usda') + usdUtils.createStageFromFile(usdScenePath) + self.setHdStormRenderer() + cmds.refresh() + + @unittest.skipUnless(mtohUtils.checkForMayaUsdPlugin(), "Requires Maya USD Plugin.") + def test_UsdPrimInstancing(self): + self.loadUsdScene() + with PluginLoaded('mayaHydraCppTests'): + cmds.mayaHydraCppTest(f="PrimInstancing.testUsdPrimInstancing") + +if __name__ == '__main__': + fixturesUtils.runTests(globals()) diff --git a/test/testSamples/testPrimInstancing/cube.usda b/test/testSamples/testPrimInstancing/cube.usda new file mode 100644 index 0000000000..edaaf69eb7 --- /dev/null +++ b/test/testSamples/testPrimInstancing/cube.usda @@ -0,0 +1,14 @@ +#usda 1.0 +( + defaultPrim = "cube" +) + +def Xform "cube" +{ + def Mesh "cubeMesh" + { + int[] faceVertexCounts = [4, 4, 4, 4, 4, 4] + int[] faceVertexIndices = [0, 1, 3, 2, 2, 3, 5, 4, 4, 5, 7, 6, 6, 7, 1, 0, 1, 7, 5, 3, 6, 0, 2, 4] + point3f[] points = [(-0.5, -0.5, 0.5), (0.5, -0.5, 0.5), (-0.5, 0.5, 0.5), (0.5, 0.5, 0.5), (-0.5, 0.5, -0.5), (0.5, 0.5, -0.5), (-0.5, -0.5, -0.5), (0.5, -0.5, -0.5)] + } +} diff --git a/test/testSamples/testPrimInstancing/instanceableCube.usda b/test/testSamples/testPrimInstancing/instanceableCube.usda new file mode 100644 index 0000000000..dfdfff10ab --- /dev/null +++ b/test/testSamples/testPrimInstancing/instanceableCube.usda @@ -0,0 +1,11 @@ +#usda 1.0 +( + defaultPrim = "instanceableCube" +) + +def Xform "instanceableCube" ( + instanceable = true + prepend references = @cube.usda@ +) +{ +} diff --git a/test/testUtils/usdUtils.py b/test/testUtils/usdUtils.py index c1c75cc343..3593a4b2c4 100644 --- a/test/testUtils/usdUtils.py +++ b/test/testUtils/usdUtils.py @@ -20,6 +20,8 @@ Helper functions regarding USD that will be used throughout the test. """ +import maya.mel as mel + import mayaUsd.ufe import mayaUsd.lib import mayaUsd_createStageWithNewLayer @@ -31,6 +33,20 @@ usdSeparator = '/' +def createStageFromFile(filePath: str): + """ + Creates a USD stage from a given path to a USD file. + Args: + filePath (str): The file path to the USD file to load. + Returns : + A string representing the UFE path to the stage's proxy shape node + """ + # Source the corresponding mel file, otherwise the procedure isn't available + mel.eval('source \"mayaUsd_createStageFromFile.mel\"') + loadStageCmd = f'mayaUsd_createStageFromFilePath(\"{filePath}\")' + # Replace backslashes with forward slashes to avoid them being interpreted + loadStageCmd = loadStageCmd.replace('\\', '/') + return mel.eval(loadStageCmd) def createUfePathSegment(usdPath): """