Skip to content
This repository has been archived by the owner on Sep 20, 2024. It is now read-only.

Maya: add loaded containers to published instance #2837

Merged
merged 8 commits into from
Mar 11, 2022

Conversation

antirotor
Copy link
Member

Enhancement

Adding ability to include loaded containers to published instance.

This is mainly useful for Layouts and Setdress families. When you create them from loaded models for example, this will pull their containers along published Layout so OpenPype will retain information about them when Layout is loaded into the new scene.

This can be set in the Settings (project_settings/maya/publish/ExtractMayaSceneRaw/add_for_families):

image

How to test:

In the new scene load bunch of models with OpenPype, create Layout and publish it. When you load this layout, you should see all content in the layout in Manager.

Close #2830

@antirotor antirotor added type: enhancement Enhancements to existing functionality host: Maya labels Mar 3, 2022
@antirotor antirotor self-assigned this Mar 3, 2022
@mkolar
Copy link
Member

mkolar commented Mar 3, 2022

@@ -57,10 +58,22 @@ def process(self, instance):
else:
members = instance[:]

loaded_containers = None
if {f.lower() for f in self.add_for_families}.intersection(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why should this be non case sensitive in the check even though families in Pyblish plugins are case sensitive, right?

Also, are we missing self.add_for_families attribute being explicitly set in the code? (Or am I just missing it in the GitHub view somehow?)

Instead of adding these in the extractor - shouldn't these originally be "collected" along instead?

Copy link
Member Author

@antirotor antirotor Mar 4, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add_for_families is added there directly from Settings, no need to manually specify.

With case sensitivity - I am not a fan of case sensitive family names as I belive it just adds to the chaos - there is no reason why layout should be different from Layout even more when you allow user to set family name by typing it somewhere in the Settings.

Copy link
Collaborator

@BigRoy BigRoy Mar 4, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd avoid the case-insensitivity here. Pyblish plug-in families are case-sensitive. This logic is tied very close to those exact families. There are more OpenPype settings exposed that related to Pyblish families and those are also case sensitive.

It's less code/logic to maintain, less cases to test and also more explicit. We're only making things more complicated by allowing the other cases. Plus I'd personally rather not see code with LaYouT and have it considered valid too.

To me plug-in families are constants. If we want to avoid human error in the settings then it should be an enum with a list to specify from. User might just as well mistype with a different character as recently was found with aftereffects being mistyped.

add_for_families is added there directly from Settings, no need to manually specify.

A code linter will likely not detect that? And most plug-ins that I've seen that specify custom settings also define the attribute on the class for readability. We should find a consistency between those two - I'd prefer the explicit method for readability.

I'd even go as far as not allowing Settings to set attributes on the plug-ins that do not exist yet to enforce this explicit code style. It could log a clear warning for when that happens to aid developers.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mkolar Any preference on this from your end? ☝️

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mkolar I saw you approved this PR - could you check in regarding this question above?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and yes, after giving it more thought than it deserves :) I agree with your point. But I believe with this we really need to implement some central way of managing families - we are currently unable to present (for example in Settings) all families we have, so in many places you just need to write it down manually and that is source of errors.

@BigRoy
Copy link
Collaborator

BigRoy commented Mar 3, 2022

What's the reason this setting is configurable? When would you NOT want this for e.g. for layout, etc.?

@antirotor
Copy link
Member Author

What's the reason this setting is configurable? When would you NOT want this for e.g. for layout, etc.?

Reason is that it allows you the decision between old behaviour and new one, even if the old one was somewhat limited. It should stay there imho for a while as deprecated feature problably (and I should state it somewhere that it is so).

@BigRoy
Copy link
Collaborator

BigRoy commented Mar 4, 2022

Reason is that it allows you the decision between old behaviour and new one, even if the old one was somewhat limited. It should stay there imho for a while as deprecated feature problably (and I should state it somewhere that it is so).

