Hi, for some diagnostic tasks I need to modify materials. My idea was to collect all materials copy them into a new stage do all modifications I need and save it as new file. This way I can layer it later to create my diagnostic shading. Usually I’d copy a prim with Sdf.CopySpec() but this only works if I have one flat usd file. As soon as I have a composed stage, this process failes.
My approach was this one:
from pxr import Sdf, Usd, UsdShade, UsdUtils
stagePath = "C:/daten/3d/HoudiniProjects/usd/refStage.usda"
overStagePath = "C:/daten/3d/HoudiniProjects/usd/setStageOver.usda"
overLayer = Sdf.Layer.CreateNew(overStagePath, args={'format':'usda'})
overStage = Usd.Stage.Open(overLayer)
stage = Usd.Stage.Open(stagePath)
for prim in stage.Traverse():
if prim.IsA(UsdShade.Material):
primPath = prim.GetPath()
Sdf.CopySpec(stage.GetRootLayer(), primPath, overStage.GetRootLayer(), primPath)
This works fine if I have a flat usd file. As soon as I have a stage like this - of course with valid geo and mtl files:
pxr.Tf.ErrorException:
Error in 'pxrInternal_v0_25_8__pxrReserved__::SdfCopySpec' at line 590 in file D:\a\OpenUSD\OpenUSD\pxr\usd\sdf\copyUtils.cpp : 'Cannot copy unknown spec at </asset/mtl/red> from layer <C:/daten/3d/HoudiniProjects/usd/mtl.usda>'
It seems that I’m missing something fundamental in my understanding of layering and stage composition, but to be honest I’m a bit lost and I’d appreciate any help here.
The reason this happens is because the Sdf APIs are for working with the layers pre-composition. When you flatten, you bake down the composition.
Therefore SDF cannot see the results of the reference composition arc.
But since you are referencing anyway, the better way to “copy” something over is to just reference it into a new layer. Since references let you pick the prim path you bring in, you can use it to isolate to just the hierarchy you want.
Careful, though… if “asset” makes any overrides on the Material network of prims, those will not be present on the new stage. If you Sdf.CopySpec (recursively) the “mtl” prim, they should then come along, and the reference comes also. But you can still wind up with differences if your asset file, for e.g. has internal references on “mtl” or any child specs, or it contains class overrides (i.e. from inherits statements established in mtl.usda), or the “asset” prim itself has references that apply overrides to its “mtl” child.
I know those exceptions seem kind of technical, but there’s (obviously not well explained or detailed!) reasons we have yet to provide any utility for copying chunks of composed scenegraph. The safest way to do what you need is to first Flatten() the asset stage to a layer and then do your copying from that layer. In so doing you will lose any “live” connection to mtl.usda, but it’s the only way I know of to guarantee that your new stage will have materials that resolve identically to your source stages.
Thanks for the feedback. I now realized that I do not have to copy anything at all. I simply modify the stage and there is no need to save something to a separate file. Since my modifications seem to work quite fast, and the diagnostic setup is only needed in a few specific situations, this process works fine as much as I can see.