Skip to content

Commit

Permalink
Merge pull request #3364 from Autodesk/bailp/EMSUSD-489/reparent-crash
Browse files Browse the repository at this point in the history
EMSUSD-489 fix reparenting crash
  • Loading branch information
seando-adsk authored Oct 5, 2023
2 parents 853fb1b + 36478d7 commit ca89f23
Show file tree
Hide file tree
Showing 7 changed files with 112 additions and 12 deletions.
3 changes: 3 additions & 0 deletions lib/mayaUsd/ufe/UsdTransform3dMatrixOp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,9 @@ class UsdSetMatrix4dUndoableCmd : public UsdUndoableCommand<Ufe::SetMatrix4dUndo
// transform3d() returns a whole-object interface, which may include
// other transform ops.
auto t3d = Ufe::Transform3d::editTransform3d(sceneItem());
if (!TF_VERIFY(t3d)) {
return;
}
t3d->setMatrix(_newM);
}

Expand Down
30 changes: 27 additions & 3 deletions lib/usdUfe/ufe/UsdUndoInsertChildCommand.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,8 @@ static void doInsertion(

enforceMutedLayer(srcPrim, "reparent");

int affectedLayersCount = 0;

// Do the insertion from the source layer to the target layer.
{
PrimLayerFunc insertionFunc
Expand All @@ -208,7 +210,7 @@ static void doInsertion(

const bool includeTopLayer = true;
const auto rootLayers = getAllSublayerRefs(stage->GetRootLayer(), includeTopLayer);
applyToSomeLayersWithOpinions(srcPrim, rootLayers, insertionFunc);
affectedLayersCount += applyToSomeLayersWithOpinions(srcPrim, rootLayers, insertionFunc);
}

// Do the insertion in all other applicable layers, which, due to the command
Expand All @@ -223,7 +225,18 @@ static void doInsertion(

const bool includeTopLayer = true;
const auto sessionLayers = getAllSublayerRefs(stage->GetSessionLayer(), includeTopLayer);
applyToSomeLayersWithOpinions(srcPrim, sessionLayers, insertionFunc);
affectedLayersCount += applyToSomeLayersWithOpinions(srcPrim, sessionLayers, insertionFunc);
}

// If no local layers were affected, then it means the prim is not local.
// It probably is inside a reference and we do not support reparent from within
// reference at this point. Report the error and abort the command.
if (0 == affectedLayersCount) {
const std::string error = TfStringPrintf(
"Cannot reparent prim \"%s\" because we found no local layer containing it.",
srcPrim.GetPath().GetText());
TF_WARN("%s", error.c_str());
throw std::runtime_error(error);
}

// Remove all scene descriptions for the source path and its subtree in the source layer.
Expand All @@ -241,7 +254,18 @@ static void doInsertion(
}
};

applyToAllLayersWithOpinions(srcPrim, removeFunc);
affectedLayersCount = applyToAllLayersWithOpinions(srcPrim, removeFunc);

// If no local layers were affected, then it means the prim is not local.
// It probably is inside a reference and we do not support reparent from within
// reference at this point. Report the error and abort the command.
if (0 == affectedLayersCount) {
const std::string error = TfStringPrintf(
"Cannot reparent prim \"%s\" because we found no local layer containing it.",
srcPrim.GetPath().GetText());
TF_WARN("%s", error.c_str());
throw std::runtime_error(error);
}
}

