OpenPype icon indicating copy to clipboard operation
OpenPype copied to clipboard

Maya: Yeti Validate Rig Input

Open m-u-r-p-h-y opened this issue 3 years ago • 10 comments

Describe the bug There is a problem with the validation of Yeti Rig Input meshes.

b'Processing Subset Name'
b'Processing Subset Name'
b'Processing Resources Unique'
// pyblish.ValidateResources : No resources to validate..
b'Processing Resources Unique'
// pyblish.ValidateResources : No resources to validate..
b'Processing Yeti Rig Input Shapes In Instance'
// Error: pyblish.plugin : Traceback (most recent call last):
  File "C:\Program Files (x86)\OpenPype\dependencies\pyblish\plugin.py", line 592, in __implicit_process
    provider.invoke(runner)
  File "C:\Program Files (x86)\OpenPype\dependencies\pyblish\plugin.py", line 113, in invoke
    return func(**inject)
  File "C:\Program Files (x86)\OpenPype\openpype\hosts\maya\plugins\publish\validate_yeti_rig_input_in_instance.py", line 21, in process
RuntimeError: Yeti Rig has invalid input meshes
Traceback (most recent call last):
  File "C:\Program Files (x86)\OpenPype\dependencies\pyblish\plugin.py", line 592, in __implicit_process
    provider.invoke(runner)
  File "C:\Program Files (x86)\OpenPype\dependencies\pyblish\plugin.py", line 113, in invoke
    return func(**inject)
  File "<string>", line 21, in process
RuntimeError: Yeti Rig has invalid input meshes // 
b'Processing Maya Units'
// pyblish.ValidateMayaUnits : Units (linear): cm
// pyblish.ValidateMayaUnits : Units (angular): deg
// pyblish.ValidateMayaUnits : Units (time): 25.0 FPS

Screenshots image

Maya 2022.3 OP 3.11.1

This particular scene is working in V2 without problems and failing in V3. As the code of Yeti implementation did not change it seems we have a problem somewhere else.

@BigRoy (thanks a lot!) is tracing the issue down to PR #3297

[cuID:OP-3454]

m-u-r-p-h-y avatar Jun 24 '22 06:06 m-u-r-p-h-y

Sorry for the slow follow up. I totally forgot to reply to this issue - I actually thought I already had posted.

I personally think this was originally a BUG in OpenPype V2 and passed by accident in the old pipeline due to the bug in the Collector described in this comment. It was an unwanted side effect of the old implementation.

The code in Validate Yeti Rig Input In Instance is intended to validate that whatever is inside input_SET is part of the Yeti Rig and should publish along as a part of the rig. So it is NOT the input to the rig, but it's the nodes inside the rigs for which we'd want to detect external inputs and store their connections. Often simulation rigs have some nodes part of the rig that are considered the 'input' nodes to which you'd e.g. connect/blendshape an animation cache.

This is how the yeti rig publish was originally intended: afbeelding

  • hero_modelMain_01_:_GRP is the latest model the rig is built against - it's external to the yeti rig.
  • fur_rig_GRP is the "rig" for this yeti fur/groom and MAY exist of multiple yeti nodes too.

Like a regular rig you have a group of nodes that define your rig - which is what you'd publish as the rig in other scenes. Then some of these are considered "inputs" that e.g. in a lighting scene would need to reconnect to the character's published alembic cache. The nodes in the input_SET would be checked for any incoming connections to nodes outside of the rig. For those nodes it'll store the cbId and what attributes to connect. That way for example the body geometry from the hero could be automatically connected in the lighting scene like:

  • Find node by cbId
  • Connect attribute to the input node.

