Hi all! Recently we’ve gotten into more practical testing of asset workflows with ayon and we ran into an issue with look loading on rigged assets – it is very similar to this post.
Our riggers find it helpful to see how the rig is deforming the shaded asset, so we’d like to be able to use the look assigner in rig scenes. However, in maya when you reference a model and start to rig, maya automatically creates copies of the shape nodes (normally called [shape name]Deformed), since it can’t directly modify the reference. The issue is that these new deformed shapes do not have a cbId, and even if you do save the scene/regenerate it, it’s not the same as the previous cbId.
This then breaks the look assignment workflow, since the data in the look assignment json has different shape names and cbIds.
I’m wondering if others have hit this issue, and if so, what kind of steps have been taken to resolve? We have a few ideas, but each has drawbacks:
Modify look assigner logic to seek children of each member transform, instead of seeking the shape directly. Might also need to modify the logic to ignore the cbId, which could cause bugs
Import the shader before starting the rig (but it’s not always available, depts work in tandem). Possibly a placeholder workflow?
Have riggers import models instead of referencing (obviously gives up other benefits of referencing)
Publishing the rig should validate for this - as such, the easiest fix is to open the publisher UI once, validate and trigger repair there.
It’s the ValidateRigOutSetNodeIds plug-in.
If you want to run the repair code yourself without that validator:
import logging
from ayon_maya.api import lib
log = logging.getLogger(__name__)
def get_invalid(shapes):
"""Get all nodes which do not match the criteria"""
invalid = []
for shape in shapes:
sibling_id = lib.get_id_from_sibling(
shape,
history_only=False
)
if sibling_id:
current_id = lib.get_id(shape)
if current_id != sibling_id:
invalid.append(shape)
return invalid
def repair(node):
# Get the original id from sibling
sibling_id = lib.get_id_from_sibling(
node,
history_only=False
)
if not sibling_id:
log.error("Could not find ID in siblings for '%s'", node)
return
# Assign the id from sibling
lib.set_id(node, sibling_id, overwrite=True)
# Get all non-intermediate meshes in scene
shapes = cmds.ls(type="mesh", noIntermediate=True, shapes=True, long=True)
for shape in get_invalid(shapes):
repair(shape)
Just so you are aware - we ARE processing the children (shapes) we just skip the intermediate objects.
Thanks for the reply! I first tried your suggestion of validating the Rig product, and while I see that the Rig Output IDs validation ran, it did seems to have just succeeded and didn’t offer to repair any missing ids That being said, running the above code directly in the script editor worked.
It only validates geometry that is in the out_SET of your rig instance. So it may be that you did not set up that part of your rig yet? Can you confirm?
The out SET is what defines, that when the published rig is loaded into an another scene that the “animation” instance it automatically generates caches the geometry that is in the out SET and does not extract the full rig with controls, etc.
In those example screenshots the meshes themselves are added into the set. But on our we tend to just have e.g. a rig like:
rig_GRP
geo_GRP <- added to out_SET
body_GEO
pants_GEO
some_subgroup_GRP
some_subgroup_GEO
controls_GRP
master_control_hierarchy_GRP
master_CTRL <- added to controls_SET
some_other_hierarchy_GRP
some_other_CTRL <- added to controls_SET
The geo_GRP is then added into the out_SET, not the individual meshes
And each control is individually added to the controls_SET which makes it so that validations run over those controls, e.g. they must all have their default values - no input keys, locked visibility attributes, etc.
I’m sorry, I’m a little confused by this last message – it is or it isn’t supposed to automatically add things to the out_SET when you create the instance?
In my case, I have a main rig group with subgroups for the geometry and the joints, but nothing was put in the out_SET when I created the instance (from the docs I had thought it was automatic).
Thanks for the clarification! Indeed now that I look at the docs again, I see the little sentence I missed saying that one should add the controls/geo manually to the set. Sorry about that, Friday brain
One more quick question regarding the rigs, what are the skeletonMesh and skeletonAnim sets for? I see that these are created automatically in the rig product instance, but not sure what is supposed to go in them.
They are for FBX exports. @moonyuet could potentially elaborate on those.
But in essence I believe:
The skeletonMesh_SET defines the static full character geometry with skinning and skeleton as an FBX product directly from the rig publish.
The skeleton_anim_SET defines the animated content that should be published to FBX from an animation scene for the animation product type.
So 1) directly generates an FBX from the rig file and 2) is used in the animation scenes upon loading the (mayascene-rig?) into Maya to define the output from the animation product type for an FBX export.
skeleton_anim_SET would publish animation content in fbx format. And once you imported it into unreal, it only imports the animation sequence. But you can export with entire set like you did in alembic animation, and you can get the blend shape. And once you imported it into unreal, it imports skeletal mesh + animation sequence
@BigRoy Thanks. You have already clarified how the fbx rig/animation workflow works.
This particular workflow is developed for the asset management in Unreal.
The user would put the full character geometry and skeleton(aka rig) into the skeletonMesh_SET and publish the fbx version of the rig (along with the ma format too).
Then the user loading the same rig in ma file and animating the character. Once the user finishes the animating process, he/she adds the animated content into skeleton_anim_SET and publish the fbx version of the animation.
Users then go to Unreal to load the rig in fbx and then load animation (also in fbx) too. The rig and animation product would be loaded in separate folders. Only skeletal mesh and skeleton would appear in the rig folder while there is merely animation sequence in the animation folder.
One more remark: Any version of the animation product can be applied to different version of the rig if the hierarchies of it does not change.(And vice versa: Different version of the animation product type can be applied to the same version of the rig, if they are animated from the same rig)