Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

EMSUSD-489 fix reparenting crash #3364

Merged
merged 1 commit into from
Oct 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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"
{
}
}