Hi! I work at Remedy Entertainment where we’re using USD as our level data format. We’re currently trying to add support for something we call (for lack of a better name) ‘External References’ and I’ve come here looking for some advice as what we tried so far hasn’t really worked.
The way we’ve structured our layers is that we have a top-level layer per level, a bunch of other layers for composable things like areas, character, items, and so on, and then we also have a layer for global data which we want to point to from various layers. (This is simplified but I think will help get the point across)
We export our levels and global data to a runtime format where we identify objects by an id that is essentially a hash of its usd path. During runtime our global data is always loaded and we might have one or more levels loaded as well at the same time.
Now, up until this point, whenever a layer needs to point to any of the global data we’ve done so by manually entering string ids for the data you want to reference. We would however much prefer to point to it via relationship targets (to make it work with other tooling we have) and convert those targets into our ids. The problem we have is that because the id is based on the object’s usd path we can’t bring the global data layer in as a usd reference because that of course changes the object’s path.
So we tried instead to sublayer the global data in. But then we stumbled upon another problem which is that the relationship targets don’t seem to survive the reference composition arc. Let me give a simplified example.
We have items.usda:
#usda 1.0
(
defaultPrim = "items"
)
def "items"
{
def "briefcase"
{
}
}
player.usda:
#usda 1.0
(
defaultPrim = "player"
subLayers = [@items.usda@]
)
def "player"
{
rel equipped_item = </items/briefcase>
}
level.usda:
#usda 1.0
(
defaultPrim = "level"
subLayers = [@items.usda@]
)
def "level"
{
def "player" (
references = @player.usda@
)
{
}
}
If we run the following code:
auto stage = pxr::UsdStage::Open( "level.usda" );
pxr::SdfPathVector items;
stage->GetRelationshipAtPath( pxr::SdfPath( "/level/player.equipped_item" ) ).GetTargets( &items );
Then we get the following warning:
In </level/player.equipped_item>: The relationship target </items/briefcase> from </player.equipped_item> in layer @player.usda@ refers to a path outside the scope of the reference from </level/player>. Ignoring. (getting targets for relationship </level/player.equipped_item> on stage @level.usda@)
And items is empty.
That makes sense (at least I think so). When composing </player.equipped_item> into </level/player.equipped_item> it doesn’t know that level.usda also sublayers in items.usda and that the path is therefore valid.
Since sublayering didn’t work, our next idea is to bring the global data layer in as usd references but do some sort of re-mapping scheme in our tooling when we export the paths into our ids for our runtime format. But is there a way to make the sublayering work? Or are there any other ideas or advice on how we could structure our data to get the sort of referencing we’re looking for?