Skip to content

Commit

Permalink
MAYA-127355 - Add removeAttributesConnections to UsdAttributes
Browse files Browse the repository at this point in the history
  • Loading branch information
alicedegirolamo committed Feb 24, 2023
1 parent 639b4ba commit 07a7801
Show file tree
Hide file tree
Showing 4 changed files with 127 additions and 116 deletions.
118 changes: 86 additions & 32 deletions lib/mayaUsd/ufe/UsdAttributes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -455,7 +455,7 @@ bool UsdAttributes::canRemoveAttribute(const UsdSceneItem::Ptr& item, const std:
}
return false;
}
static void removeConnections(PXR_NS::UsdPrim& prim, const PXR_NS::UsdAttribute& srcUsdAttr)
static void removeSrcAttrConnections(PXR_NS::UsdPrim& prim, const PXR_NS::UsdAttribute& srcUsdAttr)
{
// Remove the connections with source srcUsdAttr.
for (const auto& attribute : prim.GetAttributes()) {
Expand All @@ -472,12 +472,57 @@ static void removeConnections(PXR_NS::UsdPrim& prim, const PXR_NS::UsdAttribute&
}
}

static void removeDstAttrConnections(const PXR_NS::UsdAttribute& dstUsdAttr)
{
const auto kPrim = dstUsdAttr.GetPrim();
PXR_NS::UsdShadeConnectableAPI connectApi(kPrim);

if (!kPrim || !connectApi) {
return;
}

const auto kPrimParent = kPrim.GetParent();

if (!kPrimParent) {
return;
}

UsdShadeSourceInfoVector sourcesInfo = connectApi.GetConnectedSources(dstUsdAttr);

if (sourcesInfo.empty()) {
return;
}

// The attribute is the connection destination.
PXR_NS::UsdPrim connectedPrim = sourcesInfo[0].source.GetPrim();

if (connectedPrim) {
const std::string prefix = connectedPrim == kPrimParent
? PXR_NS::UsdShadeUtils::GetPrefixForAttributeType(PXR_NS::UsdShadeAttributeType::Input)
: PXR_NS::UsdShadeUtils::GetPrefixForAttributeType(
PXR_NS::UsdShadeAttributeType::Output);

const std::string sourceName = prefix + sourcesInfo[0].sourceName.GetString();

auto srcAttr = connectedPrim.GetAttribute(PXR_NS::TfToken(sourceName));

if (srcAttr) {
UsdShadeConnectableAPI::DisconnectSource(dstUsdAttr, srcAttr);
// Check if we can remove the property.
if (MayaUsd::ufe::canRemoveSrcProperty(srcAttr)) {
// Remove the property.
connectedPrim.RemoveProperty(srcAttr.GetName());
}
}
}
}

static void
removeAllChildrenConnections(const PXR_NS::UsdPrim& prim, const PXR_NS::UsdAttribute& srcUsdAttr)
{
// Remove the connections with source srcUsdAttr for all the children.
for (auto&& usdChild : prim.GetChildren()) {
removeConnections(usdChild, srcUsdAttr);
removeSrcAttrConnections(usdChild, srcUsdAttr);
}
}

Expand All @@ -489,10 +534,9 @@ static void removeNodeGraphConnections(const PXR_NS::UsdAttribute& attr)
return;
}

PXR_NS::UsdShadeNodeGraph ngPrim(prim);
PXR_NS::UsdShadeConnectableAPI connectApi(prim);
PXR_NS::UsdShadeNodeGraph ngPrim(prim);

if (!ngPrim || !connectApi) {
if (!ngPrim) {
return;
}

Expand All @@ -510,41 +554,51 @@ static void removeNodeGraphConnections(const PXR_NS::UsdAttribute& attr)
return;
}

UsdShadeSourceInfoVector sourcesInfo = connectApi.GetConnectedSources(attr);
// Remove the connections to the destination attribute.
removeDstAttrConnections(attr);

