diff --git a/openpype/hosts/maya/api/plugin.py b/openpype/hosts/maya/api/plugin.py index 24a57f3184..1a3bb60870 100644 --- a/openpype/hosts/maya/api/plugin.py +++ b/openpype/hosts/maya/api/plugin.py @@ -333,11 +333,7 @@ class RenderlayerCreator(NewCreator, MayaCreatorBase): # A Renderlayer is never explicitly created using the create method. # Instead, renderlayers from the scene are collected. Thus "create" # would only ever be called to say, 'hey, please refresh collect' - - # Only allow a single render instance to exist - if self._get_singleton_node(): - raise CreatorError("A Render instance already exists - only " - "one can be configured.") + self.create_singleton_node() # if no render layers are present, create default one with # asterisk selector @@ -347,16 +343,23 @@ class RenderlayerCreator(NewCreator, MayaCreatorBase): collection = render_layer.createCollection("defaultCollection") collection.getSelector().setPattern('*') + # By RenderLayerCreator.create we make it so that the renderlayer + # instances directly appear even though it just collects scene + # renderlayers. This doesn't actually 'create' any scene contents. + self.collect_instances() + + def create_singleton_node(self): + if self._get_singleton_node(): + raise CreatorError("A Render instance already exists - only " + "one can be configured.") + with lib.undo_chunk(): node = cmds.sets(empty=True, name=self.singleton_node_name) lib.imprint(node, data={ "pre_creator_identifier": self.identifier }) - # By RenderLayerCreator.create we make it so that the renderlayer - # instances directly appear even though it just collects scene - # renderlayers. This doesn't actually 'create' any scene contents. - self.collect_instances() + return node def collect_instances(self): @@ -449,11 +452,6 @@ class RenderlayerCreator(NewCreator, MayaCreatorBase): layer = instance.transient_data["layer"] instance_node = self._create_layer_instance_node(layer) instance.data["instance_node"] = instance_node - else: - # TODO: Keep name in sync with the actual renderlayer? - self.log.warning("No instance node found for to be updated " - "instance: {}".format(instance)) - continue self.imprint_instance_node(instance_node, data=instance.data_to_store()) diff --git a/openpype/hosts/maya/plugins/create/convert_legacy.py b/openpype/hosts/maya/plugins/create/convert_legacy.py index a3ff085caf..6133abc205 100644 --- a/openpype/hosts/maya/plugins/create/convert_legacy.py +++ b/openpype/hosts/maya/plugins/create/convert_legacy.py @@ -1,5 +1,9 @@ from openpype.pipeline.create.creator_plugins import SubsetConvertorPlugin from openpype.hosts.maya.api import plugin +from openpype.hosts.maya.api.lib import read + +from maya import cmds +from maya.app.renderSetup.model import renderSetup class MayaLegacyConvertor(SubsetConvertorPlugin, @@ -18,6 +22,12 @@ class MayaLegacyConvertor(SubsetConvertorPlugin, """ identifier = "io.openpype.creators.maya.legacy" + # Cases where the identifier or new family doesn't correspond to the + # original family on the legacy instances + special_family_conversions = { + "rendering": "io.openpype.creators.maya.renderlayer", + } + def find_instances(self): self.cache_subsets(self.collection_shared_data) @@ -53,17 +63,103 @@ class MayaLegacyConvertor(SubsetConvertorPlugin, "{}".format(identifier)) family_to_id[family] = identifier + family_to_id.update(self.special_family_conversions) + # We also embed the current 'task' into the instance since legacy # instances didn't store that data on the instances. The old style # logic was thus to be live to the current task to begin with. data = dict() data["task"] = self.create_context.get_current_task_name() + for family, instance_nodes in legacy.items(): - if family in family_to_id: - # We only imprint the creator identifier for it to identify - # as the new style creator - creator_id = family_to_id[family] - data["creator_identifier"] = creator_id - for instance_node in instance_nodes: - self.imprint_instance_node(instance_node, - data=data.copy()) + if family not in family_to_id: + self.log.warning( + "Unable to convert legacy instance with family '{}'" + " because there is no matching new creator's family" + "".format(family) + ) + continue + + creator_id = family_to_id[family] + creator = self.create_context.manual_creators[creator_id] + data["creator_identifier"] = creator_id + + if isinstance(creator, plugin.RenderlayerCreator): + self._convert_per_renderlayer(instance_nodes, data, creator) + else: + self._convert_regular(instance_nodes, data) + + def _convert_regular(self, instance_nodes, data): + # We only imprint the creator identifier for it to identify + # as the new style creator + for instance_node in instance_nodes: + self.imprint_instance_node(instance_node, + data=data.copy()) + + def _convert_per_renderlayer(self, instance_nodes, data, creator): + # Split the instance into an instance per layer + rs = renderSetup.instance() + layers = rs.getRenderLayers() + if not layers: + self.log.error( + "Can't convert legacy renderlayer instance because no existing" + " renderSetup layers exist in the scene." + ) + return + + creator_attribute_names = { + attr_def.key for attr_def in creator.get_instance_attr_defs() + } + + for instance_node in instance_nodes: + + # Ensure we have the new style singleton node generated + # TODO: Make function public + singleton_node = creator._get_singleton_node() + if singleton_node: + self.log.error( + "Can't convert legacy renderlayer instance '{}' because" + " new style instance '{}' already exists".format( + instance_node, + singleton_node + ) + ) + continue + + creator.create_singleton_node() + + # We are creating new nodes to replace the original instance + # Copy the attributes of the original instance to the new node + original_data = read(instance_node) + + # The family gets converted to the new family (this is due to + # "rendering" family being converted to "renderlayer" family) + original_data["family"] = creator.family + + # Convert to creator attributes when relevant + creator_attributes = {} + for key in list(original_data.keys()): + # Iterate in order of the original attributes to preserve order + # in the output creator attributes + if key in creator_attribute_names: + creator_attributes[key] = original_data.pop(key) + original_data["creator_attributes"] = creator_attributes + + # For layer in maya layers + for layer in layers: + layer_instance_node = creator.find_layer_instance_node(layer) + if not layer_instance_node: + # TODO: Make function public + layer_instance_node = creator._create_layer_instance_node( + layer + ) + + # Transfer the main attributes of the original instance + layer_data = original_data.copy() + layer_data.update(data) + + self.imprint_instance_node(layer_instance_node, + data=layer_data) + + # Delete the legacy instance node + cmds.delete(instance_node)