Skip to content

Commit

Permalink
Merge pull request #3564 from Autodesk/gamaj/LOOKDEVX-2403/allow_crea…
Browse files Browse the repository at this point in the history
…ting_custom_types_at_nodegraph_boundaries

LOOKDEVX-2403 - Allow creating custom types at NodeGraph boundaries
  • Loading branch information
seando-adsk authored Jan 19, 2024
2 parents 6cca972 + 4cf8fd3 commit ccb3c1e
Show file tree
Hide file tree
Showing 5 changed files with 64 additions and 4 deletions.
6 changes: 6 additions & 0 deletions lib/mayaUsd/ufe/UsdAttribute.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -477,6 +477,12 @@ UsdAttributeGeneric::create(const UsdSceneItem::Ptr& item, UsdAttributeHolder::U

std::string UsdAttributeGeneric::nativeType() const { return UsdAttribute::nativeType(); }

const std::string& UsdAttributeGeneric::nativeSdrTypeMetadata()
{
static const auto kMetadataName = std::string { "nativeSdrType" };
return kMetadataName;
}

#ifdef UFE_V4_FEATURES_AVAILABLE
//------------------------------------------------------------------------------
// UsdAttributeFilename:
Expand Down
4 changes: 4 additions & 0 deletions lib/mayaUsd/ufe/UsdAttribute.h
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,10 @@ class UsdAttributeGeneric

// Ufe::AttributeGeneric overrides
std::string nativeType() const override;

// Metadata used when creating a dynamic attribute on NodeGraph/Material boundaries that
// remembers the native type of a generic shader property.
static const std::string& nativeSdrTypeMetadata();
}; // UsdAttributeGeneric

#ifdef UFE_V4_FEATURES_AVAILABLE
Expand Down
12 changes: 12 additions & 0 deletions lib/mayaUsd/ufe/UsdAttributeHolder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,18 @@ std::string UsdAttributeHolder::defaultValue() const { return std::string(); }

std::string UsdAttributeHolder::nativeType() const
{
#ifdef UFE_V3_FEATURES_AVAILABLE
if (usdAttributeType() == SdfValueTypeNames->Token && PXR_NS::UsdShadeNodeGraph(usdPrim())) {
// We might have saved the Sdr native type as metadata:
if (PXR_NS::UsdShadeInput::IsInput(_usdAttr)
|| PXR_NS::UsdShadeOutput::IsOutput(_usdAttr)) {
const auto metaValue = getMetadata(UsdAttributeGeneric::nativeSdrTypeMetadata());
if (!metaValue.empty() && metaValue.isType<std::string>()) {
return metaValue.get<std::string>();
}
}
}
#endif
return usdAttributeType().GetType().GetTypeName();
}

Expand Down
16 changes: 14 additions & 2 deletions lib/mayaUsd/ufe/UsdAttributes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -373,9 +373,21 @@ Ufe::Attribute::Ptr UsdAttributes::doAddAttribute(
}
}
// Fallback to creating a nodegraph output.
connectApi.CreateOutput(baseNameAndType.first, ufeTypeToUsd(type));
auto usdType = ufeTypeToUsd(type);
auto output = connectApi.CreateOutput(
baseNameAndType.first, usdType ? usdType : SdfValueTypeNames->Token);
if (!usdType) {
output.SetSdrMetadataByKey(
TfToken(UsdAttributeGeneric::nativeSdrTypeMetadata()), type);
}
} else if (baseNameAndType.second == PXR_NS::UsdShadeAttributeType::Input) {
connectApi.CreateInput(baseNameAndType.first, ufeTypeToUsd(type));
auto usdType = ufeTypeToUsd(type);
auto input = connectApi.CreateInput(
baseNameAndType.first, usdType ? usdType : SdfValueTypeNames->Token);
if (!usdType) {
input.SetSdrMetadataByKey(
TfToken(UsdAttributeGeneric::nativeSdrTypeMetadata()), type);
}
}
}

Expand Down
30 changes: 28 additions & 2 deletions test/lib/ufe/testConnections.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ def __init__(self):
self._removedNotifications = 0
self._valueChangedNotifications = 0
self._connectionChangedNotifications = 0
self._metadataChangedNotifications = 0
self._unknownNotifications = 0

def __call__(self, notification):
Expand All @@ -48,6 +49,8 @@ def __call__(self, notification):
self._valueChangedNotifications += 1
elif isinstance(notification, ufe.AttributeConnectionChanged):
self._connectionChangedNotifications += 1
elif isinstance(notification, ufe.AttributeMetadataChanged):
self._metadataChangedNotifications += 1
else:
self._unknownNotifications += 1

Expand All @@ -56,6 +59,7 @@ def assertNotificationCount(self, test, **counters):
test.assertEqual(self._removedNotifications, counters.get("numRemoved", 0))
test.assertEqual(self._valueChangedNotifications, counters.get("numValue", 0))
test.assertEqual(self._connectionChangedNotifications, counters.get("numConnection", 0))
test.assertEqual(self._metadataChangedNotifications, counters.get("numMetadata", 0))
test.assertEqual(self._unknownNotifications, 0)


Expand Down Expand Up @@ -951,10 +955,32 @@ def testCreateNodeGraphAttributes(self):
testObserver.assertNotificationCount(self, numAdded = 1)
testAttrs.addAttribute("outputs:bar", ufe.Attribute.kFloat4)
testObserver.assertNotificationCount(self, numAdded = 2)

# Testing custom NodeGraph data types
testAttrs.addAttribute("inputs:edf", "EDF")
# The custom type is saved as metadata, which emits one value and one metadata changes
testObserver.assertNotificationCount(self, numAdded = 3, numValue=1, numMetadata=1)
customAttr = testAttrs.attribute("inputs:edf")
self.assertEqual(customAttr.type, "Generic")
# Make sure the custom shader type was remembered
self.assertEqual(customAttr.nativeType(), "EDF")

# Same thing, on the output side
testAttrs.addAttribute("outputs:srf", "surfaceshader")
testObserver.assertNotificationCount(self, numAdded = 4, numValue=2, numMetadata=2)
customAttr = testAttrs.attribute("outputs:srf")
self.assertEqual(customAttr.type, "Generic")
self.assertEqual(customAttr.nativeType(), "surfaceshader")

testAttrs.removeAttribute("inputs:foo")
testObserver.assertNotificationCount(self, numAdded = 2, numRemoved = 1)
testObserver.assertNotificationCount(self, numAdded = 4, numRemoved = 1, numValue=2, numMetadata=2)
testAttrs.removeAttribute("outputs:bar")
testObserver.assertNotificationCount(self, numAdded = 2, numRemoved = 2)
testObserver.assertNotificationCount(self, numAdded = 4, numRemoved = 2, numValue=2, numMetadata=2)
testAttrs.removeAttribute("inputs:edf")
testObserver.assertNotificationCount(self, numAdded = 4, numRemoved = 3, numValue=2, numMetadata=2)
testAttrs.removeAttribute("outputs:srf")
testObserver.assertNotificationCount(self, numAdded = 4, numRemoved = 4, numValue=2, numMetadata=2)


@unittest.skipUnless(ufeUtils.ufeFeatureSetVersion() >= 4, 'Test only available in UFE v4 or greater')
def testCompoundDisplacementPassthrough(self):
Expand Down

0 comments on commit ccb3c1e

Please sign in to comment.