This way you can do more intermediate things with the geometry in your yeti rig (like slicing it up or having an extra setting which would move the geometry in simulation space to counter big motions, etc. and then still output the final positions. You can make it as complex as you'd want.

Your simple example rig could also work like that, but then you'd consider your yeti nodes to be the nodes that have inputs from externally (they are directly connected to the alembic geometry, etc.). You can publish and validate that too. Like so:

afbeelding

Both of these pass in OpenPype V3. Even simpler (single node yeti rig) would be:

afbeelding

Or if you don't care about storing the incoming connections to potentially auto-reconnect afterwards you could even skip putting anything in the input_SET:

afbeelding

Again, these also both pass the validation.

It does seem that the documentation for Creating and Publish a Yeti Rig in OpenPype is slightly wrong on how it describes to set up a Yeti Rig since like your example it puts the wrong nodes in the input_SET.

BigRoy avatar Jun 29 '22 09:06 BigRoy

@m-u-r-p-h-y any thoughts on the above?

BigRoy avatar Aug 09 '22 13:08 BigRoy

@BigRoy Hi! went through your explanation and have a question about dependencies (incomming connections to some entities).

As I have read your explanation, I understand that in "INPUT_SET" there should be just objects which u would like to trace their inputs/outputs. Thats the reason I guess why we put those grow meshes into the set. There are texture reference objects connected to them (yeti heavily relying on tex ref objects for world position of the geometry) so it get exported with published Yeti Rig.

How about that? Im a bit confused what should be in "input_set" after all...

Also your examples doesnt use any grooms just pgyeti nodes which probably is okeyish :) as I understand your examples...one would just put everthing into the yeti_rig set (main grp)

Thanks for your reply!

LiborBatek avatar Sep 06 '22 14:09 LiborBatek

I understand that in "INPUT_SET" there should be just objects which u would like to trace their inputs/outputs.

Correct.

Thats the reason I guess why we put those grow meshes into the set. There are texture reference objects connected to them (yeti heavily relying on tex ref objects for world position of the geometry) so it get exported with published Yeti Rig.

How about that? Im a bit confused what should be in "input_set" after all...

However, that use-case we'd solve differently. Basically the texture reference objects are required to make the rig work - they are not part of the published animation, they are static inputs to the rig - so they aren't "inputs" that need to be connected later when loaded. They would just be part of the rigs content.

So say you'd have this outliner hierarchy for your full FUR RIG:

rig_GRP
  - inputs_GRP
  - yeti_GRP
  - data_GRP

The inputs group would tend to be meshes that'd have an incoming connection from a published model - so it has "somewhat" of a live link through an incoming connection.

The yeti group would have the Yeti Fur and Groom nodes. They would only be connected to inputs inside the rig_GRP. They would not use anything outside of it and thus do not touch the published model at all. In simple rigs they'd be straight connections to the geo in the inputs_GRP - but rigs can be way more complicated with e.g. custom world scaling techniques implemented between the inputs group and what goes into the yeti nodes.

The data_GRP could for example contain the Texture Reference Objects - they would just live as constant static geometry within the rig. In the lighting scene they would also not need an incoming connection from animation so we'd not need to trace any inputs of it. They would be connected as texture reference objects into the meshes in the inputs_GRP or to any later intermediate geometry that act as inputs to the yeti fur nodes - basically wherever you'd need them in your rig.

The publish instance would just contain the rig_GRP and in input_SET it would hold the meshes for which it wants to trace incoming connections which it would need to dynamically reconnect upon loading into another scene by ids to e.g. an animation cache (which would be "connect to the pointcache of the animation mesh"). Again, the texture reference objects don't need a new incoming connection, they live in the rig and thus won't need to be traced for inputs.

This is also why the input_SET logic only traces to connections that live OUTSIDE of the to be published rig_GRP. It doesn't care about connections that are part of the rig - those won't get disconnected on publish. They'd remain. It'd only break connections with the published model - save the ids to what it was linked so upon load it can search your scene for those meshes/ids and connect again

So the yetiRigMain instance could look like:

yetiRigMain
    - rig_GRP         (basically contains maya contents to be extracted for the rig)
    - input_SET
        - mesh1_GEO   (usually geometry inside e.g. |rig_GRP|inputs_GRP)
        - mesh2_GEO   (usually geometry inside e.g. |rig_GRP|inputs_GRP)

E.g.

                                              RIG_GRP
                                    ┌───────────────────────────┐
                                    │                           │
