From c57a3df1c63a1ed63bab454490c82591e7488f81 Mon Sep 17 00:00:00 2001 From: Jerry Gamache Date: Wed, 27 Apr 2022 11:47:45 -0400 Subject: [PATCH 1/5] Ufe 0.4.8: Add classifications and metadata to def Ufe 0.4.8 has multiple changes to improve NodeDef discovery: NodeDef: - Expose read-only interface to query node classifications (allows sorting them in a node picker) - Expose read-only metadata API (limited to known USD metadata tags at the moment) - Remove internally kept data. Everything is built on-the-fly from the SdrShaderNode information - Expanded the port API to allow name discovery and single port queries AttributeDef: - The base class in Ufe is now a full interface. Added an implementation for USD that returns the information directly from the associated SdrShaderProperty - Expose read-only metadata API (limited to known USD tags at the moment) --- lib/mayaUsd/ufe/CMakeLists.txt | 13 ++ lib/mayaUsd/ufe/UsdShaderAttributeDef.cpp | 102 ++++++++++++ lib/mayaUsd/ufe/UsdShaderAttributeDef.h | 70 +++++++++ lib/mayaUsd/ufe/UsdShaderNodeDef.cpp | 182 ++++++++++++++++++++++ lib/mayaUsd/ufe/UsdShaderNodeDef.h | 85 +++++++++- test/lib/ufe/testShaderNodeDef.py | 34 ++++ 6 files changed, 483 insertions(+), 3 deletions(-) create mode 100644 lib/mayaUsd/ufe/UsdShaderAttributeDef.cpp create mode 100644 lib/mayaUsd/ufe/UsdShaderAttributeDef.h diff --git a/lib/mayaUsd/ufe/CMakeLists.txt b/lib/mayaUsd/ufe/CMakeLists.txt index 979b0c601d..d18869d881 100644 --- a/lib/mayaUsd/ufe/CMakeLists.txt +++ b/lib/mayaUsd/ufe/CMakeLists.txt @@ -94,6 +94,13 @@ if(CMAKE_UFE_V4_FEATURES_AVAILABLE) UsdShaderNodeDefHandler.cpp ) endif() + + if (${UFE_PREVIEW_VERSION_NUM} GREATER_EQUAL 4008) + target_sources(${PROJECT_NAME} + PRIVATE + UsdShaderAttributeDef.cpp + ) + endif() endif() set(HEADERS @@ -186,6 +193,12 @@ if(CMAKE_UFE_V4_FEATURES_AVAILABLE) UsdShaderNodeDefHandler.h ) endif() + + if (${UFE_PREVIEW_VERSION_NUM} GREATER_EQUAL 4008) + list(APPEND HEADERS + UsdShaderAttributeDef.h + ) + endif() endif() # ----------------------------------------------------------------------------- diff --git a/lib/mayaUsd/ufe/UsdShaderAttributeDef.cpp b/lib/mayaUsd/ufe/UsdShaderAttributeDef.cpp new file mode 100644 index 0000000000..c5045d374b --- /dev/null +++ b/lib/mayaUsd/ufe/UsdShaderAttributeDef.cpp @@ -0,0 +1,102 @@ +// +// Copyright 2022 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 "UsdShaderAttributeDef.h" + +#include "Global.h" +#include "Utils.h" + +#include +#include +#include + +#include +#include + +namespace MAYAUSD_NS_DEF { +namespace ufe { + +UsdShaderAttributeDef::UsdShaderAttributeDef( + const PXR_NS::SdrShaderPropertyConstPtr& shaderAttributeDef) + : Ufe::AttributeDef() + , fShaderAttributeDef(shaderAttributeDef) +{ + PXR_NAMESPACE_USING_DIRECTIVE + if (!TF_VERIFY(fShaderAttributeDef)) { + throw std::runtime_error("Invalid shader attribute definition"); + } +} + +UsdShaderAttributeDef::~UsdShaderAttributeDef() { } + +std::string UsdShaderAttributeDef::name() const +{ + return fShaderAttributeDef ? fShaderAttributeDef->GetName().GetString() : std::string(); +} + +std::string UsdShaderAttributeDef::type() const +{ + Ufe::Attribute::Type ufeType = Ufe::Attribute::kInvalid; + if (fShaderAttributeDef) { + const PXR_NS::SdfValueTypeName typeName = fShaderAttributeDef->GetTypeAsSdfType().first; + ufeType = usdTypeToUfe(typeName); + } + return ufeType; +} + +std::string UsdShaderAttributeDef::defaultValue() const +{ + std::ostringstream defaultValue; + if (fShaderAttributeDef) { + defaultValue << fShaderAttributeDef->GetDefaultValue(); + } + return defaultValue.str(); +} + +Ufe::AttributeDef::IOType UsdShaderAttributeDef::ioType() const +{ + return (fShaderAttributeDef && fShaderAttributeDef->IsOutput()) ? Ufe::AttributeDef::OUTPUT_ATTR + : Ufe::AttributeDef::INPUT_ATTR; +} + +Ufe::Value UsdShaderAttributeDef::getMetadata(const std::string& key) const +{ + if (fShaderAttributeDef) { + const PXR_NS::NdrTokenMap& metadata = fShaderAttributeDef->GetMetadata(); + auto it = metadata.find(PXR_NS::TfToken(key)); + if (it != metadata.cend()) { + return Ufe::Value(it->second); + } + } + // TODO: Adapt UI metadata information found in SdrShaderProperty to Ufe standards + // TODO: Fix Mtlx parser in USD to populate UI metadata in SdrShaderProperty + return {}; +} + +bool UsdShaderAttributeDef::hasMetadata(const std::string& key) const +{ + if (fShaderAttributeDef) { + const PXR_NS::NdrTokenMap& metadata = fShaderAttributeDef->GetMetadata(); + auto it = metadata.find(PXR_NS::TfToken(key)); + if (it != metadata.cend()) { + return true; + } + } + return false; +} + +} // namespace ufe +} // namespace MAYAUSD_NS_DEF diff --git a/lib/mayaUsd/ufe/UsdShaderAttributeDef.h b/lib/mayaUsd/ufe/UsdShaderAttributeDef.h new file mode 100644 index 0000000000..3a01246be4 --- /dev/null +++ b/lib/mayaUsd/ufe/UsdShaderAttributeDef.h @@ -0,0 +1,70 @@ +// +// Copyright 2022 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. +// +#pragma once + +#include + +#include + +#include + +namespace MAYAUSD_NS_DEF { +namespace ufe { + +//! \brief UsdShaderAttributeDef interface. +class MAYAUSD_CORE_PUBLIC UsdShaderAttributeDef : public Ufe::AttributeDef +{ +public: + typedef std::shared_ptr Ptr; + + UsdShaderAttributeDef(const PXR_NS::SdrShaderPropertyConstPtr& shaderAttributeDef); + ~UsdShaderAttributeDef(); + + // Delete the copy/move constructors assignment operators. + UsdShaderAttributeDef(const UsdShaderAttributeDef&) = delete; + UsdShaderAttributeDef& operator=(const UsdShaderAttributeDef&) = delete; + UsdShaderAttributeDef(UsdShaderAttributeDef&&) = delete; + UsdShaderAttributeDef& operator=(UsdShaderAttributeDef&&) = delete; + + //! \return The attributeDef's name. + std::string name() const override; + + //! \return The attributeDef's type. + std::string type() const override; + + //! \return The string representation of the attributeDef's value. + std::string defaultValue() const override; + + //! \return The attribute input/output type. + IOType ioType() const override; + + /*! + Get the value of the metadata named key. + \param[in] key The metadata key to query. + \return The value of the metadata key. If the key does not exist an empty Value is returned. + */ + Ufe::Value getMetadata(const std::string& key) const override; + + //! Returns true if metadata key has a non-empty value. + bool hasMetadata(const std::string& key) const override; + +private: + const PXR_NS::SdrShaderPropertyConstPtr fShaderAttributeDef; + +}; // UsdShaderAttributeDef + +} // namespace ufe +} // namespace MAYAUSD_NS_DEF diff --git a/lib/mayaUsd/ufe/UsdShaderNodeDef.cpp b/lib/mayaUsd/ufe/UsdShaderNodeDef.cpp index daec2863e3..6414cd8f66 100644 --- a/lib/mayaUsd/ufe/UsdShaderNodeDef.cpp +++ b/lib/mayaUsd/ufe/UsdShaderNodeDef.cpp @@ -16,9 +16,15 @@ #include "UsdShaderNodeDef.h" +#if (UFE_PREVIEW_VERSION_NUM >= 4008) +#include +#endif + #include "Global.h" #include "Utils.h" +#include +#include #include #include #include @@ -33,11 +39,13 @@ namespace ufe { constexpr char UsdShaderNodeDef::kNodeDefCategoryShader[]; +#if (UFE_PREVIEW_VERSION_NUM < 4008) Ufe::Attribute::Type getUfeTypeForAttribute(const PXR_NS::SdrShaderPropertyConstPtr& shaderProperty) { const PXR_NS::SdfValueTypeName typeName = shaderProperty->GetTypeAsSdfType().first; return usdTypeToUfe(typeName); } +#endif template Ufe::ConstAttributeDefs getAttrs(const PXR_NS::SdrShaderNodeConstPtr& shaderNodeDef) @@ -54,24 +62,32 @@ Ufe::ConstAttributeDefs getAttrs(const PXR_NS::SdrShaderNodeConstPtr& shaderNode // SdrNode::GetShaderInput has to downcast a NdrProperty pointer. continue; } +#if (UFE_PREVIEW_VERSION_NUM < 4008) std::ostringstream defaultValue; defaultValue << property->GetDefaultValue(); Ufe::Attribute::Type type = getUfeTypeForAttribute(property); attrs.push_back(Ufe::AttributeDef::create(name, type, defaultValue.str(), IOTYPE)); +#else + attrs.push_back(Ufe::AttributeDef::ConstPtr(new UsdShaderAttributeDef(property))); +#endif } return attrs; } UsdShaderNodeDef::UsdShaderNodeDef(const PXR_NS::SdrShaderNodeConstPtr& shaderNodeDef) : Ufe::NodeDef() +#if (UFE_PREVIEW_VERSION_NUM < 4008) , fType(shaderNodeDef ? shaderNodeDef->GetName() : "") +#endif , fShaderNodeDef(shaderNodeDef) +#if (UFE_PREVIEW_VERSION_NUM < 4008) , fInputs( shaderNodeDef ? getAttrs(shaderNodeDef) : Ufe::ConstAttributeDefs()) , fOutputs( shaderNodeDef ? getAttrs(shaderNodeDef) : Ufe::ConstAttributeDefs()) +#endif { PXR_NAMESPACE_USING_DIRECTIVE if (!TF_VERIFY(fShaderNodeDef)) { @@ -81,12 +97,178 @@ UsdShaderNodeDef::UsdShaderNodeDef(const PXR_NS::SdrShaderNodeConstPtr& shaderNo UsdShaderNodeDef::~UsdShaderNodeDef() { } +#if (UFE_PREVIEW_VERSION_NUM < 4008) const std::string& UsdShaderNodeDef::type() const { return fType; } const Ufe::ConstAttributeDefs& UsdShaderNodeDef::inputs() const { return fInputs; } const Ufe::ConstAttributeDefs& UsdShaderNodeDef::outputs() const { return fOutputs; } +#else + +std::string UsdShaderNodeDef::type() const +{ + // Returns the NodeDef name + // - Universal context: UsdPreviewSurface, UsdUVTexture, UsdPrimvarReader_float2 + // - MaterialX context: ND_standard_surface_surfaceshader, ND_image_color3 + return fShaderNodeDef ? fShaderNodeDef->GetName() : std::string(); +} + +std::size_t UsdShaderNodeDef::nbClassifications() const +{ + // Current Sdr information available: + // + // name UsdPrimvarReader_float2 ND_image_color3 DomeLight + // family UsdPrimvarReader image - + // context usda pattern light + // sourceType glslfx mtlx USD + // category - - - + // identifier UsdPrimvarReader_float2 ND_image_color3 PortalLight + // label - image - + // role primvar texture PortalLight + + // UsdLux has 2 classification levels: + // - Context + // - SourceType + if (fShaderNodeDef->GetFamily().IsEmpty()) { + return 2; + } + + // For regular shader nodes, we seem to have 3 usable classifications: + // - family + // - role + // - sourceType + // There are quite a few misclassified nodes in MaterialX, they end up + // having their role set to the same value as the name. + + return 3; +} + +std::string UsdShaderNodeDef::classification(std::size_t level) const +{ + if (fShaderNodeDef) { + if (fShaderNodeDef->GetFamily().IsEmpty()) { + switch (level) { + // UsdLux: + case 0: return fShaderNodeDef->GetContext().GetString(); + case 1: return fShaderNodeDef->GetSourceType().GetString(); + } + } + switch (level) { + // UsdShade: These work with MaterialX and Preview surface. Need to recheck against + // third-party renderers as we discover their shading nodes. + case 0: { + return fShaderNodeDef->GetFamily().GetString(); + } + case 1: { + if (fShaderNodeDef->GetRole() == fShaderNodeDef->GetName()) { + // See https://github.com/AcademySoftwareFoundation/MaterialX/issues/921 + return "other"; + } else { + return fShaderNodeDef->GetRole(); + } + } + case 2: { + return fShaderNodeDef->GetSourceType().GetString(); + } + } + } + return {}; +} + +std::vector UsdShaderNodeDef::inputNames() const +{ + std::vector retVal; + if (fShaderNodeDef) { + for (auto&& n : fShaderNodeDef->GetInputNames()) { + retVal.push_back(n.GetString()); + } + } + return retVal; +} + +bool UsdShaderNodeDef::hasInput(const std::string& name) const +{ + return fShaderNodeDef ? fShaderNodeDef->GetShaderInput(PXR_NS::TfToken(name)) : false; +} + +Ufe::AttributeDef::ConstPtr UsdShaderNodeDef::input(const std::string& name) const +{ + if (fShaderNodeDef) { + if (PXR_NS::SdrShaderPropertyConstPtr property + = fShaderNodeDef->GetShaderInput(PXR_NS::TfToken(name))) { + return Ufe::AttributeDef::ConstPtr(new UsdShaderAttributeDef(property)); + } + } + return {}; +} + +Ufe::ConstAttributeDefs UsdShaderNodeDef::inputs() const +{ + return fShaderNodeDef ? getAttrs(fShaderNodeDef) + : Ufe::ConstAttributeDefs(); +} + +std::vector UsdShaderNodeDef::outputNames() const +{ + std::vector retVal; + if (fShaderNodeDef) { + for (auto&& n : fShaderNodeDef->GetOutputNames()) { + retVal.push_back(n.GetString()); + } + } + return retVal; +} + +bool UsdShaderNodeDef::hasOutput(const std::string& name) const +{ + return fShaderNodeDef ? fShaderNodeDef->GetShaderOutput(PXR_NS::TfToken(name)) : false; +} + +Ufe::AttributeDef::ConstPtr UsdShaderNodeDef::output(const std::string& name) const +{ + if (fShaderNodeDef) { + if (PXR_NS::SdrShaderPropertyConstPtr property + = fShaderNodeDef->GetShaderOutput(PXR_NS::TfToken(name))) { + return Ufe::AttributeDef::ConstPtr(new UsdShaderAttributeDef(property)); + } + } + return {}; +} + +Ufe::ConstAttributeDefs UsdShaderNodeDef::outputs() const +{ + return fShaderNodeDef ? getAttrs(fShaderNodeDef) + : Ufe::ConstAttributeDefs(); +} + +Ufe::Value UsdShaderNodeDef::getMetadata(const std::string& key) const +{ + if (fShaderNodeDef) { + const PXR_NS::NdrTokenMap& metadata = fShaderNodeDef->GetMetadata(); + auto it = metadata.find(PXR_NS::TfToken(key)); + if (it != metadata.cend()) { + return Ufe::Value(it->second); + } + } + // TODO: Adapt UI metadata information found in SdrShaderNode to Ufe standards + // TODO: Fix Mtlx parser in USD to populate UI metadata in SdrShaderNode + return {}; +} + +bool UsdShaderNodeDef::hasMetadata(const std::string& key) const +{ + if (fShaderNodeDef) { + const PXR_NS::NdrTokenMap& metadata = fShaderNodeDef->GetMetadata(); + auto it = metadata.find(PXR_NS::TfToken(key)); + if (it != metadata.cend()) { + return true; + } + } + return false; +} +#endif + UsdShaderNodeDef::Ptr UsdShaderNodeDef::create(const PXR_NS::SdrShaderNodeConstPtr& shaderNodeDef) { try { diff --git a/lib/mayaUsd/ufe/UsdShaderNodeDef.h b/lib/mayaUsd/ufe/UsdShaderNodeDef.h index d41094c13c..2bba08853d 100644 --- a/lib/mayaUsd/ufe/UsdShaderNodeDef.h +++ b/lib/mayaUsd/ufe/UsdShaderNodeDef.h @@ -41,6 +41,7 @@ class MAYAUSD_CORE_PUBLIC UsdShaderNodeDef : public Ufe::NodeDef UsdShaderNodeDef(UsdShaderNodeDef&&) = delete; UsdShaderNodeDef& operator=(UsdShaderNodeDef&&) = delete; +#if (UFE_PREVIEW_VERSION_NUM < 4008) //! \return The type of the shader node definition. const std::string& type() const override; @@ -49,6 +50,80 @@ class MAYAUSD_CORE_PUBLIC UsdShaderNodeDef : public Ufe::NodeDef //! \return The outputs of the shader node definition. const Ufe::ConstAttributeDefs& outputs() const override; +#else + //! \return The type of the shader node definition. + std::string type() const override; + + /*! + Queries the number of classification levels available for this node. + This can vary across runtimes. A biology implementation would have + species as the "type" and genus, family, order, class, phylum, kingdom + representing the 6 available levels. + \return The number of classification levels. + */ + std::size_t nbClassifications() const override; + + /*! + Gets the classification label applicable to this NodeNef for the + requested classification level. The most precise classification level + corresponds to level zero. + \param level The classification level to query. + \return The classification label for this node at this level. + */ + std::string classification(std::size_t level) const override; + + //! \return List of all the input names for this node definition. + std::vector inputNames() const override; + + /*! + Queries whether an input exists with the given name. + \param name The input name to check. + \return True if the object contains an input matching the name. + */ + bool hasInput(const std::string& name) const override; + + /*! + Creates an AttributeDef interface for the given input name. + \param name Name of the input to retrieve. + \return AttributeDef interface for the given name. Returns a null + pointer if no input exists for the given name. + */ + Ufe::AttributeDef::ConstPtr input(const std::string& name) const override; + + //! \return The inputs of the shader node definition. + Ufe::ConstAttributeDefs inputs() const override; + + //! \return List of all the output names for this node definition. + std::vector outputNames() const override; + + /*! + Queries whether an output exists with the given name. + \param name The output name to check. + \return True if the object contains an output matching the name. + */ + bool hasOutput(const std::string& name) const override; + + /*! + Creates an AttributeDef interface for the given output name. + \param name Name of the output to retrieve. + \return AttributeDef interface for the given name. Returns a null + pointer if no output exists for the given name. + */ + Ufe::AttributeDef::ConstPtr output(const std::string& name) const override; + + //! \return The outputs of the shader node definition. + Ufe::ConstAttributeDefs outputs() const override; + + /*! + Get the value of the metadata named key. + \param[in] key The metadata key to query. + \return The value of the metadata key. If the key does not exist an empty Value is returned. + */ + Ufe::Value getMetadata(const std::string& key) const override; + + //! Returns true if metadata key has a non-empty value. + bool hasMetadata(const std::string& key) const override; +#endif //! Create a UsdShaderNodeDef. static Ptr create(const PXR_NS::SdrShaderNodeConstPtr& shaderNodeDef); @@ -57,10 +132,14 @@ class MAYAUSD_CORE_PUBLIC UsdShaderNodeDef : public Ufe::NodeDef static Ufe::NodeDefs definitions(const std::string& category); private: - const std::string fType; +#if (UFE_PREVIEW_VERSION_NUM < 4008) + const std::string fType; +#endif const PXR_NS::SdrShaderNodeConstPtr fShaderNodeDef; - const Ufe::ConstAttributeDefs fInputs; - const Ufe::ConstAttributeDefs fOutputs; +#if (UFE_PREVIEW_VERSION_NUM < 4008) + const Ufe::ConstAttributeDefs fInputs; + const Ufe::ConstAttributeDefs fOutputs; +#endif }; // UsdShaderNodeDef diff --git a/test/lib/ufe/testShaderNodeDef.py b/test/lib/ufe/testShaderNodeDef.py index bd10dcf348..50bdf8470a 100644 --- a/test/lib/ufe/testShaderNodeDef.py +++ b/test/lib/ufe/testShaderNodeDef.py @@ -136,3 +136,37 @@ def testDefinitionByType(self): self.assertEqual(len(outputs), 1) self.assertEqual(outputs[0].name(), "out") self.assertEqual(outputs[0].type(), "ColorFloat3") + + @unittest.skipIf(os.getenv('UFE_PREVIEW_VERSION_NUM', '0000') < '4008', 'Improvements to nodeDef only available in UFE preview version 0.4.8 and greater') + def testClassificationsAndMetadata(self): + type = "ND_image_color3" + nodeDefHandler = self.getNodeDefHandler() + nodeDef = nodeDefHandler.definition(type) + self.assertIsNotNone(nodeDef) + + # Full input API: + inputNames = nodeDef.inputNames() + self.assertEqual(len(inputNames), 10) + self.assertIn("file", inputNames) + self.assertTrue(nodeDef.hasInput("file")) + self.assertFalse(nodeDef.hasInput("DefinitelyNotAnInput")) + + # Metadata API: + self.assertTrue(nodeDef.hasMetadata("role")) + self.assertEqual(nodeDef.getMetadata("role"), ufe.Value("texture")) + self.assertFalse(nodeDef.hasMetadata("DefinitelyNotAKnownMetadata")) + + # Classifications API: + self.assertGreater(nodeDef.nbClassifications(), 0) + self.assertEqual(nodeDef.classification(0), "image") + + # AttributeDef Metadata API: + fileInput = nodeDef.input("file") + self.assertTrue(fileInput.hasMetadata("__SDR__isAssetIdentifier")) + self.assertFalse(fileInput.hasMetadata("DefinitelyNotAKnownMetadata")) + nodeDef = nodeDefHandler.definition("ND_add_float") + output = nodeDef.output("out") + self.assertEqual(output.getMetadata("__SDR__defaultinput"), ufe.Value("in1")) + + + From fa239d161591c5e9f34f27ad7bde0e9a9ddd664b Mon Sep 17 00:00:00 2001 From: Jerry Gamache Date: Fri, 29 Apr 2022 15:36:27 -0400 Subject: [PATCH 2/5] Added USD shader creation command from NodeDef --- lib/mayaUsd/ufe/CMakeLists.txt | 13 ++++ lib/mayaUsd/ufe/UsdShaderNodeDef.cpp | 34 +++++++++ lib/mayaUsd/ufe/UsdShaderNodeDef.h | 17 +++++ lib/mayaUsd/ufe/UsdShaderNodeDefHandler.cpp | 25 ++++++- .../ufe/UsdUndoCreateFromNodeDefCommand.cpp | 73 +++++++++++++++++++ .../ufe/UsdUndoCreateFromNodeDefCommand.h | 69 ++++++++++++++++++ test/lib/ufe/testContextOps.py | 39 ++++++---- 7 files changed, 253 insertions(+), 17 deletions(-) create mode 100644 lib/mayaUsd/ufe/UsdUndoCreateFromNodeDefCommand.cpp create mode 100644 lib/mayaUsd/ufe/UsdUndoCreateFromNodeDefCommand.h diff --git a/lib/mayaUsd/ufe/CMakeLists.txt b/lib/mayaUsd/ufe/CMakeLists.txt index d18869d881..680937e8f5 100644 --- a/lib/mayaUsd/ufe/CMakeLists.txt +++ b/lib/mayaUsd/ufe/CMakeLists.txt @@ -101,6 +101,13 @@ if(CMAKE_UFE_V4_FEATURES_AVAILABLE) UsdShaderAttributeDef.cpp ) endif() + + if (${UFE_PREVIEW_VERSION_NUM} GREATER_EQUAL 4009) + target_sources(${PROJECT_NAME} + PRIVATE + UsdUndoCreateFromNodeDefCommand.cpp + ) + endif() endif() set(HEADERS @@ -199,6 +206,12 @@ if(CMAKE_UFE_V4_FEATURES_AVAILABLE) UsdShaderAttributeDef.h ) endif() + + if (${UFE_PREVIEW_VERSION_NUM} GREATER_EQUAL 4009) + list(APPEND HEADERS + UsdUndoCreateFromNodeDefCommand.h + ) + endif() endif() # ----------------------------------------------------------------------------- diff --git a/lib/mayaUsd/ufe/UsdShaderNodeDef.cpp b/lib/mayaUsd/ufe/UsdShaderNodeDef.cpp index 6414cd8f66..4089e695c4 100644 --- a/lib/mayaUsd/ufe/UsdShaderNodeDef.cpp +++ b/lib/mayaUsd/ufe/UsdShaderNodeDef.cpp @@ -19,6 +19,9 @@ #if (UFE_PREVIEW_VERSION_NUM >= 4008) #include #endif +#if (UFE_PREVIEW_VERSION_NUM >= 4009) +#include +#endif #include "Global.h" #include "Utils.h" @@ -269,6 +272,37 @@ bool UsdShaderNodeDef::hasMetadata(const std::string& key) const } #endif +#if (UFE_PREVIEW_VERSION_NUM >= 4009) +Ufe::SceneItem::Ptr +UsdShaderNodeDef::createNode(const Ufe::SceneItem::Ptr& parent, const Ufe::PathComponent& name) +{ + Ufe::SceneItem::Ptr createdItem = nullptr; + + if (fShaderNodeDef) { + UsdSceneItem::Ptr parentItem = std::dynamic_pointer_cast(parent); + UsdUndoCreateFromNodeDefCommand::Ptr cmd + = UsdUndoCreateFromNodeDefCommand::create(fShaderNodeDef, parentItem, name.string()); + if (cmd) { + cmd->execute(); + createdItem = cmd->insertedChild(); + } + } + + return createdItem; +} + +Ufe::InsertChildCommand::Ptr +UsdShaderNodeDef::createNodeCmd(const Ufe::SceneItem::Ptr& parent, const Ufe::PathComponent& name) +{ + if (fShaderNodeDef) { + UsdSceneItem::Ptr parentItem = std::dynamic_pointer_cast(parent); + return UsdUndoCreateFromNodeDefCommand::create(fShaderNodeDef, parentItem, name.string()); + } else { + return {}; + } +} +#endif + UsdShaderNodeDef::Ptr UsdShaderNodeDef::create(const PXR_NS::SdrShaderNodeConstPtr& shaderNodeDef) { try { diff --git a/lib/mayaUsd/ufe/UsdShaderNodeDef.h b/lib/mayaUsd/ufe/UsdShaderNodeDef.h index 2bba08853d..1a99bd37fa 100644 --- a/lib/mayaUsd/ufe/UsdShaderNodeDef.h +++ b/lib/mayaUsd/ufe/UsdShaderNodeDef.h @@ -125,6 +125,23 @@ class MAYAUSD_CORE_PUBLIC UsdShaderNodeDef : public Ufe::NodeDef bool hasMetadata(const std::string& key) const override; #endif +#if (UFE_PREVIEW_VERSION_NUM >= 4009) + //! Create a SceneItem using the current node definition as template. + //! \param parent Item under which the node is to be created. + //! \param name Name of the new node. + //! \return SceneItem for the created node, at its new path. + Ufe::SceneItem::Ptr + createNode(const Ufe::SceneItem::Ptr& parent, const Ufe::PathComponent& name) override; + + //! Create a command to create a SceneItem using the current node definition + //! as template. The command is not executed. + //! \param parent Item under which the node is to be created. + //! \param name Name of the new node. + //! \return Command whose execution will create the node. + Ufe::InsertChildCommand::Ptr + createNodeCmd(const Ufe::SceneItem::Ptr& parent, const Ufe::PathComponent& name) override; +#endif + //! Create a UsdShaderNodeDef. static Ptr create(const PXR_NS::SdrShaderNodeConstPtr& shaderNodeDef); diff --git a/lib/mayaUsd/ufe/UsdShaderNodeDefHandler.cpp b/lib/mayaUsd/ufe/UsdShaderNodeDefHandler.cpp index 7d6923f436..070fba2aeb 100644 --- a/lib/mayaUsd/ufe/UsdShaderNodeDefHandler.cpp +++ b/lib/mayaUsd/ufe/UsdShaderNodeDefHandler.cpp @@ -51,16 +51,35 @@ Ufe::NodeDef::Ptr UsdShaderNodeDefHandler::definition(const Ufe::SceneItem::Ptr& } PXR_NS::UsdPrim prim = usdItem->prim(); PXR_NS::UsdShadeShader shader(prim); - PXR_NS::TfToken mxNodeType; + if (!shader) { + return nullptr; + } + PXR_NS::TfToken mxNodeType; shader.GetIdAttr().Get(&mxNodeType); - std::string type = mxNodeType.GetString(); - return definition(type); + + // Careful around name and identifier. They are not the same concept. + // + // Here is one example from MaterialX to illustrate: + // + // ND_standard_surface_surfaceshader exists in 2 versions with identifiers: + // ND_standard_surface_surfaceshader (latest version) + // ND_standard_surface_surfaceshader_100 (version 1.0.0) + // Same name, 2 different identifiers. + PXR_NS::SdrRegistry& registry = PXR_NS::SdrRegistry::GetInstance(); + PXR_NS::SdrShaderNodeConstPtr shaderNodeDef = registry.GetShaderNodeByIdentifier(mxNodeType); + if (!shaderNodeDef) { + return nullptr; + } + return UsdShaderNodeDef::create(shaderNodeDef); } Ufe::NodeDef::Ptr UsdShaderNodeDefHandler::definition(const std::string& type) const { PXR_NS::SdrRegistry& registry = PXR_NS::SdrRegistry::GetInstance(); PXR_NS::SdrShaderNodeConstPtr shaderNodeDef = registry.GetShaderNodeByName(type); + if (!shaderNodeDef) { + return nullptr; + } return UsdShaderNodeDef::create(shaderNodeDef); } diff --git a/lib/mayaUsd/ufe/UsdUndoCreateFromNodeDefCommand.cpp b/lib/mayaUsd/ufe/UsdUndoCreateFromNodeDefCommand.cpp new file mode 100644 index 0000000000..56b7d755c7 --- /dev/null +++ b/lib/mayaUsd/ufe/UsdUndoCreateFromNodeDefCommand.cpp @@ -0,0 +1,73 @@ +// +// Copyright 2022 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 "UsdUndoCreateFromNodeDefCommand.h" + +#include + +#include +#include +#include + +PXR_NAMESPACE_USING_DIRECTIVE + +namespace MAYAUSD_NS_DEF { +namespace ufe { + +UsdUndoCreateFromNodeDefCommand::UsdUndoCreateFromNodeDefCommand( + const PXR_NS::SdrShaderNodeConstPtr shaderNodeDef, + const UsdSceneItem::Ptr& parentItem, + const Ufe::PathComponent& name) + : Ufe::InsertChildCommand() + , _shaderNodeDef(shaderNodeDef) + , _addPrimCmd(UsdUndoAddNewPrimCommand::create(parentItem, name.string(), "Shader")) +{ +} + +UsdUndoCreateFromNodeDefCommand::~UsdUndoCreateFromNodeDefCommand() { } + +UsdUndoCreateFromNodeDefCommand::Ptr UsdUndoCreateFromNodeDefCommand::create( + const PXR_NS::SdrShaderNodeConstPtr shaderNodeDef, + const UsdSceneItem::Ptr& parentItem, + const Ufe::PathComponent& name) +{ + return std::make_shared(shaderNodeDef, parentItem, name); +} + +Ufe::SceneItem::Ptr UsdUndoCreateFromNodeDefCommand::insertedChild() const +{ + return UsdSceneItem::create(_addPrimCmd->newUfePath(), _addPrimCmd->newPrim()); +} + +void UsdUndoCreateFromNodeDefCommand::execute() +{ + _addPrimCmd->execute(); + + UsdShadeShader shader(_addPrimCmd->newPrim()); + shader.CreateIdAttr(VtValue(_shaderNodeDef->GetIdentifier())); +} + +void UsdUndoCreateFromNodeDefCommand::undo() { _addPrimCmd->undo(); } + +void UsdUndoCreateFromNodeDefCommand::redo() +{ + _addPrimCmd->redo(); + + UsdShadeShader shader(_addPrimCmd->newPrim()); + shader.CreateIdAttr(VtValue(_shaderNodeDef->GetIdentifier())); +} + +} // namespace ufe +} // namespace MAYAUSD_NS_DEF diff --git a/lib/mayaUsd/ufe/UsdUndoCreateFromNodeDefCommand.h b/lib/mayaUsd/ufe/UsdUndoCreateFromNodeDefCommand.h new file mode 100644 index 0000000000..e94f37ee08 --- /dev/null +++ b/lib/mayaUsd/ufe/UsdUndoCreateFromNodeDefCommand.h @@ -0,0 +1,69 @@ +// +// Copyright 2022 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. +// +#pragma once + +#include +#include +#include + +#include + +#include +#include +#include +#include + +namespace MAYAUSD_NS_DEF { +namespace ufe { + +//! \brief UsdUndoCreateFromNodeDefCommand +class MAYAUSD_CORE_PUBLIC UsdUndoCreateFromNodeDefCommand : public Ufe::InsertChildCommand +{ +public: + typedef std::shared_ptr Ptr; + + UsdUndoCreateFromNodeDefCommand( + const PXR_NS::SdrShaderNodeConstPtr shaderNodeDef, + const UsdSceneItem::Ptr& parentItem, + const Ufe::PathComponent& name); + ~UsdUndoCreateFromNodeDefCommand() override; + + // Delete the copy/move constructors assignment operators. + UsdUndoCreateFromNodeDefCommand(const UsdUndoCreateFromNodeDefCommand&) = delete; + UsdUndoCreateFromNodeDefCommand& operator=(const UsdUndoCreateFromNodeDefCommand&) = delete; + UsdUndoCreateFromNodeDefCommand(UsdUndoCreateFromNodeDefCommand&&) = delete; + UsdUndoCreateFromNodeDefCommand& operator=(UsdUndoCreateFromNodeDefCommand&&) = delete; + + //! Create a UsdUndoCreateFromNodeDefCommand from a USD scene item and a UFE path component. + static UsdUndoCreateFromNodeDefCommand::Ptr create( + const PXR_NS::SdrShaderNodeConstPtr shaderNodeDef, + const UsdSceneItem::Ptr& parentItem, + const Ufe::PathComponent& name); + + Ufe::SceneItem::Ptr insertedChild() const override; + + void execute() override; + void undo() override; + void redo() override; + +private: + const PXR_NS::SdrShaderNodeConstPtr _shaderNodeDef; + + std::shared_ptr _addPrimCmd; +}; // UsdUndoCreateFromNodeDefCommand + +} // namespace ufe +} // namespace MAYAUSD_NS_DEF diff --git a/test/lib/ufe/testContextOps.py b/test/lib/ufe/testContextOps.py index 04dcbf9483..60122bd48c 100644 --- a/test/lib/ufe/testContextOps.py +++ b/test/lib/ufe/testContextOps.py @@ -366,25 +366,36 @@ def testMaterialBinding(self): materialItem = rootHier.children()[-1] contextOps = ufe.ContextOps.contextOps(materialItem) - - # TODO: We want to create that shader directly from a Ufe.ShaderNodeDef. This will take care - # of the "info:id" automatically and potentially provide the authorable attributes. - cmd = contextOps.doOpCmd(['Add New Prim', 'Shader']) - ufeCmd.execute(cmd) - materialHier = ufe.Hierarchy.hierarchy(materialItem) - self.assertTrue(materialHier.hasChildren()) - self.assertEqual(len(materialHier.children()), 1) + if (os.getenv('UFE_PREVIEW_VERSION_NUM', '0000') >= '4009'): + shaderName = "ND_standard_surface_surfaceshader" + nodeDefHandler = ufe.RunTimeMgr.instance().nodeDefHandler(materialItem.runTimeId()) + surfDef = nodeDefHandler.definition(shaderName) + cmd = surfDef.createNodeCmd(materialItem, ufe.PathComponent("Red1")) + ufeCmd.execute(cmd) + shaderItem = cmd.insertedChild + shaderAttrs = ufe.Attributes.attributes(shaderItem) + + self.assertTrue(shaderAttrs.hasAttribute("info:id")) + self.assertEqual(shaderAttrs.attribute("info:id").get(), shaderName) + self.assertEqual(ufe.PathString.string(shaderItem.path()), "|stage1|stageShape1,/Material1/Red11") + else: + cmd = contextOps.doOpCmd(['Add New Prim', 'Shader']) + ufeCmd.execute(cmd) + + materialHier = ufe.Hierarchy.hierarchy(materialItem) + self.assertTrue(materialHier.hasChildren()) + self.assertEqual(len(materialHier.children()), 1) - shaderItem = materialHier.children()[0] - shaderAttrs = ufe.Attributes.attributes(shaderItem) + shaderItem = materialHier.children()[0] + shaderAttrs = ufe.Attributes.attributes(shaderItem) - self.assertTrue(shaderAttrs.hasAttribute("info:id")) - shaderAttr = shaderAttrs.attribute("info:id") - shaderAttr.set("ND_standard_surface_surfaceshader") + self.assertTrue(shaderAttrs.hasAttribute("info:id")) + shaderAttr = shaderAttrs.attribute("info:id") + shaderAttr.set("ND_standard_surface_surfaceshader") # TODO: Set base_color to red - # TODO: Connect "/Material1.outputs:mtlx:surface" to "/Material1/Shader1.outputs:surface" + # TODO: Connect "/Material1.outputs:mtlx:surface" to "/Material1/Red11.outputs:surface" # Now that we have a material, we can bind it on the capsule item even if incomplete capsuleItem = rootHier.children()[0] From 47ad69771e7eb21cabff83a2d13765f52338e7db Mon Sep 17 00:00:00 2001 From: Jerry Gamache Date: Fri, 29 Apr 2022 16:41:37 -0400 Subject: [PATCH 3/5] Updated for Ufe review comments. --- lib/mayaUsd/ufe/CMakeLists.txt | 4 ++-- lib/mayaUsd/ufe/UsdShaderNodeDef.cpp | 14 ++++++++------ lib/mayaUsd/ufe/UsdShaderNodeDef.h | 6 +++--- test/lib/ufe/testContextOps.py | 3 ++- 4 files changed, 15 insertions(+), 12 deletions(-) diff --git a/lib/mayaUsd/ufe/CMakeLists.txt b/lib/mayaUsd/ufe/CMakeLists.txt index 680937e8f5..2492d87127 100644 --- a/lib/mayaUsd/ufe/CMakeLists.txt +++ b/lib/mayaUsd/ufe/CMakeLists.txt @@ -102,7 +102,7 @@ if(CMAKE_UFE_V4_FEATURES_AVAILABLE) ) endif() - if (${UFE_PREVIEW_VERSION_NUM} GREATER_EQUAL 4009) + if (${UFE_PREVIEW_VERSION_NUM} GREATER_EQUAL 4010) target_sources(${PROJECT_NAME} PRIVATE UsdUndoCreateFromNodeDefCommand.cpp @@ -207,7 +207,7 @@ if(CMAKE_UFE_V4_FEATURES_AVAILABLE) ) endif() - if (${UFE_PREVIEW_VERSION_NUM} GREATER_EQUAL 4009) + if (${UFE_PREVIEW_VERSION_NUM} GREATER_EQUAL 4010) list(APPEND HEADERS UsdUndoCreateFromNodeDefCommand.h ) diff --git a/lib/mayaUsd/ufe/UsdShaderNodeDef.cpp b/lib/mayaUsd/ufe/UsdShaderNodeDef.cpp index 4089e695c4..458e1abf50 100644 --- a/lib/mayaUsd/ufe/UsdShaderNodeDef.cpp +++ b/lib/mayaUsd/ufe/UsdShaderNodeDef.cpp @@ -19,7 +19,7 @@ #if (UFE_PREVIEW_VERSION_NUM >= 4008) #include #endif -#if (UFE_PREVIEW_VERSION_NUM >= 4009) +#if (UFE_PREVIEW_VERSION_NUM >= 4010) #include #endif @@ -272,9 +272,10 @@ bool UsdShaderNodeDef::hasMetadata(const std::string& key) const } #endif -#if (UFE_PREVIEW_VERSION_NUM >= 4009) -Ufe::SceneItem::Ptr -UsdShaderNodeDef::createNode(const Ufe::SceneItem::Ptr& parent, const Ufe::PathComponent& name) +#if (UFE_PREVIEW_VERSION_NUM >= 4010) +Ufe::SceneItem::Ptr UsdShaderNodeDef::createNode( + const Ufe::SceneItem::Ptr& parent, + const Ufe::PathComponent& name) const { Ufe::SceneItem::Ptr createdItem = nullptr; @@ -291,8 +292,9 @@ UsdShaderNodeDef::createNode(const Ufe::SceneItem::Ptr& parent, const Ufe::PathC return createdItem; } -Ufe::InsertChildCommand::Ptr -UsdShaderNodeDef::createNodeCmd(const Ufe::SceneItem::Ptr& parent, const Ufe::PathComponent& name) +Ufe::InsertChildCommand::Ptr UsdShaderNodeDef::createNodeCmd( + const Ufe::SceneItem::Ptr& parent, + const Ufe::PathComponent& name) const { if (fShaderNodeDef) { UsdSceneItem::Ptr parentItem = std::dynamic_pointer_cast(parent); diff --git a/lib/mayaUsd/ufe/UsdShaderNodeDef.h b/lib/mayaUsd/ufe/UsdShaderNodeDef.h index 1a99bd37fa..e1f2a5ce69 100644 --- a/lib/mayaUsd/ufe/UsdShaderNodeDef.h +++ b/lib/mayaUsd/ufe/UsdShaderNodeDef.h @@ -125,13 +125,13 @@ class MAYAUSD_CORE_PUBLIC UsdShaderNodeDef : public Ufe::NodeDef bool hasMetadata(const std::string& key) const override; #endif -#if (UFE_PREVIEW_VERSION_NUM >= 4009) +#if (UFE_PREVIEW_VERSION_NUM >= 4010) //! Create a SceneItem using the current node definition as template. //! \param parent Item under which the node is to be created. //! \param name Name of the new node. //! \return SceneItem for the created node, at its new path. Ufe::SceneItem::Ptr - createNode(const Ufe::SceneItem::Ptr& parent, const Ufe::PathComponent& name) override; + createNode(const Ufe::SceneItem::Ptr& parent, const Ufe::PathComponent& name) const override; //! Create a command to create a SceneItem using the current node definition //! as template. The command is not executed. @@ -139,7 +139,7 @@ class MAYAUSD_CORE_PUBLIC UsdShaderNodeDef : public Ufe::NodeDef //! \param name Name of the new node. //! \return Command whose execution will create the node. Ufe::InsertChildCommand::Ptr - createNodeCmd(const Ufe::SceneItem::Ptr& parent, const Ufe::PathComponent& name) override; + createNodeCmd(const Ufe::SceneItem::Ptr& parent, const Ufe::PathComponent& name) const override; #endif //! Create a UsdShaderNodeDef. diff --git a/test/lib/ufe/testContextOps.py b/test/lib/ufe/testContextOps.py index 60122bd48c..dcd9b88c4a 100644 --- a/test/lib/ufe/testContextOps.py +++ b/test/lib/ufe/testContextOps.py @@ -367,7 +367,8 @@ def testMaterialBinding(self): materialItem = rootHier.children()[-1] contextOps = ufe.ContextOps.contextOps(materialItem) - if (os.getenv('UFE_PREVIEW_VERSION_NUM', '0000') >= '4009'): + if (os.getenv('UFE_PREVIEW_VERSION_NUM', '0000') >= '4010'): + print("USING NEW API!!!!") shaderName = "ND_standard_surface_surfaceshader" nodeDefHandler = ufe.RunTimeMgr.instance().nodeDefHandler(materialItem.runTimeId()) surfDef = nodeDefHandler.definition(shaderName) From 013304628afebbabf6f98967038b548d32bf5a04 Mon Sep 17 00:00:00 2001 From: Jerry Gamache Date: Tue, 3 May 2022 16:44:10 -0400 Subject: [PATCH 4/5] Respond to review comments. --- lib/mayaUsd/ufe/CMakeLists.txt | 15 +- lib/mayaUsd/ufe/UsdShaderNodeDef.cpp | 215 ++++++++---------- lib/mayaUsd/ufe/UsdShaderNodeDef.h | 8 +- .../ufe/UsdUndoCreateFromNodeDefCommand.cpp | 14 +- .../ufe/UsdUndoCreateFromNodeDefCommand.h | 2 + test/lib/ufe/testContextOps.py | 121 +++++++--- test/lib/ufe/testShaderNodeDef.py | 2 +- 7 files changed, 207 insertions(+), 170 deletions(-) diff --git a/lib/mayaUsd/ufe/CMakeLists.txt b/lib/mayaUsd/ufe/CMakeLists.txt index 2492d87127..e9e4214390 100644 --- a/lib/mayaUsd/ufe/CMakeLists.txt +++ b/lib/mayaUsd/ufe/CMakeLists.txt @@ -95,16 +95,10 @@ if(CMAKE_UFE_V4_FEATURES_AVAILABLE) ) endif() - if (${UFE_PREVIEW_VERSION_NUM} GREATER_EQUAL 4008) - target_sources(${PROJECT_NAME} - PRIVATE - UsdShaderAttributeDef.cpp - ) - endif() - if (${UFE_PREVIEW_VERSION_NUM} GREATER_EQUAL 4010) target_sources(${PROJECT_NAME} PRIVATE + UsdShaderAttributeDef.cpp UsdUndoCreateFromNodeDefCommand.cpp ) endif() @@ -201,14 +195,9 @@ if(CMAKE_UFE_V4_FEATURES_AVAILABLE) ) endif() - if (${UFE_PREVIEW_VERSION_NUM} GREATER_EQUAL 4008) - list(APPEND HEADERS - UsdShaderAttributeDef.h - ) - endif() - if (${UFE_PREVIEW_VERSION_NUM} GREATER_EQUAL 4010) list(APPEND HEADERS + UsdShaderAttributeDef.h UsdUndoCreateFromNodeDefCommand.h ) endif() diff --git a/lib/mayaUsd/ufe/UsdShaderNodeDef.cpp b/lib/mayaUsd/ufe/UsdShaderNodeDef.cpp index 458e1abf50..001dee2a0d 100644 --- a/lib/mayaUsd/ufe/UsdShaderNodeDef.cpp +++ b/lib/mayaUsd/ufe/UsdShaderNodeDef.cpp @@ -16,10 +16,8 @@ #include "UsdShaderNodeDef.h" -#if (UFE_PREVIEW_VERSION_NUM >= 4008) -#include -#endif #if (UFE_PREVIEW_VERSION_NUM >= 4010) +#include #include #endif @@ -40,24 +38,27 @@ namespace MAYAUSD_NS_DEF { namespace ufe { +PXR_NAMESPACE_USING_DIRECTIVE + constexpr char UsdShaderNodeDef::kNodeDefCategoryShader[]; -#if (UFE_PREVIEW_VERSION_NUM < 4008) -Ufe::Attribute::Type getUfeTypeForAttribute(const PXR_NS::SdrShaderPropertyConstPtr& shaderProperty) +#if (UFE_PREVIEW_VERSION_NUM < 4010) +Ufe::Attribute::Type getUfeTypeForAttribute(const SdrShaderPropertyConstPtr& shaderProperty) { - const PXR_NS::SdfValueTypeName typeName = shaderProperty->GetTypeAsSdfType().first; + const SdfValueTypeName typeName = shaderProperty->GetTypeAsSdfType().first; return usdTypeToUfe(typeName); } #endif template -Ufe::ConstAttributeDefs getAttrs(const PXR_NS::SdrShaderNodeConstPtr& shaderNodeDef) +Ufe::ConstAttributeDefs getAttrs(const SdrShaderNodeConstPtr& shaderNodeDef) { Ufe::ConstAttributeDefs attrs; const bool input = (IOTYPE == Ufe::AttributeDef::INPUT_ATTR); auto names = input ? shaderNodeDef->GetInputNames() : shaderNodeDef->GetOutputNames(); - for (const PXR_NS::TfToken& name : names) { - PXR_NS::SdrShaderPropertyConstPtr property + attrs.reserve(names.size()); + for (const TfToken& name : names) { + SdrShaderPropertyConstPtr property = input ? shaderNodeDef->GetShaderInput(name) : shaderNodeDef->GetShaderOutput(name); if (!property) { // Cannot do much if the pointer is null. This can happen if the type_info for a @@ -65,25 +66,25 @@ Ufe::ConstAttributeDefs getAttrs(const PXR_NS::SdrShaderNodeConstPtr& shaderNode // SdrNode::GetShaderInput has to downcast a NdrProperty pointer. continue; } -#if (UFE_PREVIEW_VERSION_NUM < 4008) +#if (UFE_PREVIEW_VERSION_NUM < 4010) std::ostringstream defaultValue; defaultValue << property->GetDefaultValue(); Ufe::Attribute::Type type = getUfeTypeForAttribute(property); - attrs.push_back(Ufe::AttributeDef::create(name, type, defaultValue.str(), IOTYPE)); + attrs.emplace_back(Ufe::AttributeDef::create(name, type, defaultValue.str(), IOTYPE)); #else - attrs.push_back(Ufe::AttributeDef::ConstPtr(new UsdShaderAttributeDef(property))); + attrs.emplace_back(Ufe::AttributeDef::ConstPtr(new UsdShaderAttributeDef(property))); #endif } return attrs; } -UsdShaderNodeDef::UsdShaderNodeDef(const PXR_NS::SdrShaderNodeConstPtr& shaderNodeDef) +UsdShaderNodeDef::UsdShaderNodeDef(const SdrShaderNodeConstPtr& shaderNodeDef) : Ufe::NodeDef() -#if (UFE_PREVIEW_VERSION_NUM < 4008) +#if (UFE_PREVIEW_VERSION_NUM < 4010) , fType(shaderNodeDef ? shaderNodeDef->GetName() : "") #endif , fShaderNodeDef(shaderNodeDef) -#if (UFE_PREVIEW_VERSION_NUM < 4008) +#if (UFE_PREVIEW_VERSION_NUM < 4010) , fInputs( shaderNodeDef ? getAttrs(shaderNodeDef) : Ufe::ConstAttributeDefs()) @@ -92,7 +93,6 @@ UsdShaderNodeDef::UsdShaderNodeDef(const PXR_NS::SdrShaderNodeConstPtr& shaderNo : Ufe::ConstAttributeDefs()) #endif { - PXR_NAMESPACE_USING_DIRECTIVE if (!TF_VERIFY(fShaderNodeDef)) { throw std::runtime_error("Invalid shader node definition"); } @@ -100,7 +100,7 @@ UsdShaderNodeDef::UsdShaderNodeDef(const PXR_NS::SdrShaderNodeConstPtr& shaderNo UsdShaderNodeDef::~UsdShaderNodeDef() { } -#if (UFE_PREVIEW_VERSION_NUM < 4008) +#if (UFE_PREVIEW_VERSION_NUM < 4010) const std::string& UsdShaderNodeDef::type() const { return fType; } const Ufe::ConstAttributeDefs& UsdShaderNodeDef::inputs() const { return fInputs; } @@ -111,148 +111,134 @@ const Ufe::ConstAttributeDefs& UsdShaderNodeDef::outputs() const { return fOutpu std::string UsdShaderNodeDef::type() const { - // Returns the NodeDef name - // - Universal context: UsdPreviewSurface, UsdUVTexture, UsdPrimvarReader_float2 - // - MaterialX context: ND_standard_surface_surfaceshader, ND_image_color3 - return fShaderNodeDef ? fShaderNodeDef->GetName() : std::string(); + TF_AXIOM(fShaderNodeDef); + return fShaderNodeDef->GetName(); } std::size_t UsdShaderNodeDef::nbClassifications() const { - // Current Sdr information available: - // - // name UsdPrimvarReader_float2 ND_image_color3 DomeLight - // family UsdPrimvarReader image - - // context usda pattern light - // sourceType glslfx mtlx USD - // category - - - - // identifier UsdPrimvarReader_float2 ND_image_color3 PortalLight - // label - image - - // role primvar texture PortalLight - - // UsdLux has 2 classification levels: + TF_AXIOM(fShaderNodeDef); + + // Based on a review of all items found in the Sdr registry as of USD 21.11: + + // UsdLux shaders provide 2 classification levels: // - Context // - SourceType if (fShaderNodeDef->GetFamily().IsEmpty()) { return 2; } - // For regular shader nodes, we seem to have 3 usable classifications: + // Regular shader nodes provide 3 classification levels: // - family // - role // - sourceType - // There are quite a few misclassified nodes in MaterialX, they end up - // having their role set to the same value as the name. - return 3; } std::string UsdShaderNodeDef::classification(std::size_t level) const { - if (fShaderNodeDef) { - if (fShaderNodeDef->GetFamily().IsEmpty()) { - switch (level) { - // UsdLux: - case 0: return fShaderNodeDef->GetContext().GetString(); - case 1: return fShaderNodeDef->GetSourceType().GetString(); - } - } + TF_AXIOM(fShaderNodeDef); + if (fShaderNodeDef->GetFamily().IsEmpty()) { switch (level) { - // UsdShade: These work with MaterialX and Preview surface. Need to recheck against - // third-party renderers as we discover their shading nodes. - case 0: { - return fShaderNodeDef->GetFamily().GetString(); - } - case 1: { - if (fShaderNodeDef->GetRole() == fShaderNodeDef->GetName()) { - // See https://github.com/AcademySoftwareFoundation/MaterialX/issues/921 - return "other"; - } else { - return fShaderNodeDef->GetRole(); - } - } - case 2: { - return fShaderNodeDef->GetSourceType().GetString(); + // UsdLux: + case 0: return fShaderNodeDef->GetContext().GetString(); + case 1: return fShaderNodeDef->GetSourceType().GetString(); } + } + switch (level) { + // UsdShade: These work with MaterialX and Preview surface. Need to recheck against + // third-party renderers as we discover their shading nodes. + case 0: { + return fShaderNodeDef->GetFamily().GetString(); + } + case 1: { + if (fShaderNodeDef->GetRole() == fShaderNodeDef->GetName()) { + // See https://github.com/AcademySoftwareFoundation/MaterialX/issues/921 + return "other"; + } else { + return fShaderNodeDef->GetRole(); } } + case 2: { + return fShaderNodeDef->GetSourceType().GetString(); + } + } return {}; } std::vector UsdShaderNodeDef::inputNames() const { + TF_AXIOM(fShaderNodeDef); std::vector retVal; - if (fShaderNodeDef) { - for (auto&& n : fShaderNodeDef->GetInputNames()) { - retVal.push_back(n.GetString()); - } + auto names = fShaderNodeDef->GetInputNames(); + retVal.reserve(names.size()); + for (auto&& n : names) { + retVal.emplace_back(n.GetString()); } return retVal; } bool UsdShaderNodeDef::hasInput(const std::string& name) const { - return fShaderNodeDef ? fShaderNodeDef->GetShaderInput(PXR_NS::TfToken(name)) : false; + TF_AXIOM(fShaderNodeDef); + return fShaderNodeDef->GetShaderInput(TfToken(name)); } Ufe::AttributeDef::ConstPtr UsdShaderNodeDef::input(const std::string& name) const { - if (fShaderNodeDef) { - if (PXR_NS::SdrShaderPropertyConstPtr property - = fShaderNodeDef->GetShaderInput(PXR_NS::TfToken(name))) { - return Ufe::AttributeDef::ConstPtr(new UsdShaderAttributeDef(property)); - } + TF_AXIOM(fShaderNodeDef); + if (SdrShaderPropertyConstPtr property = fShaderNodeDef->GetShaderInput(TfToken(name))) { + return Ufe::AttributeDef::ConstPtr(new UsdShaderAttributeDef(property)); } return {}; } Ufe::ConstAttributeDefs UsdShaderNodeDef::inputs() const { - return fShaderNodeDef ? getAttrs(fShaderNodeDef) - : Ufe::ConstAttributeDefs(); + TF_AXIOM(fShaderNodeDef); + return getAttrs(fShaderNodeDef); } std::vector UsdShaderNodeDef::outputNames() const { + TF_AXIOM(fShaderNodeDef); std::vector retVal; - if (fShaderNodeDef) { - for (auto&& n : fShaderNodeDef->GetOutputNames()) { - retVal.push_back(n.GetString()); - } + auto names = fShaderNodeDef->GetOutputNames(); + retVal.reserve(names.size()); + for (auto&& n : names) { + retVal.emplace_back(n.GetString()); } return retVal; } bool UsdShaderNodeDef::hasOutput(const std::string& name) const { - return fShaderNodeDef ? fShaderNodeDef->GetShaderOutput(PXR_NS::TfToken(name)) : false; + TF_AXIOM(fShaderNodeDef); + return fShaderNodeDef->GetShaderOutput(TfToken(name)); } Ufe::AttributeDef::ConstPtr UsdShaderNodeDef::output(const std::string& name) const { - if (fShaderNodeDef) { - if (PXR_NS::SdrShaderPropertyConstPtr property - = fShaderNodeDef->GetShaderOutput(PXR_NS::TfToken(name))) { - return Ufe::AttributeDef::ConstPtr(new UsdShaderAttributeDef(property)); - } + TF_AXIOM(fShaderNodeDef); + if (SdrShaderPropertyConstPtr property = fShaderNodeDef->GetShaderOutput(TfToken(name))) { + return Ufe::AttributeDef::ConstPtr(new UsdShaderAttributeDef(property)); } return {}; } Ufe::ConstAttributeDefs UsdShaderNodeDef::outputs() const { - return fShaderNodeDef ? getAttrs(fShaderNodeDef) - : Ufe::ConstAttributeDefs(); + TF_AXIOM(fShaderNodeDef); + return getAttrs(fShaderNodeDef); } Ufe::Value UsdShaderNodeDef::getMetadata(const std::string& key) const { - if (fShaderNodeDef) { - const PXR_NS::NdrTokenMap& metadata = fShaderNodeDef->GetMetadata(); - auto it = metadata.find(PXR_NS::TfToken(key)); - if (it != metadata.cend()) { - return Ufe::Value(it->second); - } + TF_AXIOM(fShaderNodeDef); + const NdrTokenMap& metadata = fShaderNodeDef->GetMetadata(); + auto it = metadata.find(TfToken(key)); + if (it != metadata.cend()) { + return Ufe::Value(it->second); } // TODO: Adapt UI metadata information found in SdrShaderNode to Ufe standards // TODO: Fix Mtlx parser in USD to populate UI metadata in SdrShaderNode @@ -261,51 +247,43 @@ Ufe::Value UsdShaderNodeDef::getMetadata(const std::string& key) const bool UsdShaderNodeDef::hasMetadata(const std::string& key) const { - if (fShaderNodeDef) { - const PXR_NS::NdrTokenMap& metadata = fShaderNodeDef->GetMetadata(); - auto it = metadata.find(PXR_NS::TfToken(key)); - if (it != metadata.cend()) { - return true; - } - } - return false; + TF_AXIOM(fShaderNodeDef); + const NdrTokenMap& metadata = fShaderNodeDef->GetMetadata(); + auto it = metadata.find(TfToken(key)); + return it != metadata.cend(); } -#endif -#if (UFE_PREVIEW_VERSION_NUM >= 4010) Ufe::SceneItem::Ptr UsdShaderNodeDef::createNode( const Ufe::SceneItem::Ptr& parent, - const Ufe::PathComponent& name) const + const Ufe::PathComponent& name) const { - Ufe::SceneItem::Ptr createdItem = nullptr; - - if (fShaderNodeDef) { - UsdSceneItem::Ptr parentItem = std::dynamic_pointer_cast(parent); + TF_AXIOM(fShaderNodeDef); + UsdSceneItem::Ptr parentItem = std::dynamic_pointer_cast(parent); + if (parentItem) { UsdUndoCreateFromNodeDefCommand::Ptr cmd = UsdUndoCreateFromNodeDefCommand::create(fShaderNodeDef, parentItem, name.string()); if (cmd) { cmd->execute(); - createdItem = cmd->insertedChild(); + return cmd->insertedChild(); } } - - return createdItem; + return {}; } Ufe::InsertChildCommand::Ptr UsdShaderNodeDef::createNodeCmd( const Ufe::SceneItem::Ptr& parent, - const Ufe::PathComponent& name) const + const Ufe::PathComponent& name) const { - if (fShaderNodeDef) { - UsdSceneItem::Ptr parentItem = std::dynamic_pointer_cast(parent); + TF_AXIOM(fShaderNodeDef); + UsdSceneItem::Ptr parentItem = std::dynamic_pointer_cast(parent); + if (parentItem) { return UsdUndoCreateFromNodeDefCommand::create(fShaderNodeDef, parentItem, name.string()); - } else { - return {}; } + return {}; } #endif -UsdShaderNodeDef::Ptr UsdShaderNodeDef::create(const PXR_NS::SdrShaderNodeConstPtr& shaderNodeDef) +UsdShaderNodeDef::Ptr UsdShaderNodeDef::create(const SdrShaderNodeConstPtr& shaderNodeDef) { try { return std::make_shared(shaderNodeDef); @@ -319,10 +297,11 @@ Ufe::NodeDefs UsdShaderNodeDef::definitions(const std::string& category) Ufe::NodeDefs result; if (category == std::string(Ufe::NodeDefHandler::kNodeDefCategoryAll) || category == std::string(kNodeDefCategoryShader)) { - PXR_NS::SdrRegistry& registry = PXR_NS::SdrRegistry::GetInstance(); - PXR_NS::SdrShaderNodePtrVec shaderNodeDefs = registry.GetShaderNodesByFamily(); - for (const PXR_NS::SdrShaderNodeConstPtr& shaderNodeDef : shaderNodeDefs) { - result.push_back(UsdShaderNodeDef::create(shaderNodeDef)); + SdrRegistry& registry = SdrRegistry::GetInstance(); + SdrShaderNodePtrVec shaderNodeDefs = registry.GetShaderNodesByFamily(); + result.reserve(shaderNodeDefs.size()); + for (const SdrShaderNodeConstPtr& shaderNodeDef : shaderNodeDefs) { + result.emplace_back(UsdShaderNodeDef::create(shaderNodeDef)); } } return result; diff --git a/lib/mayaUsd/ufe/UsdShaderNodeDef.h b/lib/mayaUsd/ufe/UsdShaderNodeDef.h index e1f2a5ce69..ac387536b6 100644 --- a/lib/mayaUsd/ufe/UsdShaderNodeDef.h +++ b/lib/mayaUsd/ufe/UsdShaderNodeDef.h @@ -41,7 +41,7 @@ class MAYAUSD_CORE_PUBLIC UsdShaderNodeDef : public Ufe::NodeDef UsdShaderNodeDef(UsdShaderNodeDef&&) = delete; UsdShaderNodeDef& operator=(UsdShaderNodeDef&&) = delete; -#if (UFE_PREVIEW_VERSION_NUM < 4008) +#if (UFE_PREVIEW_VERSION_NUM < 4010) //! \return The type of the shader node definition. const std::string& type() const override; @@ -123,9 +123,7 @@ class MAYAUSD_CORE_PUBLIC UsdShaderNodeDef : public Ufe::NodeDef //! Returns true if metadata key has a non-empty value. bool hasMetadata(const std::string& key) const override; -#endif -#if (UFE_PREVIEW_VERSION_NUM >= 4010) //! Create a SceneItem using the current node definition as template. //! \param parent Item under which the node is to be created. //! \param name Name of the new node. @@ -149,11 +147,11 @@ class MAYAUSD_CORE_PUBLIC UsdShaderNodeDef : public Ufe::NodeDef static Ufe::NodeDefs definitions(const std::string& category); private: -#if (UFE_PREVIEW_VERSION_NUM < 4008) +#if (UFE_PREVIEW_VERSION_NUM < 4010) const std::string fType; #endif const PXR_NS::SdrShaderNodeConstPtr fShaderNodeDef; -#if (UFE_PREVIEW_VERSION_NUM < 4008) +#if (UFE_PREVIEW_VERSION_NUM < 4010) const Ufe::ConstAttributeDefs fInputs; const Ufe::ConstAttributeDefs fOutputs; #endif diff --git a/lib/mayaUsd/ufe/UsdUndoCreateFromNodeDefCommand.cpp b/lib/mayaUsd/ufe/UsdUndoCreateFromNodeDefCommand.cpp index 56b7d755c7..d8aad50d90 100644 --- a/lib/mayaUsd/ufe/UsdUndoCreateFromNodeDefCommand.cpp +++ b/lib/mayaUsd/ufe/UsdUndoCreateFromNodeDefCommand.cpp @@ -54,17 +54,23 @@ Ufe::SceneItem::Ptr UsdUndoCreateFromNodeDefCommand::insertedChild() const void UsdUndoCreateFromNodeDefCommand::execute() { _addPrimCmd->execute(); - - UsdShadeShader shader(_addPrimCmd->newPrim()); - shader.CreateIdAttr(VtValue(_shaderNodeDef->GetIdentifier())); + setIdAttr(); } -void UsdUndoCreateFromNodeDefCommand::undo() { _addPrimCmd->undo(); } +void UsdUndoCreateFromNodeDefCommand::undo() +{ + _addPrimCmd->undo(); + // Nothing to do for the node:id attribute. It will get deleted with the prim. +} void UsdUndoCreateFromNodeDefCommand::redo() { _addPrimCmd->redo(); + setIdAttr(); +} +void UsdUndoCreateFromNodeDefCommand::setIdAttr() +{ UsdShadeShader shader(_addPrimCmd->newPrim()); shader.CreateIdAttr(VtValue(_shaderNodeDef->GetIdentifier())); } diff --git a/lib/mayaUsd/ufe/UsdUndoCreateFromNodeDefCommand.h b/lib/mayaUsd/ufe/UsdUndoCreateFromNodeDefCommand.h index e94f37ee08..9dbb53aa86 100644 --- a/lib/mayaUsd/ufe/UsdUndoCreateFromNodeDefCommand.h +++ b/lib/mayaUsd/ufe/UsdUndoCreateFromNodeDefCommand.h @@ -63,6 +63,8 @@ class MAYAUSD_CORE_PUBLIC UsdUndoCreateFromNodeDefCommand : public Ufe::InsertCh const PXR_NS::SdrShaderNodeConstPtr _shaderNodeDef; std::shared_ptr _addPrimCmd; + + void setIdAttr(); }; // UsdUndoCreateFromNodeDefCommand } // namespace ufe diff --git a/test/lib/ufe/testContextOps.py b/test/lib/ufe/testContextOps.py index dcd9b88c4a..c7bd81ab1c 100644 --- a/test/lib/ufe/testContextOps.py +++ b/test/lib/ufe/testContextOps.py @@ -341,8 +341,7 @@ def testAddNewPrim(self): @unittest.skipUnless(Usd.GetVersion() >= (0, 21, 8), 'Requires CanApplySchema from USD') def testMaterialBinding(self): - """In this test we will go as far as possible towards creating and binding a working - material using only Ufe and Maya commands (for full undo capabilities)""" + """This test builds a material using only Ufe pre-4.10 capabilities.""" cmds.file(new=True, force=True) # Create a proxy shape with empty stage to start with. @@ -367,36 +366,19 @@ def testMaterialBinding(self): materialItem = rootHier.children()[-1] contextOps = ufe.ContextOps.contextOps(materialItem) - if (os.getenv('UFE_PREVIEW_VERSION_NUM', '0000') >= '4010'): - print("USING NEW API!!!!") - shaderName = "ND_standard_surface_surfaceshader" - nodeDefHandler = ufe.RunTimeMgr.instance().nodeDefHandler(materialItem.runTimeId()) - surfDef = nodeDefHandler.definition(shaderName) - cmd = surfDef.createNodeCmd(materialItem, ufe.PathComponent("Red1")) - ufeCmd.execute(cmd) - shaderItem = cmd.insertedChild - shaderAttrs = ufe.Attributes.attributes(shaderItem) - - self.assertTrue(shaderAttrs.hasAttribute("info:id")) - self.assertEqual(shaderAttrs.attribute("info:id").get(), shaderName) - self.assertEqual(ufe.PathString.string(shaderItem.path()), "|stage1|stageShape1,/Material1/Red11") - else: - cmd = contextOps.doOpCmd(['Add New Prim', 'Shader']) - ufeCmd.execute(cmd) - - materialHier = ufe.Hierarchy.hierarchy(materialItem) - self.assertTrue(materialHier.hasChildren()) - self.assertEqual(len(materialHier.children()), 1) + cmd = contextOps.doOpCmd(['Add New Prim', 'Shader']) + ufeCmd.execute(cmd) - shaderItem = materialHier.children()[0] - shaderAttrs = ufe.Attributes.attributes(shaderItem) + materialHier = ufe.Hierarchy.hierarchy(materialItem) + self.assertTrue(materialHier.hasChildren()) + self.assertEqual(len(materialHier.children()), 1) - self.assertTrue(shaderAttrs.hasAttribute("info:id")) - shaderAttr = shaderAttrs.attribute("info:id") - shaderAttr.set("ND_standard_surface_surfaceshader") + shaderItem = materialHier.children()[0] + shaderAttrs = ufe.Attributes.attributes(shaderItem) - # TODO: Set base_color to red - # TODO: Connect "/Material1.outputs:mtlx:surface" to "/Material1/Red11.outputs:surface" + self.assertTrue(shaderAttrs.hasAttribute("info:id")) + shaderAttr = shaderAttrs.attribute("info:id") + shaderAttr.set("ND_standard_surface_surfaceshader") # Now that we have a material, we can bind it on the capsule item even if incomplete capsuleItem = rootHier.children()[0] @@ -427,6 +409,87 @@ def testMaterialBinding(self): cmds.redo() self.assertTrue(capsuleBindAPI.GetDirectBinding().GetMaterialPath().isEmpty) + @unittest.skipIf(os.getenv('UFE_PREVIEW_VERSION_NUM', '0000') < '4010', 'Test only available in UFE preview version 0.4.10 and greater') + @unittest.skipUnless(Usd.GetVersion() >= (0, 21, 8), 'Requires CanApplySchema from USD') + def testMaterialBindingWithNodeDefHandler(self): + """In this test we will go as far as possible towards creating and binding a working + material using only Ufe and Maya commands (for full undo capabilities). It is locked + at what Ufe 0.4.10 offers.""" + cmds.file(new=True, force=True) + + # Create a proxy shape with empty stage to start with. + import mayaUsd_createStageWithNewLayer + proxyShape = mayaUsd_createStageWithNewLayer.createStageWithNewLayer() + + # Create a ContextOps interface for the proxy shape. + proxyPathSegment = mayaUtils.createUfePathSegment(proxyShape) + proxyShapePath = ufe.Path([proxyPathSegment]) + proxyShapeItem = ufe.Hierarchy.createItem(proxyShapePath) + contextOps = ufe.ContextOps.contextOps(proxyShapeItem) + + cmd = contextOps.doOpCmd(['Add New Prim', 'Capsule']) + ufeCmd.execute(cmd) + cmd = contextOps.doOpCmd(['Add New Prim', 'Material']) + ufeCmd.execute(cmd) + + rootHier = ufe.Hierarchy.hierarchy(proxyShapeItem) + self.assertTrue(rootHier.hasChildren()) + self.assertEqual(len(rootHier.children()), 2) + + materialItem = rootHier.children()[-1] + contextOps = ufe.ContextOps.contextOps(materialItem) + + shaderName = "ND_standard_surface_surfaceshader" + surfDef = ufe.NodeDef.definition(materialItem.runTimeId(), shaderName) + cmd = surfDef.createNodeCmd(materialItem, ufe.PathComponent("Red1")) + ufeCmd.execute(cmd) + shaderItem = cmd.insertedChild + shaderAttrs = ufe.Attributes.attributes(shaderItem) + + self.assertTrue(shaderAttrs.hasAttribute("info:id")) + self.assertEqual(shaderAttrs.attribute("info:id").get(), shaderName) + self.assertEqual(ufe.PathString.string(shaderItem.path()), "|stage1|stageShape1,/Material1/Red11") + materialHier = ufe.Hierarchy.hierarchy(materialItem) + self.assertTrue(materialHier.hasChildren()) + + cmds.undo() + materialHier = ufe.Hierarchy.hierarchy(materialItem) + self.assertFalse(materialHier.hasChildren()) + + cmds.redo() + materialHier = ufe.Hierarchy.hierarchy(materialItem) + self.assertTrue(materialHier.hasChildren()) + shaderItem = cmd.insertedChild + shaderAttrs = ufe.Attributes.attributes(shaderItem) + + # Now that we have a material, we can bind it on the capsule item even if incomplete + capsuleItem = rootHier.children()[0] + capsulePrim = usdUtils.getPrimFromSceneItem(capsuleItem) + self.assertFalse(capsulePrim.HasAPI(UsdShade.MaterialBindingAPI)) + + contextOps = ufe.ContextOps.contextOps(capsuleItem) + cmd = contextOps.doOpCmd(['Bind Material', '/Material1']) + self.assertTrue(cmd) + ufeCmd.execute(cmd) + self.assertTrue(capsulePrim.HasAPI(UsdShade.MaterialBindingAPI)) + capsuleBindAPI = UsdShade.MaterialBindingAPI(capsulePrim) + self.assertEqual(capsuleBindAPI.GetDirectBinding().GetMaterialPath(), Sdf.Path("/Material1")) + + cmds.undo() + self.assertFalse(capsulePrim.HasAPI(UsdShade.MaterialBindingAPI)) + cmds.redo() + self.assertTrue(capsulePrim.HasAPI(UsdShade.MaterialBindingAPI)) + self.assertEqual(capsuleBindAPI.GetDirectBinding().GetMaterialPath(), Sdf.Path("/Material1")) + + cmd = contextOps.doOpCmd(['Unbind Material']) + self.assertTrue(cmd) + ufeCmd.execute(cmd) + + self.assertTrue(capsuleBindAPI.GetDirectBinding().GetMaterialPath().isEmpty) + cmds.undo() + self.assertEqual(capsuleBindAPI.GetDirectBinding().GetMaterialPath(), Sdf.Path("/Material1")) + cmds.redo() + self.assertTrue(capsuleBindAPI.GetDirectBinding().GetMaterialPath().isEmpty) def testAddNewPrimWithDelete(self): cmds.file(new=True, force=True) diff --git a/test/lib/ufe/testShaderNodeDef.py b/test/lib/ufe/testShaderNodeDef.py index 50bdf8470a..e44dbdd71c 100644 --- a/test/lib/ufe/testShaderNodeDef.py +++ b/test/lib/ufe/testShaderNodeDef.py @@ -137,7 +137,7 @@ def testDefinitionByType(self): self.assertEqual(outputs[0].name(), "out") self.assertEqual(outputs[0].type(), "ColorFloat3") - @unittest.skipIf(os.getenv('UFE_PREVIEW_VERSION_NUM', '0000') < '4008', 'Improvements to nodeDef only available in UFE preview version 0.4.8 and greater') + @unittest.skipIf(os.getenv('UFE_PREVIEW_VERSION_NUM', '0000') < '4010', 'Improvements to nodeDef only available in UFE preview version 0.4.8 and greater') def testClassificationsAndMetadata(self): type = "ND_image_color3" nodeDefHandler = self.getNodeDefHandler() From 21b11437df2d364c095a9106d7b1dea0903f3527 Mon Sep 17 00:00:00 2001 From: Jerry Gamache Date: Tue, 3 May 2022 16:49:54 -0400 Subject: [PATCH 5/5] Cleanup unreachable code in UsdShaderAttributeDef --- lib/mayaUsd/ufe/UsdShaderAttributeDef.cpp | 48 ++++++++++------------- 1 file changed, 21 insertions(+), 27 deletions(-) diff --git a/lib/mayaUsd/ufe/UsdShaderAttributeDef.cpp b/lib/mayaUsd/ufe/UsdShaderAttributeDef.cpp index c5045d374b..fde1352097 100644 --- a/lib/mayaUsd/ufe/UsdShaderAttributeDef.cpp +++ b/lib/mayaUsd/ufe/UsdShaderAttributeDef.cpp @@ -29,12 +29,13 @@ namespace MAYAUSD_NS_DEF { namespace ufe { +PXR_NAMESPACE_USING_DIRECTIVE + UsdShaderAttributeDef::UsdShaderAttributeDef( const PXR_NS::SdrShaderPropertyConstPtr& shaderAttributeDef) : Ufe::AttributeDef() , fShaderAttributeDef(shaderAttributeDef) { - PXR_NAMESPACE_USING_DIRECTIVE if (!TF_VERIFY(fShaderAttributeDef)) { throw std::runtime_error("Invalid shader attribute definition"); } @@ -44,42 +45,39 @@ UsdShaderAttributeDef::~UsdShaderAttributeDef() { } std::string UsdShaderAttributeDef::name() const { - return fShaderAttributeDef ? fShaderAttributeDef->GetName().GetString() : std::string(); + TF_AXIOM(fShaderAttributeDef); + return fShaderAttributeDef->GetName().GetString(); } std::string UsdShaderAttributeDef::type() const { - Ufe::Attribute::Type ufeType = Ufe::Attribute::kInvalid; - if (fShaderAttributeDef) { - const PXR_NS::SdfValueTypeName typeName = fShaderAttributeDef->GetTypeAsSdfType().first; - ufeType = usdTypeToUfe(typeName); - } - return ufeType; + TF_AXIOM(fShaderAttributeDef); + const PXR_NS::SdfValueTypeName typeName = fShaderAttributeDef->GetTypeAsSdfType().first; + return usdTypeToUfe(typeName); } std::string UsdShaderAttributeDef::defaultValue() const { + TF_AXIOM(fShaderAttributeDef); std::ostringstream defaultValue; - if (fShaderAttributeDef) { - defaultValue << fShaderAttributeDef->GetDefaultValue(); - } + defaultValue << fShaderAttributeDef->GetDefaultValue(); return defaultValue.str(); } Ufe::AttributeDef::IOType UsdShaderAttributeDef::ioType() const { - return (fShaderAttributeDef && fShaderAttributeDef->IsOutput()) ? Ufe::AttributeDef::OUTPUT_ATTR - : Ufe::AttributeDef::INPUT_ATTR; + TF_AXIOM(fShaderAttributeDef); + return fShaderAttributeDef->IsOutput() ? Ufe::AttributeDef::OUTPUT_ATTR + : Ufe::AttributeDef::INPUT_ATTR; } Ufe::Value UsdShaderAttributeDef::getMetadata(const std::string& key) const { - if (fShaderAttributeDef) { - const PXR_NS::NdrTokenMap& metadata = fShaderAttributeDef->GetMetadata(); - auto it = metadata.find(PXR_NS::TfToken(key)); - if (it != metadata.cend()) { - return Ufe::Value(it->second); - } + TF_AXIOM(fShaderAttributeDef); + const PXR_NS::NdrTokenMap& metadata = fShaderAttributeDef->GetMetadata(); + auto it = metadata.find(PXR_NS::TfToken(key)); + if (it != metadata.cend()) { + return Ufe::Value(it->second); } // TODO: Adapt UI metadata information found in SdrShaderProperty to Ufe standards // TODO: Fix Mtlx parser in USD to populate UI metadata in SdrShaderProperty @@ -88,14 +86,10 @@ Ufe::Value UsdShaderAttributeDef::getMetadata(const std::string& key) const bool UsdShaderAttributeDef::hasMetadata(const std::string& key) const { - if (fShaderAttributeDef) { - const PXR_NS::NdrTokenMap& metadata = fShaderAttributeDef->GetMetadata(); - auto it = metadata.find(PXR_NS::TfToken(key)); - if (it != metadata.cend()) { - return true; - } - } - return false; + TF_AXIOM(fShaderAttributeDef); + const PXR_NS::NdrTokenMap& metadata = fShaderAttributeDef->GetMetadata(); + auto it = metadata.find(PXR_NS::TfToken(key)); + return (it != metadata.cend()); } } // namespace ufe