static void
Expand Down
26 changes: 21 additions & 5 deletions lib/usdUfe/utils/layers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ void getAllSublayers(
processing.pop_front();
SdfSubLayerProxy sublayerPaths = layerToProcess->GetSubLayerPaths();
for (auto path : sublayerPaths) {
SdfLayerRefPtr sublayer = SdfLayer::FindOrOpen(path);
SdfLayerRefPtr sublayer = SdfLayer::FindRelativeToLayer(layer, path);
if (sublayer) {
if (layerIds)
layerIds->insert(path);
Expand Down Expand Up @@ -117,34 +117,50 @@ void enforceMutedLayer(const PXR_NS::UsdPrim& prim, const char* command)
}
}

void applyToAllPrimSpecs(const UsdPrim& prim, const PrimSpecFunc& func)
int applyToAllPrimSpecs(const UsdPrim& prim, const PrimSpecFunc& func)
{
int count = 0;

const SdfPrimSpecHandleVector primStack = getLocalPrimStack(prim);
for (const SdfPrimSpecHandle& spec : primStack)
for (const SdfPrimSpecHandle& spec : primStack) {
func(prim, spec);
++count;
}

return count;
}

void applyToAllLayersWithOpinions(const UsdPrim& prim, PrimLayerFunc& func)
int applyToAllLayersWithOpinions(const UsdPrim& prim, PrimLayerFunc& func)
{
int count = 0;

const SdfPrimSpecHandleVector primStack = getLocalPrimStack(prim);
for (const SdfPrimSpecHandle& spec : primStack) {
const auto layer = spec->GetLayer();
func(prim, layer);
++count;
}

return count;
}

void applyToSomeLayersWithOpinions(
int applyToSomeLayersWithOpinions(
const UsdPrim& prim,
const std::set<SdfLayerRefPtr>& layers,
PrimLayerFunc& func)
{
int count = 0;

const SdfPrimSpecHandleVector primStack = getLocalPrimStack(prim);
for (const SdfPrimSpecHandle& spec : primStack) {
const auto layer = spec->GetLayer();
if (layers.count(layer) == 0)
continue;
func(prim, layer);
++count;
}

return count;
}

bool isLayerInStage(const PXR_NS::SdfLayerHandle& layer, const PXR_NS::UsdStage& stage)
Expand Down
9 changes: 6 additions & 3 deletions lib/usdUfe/utils/layers.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,24 +90,26 @@ void enforceMutedLayer(const PXR_NS::UsdPrim& prim, const char* command);
*
* @param prim The prim to be modified.
* @param func The function to be applied.
* @return the number of prim specs that were affected.
*/

using PrimSpecFunc = std::function<void(const PXR_NS::UsdPrim&, const PXR_NS::SdfPrimSpecHandle&)>;

USDUFE_PUBLIC
void applyToAllPrimSpecs(const PXR_NS::UsdPrim& prim, const PrimSpecFunc& func);
int applyToAllPrimSpecs(const PXR_NS::UsdPrim& prim, const PrimSpecFunc& func);

/**
* Apply the given function to all the layers that have an opinion about the given prim.
*
* @param prim The prim to be modified.
* @param func The function to be applied.
* @return the number of layers that were affected.
*/

using PrimLayerFunc = std::function<void(const PXR_NS::UsdPrim&, const PXR_NS::SdfLayerRefPtr&)>;

USDUFE_PUBLIC
void applyToAllLayersWithOpinions(const PXR_NS::UsdPrim& prim, PrimLayerFunc& func);
int applyToAllLayersWithOpinions(const PXR_NS::UsdPrim& prim, PrimLayerFunc& func);

/**
* Apply the given function to some of the layers that have an opinion about the given prim.
Expand All @@ -116,10 +118,11 @@ void applyToAllLayersWithOpinions(const PXR_NS::UsdPrim& prim, PrimLayerFunc& fu
* @param prim The prim to be modified.
* @param layers The set of layers that can be affected if they contain an opinion.
* @param func The function to be applied.
* @return the number of layers that were affected.
*/

USDUFE_PUBLIC
void applyToSomeLayersWithOpinions(
int applyToSomeLayersWithOpinions(
const PXR_NS::UsdPrim& prim,
const std::set<PXR_NS::SdfLayerRefPtr>& layers,
PrimLayerFunc& func);
Expand Down
15 changes: 14 additions & 1 deletion test/lib/ufe/testParentCmd.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@

import mayaUsd.ufe

from pxr import UsdGeom, Vt, Gf, Sdf
from pxr import UsdGeom, Vt, Gf, Sdf, Usd

from maya import cmds
from maya import standalone
Expand Down Expand Up @@ -275,6 +275,19 @@ def testParentAbsolute(self):
cylChildren = cylHier.children()
self.assertEqual(len(cylChildren), 1)

def testParentRelativeLayer(self):
'''
Test that parenting in sub-layer that are loaded in relative mode works.
'''
usdFileName = testUtils.getTestScene('relativeSubLayer', 'root.usda')
shapeNode, stage = mayaUtils.createProxyFromFile(usdFileName)
self.assertEqual(len(stage.GetRootLayer().subLayerPaths), 1)
sublayer = Sdf.Layer.FindRelativeToLayer(stage.GetRootLayer(), stage.GetRootLayer().subLayerPaths[0])
with Usd.EditContext(stage, sublayer):
cmds.parent(shapeNode + ',/group/geo', shapeNode + ',/group/other')
movedCube = stage.GetPrimAtPath('/group/other/geo/cube')
self.assertTrue(movedCube)

@unittest.skipUnless(mayaUtils.mayaMajorVersion() >= 2023, 'Requires Maya fixes only available in Maya 2023 or greater.')
def testParentAbsoluteSingleMatrixOp(self):
"""Test parent -absolute on prim with a single matrix op."""
Expand Down
14 changes: 14 additions & 0 deletions test/testSamples/relativeSubLayer/root.usda
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#usda 1.0
(
subLayers = [
@sublayer.usda@,
]
)

# With sub-layer, the hierarchy is group/geo/cube and group/other
def Xform "group" (
kind = "component"
)
{
}

27 changes: 27 additions & 0 deletions test/testSamples/relativeSubLayer/sublayer.usda
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#usda 1.0

over Xform "group" (
kind = "component"
)
{
double3 xformOp:translate = (5.8646097315075165, 0, 2.156596612263078)
uniform token[] xformOpOrder = ["xformOp:translate"]

def Xform "geo"
{
def Mesh "cube"
{
float3[] extent = [(-0.5, -0.5, -0.5), (0.5, 0.5, 0.5)]
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)]
color3f[] primvars:displayColor = [(0.4, 0.4, 0.4)]
uniform token subdivisionScheme = "none"
}
}

def Xform "other"
{
}
}

0 comments on commit ca89f23

Please sign in to comment.