┌───────────────────┐               │  ┌─────────────────────┐  │
│                   │               │  │                     │  │
│  PUBLISHED MODEL  ├───────────────┼─►│      INPUTS_GRP     │  │
│                   │               │  │                     │  │
└───────────────────┘               │  └─────────┬───────────┘  │
                                    │            │              │
                                    │  ┌─────────▼───────────┐  │
                                    │  │                     │  │
                                    │  │      YETI_GRP       │  │
                                    │  │                     │  │
                                    │  └─────────▲───────────┘  │
                                    │            │              │
                                    │  ┌─────────┴───────────┐  │
                                    │  │                     │  │
                                    │  │      DATA_GRP       │  │
                                    │  │                     │  │
                                    │  └─────────────────────┘  │
                                    │                           │
                                    └───────────────────────────┘

This is a barebones representation of what's described. TL;DR

  • inputs_GRP: Put in what to trace dynamic incoming connections for - those that would need a new connection linked on loading the published yeti rig
  • yeti_GRP: The yeti furs/grooms. Usually connected to the the inputs_GRP
  • data_GRP: Rig related constant geometry or other nodes - You can do crazy stuff in your rigs if you want ☝️ but could also just be static texture reference objects part of what the fur rig needs to function correctly.

Technically you can go without the inputs_GRP and just trace incoming connections from the yeti nodes - but we've even had cases where we would sometimes cut up the mesh dynamically, or do some post-deformation tricks inside the rig on top of the incoming mesh and it's easier to track/develop these when building those connections inside your rig so you keep being aware of what's IN your rig and what is the incoming connection. That way the rigger doesn't by accidentally do something on the published model that would be lost as "required change for the fur rig" wherever you load the rig - since there it connects to the new animated pointcache, etc.


Also your examples doesnt use any grooms just pgyeti nodes which probably is okeyish :) as I understand your examples...one would just put everthing into the yeti_rig set (main grp)

Yup - that shouldn't matter at all. Both worked when we used it.


@LiborBatek does that better explain the situation?

BigRoy avatar Sep 06 '22 18:09 BigRoy

@BigRoy Thanks for soo indepth answer! And so quick response... I will test it asap, unfortunatelly we currently doesnt have any Yeti license so I have to postpone it...

Will let you know then...

Thx again! Libor

LiborBatek avatar Sep 07 '22 09:09 LiborBatek

Finally get to testing again!! Peregrine finally provided us a license for Yeti...

Well I ve tested both ways to publish YetiRig...

First my old "used to do" way but no luck (basically you said that already): Yeti_Publish_01a

It just didnt come through Publish. So then I ve tried your proposed way of layout items to subset this time worked out but with some issues later... here is the layout which published ok: Yeti_Publish_01b

...however when trying to apply it on my rigged character in different scene...it all went crazy (I can imagine why...simply another instance of fully rigged char appeared in the scene plus the Yeti rig on top). heres my screen cap: Yeti_Publish_02

Dont want to make any conclusions but my thoughs are:

  1. Its not much logical to put first the whole Yeti_GRP to YetiRig subset and also put actual pgYetiNode to "Input" subset...a bit double effect dont u think?

  2. the published YetiRig should only contain those Yeti nodes (pgYetiNode, Groom, Feather or any other Yeti exclusive nodes) and info about mesh (ShapeNode) to connect later to. Regarding the textureRef object, this could be done when building the scene when loading the YetiRig Asset to the scene/shot

Hope this all make sense! P.S. Basically thats how it used to work back then.

LiborBatek avatar Sep 27 '22 12:09 LiborBatek

Thinking about proper workflow, the best user experience would be just select PgYeti node (the main yeti node) and create yetiRig subset/family in OP menu. ...the rest should happen during publish automatically - collecting all the necessary yeti nodes/ maya shapeNodes etc. for later building it in shot scene. If not possible to collect everthing within a maya scene, user could simply drag maya objects to the subset INPUT as it used to be before...

LiborBatek avatar Oct 11 '22 08:10 LiborBatek

Thinking about proper workflow, the best user experience would be just select PgYeti node (the main yeti node) and create yetiRig subset/family in OP menu. ...the rest should happen during publish automatically - collecting all the necessary yeti nodes/ maya shapeNodes etc. for later building it in shot scene. If not possible to collect everthing within a maya scene, user could simply drag maya objects to the subset INPUT as it used to be before...