Somehow I feel this should and could be simplified but I'm having a hard time thinking of a clean solution now. Adding a setting that we already know would be considered "deprecated" behavior just doesn't feel right and we're only introducing more technical/code debt that way, no?

@mkolar
Copy link
Member

mkolar commented Mar 4, 2022

Somehow I feel this should and could be simplified but I'm having a hard time thinking of a clean solution now

I agree and we should probably log an issue or discussion so it doesn't get covered by a dust of time, but for now, this works well enough for production use-cases we have.

@mkolar
Copy link
Member

mkolar commented Mar 8, 2022

@antirotor antirotor requested a review from mkolar March 10, 2022 23:22
@mkolar
Copy link
Member

mkolar commented Mar 11, 2022

Good with me. let's merge it, it's needed in production

@mkolar mkolar merged commit bd8f2ee into develop Mar 11, 2022
@mkolar mkolar deleted the enhancement/OP-2825_attach-loaded-containers branch March 11, 2022 09:00
Comment on lines +130 to +135
def load(self, context, name=None, namespace=None, options=None):
container = super(ReferenceLoader, self).load(
context, name, namespace, options)
# clean containers if present to AVALON_CONTAINERS
self._organize_containers(self[:], container[0])

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can now be removed completely now the logic is implemented in the parent class. Correct?

loaded_containers = None
if set(self.add_for_families).intersection(
set(instance.data.get("families")),
set(instance.data.get("family").lower())):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. set(instance.data.get("family").lower()) this is incorrect? Family is not a list and thus this would turn into e.g. set("model".lower()) which turns into set("model") which becomes {"m", "o", "d", "e", "l"} :)
  2. .lower() can be removed?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, are you sure you require the family to also be present in families which is what the current logic is doing because a.intersection(b, c) returns a set with items that is present in all 3 sets.

I'd rather detect whether it's at least present in either as in my pseudocode mockup

Comment on lines +67 to +70
selection = members
if loaded_containers:
self.log.info(loaded_containers)
selection += loaded_containers
Copy link
Collaborator

@BigRoy BigRoy Mar 11, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This if statement can be moved into the if statement above.

# psuedocode
families = set([instance.data.get("family", "")] + instance.data.get("families", []))
if families.intersection(set(self.add_for_families)):
    members += self._get_loaded_containers(members)  # note that I also refactored this method to a more logical name

Comment on lines +102 to +127
refs_to_include = [
cmds.referenceQuery(ref, referenceNode=True)
for ref in members
if cmds.referenceQuery(ref, isNodeReferenced=True)
]

refs_to_include = set(refs_to_include)

obj_sets = cmds.ls("*.id", long=True, type="objectSet", recursive=True,
objectsOnly=True)

loaded_containers = []
for obj_set in obj_sets:

if not cmds.attributeQuery("id", node=obj_set, exists=True):
continue

id_attr = "{}.id".format(obj_set)
if cmds.getAttr(id_attr) != AVALON_CONTAINER_ID:
continue

set_content = set(cmds.sets(obj_set, query=True))
if set_content.intersection(refs_to_include):
loaded_containers.append(obj_set)

return loaded_containers
Copy link
Collaborator

@BigRoy BigRoy Mar 11, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this logic would fail to detect e.g. loaded gpuCache containers, yetiCache containers, etc. and others that aren't referenced. So this logic would not be correct?


members_with_refs= set(members) + set(refs_to_include)     # line 108
...

if set_content.intersection(members_with_refs):    # line 124

Likely you'd need something like that?

@BigRoy
Copy link
Collaborator

BigRoy commented Mar 11, 2022

Good with me. let's merge it, it's needed in production

Ouch. Please see my notes above. :)

@mkolar mkolar added this to the 3.9.0 milestone Mar 15, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
host: Maya type: enhancement Enhancements to existing functionality
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Maya: add option to attach loaded containers to specific families
3 participants