if (!sourcesInfo.empty()) {
// The attribute is the connection destination.
PXR_NS::UsdPrim connectedPrim = sourcesInfo[0].source.GetPrim();
if (baseNameAndType.second == PXR_NS::UsdShadeAttributeType::Output) {
// Remove the connections from the source attribute.
removeAllChildrenConnections(primParent, attr);
removeSrcAttrConnections(primParent, attr);
}

if (connectedPrim) {
const std::string prefix = connectedPrim == primParent
? PXR_NS::UsdShadeUtils::GetPrefixForAttributeType(
PXR_NS::UsdShadeAttributeType::Input)
: PXR_NS::UsdShadeUtils::GetPrefixForAttributeType(
PXR_NS::UsdShadeAttributeType::Output);
if (baseNameAndType.second == PXR_NS::UsdShadeAttributeType::Input) {
removeAllChildrenConnections(prim, attr);
}
}

const std::string sourceName = prefix + sourcesInfo[0].sourceName.GetString();
void UsdAttributes::removeAttributesConnections(const PXR_NS::UsdPrim& prim)
{

auto srcAttr = connectedPrim.GetAttribute(PXR_NS::TfToken(sourceName));
auto primParent = prim.GetParent();

if (srcAttr) {
UsdShadeConnectableAPI::DisconnectSource(attr, srcAttr);
// Check if we can remove the property.
if (MayaUsd::ufe::canRemoveSrcProperty(srcAttr)) {
// Remove the property.
connectedPrim.RemoveProperty(srcAttr.GetName());
}
}
}
if (!primParent) {
return;
}

if (baseNameAndType.second == PXR_NS::UsdShadeAttributeType::Output) {
removeAllChildrenConnections(primParent, attr);
removeConnections(primParent, attr);
}
const auto kPrimAttrs = prim.GetAttributes();

if (baseNameAndType.second == PXR_NS::UsdShadeAttributeType::Input) {
removeAllChildrenConnections(prim, attr);
// Remove all the connections to/from the attribute.
for (const auto& attr : kPrimAttrs) {
const auto kBaseNameAndType
= PXR_NS::UsdShadeUtils::GetBaseNameAndType(PXR_NS::TfToken(attr.GetName()));

if (kBaseNameAndType.second != PXR_NS::UsdShadeAttributeType::Output
&& kBaseNameAndType.second != PXR_NS::UsdShadeAttributeType::Input) {
continue;
}

if (kBaseNameAndType.second == PXR_NS::UsdShadeAttributeType::Input) {
// Remove the connections to the destination attribute.
removeDstAttrConnections(attr);
}

if (kBaseNameAndType.second == PXR_NS::UsdShadeAttributeType::Output) {
removeAllChildrenConnections(primParent, attr);
// Remove the connections from the source attribute.
removeSrcAttrConnections(primParent, attr);
}
}
}

Expand Down
1 change: 1 addition & 0 deletions lib/mayaUsd/ufe/UsdAttributes.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ class UsdAttributes : public Ufe::Attributes
static std::string getUniqueAttrName(const UsdSceneItem::Ptr& item, const std::string& name);
static bool canRemoveAttribute(const UsdSceneItem::Ptr& item, const std::string& name);
static bool doRemoveAttribute(const UsdSceneItem::Ptr& item, const std::string& name);
static void removeAttributesConnections(const PXR_NS::UsdPrim& prim);
#endif
#if (UFE_PREVIEW_VERSION_NUM >= 4034)
static bool canRenameAttribute(
Expand Down
91 changes: 9 additions & 82 deletions lib/mayaUsd/ufe/UsdUndoDeleteCommand.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,13 @@
#include <pxr/usd/sdf/layer.h>

#ifdef UFE_V2_FEATURES_AVAILABLE
#include <mayaUsd/ufe/UsdAttributes.h>
#include <mayaUsd/undo/UsdUndoBlock.h>
#endif

#ifdef UFE_V4_FEATURES_AVAILABLE
#include <mayaUsd/ufe/UsdAttributes.h>
#endif

namespace {
#ifdef MAYA_ENABLE_NEW_PRIM_DELETE
bool hasLayersMuted(const PXR_NS::UsdPrim& prim)
Expand Down Expand Up @@ -68,86 +71,6 @@ UsdUndoDeleteCommand::Ptr UsdUndoDeleteCommand::create(const PXR_NS::UsdPrim& pr
}

#ifdef UFE_V2_FEATURES_AVAILABLE

void removeAttributesConnections(const PXR_NS::UsdPrim& prim)
{

PXR_NS::UsdShadeConnectableAPI connectApi(prim);
const auto kPrimParent = prim.GetParent();

if (!connectApi || !kPrimParent) {
return;
}

const PXR_NS::SdfPath kPrimPath = prim.GetPath();
const auto kPrimAttrs = prim.GetAttributes();

for (const auto& attr : kPrimAttrs) {
const PXR_NS::SdfPath kPropertyPath = kPrimPath.AppendProperty(attr.GetName());
const auto kBaseNameAndType
= PXR_NS::UsdShadeUtils::GetBaseNameAndType(PXR_NS::TfToken(attr.GetName()));

if (kBaseNameAndType.second != PXR_NS::UsdShadeAttributeType::Output
&& kBaseNameAndType.second != PXR_NS::UsdShadeAttributeType::Input) {
continue;
}

if (kBaseNameAndType.second == PXR_NS::UsdShadeAttributeType::Input) {
UsdShadeSourceInfoVector sourcesInfo = connectApi.GetConnectedSources(attr);

if (!sourcesInfo.empty()) {
// The attribute is the connection destination.
const PXR_NS::UsdPrim connectedPrim = sourcesInfo[0].source.GetPrim();

if (connectedPrim) {
const std::string prefix = connectedPrim == kPrimParent
? PXR_NS::UsdShadeUtils::GetPrefixForAttributeType(
PXR_NS::UsdShadeAttributeType::Input)
: PXR_NS::UsdShadeUtils::GetPrefixForAttributeType(
PXR_NS::UsdShadeAttributeType::Output);

const std::string sourceName = prefix + sourcesInfo[0].sourceName.GetString();

auto srcAttr = connectedPrim.GetAttribute(PXR_NS::TfToken(sourceName));

if (srcAttr) {
UsdShadeConnectableAPI::DisconnectSource(attr, srcAttr);
// Check if we can remove also the property.
// Remove the property.
}
}
}
}

auto removeConnections
= [](const PXR_NS::UsdPrim& prim, const PXR_NS::SdfPath& srcPropertyPath) {
for (const auto& attribute : prim.GetAttributes()) {
PXR_NS::UsdAttribute attr = attribute.As<PXR_NS::UsdAttribute>();
PXR_NS::SdfPathVector sources;
attr.GetConnections(&sources);

for (size_t i = 0; i < sources.size(); ++i) {
if (sources[i] == srcPropertyPath) {
attr.RemoveConnection(srcPropertyPath);
// Check if we can remove also the property.
// Remove the property.
break;
}
}
}
};

if (kBaseNameAndType.second == PXR_NS::UsdShadeAttributeType::Output) {
removeConnections(kPrimParent, kPropertyPath);
for (const auto& kChildPrim : kPrimParent.GetChildren()) {
if (kChildPrim != prim) {
removeConnections(kChildPrim, kPropertyPath);
}
}
}
}
}

void UsdUndoDeleteCommand::execute()
{
if (!_prim.IsValid())
Expand All @@ -167,7 +90,11 @@ void UsdUndoDeleteCommand::execute()
}

if (MayaUsd::ufe::applyCommandRestrictionNoThrow(_prim, "delete")) {
removeAttributesConnections(_prim);
#ifdef UFE_V4_FEATURES_AVAILABLE
#if (UFE_PREVIEW_VERSION_NUM >= 4024)
UsdAttributes::removeAttributesConnections(_prim);
#endif
#endif
auto retVal = stage->RemovePrim(_prim.GetPath());
if (!retVal) {
TF_VERIFY(retVal, "Failed to delete '%s'", _prim.GetPath().GetText());
Expand Down
33 changes: 31 additions & 2 deletions test/lib/ufe/testDeleteCmd.py
Original file line number Diff line number Diff line change
Expand Up @@ -365,8 +365,12 @@ def testDeleteAndRemoveConnections(self):
'''Test deleting a prim and its connections'''

# Load a scene with a compound.

mayaUtils.openTestScene("MaterialX", "multiple_connections.ma" )
mayaUtils.openTestScene("MaterialX", "multiple_connections.ma")

# Get the stage.
mayaPathSegment = mayaUtils.createUfePathSegment('|multiple_connections|multiple_connectionsShape')
stage = mayaUsd.ufe.getStage(str(mayaPathSegment))
self.assertTrue(stage)

deleteItemPath = ufe.PathString.path('|multiple_connections|multiple_connectionsShape,/Material1/UsdPreviewSurface1')
previewItemPath = ufe.PathString.path('|multiple_connections|multiple_connectionsShape,/Material1/UsdPreviewSurface2')
Expand Down Expand Up @@ -435,6 +439,21 @@ def testDeleteAndRemoveConnections(self):
conns = connections.allConnections()
self.assertEqual(len(conns), 1)

# Test the properties.
parentPrim = stage.GetPrimAtPath('/Material1')
surface1Prim = stage.GetPrimAtPath('/Material1/surface1')
previewSurface2Prim = stage.GetPrimAtPath('/Material1/UsdPreviewSurface2')
fractal3d1Prim = stage.GetPrimAtPath('/Material1/fractal3d1')
self.assertTrue(parentPrim)
self.assertTrue(surface1Prim)
self.assertTrue(previewSurface2Prim)
self.assertTrue(fractal3d1Prim)
self.assertTrue(parentPrim.HasProperty('inputs:clearcoat'))
self.assertTrue(parentPrim.HasProperty('outputs:displacement1'))
self.assertFalse(surface1Prim.HasProperty('outputs:out'))
self.assertFalse(fractal3d1Prim.HasProperty('inputs:amplitude'))
self.assertFalse(previewSurface2Prim.HasProperty('inputs:diffuseColor'))

# Delete the compound.
cmds.delete('|multiple_connections|multiple_connectionsShape,/Material1/compound')

Expand All @@ -446,5 +465,15 @@ def testDeleteAndRemoveConnections(self):
conns = connections.allConnections()
self.assertEqual(len(conns), 0)

# Test the properties.
surface2Prim = stage.GetPrimAtPath('/Material1/surface2')
surface3Prim = stage.GetPrimAtPath('/Material1/surface3')
self.assertTrue(surface2Prim)
self.assertTrue(surface3Prim)
self.assertTrue(parentPrim.HasProperty('inputs:clearcoat1'))
self.assertTrue(parentPrim.HasProperty('outputs:displacement'))
self.assertFalse(surface2Prim.HasProperty('outputs:out'))
self.assertFalse(surface3Prim.HasProperty('inputs:bsdf'))

if __name__ == '__main__':
unittest.main(verbosity=2)

0 comments on commit 07a7801

Please sign in to comment.