I can see where you're coming from but I feel that would allow way too much freedom to produce a "controlled environment" to publish. We've had input meshes that are standin geometry in the grooms but also input models attached. You'll want to be able to tell the difference between the two.

Admittedly the input_SET is confusing maybe. Maybe it makes more sense if the input_SET would instead hold the objects that are used as inputs instead of the objects from which we'd want to collect the inputs. The downside of making that change is that the objects that are inputs (e.g. the model) aren't part of the rig and thus can change easily whereas the object to which things are connected as inputs are part of the rig (and thus much more reliable/static for publishing). --> I think it's this difference in particular which makes your "OLD" workflow not work.

Its not much logical to put first the whole Yeti_GRP to YetiRig subset and also put actual pgYetiNode to "Input" subset...a bit double effect dont u think?

This is done to identify which objects should actually be considered to retrieve inputs for. Since other nodes in the Yeti_GRP have the tendency to make connections anyway, to e.g. time, node editor relationships and most of all they tend to have a lot of connections INSIDE the rig (inside the group) and we'd need to check each connections to see if it is a connection to a node outside the group. And that logic would actually ONLY work for DAG nodes, and not dependency nodes - which would be supported currently.

the published YetiRig should only contain those Yeti nodes (pgYetiNode, Groom, Feather or any other Yeti exclusive nodes) and info about mesh (ShapeNode) to connect later to.

Yes, agreed. Note that this should contain any node "inside the rig" and this could also be shape nodes with controls, etc. (We've had rig where we're able to "animate" an extra layer of 'wind' or 'gusts of wind' using a control in the yeti rig, etc.)

Regarding the textureRef object, this could be done when building the scene when loading the YetiRig Asset to the scene/shot

Not sure. What would be the texture ref for an animated pointcache - you wouldn't be able to identify the "t-pose mesh". I'd say the texture reference object is actually part of the rig (it's the static part inside your yeti rig). Thus on load that is loaded into the scene as well, and you'd only need to connect the animated mesh.


EDIT: By the way, these screenshots/details would be way more useful if they would also include the LOG/PRINTS of the Loader plug-in

BigRoy avatar Oct 11 '22 08:10 BigRoy

...however when trying to apply it on my rigged character in different scene...it all went crazy (I can imagine why...simply another instance of fully rigged char appeared in the scene plus the Yeti rig on top). heres my screen cap:

Looking at the logic in the Loader this doesn't at all use the collected inputs information thus the bug is elsewhere. I suspect this would even happen if you would NOT add the input_SET content.

This is what is done during load.

  1. The logic is basically saying that if it finds ANY nodes in the scene that match a cbId of ANY mesh shape node in the loaded yeti rig maya file reference it'd auto connect it to the LAST one found in the scene. (It doesn't expect the same cbId more than once) thus this logic also would not work for multiple of the same characters in the scene.

  2. This is what input connections are collected during publish. This information is actually UNUSED on load. It currently does nothing.

I feel like 1) is assuming to be way too automatic and we should provide a dedicated way to apply the connections of 2) with any matching content in the scene by choice. For example, we currently have a project with a single cow groom on multiple characters in the scene and this "auto-connect" would already fail our use case. We've actually never hit this "auto-connect" feature because our published yeti rig do not have the source shapes with their IDs of the original in the yeti rig to begin with - and thus it usually wouldn't find the matching "mesh" shapes. I suspect that if you have a mesh shape in the Yeti rig and load the rig twice you might already hit this bug actually - even without input set.

BigRoy avatar Oct 11 '22 09:10 BigRoy

Roy, thanks for your indepth answer its obivous that you can see much further/deeper than me :) Me looking on it from user pov not seeing all those technicalities :)

So whats next then? Any conclusion? Or what comes to my mind ...how u use it guys then?! your workflow in OP.

L.

LiborBatek avatar Oct 12 '22 06:10 LiborBatek

Fixed with https://github.com/ynput/OpenPype/pull/4554

tokejepsen avatar Apr 17 '23 11:04 tokejepsen