diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index f484016bfe..6f651076ce 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -35,6 +35,12 @@ body: label: Version description: What version are you running? Look to OpenPype Tray options: + - 3.17.7-nightly.7 + - 3.17.7-nightly.6 + - 3.17.7-nightly.5 + - 3.17.7-nightly.4 + - 3.17.7-nightly.3 + - 3.17.7-nightly.2 - 3.17.7-nightly.1 - 3.17.6 - 3.17.6-nightly.3 @@ -129,12 +135,6 @@ body: - 3.15.3-nightly.3 - 3.15.3-nightly.2 - 3.15.3-nightly.1 - - 3.15.2 - - 3.15.2-nightly.6 - - 3.15.2-nightly.5 - - 3.15.2-nightly.4 - - 3.15.2-nightly.3 - - 3.15.2-nightly.2 validations: required: true - type: dropdown diff --git a/openpype/cli.py b/openpype/cli.py index f0fe550a1f..8caa139765 100644 --- a/openpype/cli.py +++ b/openpype/cli.py @@ -296,12 +296,15 @@ def run(script): @click.option("--mongo_url", help="MongoDB for testing.", default=None) +@click.option("--dump_databases", + help="Dump all databases to data folder.", + default=None) def runtests(folder, mark, pyargs, test_data_folder, persist, app_variant, - timeout, setup_only, mongo_url, app_group): + timeout, setup_only, mongo_url, app_group, dump_databases): """Run all automatic tests after proper initialization via start.py""" PypeCommands().run_tests(folder, mark, pyargs, test_data_folder, persist, app_variant, timeout, setup_only, - mongo_url, app_group) + mongo_url, app_group, dump_databases) @main.command(help="DEPRECATED - run sync server") diff --git a/openpype/client/__init__.py b/openpype/client/__init__.py index fe6dc97877..ba36d940e3 100644 --- a/openpype/client/__init__.py +++ b/openpype/client/__init__.py @@ -44,6 +44,8 @@ from .entities import ( get_thumbnail_id_from_source, get_workfile_info, + + get_asset_name_identifier, ) from .entity_links import ( @@ -108,4 +110,6 @@ __all__ = ( "get_linked_representation_id", "create_project", + + "get_asset_name_identifier", ) diff --git a/openpype/client/entities.py b/openpype/client/entities.py index 5d9654c611..cbaa943743 100644 --- a/openpype/client/entities.py +++ b/openpype/client/entities.py @@ -4,3 +4,22 @@ if not AYON_SERVER_ENABLED: from .mongo.entities import * else: from .server.entities import * + + +def get_asset_name_identifier(asset_doc): + """Get asset name identifier by asset document. + + This function is added because of AYON implementation where name + identifier is not just a name but full path. + + Asset document must have "name" key, and "data.parents" when in AYON mode. + + Args: + asset_doc (dict[str, Any]): Asset document. + """ + + if not AYON_SERVER_ENABLED: + return asset_doc["name"] + parents = list(asset_doc["data"]["parents"]) + parents.append(asset_doc["name"]) + return "/" + "/".join(parents) diff --git a/openpype/client/server/conversion_utils.py b/openpype/client/server/conversion_utils.py index 51af99e722..e8d3c4cbe4 100644 --- a/openpype/client/server/conversion_utils.py +++ b/openpype/client/server/conversion_utils.py @@ -606,7 +606,7 @@ def convert_v4_version_to_v3(version): output_data[dst_key] = version[src_key] if "createdAt" in version: - created_at = arrow.get(version["createdAt"]) + created_at = arrow.get(version["createdAt"]).to("local") output_data["time"] = created_at.strftime("%Y%m%dT%H%M%SZ") output["data"] = output_data diff --git a/openpype/client/server/entities.py b/openpype/client/server/entities.py index b41727a797..75b5dc2cdd 100644 --- a/openpype/client/server/entities.py +++ b/openpype/client/server/entities.py @@ -80,8 +80,8 @@ def _get_subsets( for subset in con.get_products( project_name, - subset_ids, - subset_names, + product_ids=subset_ids, + product_names=subset_names, folder_ids=folder_ids, names_by_folder_ids=names_by_folder_ids, active=active, @@ -113,23 +113,23 @@ def _get_versions( queried_versions = con.get_versions( project_name, - version_ids, - subset_ids, - versions, - hero, - standard, - latest, + version_ids=version_ids, + product_ids=subset_ids, + versions=versions, + hero=hero, + standard=standard, + latest=latest, active=active, fields=fields ) - versions = [] + version_entities = [] hero_versions = [] for version in queried_versions: if version["version"] < 0: hero_versions.append(version) else: - versions.append(convert_v4_version_to_v3(version)) + version_entities.append(convert_v4_version_to_v3(version)) if hero_versions: subset_ids = set() @@ -159,9 +159,9 @@ def _get_versions( break conv_hero = convert_v4_version_to_v3(hero_version) conv_hero["version_id"] = version_id - versions.append(conv_hero) + version_entities.append(conv_hero) - return versions + return version_entities def get_asset_by_id(project_name, asset_id, fields=None): @@ -182,6 +182,19 @@ def get_asset_by_name(project_name, asset_name, fields=None): return None +def _folders_query(project_name, con, fields, **kwargs): + if fields is None or "tasks" in fields: + folders = get_folders_with_tasks( + con, project_name, fields=fields, **kwargs + ) + + else: + folders = con.get_folders(project_name, fields=fields, **kwargs) + + for folder in folders: + yield folder + + def get_assets( project_name, asset_ids=None, @@ -201,20 +214,39 @@ def get_assets( fields = folder_fields_v3_to_v4(fields, con) kwargs = dict( folder_ids=asset_ids, - folder_names=asset_names, parent_ids=parent_ids, active=active, - fields=fields ) + if not asset_names: + for folder in _folders_query(project_name, con, fields, **kwargs): + yield convert_v4_folder_to_v3(folder, project_name) + return - if fields is None or "tasks" in fields: - folders = get_folders_with_tasks(con, project_name, **kwargs) + new_asset_names = set() + folder_paths = set() + for name in asset_names: + if "/" in name: + folder_paths.add(name) + else: + new_asset_names.add(name) - else: - folders = con.get_folders(project_name, **kwargs) + yielded_ids = set() + if folder_paths: + for folder in _folders_query( + project_name, con, fields, folder_paths=folder_paths, **kwargs + ): + yielded_ids.add(folder["id"]) + yield convert_v4_folder_to_v3(folder, project_name) - for folder in folders: - yield convert_v4_folder_to_v3(folder, project_name) + if not new_asset_names: + return + + for folder in _folders_query( + project_name, con, fields, folder_names=new_asset_names, **kwargs + ): + if folder["id"] not in yielded_ids: + yielded_ids.add(folder["id"]) + yield convert_v4_folder_to_v3(folder, project_name) def get_archived_assets( @@ -507,11 +539,11 @@ def get_representations( representations = con.get_representations( project_name, - representation_ids, - representation_names, - version_ids, - names_by_version_ids, - active, + representation_ids=representation_ids, + representation_names=representation_names, + version_ids=version_ids, + names_by_version_ids=names_by_version_ids, + active=active, fields=fields ) for representation in representations: diff --git a/openpype/hooks/pre_add_last_workfile_arg.py b/openpype/hooks/pre_add_last_workfile_arg.py index 1418bc210b..6e255ae82a 100644 --- a/openpype/hooks/pre_add_last_workfile_arg.py +++ b/openpype/hooks/pre_add_last_workfile_arg.py @@ -27,6 +27,7 @@ class AddLastWorkfileToLaunchArgs(PreLaunchHook): "tvpaint", "substancepainter", "aftereffects", + "wrap" } launch_types = {LaunchTypes.local} diff --git a/openpype/hooks/pre_copy_template_workfile.py b/openpype/hooks/pre_copy_template_workfile.py index 2203ff4396..4d91d83c95 100644 --- a/openpype/hooks/pre_copy_template_workfile.py +++ b/openpype/hooks/pre_copy_template_workfile.py @@ -19,7 +19,8 @@ class CopyTemplateWorkfile(PreLaunchHook): # Before `AddLastWorkfileToLaunchArgs` order = 0 - app_groups = {"blender", "photoshop", "tvpaint", "aftereffects"} + app_groups = {"blender", "photoshop", "tvpaint", "aftereffects", + "wrap"} launch_types = {LaunchTypes.local} def execute(self): diff --git a/openpype/host/host.py b/openpype/host/host.py index 630fb873a8..afe06d1f55 100644 --- a/openpype/host/host.py +++ b/openpype/host/host.py @@ -170,7 +170,7 @@ class HostBase(object): if project_name: items.append(project_name) if asset_name: - items.append(asset_name) + items.append(asset_name.lstrip("/")) if task_name: items.append(task_name) if items: diff --git a/openpype/hosts/aftereffects/plugins/create/create_render.py b/openpype/hosts/aftereffects/plugins/create/create_render.py index fbe600ae68..fadfc0c206 100644 --- a/openpype/hosts/aftereffects/plugins/create/create_render.py +++ b/openpype/hosts/aftereffects/plugins/create/create_render.py @@ -56,16 +56,15 @@ class RenderCreator(Creator): use_composition_name = (pre_create_data.get("use_composition_name") or len(comps) > 1) for comp in comps: + composition_name = re.sub( + "[^{}]+".format(SUBSET_NAME_ALLOWED_SYMBOLS), + "", + comp.name + ) if use_composition_name: if "{composition}" not in subset_name_from_ui.lower(): subset_name_from_ui += "{Composition}" - composition_name = re.sub( - "[^{}]+".format(SUBSET_NAME_ALLOWED_SYMBOLS), - "", - comp.name - ) - dynamic_fill = prepare_template_data({"composition": composition_name}) subset_name = subset_name_from_ui.format(**dynamic_fill) @@ -81,6 +80,8 @@ class RenderCreator(Creator): inst.subset_name)) data["members"] = [comp.id] + data["orig_comp_name"] = composition_name + new_instance = CreatedInstance(self.family, subset_name, data, self) if "farm" in pre_create_data: @@ -88,7 +89,7 @@ class RenderCreator(Creator): new_instance.creator_attributes["farm"] = use_farm review = pre_create_data["mark_for_review"] - new_instance.creator_attributes["mark_for_review"] = review + new_instance. creator_attributes["mark_for_review"] = review api.get_stub().imprint(new_instance.id, new_instance.data_to_store()) @@ -150,16 +151,18 @@ class RenderCreator(Creator): subset_change.new_value) def remove_instances(self, instances): + """Removes metadata and renames to original comp name if available.""" for instance in instances: self._remove_instance_from_context(instance) self.host.remove_instance(instance) - subset = instance.data["subset"] comp_id = instance.data["members"][0] comp = api.get_stub().get_item(comp_id) + orig_comp_name = instance.data.get("orig_comp_name") if comp: - new_comp_name = comp.name.replace(subset, '') - if not new_comp_name: + if orig_comp_name: + new_comp_name = orig_comp_name + else: new_comp_name = "dummyCompName" api.get_stub().rename_item(comp_id, new_comp_name) diff --git a/openpype/hosts/aftereffects/plugins/create/workfile_creator.py b/openpype/hosts/aftereffects/plugins/create/workfile_creator.py index 2e7b9d4a7e..5dc3d6592d 100644 --- a/openpype/hosts/aftereffects/plugins/create/workfile_creator.py +++ b/openpype/hosts/aftereffects/plugins/create/workfile_creator.py @@ -1,3 +1,4 @@ +from openpype import AYON_SERVER_ENABLED import openpype.hosts.aftereffects.api as api from openpype.client import get_asset_by_name from openpype.pipeline import ( @@ -43,6 +44,14 @@ class AEWorkfileCreator(AutoCreator): task_name = context.get_current_task_name() host_name = context.host_name + existing_asset_name = None + if existing_instance is not None: + if AYON_SERVER_ENABLED: + existing_asset_name = existing_instance.get("folderPath") + + if existing_asset_name is None: + existing_asset_name = existing_instance["asset"] + if existing_instance is None: asset_doc = get_asset_by_name(project_name, asset_name) subset_name = self.get_subset_name( @@ -50,10 +59,13 @@ class AEWorkfileCreator(AutoCreator): project_name, host_name ) data = { - "asset": asset_name, "task": task_name, "variant": self.default_variant } + if AYON_SERVER_ENABLED: + data["folderPath"] = asset_name + else: + data["asset"] = asset_name data.update(self.get_dynamic_data( self.default_variant, task_name, asset_doc, project_name, host_name, None @@ -68,7 +80,7 @@ class AEWorkfileCreator(AutoCreator): new_instance.data_to_store()) elif ( - existing_instance["asset"] != asset_name + existing_asset_name != asset_name or existing_instance["task"] != task_name ): asset_doc = get_asset_by_name(project_name, asset_name) @@ -76,6 +88,10 @@ class AEWorkfileCreator(AutoCreator): self.default_variant, task_name, asset_doc, project_name, host_name ) - existing_instance["asset"] = asset_name + if AYON_SERVER_ENABLED: + existing_instance["folderPath"] = asset_name + else: + existing_instance["asset"] = asset_name + existing_instance["task"] = task_name existing_instance["subset"] = subset_name diff --git a/openpype/hosts/aftereffects/plugins/publish/collect_workfile.py b/openpype/hosts/aftereffects/plugins/publish/collect_workfile.py index dc557f67fc..58d2757840 100644 --- a/openpype/hosts/aftereffects/plugins/publish/collect_workfile.py +++ b/openpype/hosts/aftereffects/plugins/publish/collect_workfile.py @@ -1,6 +1,8 @@ import os import pyblish.api + +from openpype.client import get_asset_name_identifier from openpype.pipeline.create import get_subset_name @@ -48,9 +50,11 @@ class CollectWorkfile(pyblish.api.ContextPlugin): asset_entity = context.data["assetEntity"] project_entity = context.data["projectEntity"] + asset_name = get_asset_name_identifier(asset_entity) + instance_data = { "active": True, - "asset": asset_entity["name"], + "asset": asset_name, "task": task, "frameStart": context.data['frameStart'], "frameEnd": context.data['frameEnd'], diff --git a/openpype/hosts/aftereffects/plugins/publish/extract_local_render.py b/openpype/hosts/aftereffects/plugins/publish/extract_local_render.py index bdb48e11f8..b44e986d83 100644 --- a/openpype/hosts/aftereffects/plugins/publish/extract_local_render.py +++ b/openpype/hosts/aftereffects/plugins/publish/extract_local_render.py @@ -60,8 +60,9 @@ class ExtractLocalRender(publish.Extractor): first_repre = not representations if instance.data["review"] and first_repre: repre_data["tags"] = ["review"] - thumbnail_path = os.path.join(staging_dir, files[0]) - instance.data["thumbnailSource"] = thumbnail_path + # TODO return back when Extract from source same as regular + # thumbnail_path = os.path.join(staging_dir, files[0]) + # instance.data["thumbnailSource"] = thumbnail_path representations.append(repre_data) diff --git a/openpype/hosts/blender/api/plugin.py b/openpype/hosts/blender/api/plugin.py index 8d33187da3..568d8f6695 100644 --- a/openpype/hosts/blender/api/plugin.py +++ b/openpype/hosts/blender/api/plugin.py @@ -6,11 +6,11 @@ from typing import Dict, List, Optional import bpy +from openpype import AYON_SERVER_ENABLED from openpype.pipeline import ( Creator, CreatedInstance, LoaderPlugin, - get_current_task_name, ) from openpype.lib import BoolDef @@ -225,7 +225,12 @@ class BaseCreator(Creator): bpy.context.scene.collection.children.link(instances) # Create asset group - name = prepare_scene_name(instance_data["asset"], subset_name) + if AYON_SERVER_ENABLED: + asset_name = instance_data["folderPath"] + else: + asset_name = instance_data["asset"] + + name = prepare_scene_name(asset_name, subset_name) if self.create_as_asset_group: # Create instance as empty instance_node = bpy.data.objects.new(name=name, object_data=None) @@ -281,7 +286,14 @@ class BaseCreator(Creator): Args: update_list(List[UpdateData]): Changed instances - and their changes, as a list of tuples.""" + and their changes, as a list of tuples. + """ + + if AYON_SERVER_ENABLED: + asset_name_key = "folderPath" + else: + asset_name_key = "asset" + for created_instance, changes in update_list: data = created_instance.data_to_store() node = created_instance.transient_data["instance_node"] @@ -295,11 +307,12 @@ class BaseCreator(Creator): # Rename the instance node in the scene if subset or asset changed if ( - "subset" in changes.changed_keys - or "asset" in changes.changed_keys + "subset" in changes.changed_keys + or asset_name_key in changes.changed_keys ): + asset_name = data[asset_name_key] name = prepare_scene_name( - asset=data["asset"], subset=data["subset"] + asset=asset_name, subset=data["subset"] ) node.name = name diff --git a/openpype/hosts/blender/api/render_lib.py b/openpype/hosts/blender/api/render_lib.py index d564b5ebcb..b437078ad8 100644 --- a/openpype/hosts/blender/api/render_lib.py +++ b/openpype/hosts/blender/api/render_lib.py @@ -1,4 +1,4 @@ -import os +from pathlib import Path import bpy @@ -59,7 +59,7 @@ def get_render_product(output_path, name, aov_sep): instance (pyblish.api.Instance): The instance to publish. ext (str): The image format to render. """ - filepath = os.path.join(output_path, name) + filepath = output_path / name.lstrip("/") render_product = f"{filepath}{aov_sep}beauty.####" render_product = render_product.replace("\\", "/") @@ -180,7 +180,7 @@ def set_node_tree(output_path, name, aov_sep, ext, multilayer): return [] output.file_slots.clear() - output.base_path = output_path + output.base_path = str(output_path) aov_file_products = [] @@ -191,8 +191,9 @@ def set_node_tree(output_path, name, aov_sep, ext, multilayer): output.file_slots.new(filepath) - aov_file_products.append( - (render_pass.name, os.path.join(output_path, filepath))) + filename = str(output_path / filepath.lstrip("/")) + + aov_file_products.append((render_pass.name, filename)) node_input = output.inputs[-1] @@ -214,12 +215,11 @@ def imprint_render_settings(node, data): def prepare_rendering(asset_group): name = asset_group.name - filepath = bpy.data.filepath + filepath = Path(bpy.data.filepath) assert filepath, "Workfile not saved. Please save the file first." - file_path = os.path.dirname(filepath) - file_name = os.path.basename(filepath) - file_name, _ = os.path.splitext(file_name) + dirpath = filepath.parent + file_name = Path(filepath.name).stem project = get_current_project_name() settings = get_project_settings(project) @@ -232,7 +232,7 @@ def prepare_rendering(asset_group): set_render_format(ext, multilayer) aov_list, custom_passes = set_render_passes(settings) - output_path = os.path.join(file_path, render_folder, file_name) + output_path = Path.joinpath(dirpath, render_folder, file_name) render_product = get_render_product(output_path, name, aov_sep) aov_file_product = set_node_tree( diff --git a/openpype/hosts/blender/plugins/create/create_workfile.py b/openpype/hosts/blender/plugins/create/create_workfile.py index 9245434766..ceec3e0552 100644 --- a/openpype/hosts/blender/plugins/create/create_workfile.py +++ b/openpype/hosts/blender/plugins/create/create_workfile.py @@ -1,5 +1,6 @@ import bpy +from openpype import AYON_SERVER_ENABLED from openpype.pipeline import CreatedInstance, AutoCreator from openpype.client import get_asset_by_name from openpype.hosts.blender.api.plugin import BaseCreator @@ -24,7 +25,7 @@ class CreateWorkfile(BaseCreator, AutoCreator): def create(self): """Create workfile instances.""" - current_instance = next( + existing_instance = next( ( instance for instance in self.create_context.instances if instance.creator_identifier == self.identifier @@ -37,16 +38,27 @@ class CreateWorkfile(BaseCreator, AutoCreator): task_name = self.create_context.get_current_task_name() host_name = self.create_context.host_name - if not current_instance: + existing_asset_name = None + if existing_instance is not None: + if AYON_SERVER_ENABLED: + existing_asset_name = existing_instance.get("folderPath") + + if existing_asset_name is None: + existing_asset_name = existing_instance["asset"] + + if not existing_instance: asset_doc = get_asset_by_name(project_name, asset_name) subset_name = self.get_subset_name( task_name, task_name, asset_doc, project_name, host_name ) data = { - "asset": asset_name, "task": task_name, "variant": task_name, } + if AYON_SERVER_ENABLED: + data["folderPath"] = asset_name + else: + data["asset"] = asset_name data.update( self.get_dynamic_data( task_name, @@ -54,7 +66,7 @@ class CreateWorkfile(BaseCreator, AutoCreator): asset_doc, project_name, host_name, - current_instance, + existing_instance, ) ) self.log.info("Auto-creating workfile instance...") @@ -65,17 +77,21 @@ class CreateWorkfile(BaseCreator, AutoCreator): current_instance.transient_data["instance_node"] = instance_node self._add_instance_to_context(current_instance) elif ( - current_instance["asset"] != asset_name - or current_instance["task"] != task_name + existing_asset_name != asset_name + or existing_instance["task"] != task_name ): # Update instance context if it's different asset_doc = get_asset_by_name(project_name, asset_name) subset_name = self.get_subset_name( task_name, task_name, asset_doc, project_name, host_name ) - current_instance["asset"] = asset_name - current_instance["task"] = task_name - current_instance["subset"] = subset_name + if AYON_SERVER_ENABLED: + existing_instance["folderPath"] = asset_name + else: + existing_instance["asset"] = asset_name + + existing_instance["task"] = task_name + existing_instance["subset"] = subset_name def collect_instances(self): diff --git a/openpype/hosts/blender/plugins/publish/collect_render.py b/openpype/hosts/blender/plugins/publish/collect_render.py index 00faf85aed..da02f99052 100644 --- a/openpype/hosts/blender/plugins/publish/collect_render.py +++ b/openpype/hosts/blender/plugins/publish/collect_render.py @@ -11,12 +11,12 @@ import pyblish.api class CollectBlenderRender(pyblish.api.InstancePlugin): - """Gather all publishable render layers from renderSetup.""" + """Gather all publishable render instances.""" order = pyblish.api.CollectorOrder + 0.01 hosts = ["blender"] families = ["render"] - label = "Collect Render Layers" + label = "Collect Render" sync_workfile_version = False @staticmethod @@ -78,8 +78,6 @@ class CollectBlenderRender(pyblish.api.InstancePlugin): assert render_data, "No render data found." - self.log.debug(f"render_data: {dict(render_data)}") - render_product = render_data.get("render_product") aov_file_product = render_data.get("aov_file_product") ext = render_data.get("image_format") @@ -101,7 +99,7 @@ class CollectBlenderRender(pyblish.api.InstancePlugin): expected_files = expected_beauty | expected_aovs instance.data.update({ - "family": "render.farm", + "families": ["render", "render.farm"], "frameStart": frame_start, "frameEnd": frame_end, "frameStartHandle": frame_handle_start, @@ -120,5 +118,3 @@ class CollectBlenderRender(pyblish.api.InstancePlugin): "colorspaceView": "ACES 1.0 SDR-video", "renderProducts": colorspace.ARenderProduct(), }) - - self.log.debug(f"data: {instance.data}") diff --git a/openpype/hosts/blender/plugins/publish/extract_abc.py b/openpype/hosts/blender/plugins/publish/extract_abc.py index 12d062d925..0e242e9d53 100644 --- a/openpype/hosts/blender/plugins/publish/extract_abc.py +++ b/openpype/hosts/blender/plugins/publish/extract_abc.py @@ -19,7 +19,10 @@ class ExtractABC(publish.Extractor, publish.OptionalPyblishPluginMixin): # Define extract output file path stagingdir = self.staging_dir(instance) - filename = f"{instance.name}.abc" + asset_name = instance.data["assetEntity"]["name"] + subset = instance.data["subset"] + instance_name = f"{asset_name}_{subset}" + filename = f"{instance_name}.abc" filepath = os.path.join(stagingdir, filename) # Perform extraction diff --git a/openpype/hosts/blender/plugins/publish/extract_abc_animation.py b/openpype/hosts/blender/plugins/publish/extract_abc_animation.py index 1c23fc8acb..6ef9b29693 100644 --- a/openpype/hosts/blender/plugins/publish/extract_abc_animation.py +++ b/openpype/hosts/blender/plugins/publish/extract_abc_animation.py @@ -23,7 +23,11 @@ class ExtractAnimationABC( # Define extract output file path stagingdir = self.staging_dir(instance) - filename = f"{instance.name}.abc" + asset_name = instance.data["assetEntity"]["name"] + subset = instance.data["subset"] + instance_name = f"{asset_name}_{subset}" + filename = f"{instance_name}.abc" + filepath = os.path.join(stagingdir, filename) # Perform extraction diff --git a/openpype/hosts/blender/plugins/publish/extract_blend.py b/openpype/hosts/blender/plugins/publish/extract_blend.py index a1b49dcd8f..94e87d537c 100644 --- a/openpype/hosts/blender/plugins/publish/extract_blend.py +++ b/openpype/hosts/blender/plugins/publish/extract_blend.py @@ -20,7 +20,10 @@ class ExtractBlend(publish.Extractor, publish.OptionalPyblishPluginMixin): # Define extract output file path stagingdir = self.staging_dir(instance) - filename = f"{instance.name}.blend" + asset_name = instance.data["assetEntity"]["name"] + subset = instance.data["subset"] + instance_name = f"{asset_name}_{subset}" + filename = f"{instance_name}.blend" filepath = os.path.join(stagingdir, filename) # Perform extraction diff --git a/openpype/hosts/blender/plugins/publish/extract_blend_animation.py b/openpype/hosts/blender/plugins/publish/extract_blend_animation.py index 2e0de9317e..11eb268271 100644 --- a/openpype/hosts/blender/plugins/publish/extract_blend_animation.py +++ b/openpype/hosts/blender/plugins/publish/extract_blend_animation.py @@ -23,7 +23,10 @@ class ExtractBlendAnimation( # Define extract output file path stagingdir = self.staging_dir(instance) - filename = f"{instance.name}.blend" + asset_name = instance.data["assetEntity"]["name"] + subset = instance.data["subset"] + instance_name = f"{asset_name}_{subset}" + filename = f"{instance_name}.blend" filepath = os.path.join(stagingdir, filename) # Perform extraction diff --git a/openpype/hosts/blender/plugins/publish/extract_camera_abc.py b/openpype/hosts/blender/plugins/publish/extract_camera_abc.py index 9d0b7f132b..df68668eae 100644 --- a/openpype/hosts/blender/plugins/publish/extract_camera_abc.py +++ b/openpype/hosts/blender/plugins/publish/extract_camera_abc.py @@ -21,7 +21,10 @@ class ExtractCameraABC(publish.Extractor, publish.OptionalPyblishPluginMixin): # Define extract output file path stagingdir = self.staging_dir(instance) - filename = f"{instance.name}.abc" + asset_name = instance.data["assetEntity"]["name"] + subset = instance.data["subset"] + instance_name = f"{asset_name}_{subset}" + filename = f"{instance_name}.abc" filepath = os.path.join(stagingdir, filename) # Perform extraction diff --git a/openpype/hosts/blender/plugins/publish/extract_camera_fbx.py b/openpype/hosts/blender/plugins/publish/extract_camera_fbx.py index 9bbcf047cc..ee046b7d11 100644 --- a/openpype/hosts/blender/plugins/publish/extract_camera_fbx.py +++ b/openpype/hosts/blender/plugins/publish/extract_camera_fbx.py @@ -20,7 +20,10 @@ class ExtractCamera(publish.Extractor, publish.OptionalPyblishPluginMixin): # Define extract output file path stagingdir = self.staging_dir(instance) - filename = f"{instance.name}.fbx" + asset_name = instance.data["assetEntity"]["name"] + subset = instance.data["subset"] + instance_name = f"{asset_name}_{subset}" + filename = f"{instance_name}.fbx" filepath = os.path.join(stagingdir, filename) # Perform extraction diff --git a/openpype/hosts/blender/plugins/publish/extract_fbx.py b/openpype/hosts/blender/plugins/publish/extract_fbx.py index 0ba82eca4e..4ae6501f7d 100644 --- a/openpype/hosts/blender/plugins/publish/extract_fbx.py +++ b/openpype/hosts/blender/plugins/publish/extract_fbx.py @@ -21,7 +21,10 @@ class ExtractFBX(publish.Extractor, publish.OptionalPyblishPluginMixin): # Define extract output file path stagingdir = self.staging_dir(instance) - filename = f"{instance.name}.fbx" + asset_name = instance.data["assetEntity"]["name"] + subset = instance.data["subset"] + instance_name = f"{asset_name}_{subset}" + filename = f"{instance_name}.fbx" filepath = os.path.join(stagingdir, filename) # Perform extraction diff --git a/openpype/hosts/blender/plugins/publish/extract_fbx_animation.py b/openpype/hosts/blender/plugins/publish/extract_fbx_animation.py index a705345edb..4fc8230a1b 100644 --- a/openpype/hosts/blender/plugins/publish/extract_fbx_animation.py +++ b/openpype/hosts/blender/plugins/publish/extract_fbx_animation.py @@ -145,7 +145,10 @@ class ExtractAnimationFBX( root.select_set(True) armature.select_set(True) - fbx_filename = f"{instance.name}_{armature.name}.fbx" + asset_name = instance.data["assetEntity"]["name"] + subset = instance.data["subset"] + instance_name = f"{asset_name}_{subset}" + fbx_filename = f"{instance_name}_{armature.name}.fbx" filepath = os.path.join(stagingdir, fbx_filename) override = plugin.create_blender_context( @@ -178,7 +181,7 @@ class ExtractAnimationFBX( pair[1].user_clear() bpy.data.actions.remove(pair[1]) - json_filename = f"{instance.name}.json" + json_filename = f"{instance_name}.json" json_path = os.path.join(stagingdir, json_filename) json_dict = { diff --git a/openpype/hosts/blender/plugins/publish/extract_layout.py b/openpype/hosts/blender/plugins/publish/extract_layout.py index 73d92961bc..3e8978c8d3 100644 --- a/openpype/hosts/blender/plugins/publish/extract_layout.py +++ b/openpype/hosts/blender/plugins/publish/extract_layout.py @@ -14,7 +14,7 @@ from openpype.hosts.blender.api.pipeline import AVALON_PROPERTY class ExtractLayout(publish.Extractor, publish.OptionalPyblishPluginMixin): """Extract a layout.""" - label = "Extract Layout" + label = "Extract Layout (JSON)" hosts = ["blender"] families = ["layout"] optional = True @@ -224,7 +224,11 @@ class ExtractLayout(publish.Extractor, publish.OptionalPyblishPluginMixin): json_data.append(json_element) - json_filename = "{}.json".format(instance.name) + asset_name = instance.data["assetEntity"]["name"] + subset = instance.data["subset"] + instance_name = f"{asset_name}_{subset}" + json_filename = f"{instance_name}.json" + json_path = os.path.join(stagingdir, json_filename) with open(json_path, "w+") as file: diff --git a/openpype/hosts/blender/plugins/publish/extract_playblast.py b/openpype/hosts/blender/plugins/publish/extract_playblast.py index fe005c6593..a78aa14138 100644 --- a/openpype/hosts/blender/plugins/publish/extract_playblast.py +++ b/openpype/hosts/blender/plugins/publish/extract_playblast.py @@ -51,7 +51,10 @@ class ExtractPlayblast(publish.Extractor, publish.OptionalPyblishPluginMixin): # get output path stagingdir = self.staging_dir(instance) - filename = instance.name + asset_name = instance.data["assetEntity"]["name"] + subset = instance.data["subset"] + filename = f"{asset_name}_{subset}" + path = os.path.join(stagingdir, filename) self.log.debug(f"Outputting images to {path}") diff --git a/openpype/hosts/blender/plugins/publish/extract_thumbnail.py b/openpype/hosts/blender/plugins/publish/extract_thumbnail.py index 52e5d98fc4..e593e0de27 100644 --- a/openpype/hosts/blender/plugins/publish/extract_thumbnail.py +++ b/openpype/hosts/blender/plugins/publish/extract_thumbnail.py @@ -26,8 +26,15 @@ class ExtractThumbnail(publish.Extractor): def process(self, instance): self.log.debug("Extracting capture..") + if instance.data.get("thumbnailSource"): + self.log.debug("Thumbnail source found, skipping...") + return + stagingdir = self.staging_dir(instance) - filename = instance.name + asset_name = instance.data["assetEntity"]["name"] + subset = instance.data["subset"] + filename = f"{asset_name}_{subset}" + path = os.path.join(stagingdir, filename) self.log.debug(f"Outputting images to {path}") diff --git a/openpype/hosts/blender/plugins/publish/increment_workfile_version.py b/openpype/hosts/blender/plugins/publish/increment_workfile_version.py index 7e33fd53fa..9f8d20aedc 100644 --- a/openpype/hosts/blender/plugins/publish/increment_workfile_version.py +++ b/openpype/hosts/blender/plugins/publish/increment_workfile_version.py @@ -14,7 +14,7 @@ class IncrementWorkfileVersion( optional = True hosts = ["blender"] families = ["animation", "model", "rig", "action", "layout", "blendScene", - "pointcache", "render"] + "pointcache", "render.farm"] def process(self, context): if not self.is_active(context.data): diff --git a/openpype/hosts/blender/plugins/publish/validate_deadline_publish.py b/openpype/hosts/blender/plugins/publish/validate_deadline_publish.py index d8826adc9c..bb243f08cc 100644 --- a/openpype/hosts/blender/plugins/publish/validate_deadline_publish.py +++ b/openpype/hosts/blender/plugins/publish/validate_deadline_publish.py @@ -19,7 +19,7 @@ class ValidateDeadlinePublish(pyblish.api.InstancePlugin, """ order = ValidateContentsOrder - families = ["render.farm"] + families = ["render"] hosts = ["blender"] label = "Validate Render Output for Deadline" optional = True diff --git a/openpype/hosts/celaction/plugins/publish/collect_celaction_instances.py b/openpype/hosts/celaction/plugins/publish/collect_celaction_instances.py index c815c1edd4..875f15fcc5 100644 --- a/openpype/hosts/celaction/plugins/publish/collect_celaction_instances.py +++ b/openpype/hosts/celaction/plugins/publish/collect_celaction_instances.py @@ -1,6 +1,8 @@ import os import pyblish.api +from openpype.client import get_asset_name_identifier + class CollectCelactionInstances(pyblish.api.ContextPlugin): """ Adds the celaction render instances """ @@ -17,8 +19,10 @@ class CollectCelactionInstances(pyblish.api.ContextPlugin): asset_entity = context.data["assetEntity"] project_entity = context.data["projectEntity"] + asset_name = get_asset_name_identifier(asset_entity) + shared_instance_data = { - "asset": asset_entity["name"], + "asset": asset_name, "frameStart": asset_entity["data"]["frameStart"], "frameEnd": asset_entity["data"]["frameEnd"], "handleStart": asset_entity["data"]["handleStart"], diff --git a/openpype/hosts/flame/plugins/publish/collect_timeline_otio.py b/openpype/hosts/flame/plugins/publish/collect_timeline_otio.py index f8cfa9e963..20ac048986 100644 --- a/openpype/hosts/flame/plugins/publish/collect_timeline_otio.py +++ b/openpype/hosts/flame/plugins/publish/collect_timeline_otio.py @@ -1,5 +1,6 @@ import pyblish.api +from openpype.client import get_asset_name_identifier import openpype.hosts.flame.api as opfapi from openpype.hosts.flame.otio import flame_export from openpype.pipeline.create import get_subset_name @@ -33,13 +34,15 @@ class CollecTimelineOTIO(pyblish.api.ContextPlugin): project_settings=context.data["project_settings"] ) + asset_name = get_asset_name_identifier(asset_doc) + # adding otio timeline to context with opfapi.maintained_segment_selection(sequence) as selected_seg: otio_timeline = flame_export.create_otio_timeline(sequence) instance_data = { "name": subset_name, - "asset": asset_doc["name"], + "asset": asset_name, "subset": subset_name, "family": "workfile", "families": [] diff --git a/openpype/hosts/fusion/api/menu.py b/openpype/hosts/fusion/api/menu.py index 50250a6656..0b9ad1a43b 100644 --- a/openpype/hosts/fusion/api/menu.py +++ b/openpype/hosts/fusion/api/menu.py @@ -1,3 +1,4 @@ +import os import sys from qtpy import QtWidgets, QtCore, QtGui @@ -18,6 +19,10 @@ from openpype.resources import get_openpype_icon_filepath from .pipeline import FusionEventHandler from .pulse import FusionPulse + +MENU_LABEL = os.environ["AVALON_LABEL"] + + self = sys.modules[__name__] self.menu = None @@ -26,7 +31,7 @@ class OpenPypeMenu(QtWidgets.QWidget): def __init__(self, *args, **kwargs): super(OpenPypeMenu, self).__init__(*args, **kwargs) - self.setObjectName("OpenPypeMenu") + self.setObjectName(f"{MENU_LABEL}Menu") icon_path = get_openpype_icon_filepath() icon = QtGui.QIcon(icon_path) @@ -41,7 +46,7 @@ class OpenPypeMenu(QtWidgets.QWidget): | QtCore.Qt.WindowStaysOnTopHint ) self.render_mode_widget = None - self.setWindowTitle("OpenPype") + self.setWindowTitle(MENU_LABEL) asset_label = QtWidgets.QLabel("Context", self) asset_label.setStyleSheet( diff --git a/openpype/hosts/fusion/deploy/MenuScripts/openpype_menu.py b/openpype/hosts/fusion/deploy/MenuScripts/launch_menu.py similarity index 100% rename from openpype/hosts/fusion/deploy/MenuScripts/openpype_menu.py rename to openpype/hosts/fusion/deploy/MenuScripts/launch_menu.py diff --git a/openpype/hosts/fusion/deploy/ayon/Config/menu.fu b/openpype/hosts/fusion/deploy/ayon/Config/menu.fu new file mode 100644 index 0000000000..c968a1bb3d --- /dev/null +++ b/openpype/hosts/fusion/deploy/ayon/Config/menu.fu @@ -0,0 +1,60 @@ +{ + Action + { + ID = "AYON_Menu", + Category = "AYON", + Name = "AYON Menu", + + Targets = + { + Composition = + { + Execute = _Lua [=[ + local scriptPath = app:MapPath("AYON:../MenuScripts/launch_menu.py") + if bmd.fileexists(scriptPath) == false then + print("[AYON Error] Can't run file: " .. scriptPath) + else + target:RunScript(scriptPath) + end + ]=], + }, + }, + }, + Action + { + ID = "AYON_Install_PySide2", + Category = "AYON", + Name = "Install PySide2", + + Targets = + { + Composition = + { + Execute = _Lua [=[ + local scriptPath = app:MapPath("AYON:../MenuScripts/install_pyside2.py") + if bmd.fileexists(scriptPath) == false then + print("[AYON Error] Can't run file: " .. scriptPath) + else + target:RunScript(scriptPath) + end + ]=], + }, + }, + }, + Menus + { + Target = "ChildFrame", + + Before "Help" + { + Sub "AYON" + { + "AYON_Menu{}", + "_", + Sub "Admin" { + "AYON_Install_PySide2{}" + } + } + }, + }, +} diff --git a/openpype/hosts/fusion/deploy/ayon/fusion_shared.prefs b/openpype/hosts/fusion/deploy/ayon/fusion_shared.prefs new file mode 100644 index 0000000000..9c67af7db9 --- /dev/null +++ b/openpype/hosts/fusion/deploy/ayon/fusion_shared.prefs @@ -0,0 +1,19 @@ +{ +Locked = true, +Global = { + Paths = { + Map = { + ["AYON:"] = "$(OPENPYPE_FUSION)/deploy/ayon", + ["Config:"] = "UserPaths:Config;AYON:Config", + ["Scripts:"] = "UserPaths:Scripts;Reactor:System/Scripts", + }, + }, + Script = { + PythonVersion = 3, + Python3Forced = true + }, + UserInterface = { + Language = "en_US" + }, + }, +} diff --git a/openpype/hosts/fusion/deploy/Config/openpype_menu.fu b/openpype/hosts/fusion/deploy/openpype/Config/menu.fu similarity index 87% rename from openpype/hosts/fusion/deploy/Config/openpype_menu.fu rename to openpype/hosts/fusion/deploy/openpype/Config/menu.fu index 8b8d448259..85134d2c62 100644 --- a/openpype/hosts/fusion/deploy/Config/openpype_menu.fu +++ b/openpype/hosts/fusion/deploy/openpype/Config/menu.fu @@ -10,7 +10,7 @@ Composition = { Execute = _Lua [=[ - local scriptPath = app:MapPath("OpenPype:MenuScripts/openpype_menu.py") + local scriptPath = app:MapPath("OpenPype:../MenuScripts/launch_menu.py") if bmd.fileexists(scriptPath) == false then print("[OpenPype Error] Can't run file: " .. scriptPath) else @@ -31,7 +31,7 @@ Composition = { Execute = _Lua [=[ - local scriptPath = app:MapPath("OpenPype:MenuScripts/install_pyside2.py") + local scriptPath = app:MapPath("OpenPype:../MenuScripts/install_pyside2.py") if bmd.fileexists(scriptPath) == false then print("[OpenPype Error] Can't run file: " .. scriptPath) else diff --git a/openpype/hosts/fusion/deploy/fusion_shared.prefs b/openpype/hosts/fusion/deploy/openpype/fusion_shared.prefs similarity index 83% rename from openpype/hosts/fusion/deploy/fusion_shared.prefs rename to openpype/hosts/fusion/deploy/openpype/fusion_shared.prefs index 93b08aa886..0035a38990 100644 --- a/openpype/hosts/fusion/deploy/fusion_shared.prefs +++ b/openpype/hosts/fusion/deploy/openpype/fusion_shared.prefs @@ -3,7 +3,7 @@ Locked = true, Global = { Paths = { Map = { - ["OpenPype:"] = "$(OPENPYPE_FUSION)/deploy", + ["OpenPype:"] = "$(OPENPYPE_FUSION)/deploy/openpype", ["Config:"] = "UserPaths:Config;OpenPype:Config", ["Scripts:"] = "UserPaths:Scripts;Reactor:System/Scripts", }, diff --git a/openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py b/openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py index 66b0f803aa..59053ba62a 100644 --- a/openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py +++ b/openpype/hosts/fusion/hooks/pre_fusion_profile_hook.py @@ -2,6 +2,7 @@ import os import shutil import platform from pathlib import Path +from openpype import AYON_SERVER_ENABLED from openpype.hosts.fusion import ( FUSION_HOST_DIR, FUSION_VERSIONS_DICT, @@ -161,6 +162,13 @@ class FusionCopyPrefsPrelaunch(PreLaunchHook): # profile directory variables to customize Fusion # to define where it can read custom scripts and tools from master_prefs_variable = f"FUSION{profile_version}_MasterPrefs" - master_prefs = Path(FUSION_HOST_DIR, "deploy", "fusion_shared.prefs") + + if AYON_SERVER_ENABLED: + master_prefs = Path( + FUSION_HOST_DIR, "deploy", "ayon", "fusion_shared.prefs") + else: + master_prefs = Path( + FUSION_HOST_DIR, "deploy", "openpype", "fusion_shared.prefs") + self.log.info(f"Setting {master_prefs_variable}: {master_prefs}") self.launch_context.env[master_prefs_variable] = str(master_prefs) diff --git a/openpype/hosts/fusion/plugins/create/create_workfile.py b/openpype/hosts/fusion/plugins/create/create_workfile.py index 8acaaa172f..4092086ea4 100644 --- a/openpype/hosts/fusion/plugins/create/create_workfile.py +++ b/openpype/hosts/fusion/plugins/create/create_workfile.py @@ -1,6 +1,7 @@ from openpype.hosts.fusion.api import ( get_current_comp ) +from openpype import AYON_SERVER_ENABLED from openpype.client import get_asset_by_name from openpype.pipeline import ( AutoCreator, @@ -68,6 +69,13 @@ class FusionWorkfileCreator(AutoCreator): task_name = self.create_context.get_current_task_name() host_name = self.create_context.host_name + if existing_instance is None: + existing_instance_asset = None + elif AYON_SERVER_ENABLED: + existing_instance_asset = existing_instance["folderPath"] + else: + existing_instance_asset = existing_instance["asset"] + if existing_instance is None: asset_doc = get_asset_by_name(project_name, asset_name) subset_name = self.get_subset_name( @@ -75,10 +83,13 @@ class FusionWorkfileCreator(AutoCreator): project_name, host_name ) data = { - "asset": asset_name, "task": task_name, "variant": self.default_variant } + if AYON_SERVER_ENABLED: + data["folderPath"] = asset_name + else: + data["asset"] = asset_name data.update(self.get_dynamic_data( self.default_variant, task_name, asset_doc, project_name, host_name, None @@ -91,7 +102,7 @@ class FusionWorkfileCreator(AutoCreator): self._add_instance_to_context(new_instance) elif ( - existing_instance["asset"] != asset_name + existing_instance_asset != asset_name or existing_instance["task"] != task_name ): asset_doc = get_asset_by_name(project_name, asset_name) @@ -99,6 +110,9 @@ class FusionWorkfileCreator(AutoCreator): self.default_variant, task_name, asset_doc, project_name, host_name ) - existing_instance["asset"] = asset_name + if AYON_SERVER_ENABLED: + existing_instance["folderPath"] = asset_name + else: + existing_instance["asset"] = asset_name existing_instance["task"] = task_name existing_instance["subset"] = subset_name diff --git a/openpype/hosts/fusion/plugins/publish/extract_render_local.py b/openpype/hosts/fusion/plugins/publish/extract_render_local.py index 25c101cf00..08d608139d 100644 --- a/openpype/hosts/fusion/plugins/publish/extract_render_local.py +++ b/openpype/hosts/fusion/plugins/publish/extract_render_local.py @@ -25,20 +25,24 @@ def enabled_savers(comp, savers): """ passthrough_key = "TOOLB_PassThrough" original_states = {} - enabled_save_names = {saver.Name for saver in savers} + enabled_saver_names = {saver.Name for saver in savers} + + all_savers = comp.GetToolList(False, "Saver").values() + savers_by_name = {saver.Name: saver for saver in all_savers} + try: - all_savers = comp.GetToolList(False, "Saver").values() for saver in all_savers: original_state = saver.GetAttrs()[passthrough_key] - original_states[saver] = original_state + original_states[saver.Name] = original_state # The passthrough state we want to set (passthrough != enabled) - state = saver.Name not in enabled_save_names + state = saver.Name not in enabled_saver_names if state != original_state: saver.SetAttrs({passthrough_key: state}) yield finally: - for saver, original_state in original_states.items(): + for saver_name, original_state in original_states.items(): + saver = savers_by_name[saver_name] saver.SetAttrs({"TOOLB_PassThrough": original_state}) diff --git a/openpype/hosts/harmony/api/TB_sceneOpened.js b/openpype/hosts/harmony/api/TB_sceneOpened.js index a284a6ec5c..48daf094dd 100644 --- a/openpype/hosts/harmony/api/TB_sceneOpened.js +++ b/openpype/hosts/harmony/api/TB_sceneOpened.js @@ -13,7 +13,7 @@ var LD_OPENHARMONY_PATH = System.getenv('LIB_OPENHARMONY_PATH'); LD_OPENHARMONY_PATH = LD_OPENHARMONY_PATH + '/openHarmony.js'; LD_OPENHARMONY_PATH = LD_OPENHARMONY_PATH.replace(/\\/g, "/"); include(LD_OPENHARMONY_PATH); -this.__proto__['$'] = $; +//this.__proto__['$'] = $; function Client() { var self = this; diff --git a/openpype/hosts/harmony/plugins/publish/extract_render.py b/openpype/hosts/harmony/plugins/publish/extract_render.py index 5825d95a4a..96a375716b 100644 --- a/openpype/hosts/harmony/plugins/publish/extract_render.py +++ b/openpype/hosts/harmony/plugins/publish/extract_render.py @@ -59,8 +59,8 @@ class ExtractRender(pyblish.api.InstancePlugin): args = [application_path, "-batch", "-frames", str(frame_start), str(frame_end), - "-scene", scene_path] - self.log.info(f"running [ {application_path} {' '.join(args)}") + scene_path] + self.log.info(f"running: {' '.join(args)}") proc = subprocess.Popen( args, stdout=subprocess.PIPE, diff --git a/openpype/hosts/hiero/api/menu.py b/openpype/hosts/hiero/api/menu.py index 9967e9c875..ca611570cc 100644 --- a/openpype/hosts/hiero/api/menu.py +++ b/openpype/hosts/hiero/api/menu.py @@ -95,18 +95,18 @@ def menu_install(): menu.addSeparator() - publish_action = menu.addAction("Publish...") - publish_action.setIcon(QtGui.QIcon("icons:Output.png")) - publish_action.triggered.connect( - lambda *args: publish(hiero.ui.mainWindow()) - ) - creator_action = menu.addAction("Create...") creator_action.setIcon(QtGui.QIcon("icons:CopyRectangle.png")) creator_action.triggered.connect( lambda: host_tools.show_creator(parent=main_window) ) + publish_action = menu.addAction("Publish...") + publish_action.setIcon(QtGui.QIcon("icons:Output.png")) + publish_action.triggered.connect( + lambda *args: publish(hiero.ui.mainWindow()) + ) + loader_action = menu.addAction("Load...") loader_action.setIcon(QtGui.QIcon("icons:CopyRectangle.png")) loader_action.triggered.connect( diff --git a/openpype/hosts/hiero/api/plugin.py b/openpype/hosts/hiero/api/plugin.py index 52f96261b2..b0c73e41fb 100644 --- a/openpype/hosts/hiero/api/plugin.py +++ b/openpype/hosts/hiero/api/plugin.py @@ -11,7 +11,6 @@ import qargparse from openpype.settings import get_current_project_settings from openpype.lib import Logger from openpype.pipeline import LoaderPlugin, LegacyCreator -from openpype.pipeline.context_tools import get_current_project_asset from openpype.pipeline.load import get_representation_path_from_context from . import lib @@ -32,7 +31,7 @@ def load_stylesheet(): class CreatorWidget(QtWidgets.QDialog): # output items - items = dict() + items = {} def __init__(self, name, info, ui_inputs, parent=None): super(CreatorWidget, self).__init__(parent) @@ -494,9 +493,8 @@ class ClipLoader: joint `data` key with asset.data dict into the representation """ - asset_name = self.context["representation"]["context"]["asset"] - asset_doc = get_current_project_asset(asset_name) - log.debug("__ asset_doc: {}".format(pformat(asset_doc))) + + asset_doc = self.context["asset"] self.data["assetData"] = asset_doc["data"] def _make_track_item(self, source_bin_item, audio=False): @@ -644,8 +642,8 @@ class PublishClip: Returns: hiero.core.TrackItem: hiero track item object with pype tag """ - vertical_clip_match = dict() - tag_data = dict() + vertical_clip_match = {} + tag_data = {} types = { "shot": "shot", "folder": "folder", @@ -707,9 +705,10 @@ class PublishClip: self._create_parents() def convert(self): - # solve track item data and add them to tag data - self._convert_to_tag_data() + tag_hierarchy_data = self._convert_to_tag_data() + + self.tag_data.update(tag_hierarchy_data) # if track name is in review track name and also if driving track name # is not in review track name: skip tag creation @@ -723,16 +722,23 @@ class PublishClip: if self.rename: # rename track item self.track_item.setName(new_name) - self.tag_data["asset"] = new_name + self.tag_data["asset_name"] = new_name else: - self.tag_data["asset"] = self.ti_name + self.tag_data["asset_name"] = self.ti_name self.tag_data["hierarchyData"]["shot"] = self.ti_name + # AYON unique identifier + folder_path = "/{}/{}".format( + tag_hierarchy_data["hierarchy"], + self.tag_data["asset_name"] + ) + self.tag_data["folderPath"] = folder_path if self.tag_data["heroTrack"] and self.review_layer: self.tag_data.update({"reviewTrack": self.review_layer}) else: self.tag_data.update({"reviewTrack": None}) + # TODO: remove debug print log.debug("___ self.tag_data: {}".format( pformat(self.tag_data) )) @@ -891,7 +897,7 @@ class PublishClip: tag_hierarchy_data = hero_data # add data to return data dict - self.tag_data.update(tag_hierarchy_data) + return tag_hierarchy_data def _solve_tag_hierarchy_data(self, hierarchy_formatting_data): """ Solve tag data from hierarchy data and templates. """ diff --git a/openpype/hosts/hiero/plugins/publish/collect_frame_tag_instances.py b/openpype/hosts/hiero/plugins/publish/collect_frame_tag_instances.py index 982a34efd6..79bf67b336 100644 --- a/openpype/hosts/hiero/plugins/publish/collect_frame_tag_instances.py +++ b/openpype/hosts/hiero/plugins/publish/collect_frame_tag_instances.py @@ -5,6 +5,8 @@ import json import pyblish.api +from openpype.client import get_asset_name_identifier + class CollectFrameTagInstances(pyblish.api.ContextPlugin): """Collect frames from tags. @@ -99,6 +101,9 @@ class CollectFrameTagInstances(pyblish.api.ContextPlugin): # first collect all available subset tag frames subset_data = {} + context_asset_doc = context.data["assetEntity"] + context_asset_name = get_asset_name_identifier(context_asset_doc) + for tag_data in sequence_tags: frame = int(tag_data["start"]) @@ -115,7 +120,7 @@ class CollectFrameTagInstances(pyblish.api.ContextPlugin): subset_data[subset] = { "frames": [frame], "format": tag_data["format"], - "asset": context.data["assetEntity"]["name"] + "asset": context_asset_name } return subset_data diff --git a/openpype/hosts/hiero/plugins/publish/precollect_instances.py b/openpype/hosts/hiero/plugins/publish/precollect_instances.py index 3f9da2cf60..590d7b7050 100644 --- a/openpype/hosts/hiero/plugins/publish/precollect_instances.py +++ b/openpype/hosts/hiero/plugins/publish/precollect_instances.py @@ -1,9 +1,12 @@ import pyblish + +from openpype import AYON_SERVER_ENABLED from openpype.pipeline.editorial import is_overlapping_otio_ranges + from openpype.hosts.hiero import api as phiero from openpype.hosts.hiero.api.otio import hiero_export -import hiero +import hiero # # developer reload modules from pprint import pformat @@ -80,25 +83,24 @@ class PrecollectInstances(pyblish.api.ContextPlugin): if k not in ("id", "applieswhole", "label") }) - asset = tag_data["asset"] + asset, asset_name = self._get_asset_data(tag_data) + subset = tag_data["subset"] # insert family into families - family = tag_data["family"] families = [str(f) for f in tag_data["families"]] - families.insert(0, str(family)) # form label - label = asset - if asset != clip_name: + label = "{} -".format(asset) + if asset_name != clip_name: label += " ({})".format(clip_name) label += " {}".format(subset) - label += " {}".format("[" + ", ".join(families) + "]") data.update({ "name": "{}_{}".format(asset, subset), "label": label, "asset": asset, + "asset_name": asset_name, "item": track_item, "families": families, "publish": tag_data["publish"], @@ -176,9 +178,9 @@ class PrecollectInstances(pyblish.api.ContextPlugin): }) def create_shot_instance(self, context, **data): + subset = "shotMain" master_layer = data.get("heroTrack") hierarchy_data = data.get("hierarchyData") - asset = data.get("asset") item = data.get("item") clip_name = item.name() @@ -189,23 +191,21 @@ class PrecollectInstances(pyblish.api.ContextPlugin): return asset = data["asset"] - subset = "shotMain" + asset_name = data["asset_name"] # insert family into families family = "shot" # form label - label = asset - if asset != clip_name: + label = "{} -".format(asset) + if asset_name != clip_name: label += " ({}) ".format(clip_name) label += " {}".format(subset) - label += " [{}]".format(family) data.update({ "name": "{}_{}".format(asset, subset), "label": label, "subset": subset, - "asset": asset, "family": family, "families": [] }) @@ -215,7 +215,33 @@ class PrecollectInstances(pyblish.api.ContextPlugin): self.log.debug( "_ instance.data: {}".format(pformat(instance.data))) + def _get_asset_data(self, data): + folder_path = data.pop("folderPath", None) + + if data.get("asset_name"): + asset_name = data["asset_name"] + else: + asset_name = data["asset"] + + # backward compatibility for clip tags + # which are missing folderPath key + # TODO remove this in future versions + if not folder_path: + hierarchy_path = data["hierarchy"] + folder_path = "/{}/{}".format( + hierarchy_path, + asset_name + ) + + if AYON_SERVER_ENABLED: + asset = folder_path + else: + asset = asset_name + + return asset, asset_name + def create_audio_instance(self, context, **data): + subset = "audioMain" master_layer = data.get("heroTrack") if not master_layer: @@ -230,23 +256,21 @@ class PrecollectInstances(pyblish.api.ContextPlugin): return asset = data["asset"] - subset = "audioMain" + asset_name = data["asset_name"] # insert family into families family = "audio" # form label - label = asset - if asset != clip_name: + label = "{} -".format(asset) + if asset_name != clip_name: label += " ({}) ".format(clip_name) label += " {}".format(subset) - label += " [{}]".format(family) data.update({ "name": "{}_{}".format(asset, subset), "label": label, "subset": subset, - "asset": asset, "family": family, "families": ["clip"] }) diff --git a/openpype/hosts/hiero/plugins/publish/precollect_workfile.py b/openpype/hosts/hiero/plugins/publish/precollect_workfile.py index 5a66581531..8abb0885c6 100644 --- a/openpype/hosts/hiero/plugins/publish/precollect_workfile.py +++ b/openpype/hosts/hiero/plugins/publish/precollect_workfile.py @@ -7,6 +7,7 @@ from qtpy.QtGui import QPixmap import hiero.ui +from openpype import AYON_SERVER_ENABLED from openpype.hosts.hiero.api.otio import hiero_export @@ -17,9 +18,11 @@ class PrecollectWorkfile(pyblish.api.ContextPlugin): order = pyblish.api.CollectorOrder - 0.491 def process(self, context): - asset = context.data["asset"] - subset = "workfile" + asset_name = asset + if AYON_SERVER_ENABLED: + asset_name = asset_name.split("/")[-1] + active_timeline = hiero.ui.activeSequence() project = active_timeline.project() fps = active_timeline.framerate().toFloat() @@ -27,7 +30,7 @@ class PrecollectWorkfile(pyblish.api.ContextPlugin): # adding otio timeline to context otio_timeline = hiero_export.create_otio_timeline() - # get workfile thumnail paths + # get workfile thumbnail paths tmp_staging = tempfile.mkdtemp(prefix="pyblish_tmp_") thumbnail_name = "workfile_thumbnail.png" thumbnail_path = os.path.join(tmp_staging, thumbnail_name) @@ -49,8 +52,8 @@ class PrecollectWorkfile(pyblish.api.ContextPlugin): } # get workfile paths - curent_file = project.path() - staging_dir, base_name = os.path.split(curent_file) + current_file = project.path() + staging_dir, base_name = os.path.split(current_file) # creating workfile representation workfile_representation = { @@ -59,13 +62,16 @@ class PrecollectWorkfile(pyblish.api.ContextPlugin): 'files': base_name, "stagingDir": staging_dir, } - + family = "workfile" instance_data = { - "name": "{}_{}".format(asset, subset), - "asset": asset, - "subset": "{}{}".format(asset, subset.capitalize()), + "label": "{} - {}Main".format( + asset, family), + "name": "{}_{}".format(asset_name, family), + "asset": context.data["asset"], + # TODO use 'get_subset_name' + "subset": "{}{}Main".format(asset_name, family.capitalize()), "item": project, - "family": "workfile", + "family": family, "families": [], "representations": [workfile_representation, thumb_representation] } @@ -78,7 +84,7 @@ class PrecollectWorkfile(pyblish.api.ContextPlugin): "activeProject": project, "activeTimeline": active_timeline, "otioTimeline": otio_timeline, - "currentFile": curent_file, + "currentFile": current_file, "colorspace": self.get_colorspace(project), "fps": fps } diff --git a/openpype/hosts/hiero/plugins/publish_old_workflow/collect_assetbuilds.py b/openpype/hosts/hiero/plugins/publish_old_workflow/collect_assetbuilds.py index 767f7c30f7..37370497a5 100644 --- a/openpype/hosts/hiero/plugins/publish_old_workflow/collect_assetbuilds.py +++ b/openpype/hosts/hiero/plugins/publish_old_workflow/collect_assetbuilds.py @@ -1,5 +1,6 @@ from pyblish import api -from openpype.client import get_assets + +from openpype.client import get_assets, get_asset_name_identifier class CollectAssetBuilds(api.ContextPlugin): @@ -19,10 +20,13 @@ class CollectAssetBuilds(api.ContextPlugin): def process(self, context): project_name = context.data["projectName"] asset_builds = {} - for asset in get_assets(project_name): - if asset["data"]["entityType"] == "AssetBuild": - self.log.debug("Found \"{}\" in database.".format(asset)) - asset_builds[asset["name"]] = asset + for asset_doc in get_assets(project_name): + if asset_doc["data"].get("entityType") != "AssetBuild": + continue + + asset_name = get_asset_name_identifier(asset_doc) + self.log.debug("Found \"{}\" in database.".format(asset_doc)) + asset_builds[asset_name] = asset_doc for instance in context: if instance.data["family"] != "clip": @@ -50,9 +54,7 @@ class CollectAssetBuilds(api.ContextPlugin): # Collect asset builds. data = {"assetbuilds": []} for name in asset_names: - data["assetbuilds"].append( - asset_builds[name] - ) + data["assetbuilds"].append(asset_builds[name]) self.log.debug( "Found asset builds: {}".format(data["assetbuilds"]) ) diff --git a/openpype/hosts/houdini/api/lib.py b/openpype/hosts/houdini/api/lib.py index 8b058e605d..614052431f 100644 --- a/openpype/hosts/houdini/api/lib.py +++ b/openpype/hosts/houdini/api/lib.py @@ -121,8 +121,8 @@ def get_id_required_nodes(): return list(nodes) -def get_output_parameter(node): - """Return the render output parameter name of the given node +def get_export_parameter(node): + """Return the export output parameter of the given node Example: root = hou.node("/obj") @@ -137,13 +137,70 @@ def get_output_parameter(node): hou.Parm """ + node_type = node.type().description() - node_type = node.type().name() - if node_type == "geometry": + # Ensures the proper Take is selected for each ROP to retrieve the correct + # ifd + try: + rop_take = hou.takes.findTake(node.parm("take").eval()) + if rop_take is not None: + hou.takes.setCurrentTake(rop_take) + except AttributeError: + # hou object doesn't always have the 'takes' attribute + pass + + if node_type == "Mantra" and node.parm("soho_outputmode").eval(): + return node.parm("soho_diskfile") + elif node_type == "Alfred": + return node.parm("alf_diskfile") + elif (node_type == "RenderMan" or node_type == "RenderMan RIS"): + pre_ris22 = node.parm("rib_outputmode") and \ + node.parm("rib_outputmode").eval() + ris22 = node.parm("diskfile") and node.parm("diskfile").eval() + if pre_ris22 or ris22: + return node.parm("soho_diskfile") + elif node_type == "Redshift" and node.parm("RS_archive_enable").eval(): + return node.parm("RS_archive_file") + elif node_type == "Wedge" and node.parm("driver").eval(): + return get_export_parameter(node.node(node.parm("driver").eval())) + elif node_type == "Arnold": + return node.parm("ar_ass_file") + elif node_type == "Alembic" and node.parm("use_sop_path").eval(): + return node.parm("sop_path") + elif node_type == "Shotgun Mantra" and node.parm("soho_outputmode").eval(): + return node.parm("sgtk_soho_diskfile") + elif node_type == "Shotgun Alembic" and node.parm("use_sop_path").eval(): + return node.parm("sop_path") + elif node.type().nameWithCategory() == "Driver/vray_renderer": + return node.parm("render_export_filepath") + + raise TypeError("Node type '%s' not supported" % node_type) + + +def get_output_parameter(node): + """Return the render output parameter of the given node + + Example: + root = hou.node("/obj") + my_alembic_node = root.createNode("alembic") + get_output_parameter(my_alembic_node) + # Result: "output" + + Args: + node(hou.Node): node instance + + Returns: + hou.Parm + + """ + node_type = node.type().description() + category = node.type().category().name() + + # Figure out which type of node is being rendered + if node_type == "Geometry" or node_type == "Filmbox FBX" or \ + (node_type == "ROP Output Driver" and category == "Sop"): return node.parm("sopoutput") - elif node_type == "alembic": - return node.parm("filename") - elif node_type == "comp": + elif node_type == "Composite": return node.parm("copoutput") elif node_type == "opengl": return node.parm("picture") @@ -152,6 +209,17 @@ def get_output_parameter(node): return node.parm("ar_ass_file") elif node_type == "Redshift_Proxy_Output": return node.parm("RS_archive_file") + elif node_type == "ifd": + if node.evalParm("soho_outputmode"): + return node.parm("soho_diskfile") + elif node_type == "Octane": + return node.parm("HO_img_fileName") + elif node_type == "Fetch": + inner_node = node.node(node.parm("source").eval()) + if inner_node: + return get_output_parameter(inner_node) + elif node.type().nameWithCategory() == "Driver/vray_renderer": + return node.parm("SettingsOutput_img_file_path") raise TypeError("Node type '%s' not supported" % node_type) diff --git a/openpype/hosts/houdini/api/pipeline.py b/openpype/hosts/houdini/api/pipeline.py index 11135e20b2..d0f45c36b5 100644 --- a/openpype/hosts/houdini/api/pipeline.py +++ b/openpype/hosts/houdini/api/pipeline.py @@ -66,10 +66,6 @@ class HoudiniHost(HostBase, IWorkfileHost, ILoadHost, IPublishHost): register_event_callback("new", on_new) self._has_been_setup = True - # add houdini vendor packages - hou_pythonpath = os.path.join(HOUDINI_HOST_DIR, "vendor") - - sys.path.append(hou_pythonpath) # Set asset settings for the empty scene directly after launch of # Houdini so it initializes into the correct scene FPS, diff --git a/openpype/hosts/houdini/api/plugin.py b/openpype/hosts/houdini/api/plugin.py index 72565f7211..e162d0e461 100644 --- a/openpype/hosts/houdini/api/plugin.py +++ b/openpype/hosts/houdini/api/plugin.py @@ -6,6 +6,8 @@ from abc import ( ) import six import hou + +from openpype import AYON_SERVER_ENABLED from openpype.pipeline import ( CreatorError, LegacyCreator, @@ -142,12 +144,13 @@ class HoudiniCreatorBase(object): @staticmethod def create_instance_node( - node_name, parent, - node_type="geometry"): + asset_name, node_name, parent, node_type="geometry" + ): # type: (str, str, str) -> hou.Node """Create node representing instance. Arguments: + asset_name (str): Asset name. node_name (str): Name of the new node. parent (str): Name of the parent node. node_type (str, optional): Type of the node. @@ -182,8 +185,13 @@ class HoudiniCreator(NewCreator, HoudiniCreatorBase): if node_type is None: node_type = "geometry" + if AYON_SERVER_ENABLED: + asset_name = instance_data["folderPath"] + else: + asset_name = instance_data["asset"] + instance_node = self.create_instance_node( - subset_name, "/out", node_type) + asset_name, subset_name, "/out", node_type) self.customize_node_look(instance_node) diff --git a/openpype/hosts/houdini/plugins/create/create_arnold_ass.py b/openpype/hosts/houdini/plugins/create/create_arnold_ass.py index 12d08f7d83..437a14c723 100644 --- a/openpype/hosts/houdini/plugins/create/create_arnold_ass.py +++ b/openpype/hosts/houdini/plugins/create/create_arnold_ass.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- """Creator plugin for creating Arnold ASS files.""" from openpype.hosts.houdini.api import plugin +from openpype.lib import BoolDef class CreateArnoldAss(plugin.HoudiniCreator): @@ -21,6 +22,9 @@ class CreateArnoldAss(plugin.HoudiniCreator): instance_data.pop("active", None) instance_data.update({"node_type": "arnold"}) + creator_attributes = instance_data.setdefault( + "creator_attributes", dict()) + creator_attributes["farm"] = pre_create_data["farm"] instance = super(CreateArnoldAss, self).create( subset_name, @@ -52,3 +56,15 @@ class CreateArnoldAss(plugin.HoudiniCreator): # Lock any parameters in this list to_lock = ["ar_ass_export_enable", "family", "id"] self.lock_parameters(instance_node, to_lock) + + def get_instance_attr_defs(self): + return [ + BoolDef("farm", + label="Submitting to Farm", + default=False) + ] + + def get_pre_create_attr_defs(self): + attrs = super().get_pre_create_attr_defs() + # Use same attributes as for instance attributes + return attrs + self.get_instance_attr_defs() diff --git a/openpype/hosts/houdini/plugins/create/create_arnold_rop.py b/openpype/hosts/houdini/plugins/create/create_arnold_rop.py index b58c377a20..85c4f0f5ff 100644 --- a/openpype/hosts/houdini/plugins/create/create_arnold_rop.py +++ b/openpype/hosts/houdini/plugins/create/create_arnold_rop.py @@ -13,6 +13,9 @@ class CreateArnoldRop(plugin.HoudiniCreator): # Default extension ext = "exr" + # Default to split export and render jobs + export_job = True + def create(self, subset_name, instance_data, pre_create_data): import hou @@ -48,6 +51,15 @@ class CreateArnoldRop(plugin.HoudiniCreator): "ar_exr_half_precision": 1 # half precision } + if pre_create_data.get("export_job"): + ass_filepath = \ + "{export_dir}{subset_name}/{subset_name}.$F4.ass".format( + export_dir=hou.text.expandString("$HIP/pyblish/ass/"), + subset_name=subset_name, + ) + parms["ar_ass_export_enable"] = 1 + parms["ar_ass_file"] = ass_filepath + instance_node.setParms(parms) # Lock any parameters in this list @@ -66,6 +78,9 @@ class CreateArnoldRop(plugin.HoudiniCreator): BoolDef("farm", label="Submitting to Farm", default=True), + BoolDef("export_job", + label="Split export and render jobs", + default=self.export_job), EnumDef("image_format", image_format_enum, default=self.ext, diff --git a/openpype/hosts/houdini/plugins/create/create_bgeo.py b/openpype/hosts/houdini/plugins/create/create_bgeo.py index 0f629cf9c9..4140919202 100644 --- a/openpype/hosts/houdini/plugins/create/create_bgeo.py +++ b/openpype/hosts/houdini/plugins/create/create_bgeo.py @@ -2,8 +2,8 @@ """Creator plugin for creating pointcache bgeo files.""" from openpype.hosts.houdini.api import plugin from openpype.pipeline import CreatedInstance, CreatorError -from openpype.lib import EnumDef import hou +from openpype.lib import EnumDef, BoolDef class CreateBGEO(plugin.HoudiniCreator): @@ -18,6 +18,9 @@ class CreateBGEO(plugin.HoudiniCreator): instance_data.pop("active", None) instance_data.update({"node_type": "geometry"}) + creator_attributes = instance_data.setdefault( + "creator_attributes", dict()) + creator_attributes["farm"] = pre_create_data["farm"] instance = super(CreateBGEO, self).create( subset_name, @@ -58,6 +61,13 @@ class CreateBGEO(plugin.HoudiniCreator): instance_node.setParms(parms) + def get_instance_attr_defs(self): + return [ + BoolDef("farm", + label="Submitting to Farm", + default=False) + ] + def get_pre_create_attr_defs(self): attrs = super().get_pre_create_attr_defs() bgeo_enum = [ @@ -89,7 +99,7 @@ class CreateBGEO(plugin.HoudiniCreator): return attrs + [ EnumDef("bgeo_type", bgeo_enum, label="BGEO Options"), - ] + ] + self.get_instance_attr_defs() def get_network_categories(self): return [ diff --git a/openpype/hosts/houdini/plugins/create/create_hda.py b/openpype/hosts/houdini/plugins/create/create_hda.py index ac075d2072..f670b55eb6 100644 --- a/openpype/hosts/houdini/plugins/create/create_hda.py +++ b/openpype/hosts/houdini/plugins/create/create_hda.py @@ -17,13 +17,13 @@ class CreateHDA(plugin.HoudiniCreator): icon = "gears" maintain_selection = False - def _check_existing(self, subset_name): + def _check_existing(self, asset_name, subset_name): # type: (str) -> bool """Check if existing subset name versions already exists.""" # Get all subsets of the current asset project_name = self.project_name asset_doc = get_asset_by_name( - project_name, self.data["asset"], fields=["_id"] + project_name, asset_name, fields=["_id"] ) subset_docs = get_subsets( project_name, asset_ids=[asset_doc["_id"]], fields=["name"] @@ -35,7 +35,8 @@ class CreateHDA(plugin.HoudiniCreator): return subset_name.lower() in existing_subset_names_low def create_instance_node( - self, node_name, parent, node_type="geometry"): + self, asset_name, node_name, parent, node_type="geometry" + ): parent_node = hou.node("/obj") if self.selected_nodes: @@ -61,7 +62,7 @@ class CreateHDA(plugin.HoudiniCreator): hda_file_name="$HIP/{}.hda".format(node_name) ) hda_node.layoutChildren() - elif self._check_existing(node_name): + elif self._check_existing(asset_name, node_name): raise plugin.OpenPypeCreatorError( ("subset {} is already published with different HDA" "definition.").format(node_name)) diff --git a/openpype/hosts/houdini/plugins/create/create_mantra_ifd.py b/openpype/hosts/houdini/plugins/create/create_mantra_ifd.py new file mode 100644 index 0000000000..7ea7d1042f --- /dev/null +++ b/openpype/hosts/houdini/plugins/create/create_mantra_ifd.py @@ -0,0 +1,56 @@ +# -*- coding: utf-8 -*- +"""Creator plugin for creating pointcache alembics.""" +from openpype.hosts.houdini.api import plugin +from openpype.pipeline import CreatedInstance +from openpype.lib import BoolDef + + +class CreateMantraIFD(plugin.HoudiniCreator): + """Mantra .ifd Archive""" + identifier = "io.openpype.creators.houdini.mantraifd" + label = "Mantra IFD" + family = "mantraifd" + icon = "gears" + + def create(self, subset_name, instance_data, pre_create_data): + import hou + instance_data.pop("active", None) + instance_data.update({"node_type": "ifd"}) + creator_attributes = instance_data.setdefault( + "creator_attributes", dict()) + creator_attributes["farm"] = pre_create_data["farm"] + instance = super(CreateMantraIFD, self).create( + subset_name, + instance_data, + pre_create_data) # type: CreatedInstance + + instance_node = hou.node(instance.get("instance_node")) + + filepath = "{}{}".format( + hou.text.expandString("$HIP/pyblish/"), + "{}.$F4.ifd".format(subset_name)) + parms = { + # Render frame range + "trange": 1, + # Arnold ROP settings + "soho_diskfile": filepath, + "soho_outputmode": 1 + } + + instance_node.setParms(parms) + + # Lock any parameters in this list + to_lock = ["soho_outputmode", "family", "id"] + self.lock_parameters(instance_node, to_lock) + + def get_instance_attr_defs(self): + return [ + BoolDef("farm", + label="Submitting to Farm", + default=False) + ] + + def get_pre_create_attr_defs(self): + attrs = super().get_pre_create_attr_defs() + # Use same attributes as for instance attributes + return attrs + self.get_instance_attr_defs() diff --git a/openpype/hosts/houdini/plugins/create/create_mantra_rop.py b/openpype/hosts/houdini/plugins/create/create_mantra_rop.py index d2f0e735a8..8ecfbea802 100644 --- a/openpype/hosts/houdini/plugins/create/create_mantra_rop.py +++ b/openpype/hosts/houdini/plugins/create/create_mantra_rop.py @@ -12,6 +12,9 @@ class CreateMantraROP(plugin.HoudiniCreator): family = "mantra_rop" icon = "magic" + # Default to split export and render jobs + export_job = True + def create(self, subset_name, instance_data, pre_create_data): import hou # noqa @@ -44,6 +47,15 @@ class CreateMantraROP(plugin.HoudiniCreator): "vm_picture": filepath, } + if pre_create_data.get("export_job"): + ifd_filepath = \ + "{export_dir}{subset_name}/{subset_name}.$F4.ifd".format( + export_dir=hou.text.expandString("$HIP/pyblish/ifd/"), + subset_name=subset_name, + ) + parms["soho_outputmode"] = 1 + parms["soho_diskfile"] = ifd_filepath + if self.selected_nodes: # If camera found in selection # we will use as render camera @@ -78,6 +90,9 @@ class CreateMantraROP(plugin.HoudiniCreator): BoolDef("farm", label="Submitting to Farm", default=True), + BoolDef("export_job", + label="Split export and render jobs", + default=self.export_job), EnumDef("image_format", image_format_enum, default="exr", diff --git a/openpype/hosts/houdini/plugins/create/create_pointcache.py b/openpype/hosts/houdini/plugins/create/create_pointcache.py index 7eaf2aff2b..2d2f89cc48 100644 --- a/openpype/hosts/houdini/plugins/create/create_pointcache.py +++ b/openpype/hosts/houdini/plugins/create/create_pointcache.py @@ -1,10 +1,12 @@ # -*- coding: utf-8 -*- """Creator plugin for creating pointcache alembics.""" from openpype.hosts.houdini.api import plugin +from openpype.lib import BoolDef import hou + class CreatePointCache(plugin.HoudiniCreator): """Alembic ROP to pointcache""" identifier = "io.openpype.creators.houdini.pointcache" @@ -15,6 +17,9 @@ class CreatePointCache(plugin.HoudiniCreator): def create(self, subset_name, instance_data, pre_create_data): instance_data.pop("active", None) instance_data.update({"node_type": "alembic"}) + creator_attributes = instance_data.setdefault( + "creator_attributes", dict()) + creator_attributes["farm"] = pre_create_data["farm"] instance = super(CreatePointCache, self).create( subset_name, @@ -105,3 +110,15 @@ class CreatePointCache(plugin.HoudiniCreator): else: return min(outputs, key=lambda node: node.evalParm('outputidx')) + + def get_instance_attr_defs(self): + return [ + BoolDef("farm", + label="Submitting to Farm", + default=False) + ] + + def get_pre_create_attr_defs(self): + attrs = super().get_pre_create_attr_defs() + # Use same attributes as for instance attributes + return attrs + self.get_instance_attr_defs() diff --git a/openpype/hosts/houdini/plugins/create/create_redshift_proxy.py b/openpype/hosts/houdini/plugins/create/create_redshift_proxy.py index 3a4ab7008b..e1577c92e9 100644 --- a/openpype/hosts/houdini/plugins/create/create_redshift_proxy.py +++ b/openpype/hosts/houdini/plugins/create/create_redshift_proxy.py @@ -2,6 +2,7 @@ """Creator plugin for creating Redshift proxies.""" from openpype.hosts.houdini.api import plugin import hou +from openpype.lib import BoolDef class CreateRedshiftProxy(plugin.HoudiniCreator): @@ -24,6 +25,9 @@ class CreateRedshiftProxy(plugin.HoudiniCreator): # TODO: Somehow enforce so that it only shows the original limited # attributes of the Redshift_Proxy_Output node type instance_data.update({"node_type": "Redshift_Proxy_Output"}) + creator_attributes = instance_data.setdefault( + "creator_attributes", dict()) + creator_attributes["farm"] = pre_create_data["farm"] instance = super(CreateRedshiftProxy, self).create( subset_name, @@ -50,3 +54,15 @@ class CreateRedshiftProxy(plugin.HoudiniCreator): hou.ropNodeTypeCategory(), hou.sopNodeTypeCategory() ] + + def get_instance_attr_defs(self): + return [ + BoolDef("farm", + label="Submitting to Farm", + default=False) + ] + + def get_pre_create_attr_defs(self): + attrs = super().get_pre_create_attr_defs() + # Use same attributes as for instance attributes + return attrs + self.get_instance_attr_defs() diff --git a/openpype/hosts/houdini/plugins/create/create_vbd_cache.py b/openpype/hosts/houdini/plugins/create/create_vbd_cache.py index 69418f9575..53df9dda68 100644 --- a/openpype/hosts/houdini/plugins/create/create_vbd_cache.py +++ b/openpype/hosts/houdini/plugins/create/create_vbd_cache.py @@ -2,6 +2,7 @@ """Creator plugin for creating VDB Caches.""" from openpype.hosts.houdini.api import plugin from openpype.pipeline import CreatedInstance +from openpype.lib import BoolDef import hou @@ -19,15 +20,20 @@ class CreateVDBCache(plugin.HoudiniCreator): instance_data.pop("active", None) instance_data.update({"node_type": "geometry"}) - + creator_attributes = instance_data.setdefault( + "creator_attributes", dict()) + creator_attributes["farm"] = pre_create_data["farm"] instance = super(CreateVDBCache, self).create( subset_name, instance_data, pre_create_data) # type: CreatedInstance instance_node = hou.node(instance.get("instance_node")) + file_path = "{}{}".format( + hou.text.expandString("$HIP/pyblish/"), + "{}.$F4.vdb".format(subset_name)) parms = { - "sopoutput": "$HIP/pyblish/{}.$F4.vdb".format(subset_name), + "sopoutput": file_path, "initsim": True, "trange": 1 } @@ -103,3 +109,15 @@ class CreateVDBCache(plugin.HoudiniCreator): else: return min(outputs, key=lambda node: node.evalParm('outputidx')) + + def get_instance_attr_defs(self): + return [ + BoolDef("farm", + label="Submitting to Farm", + default=False) + ] + + def get_pre_create_attr_defs(self): + attrs = super().get_pre_create_attr_defs() + # Use same attributes as for instance attributes + return attrs + self.get_instance_attr_defs() diff --git a/openpype/hosts/houdini/plugins/create/create_vray_rop.py b/openpype/hosts/houdini/plugins/create/create_vray_rop.py index 793a544fdf..272b57b548 100644 --- a/openpype/hosts/houdini/plugins/create/create_vray_rop.py +++ b/openpype/hosts/houdini/plugins/create/create_vray_rop.py @@ -16,6 +16,9 @@ class CreateVrayROP(plugin.HoudiniCreator): icon = "magic" ext = "exr" + # Default to split export and render jobs + export_job = True + def create(self, subset_name, instance_data, pre_create_data): instance_data.pop("active", None) @@ -52,6 +55,17 @@ class CreateVrayROP(plugin.HoudiniCreator): "SettingsEXR_bits_per_channel": "16" # half precision } + if pre_create_data.get("export_job"): + scene_filepath = \ + "{export_dir}{subset_name}/{subset_name}.$F4.vrscene".format( + export_dir=hou.text.expandString("$HIP/pyblish/vrscene/"), + subset_name=subset_name, + ) + # Setting render_export_mode to "2" because that's for + # "Export only" ("1" is for "Export & Render") + parms["render_export_mode"] = "2" + parms["render_export_filepath"] = scene_filepath + if self.selected_nodes: # set up the render camera from the selected node camera = None @@ -140,6 +154,9 @@ class CreateVrayROP(plugin.HoudiniCreator): BoolDef("farm", label="Submitting to Farm", default=True), + BoolDef("export_job", + label="Split export and render jobs", + default=self.export_job), EnumDef("image_format", image_format_enum, default=self.ext, diff --git a/openpype/hosts/houdini/plugins/create/create_workfile.py b/openpype/hosts/houdini/plugins/create/create_workfile.py index cc45a6c2a8..850f5c994e 100644 --- a/openpype/hosts/houdini/plugins/create/create_workfile.py +++ b/openpype/hosts/houdini/plugins/create/create_workfile.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- """Creator plugin for creating workfiles.""" +from openpype import AYON_SERVER_ENABLED from openpype.hosts.houdini.api import plugin from openpype.hosts.houdini.api.lib import read, imprint from openpype.hosts.houdini.api.pipeline import CONTEXT_CONTAINER @@ -30,16 +31,27 @@ class CreateWorkfile(plugin.HoudiniCreatorBase, AutoCreator): task_name = self.create_context.get_current_task_name() host_name = self.host_name + if current_instance is None: + current_instance_asset = None + elif AYON_SERVER_ENABLED: + current_instance_asset = current_instance["folderPath"] + else: + current_instance_asset = current_instance["asset"] + if current_instance is None: asset_doc = get_asset_by_name(project_name, asset_name) subset_name = self.get_subset_name( variant, task_name, asset_doc, project_name, host_name ) data = { - "asset": asset_name, "task": task_name, "variant": variant } + if AYON_SERVER_ENABLED: + data["folderPath"] = asset_name + else: + data["asset"] = asset_name + data.update( self.get_dynamic_data( variant, task_name, asset_doc, @@ -51,15 +63,18 @@ class CreateWorkfile(plugin.HoudiniCreatorBase, AutoCreator): ) self._add_instance_to_context(current_instance) elif ( - current_instance["asset"] != asset_name - or current_instance["task"] != task_name + current_instance_asset != asset_name + or current_instance["task"] != task_name ): # Update instance context if is not the same asset_doc = get_asset_by_name(project_name, asset_name) subset_name = self.get_subset_name( variant, task_name, asset_doc, project_name, host_name ) - current_instance["asset"] = asset_name + if AYON_SERVER_ENABLED: + current_instance["folderPath"] = asset_name + else: + current_instance["asset"] = asset_name current_instance["task"] = task_name current_instance["subset"] = subset_name diff --git a/openpype/hosts/houdini/plugins/publish/collect_arnold_rop.py b/openpype/hosts/houdini/plugins/publish/collect_arnold_rop.py index d95f763826..c7da8397dc 100644 --- a/openpype/hosts/houdini/plugins/publish/collect_arnold_rop.py +++ b/openpype/hosts/houdini/plugins/publish/collect_arnold_rop.py @@ -40,6 +40,25 @@ class CollectArnoldROPRenderProducts(pyblish.api.InstancePlugin): default_prefix = evalParmNoFrame(rop, "ar_picture") render_products = [] + # Store whether we are splitting the render job (export + render) + export_job = bool(rop.parm("ar_ass_export_enable").eval()) + instance.data["exportJob"] = export_job + export_prefix = None + export_products = [] + if export_job: + export_prefix = evalParmNoFrame( + rop, "ar_ass_file", pad_character="0" + ) + beauty_export_product = self.get_render_product_name( + prefix=export_prefix, + suffix=None) + export_products.append(beauty_export_product) + self.log.debug( + "Found export product: {}".format(beauty_export_product) + ) + instance.data["ifdFile"] = beauty_export_product + instance.data["exportFiles"] = list(export_products) + # Default beauty AOV beauty_product = self.get_render_product_name(prefix=default_prefix, suffix=None) diff --git a/openpype/hosts/houdini/plugins/publish/collect_cache_farm.py b/openpype/hosts/houdini/plugins/publish/collect_cache_farm.py new file mode 100644 index 0000000000..36ade32a35 --- /dev/null +++ b/openpype/hosts/houdini/plugins/publish/collect_cache_farm.py @@ -0,0 +1,75 @@ +import os +import pyblish.api +import hou +from openpype.hosts.houdini.api import lib + + +class CollectDataforCache(pyblish.api.InstancePlugin): + """Collect data for caching to Deadline.""" + + order = pyblish.api.CollectorOrder + 0.04 + families = ["ass", "pointcache", + "mantraifd", "redshiftproxy", + "vdbcache"] + hosts = ["houdini"] + targets = ["local", "remote"] + label = "Collect Data for Cache" + + def process(self, instance): + creator_attribute = instance.data["creator_attributes"] + farm_enabled = creator_attribute["farm"] + instance.data["farm"] = farm_enabled + if not farm_enabled: + self.log.debug("Caching on farm is disabled. " + "Skipping farm collecting.") + return + # Why do we need this particular collector to collect the expected + # output files from a ROP node. Don't we have a dedicated collector + # for that yet? + # Collect expected files + ropnode = hou.node(instance.data["instance_node"]) + output_parm = lib.get_output_parameter(ropnode) + expected_filepath = output_parm.eval() + instance.data.setdefault("files", list()) + instance.data.setdefault("expectedFiles", list()) + if instance.data.get("frames"): + files = self.get_files(instance, expected_filepath) + # list of files + instance.data["files"].extend(files) + else: + # single file + instance.data["files"].append(output_parm.eval()) + cache_files = {"_": instance.data["files"]} + # Convert instance family to pointcache if it is bgeo or abc + # because ??? + for family in instance.data["families"]: + if family == "bgeo" or "abc": + instance.data["family"] = "pointcache" + break + instance.data.update({ + "plugin": "Houdini", + "publish": True + }) + instance.data["families"].append("publish.hou") + instance.data["expectedFiles"].append(cache_files) + + self.log.debug("{}".format(instance.data)) + + def get_files(self, instance, output_parm): + """Get the files with the frame range data + + Args: + instance (_type_): instance + output_parm (_type_): path of output parameter + + Returns: + files: a list of files + """ + directory = os.path.dirname(output_parm) + + files = [ + os.path.join(directory, frame).replace("\\", "/") + for frame in instance.data["frames"] + ] + + return files diff --git a/openpype/hosts/houdini/plugins/publish/collect_chunk_size.py b/openpype/hosts/houdini/plugins/publish/collect_chunk_size.py new file mode 100644 index 0000000000..1c867e930a --- /dev/null +++ b/openpype/hosts/houdini/plugins/publish/collect_chunk_size.py @@ -0,0 +1,39 @@ +import pyblish.api +from openpype.lib import NumberDef +from openpype.pipeline import OpenPypePyblishPluginMixin + + +class CollectChunkSize(pyblish.api.InstancePlugin, + OpenPypePyblishPluginMixin): + """Collect chunk size for cache submission to Deadline.""" + + order = pyblish.api.CollectorOrder + 0.05 + families = ["ass", "pointcache", + "vdbcache", "mantraifd", + "redshiftproxy"] + hosts = ["houdini"] + targets = ["local", "remote"] + label = "Collect Chunk Size" + chunkSize = 999999 + + def process(self, instance): + # need to get the chunk size info from the setting + attr_values = self.get_attr_values_from_data(instance.data) + instance.data["chunkSize"] = attr_values.get("chunkSize") + + @classmethod + def apply_settings(cls, project_settings): + project_setting = project_settings["houdini"]["publish"]["CollectChunkSize"] # noqa + cls.chunkSize = project_setting["chunk_size"] + + @classmethod + def get_attribute_defs(cls): + return [ + NumberDef("chunkSize", + minimum=1, + maximum=999999, + decimals=0, + default=cls.chunkSize, + label="Frame Per Task") + + ] diff --git a/openpype/hosts/houdini/plugins/publish/collect_frames.py b/openpype/hosts/houdini/plugins/publish/collect_frames.py index cdef642174..089fae6b1b 100644 --- a/openpype/hosts/houdini/plugins/publish/collect_frames.py +++ b/openpype/hosts/houdini/plugins/publish/collect_frames.py @@ -16,7 +16,8 @@ class CollectFrames(pyblish.api.InstancePlugin): order = pyblish.api.CollectorOrder + 0.1 label = "Collect Frames" families = ["vdbcache", "imagesequence", "ass", - "redshiftproxy", "review", "bgeo"] + "mantraifd", "redshiftproxy", "review", + "bgeo"] def process(self, instance): diff --git a/openpype/hosts/houdini/plugins/publish/collect_mantra_rop.py b/openpype/hosts/houdini/plugins/publish/collect_mantra_rop.py index a3e7927807..bc71576174 100644 --- a/openpype/hosts/houdini/plugins/publish/collect_mantra_rop.py +++ b/openpype/hosts/houdini/plugins/publish/collect_mantra_rop.py @@ -44,6 +44,25 @@ class CollectMantraROPRenderProducts(pyblish.api.InstancePlugin): default_prefix = evalParmNoFrame(rop, "vm_picture") render_products = [] + # Store whether we are splitting the render job (export + render) + export_job = bool(rop.parm("soho_outputmode").eval()) + instance.data["exportJob"] = export_job + export_prefix = None + export_products = [] + if export_job: + export_prefix = evalParmNoFrame( + rop, "soho_diskfile", pad_character="0" + ) + beauty_export_product = self.get_render_product_name( + prefix=export_prefix, + suffix=None) + export_products.append(beauty_export_product) + self.log.debug( + "Found export product: {}".format(beauty_export_product) + ) + instance.data["ifdFile"] = beauty_export_product + instance.data["exportFiles"] = list(export_products) + # Default beauty AOV beauty_product = self.get_render_product_name( prefix=default_prefix, suffix=None diff --git a/openpype/hosts/houdini/plugins/publish/collect_usd_bootstrap.py b/openpype/hosts/houdini/plugins/publish/collect_usd_bootstrap.py index 14a8e3c056..462cf99b9c 100644 --- a/openpype/hosts/houdini/plugins/publish/collect_usd_bootstrap.py +++ b/openpype/hosts/houdini/plugins/publish/collect_usd_bootstrap.py @@ -1,6 +1,10 @@ import pyblish.api -from openpype.client import get_subset_by_name, get_asset_by_name +from openpype.client import ( + get_subset_by_name, + get_asset_by_name, + get_asset_name_identifier, +) import openpype.lib.usdlib as usdlib @@ -51,8 +55,9 @@ class CollectUsdBootstrap(pyblish.api.InstancePlugin): self.log.debug("Add bootstrap for: %s" % bootstrap) project_name = instance.context.data["projectName"] - asset = get_asset_by_name(project_name, instance.data["asset"]) - assert asset, "Asset must exist: %s" % asset + asset_name = instance.data["asset"] + asset_doc = get_asset_by_name(project_name, asset_name) + assert asset_doc, "Asset must exist: %s" % asset_name # Check which are not about to be created and don't exist yet required = {"shot": ["usdShot"], "asset": ["usdAsset"]}.get(bootstrap) @@ -67,19 +72,21 @@ class CollectUsdBootstrap(pyblish.api.InstancePlugin): required += list(layers) self.log.debug("Checking required bootstrap: %s" % required) - for subset in required: - if self._subset_exists(project_name, instance, subset, asset): + for subset_name in required: + if self._subset_exists( + project_name, instance, subset_name, asset_doc + ): continue self.log.debug( "Creating {0} USD bootstrap: {1} {2}".format( - bootstrap, asset["name"], subset + bootstrap, asset_name, subset_name ) ) - new = instance.context.create_instance(subset) - new.data["subset"] = subset - new.data["label"] = "{0} ({1})".format(subset, asset["name"]) + new = instance.context.create_instance(subset_name) + new.data["subset"] = subset_name + new.data["label"] = "{0} ({1})".format(subset_name, asset_name) new.data["family"] = "usd.bootstrap" new.data["comment"] = "Automated bootstrap USD file." new.data["publishFamilies"] = ["usd"] @@ -91,21 +98,23 @@ class CollectUsdBootstrap(pyblish.api.InstancePlugin): for key in ["asset"]: new.data[key] = instance.data[key] - def _subset_exists(self, project_name, instance, subset, asset): + def _subset_exists(self, project_name, instance, subset_name, asset_doc): """Return whether subset exists in current context or in database.""" # Allow it to be created during this publish session context = instance.context + + asset_doc_name = get_asset_name_identifier(asset_doc) for inst in context: if ( - inst.data["subset"] == subset - and inst.data["asset"] == asset["name"] + inst.data["subset"] == subset_name + and inst.data["asset"] == asset_doc_name ): return True # Or, if they already exist in the database we can # skip them too. if get_subset_by_name( - project_name, subset, asset["_id"], fields=["_id"] + project_name, subset_name, asset_doc["_id"], fields=["_id"] ): return True return False diff --git a/openpype/hosts/houdini/plugins/publish/collect_vray_rop.py b/openpype/hosts/houdini/plugins/publish/collect_vray_rop.py index 64de2079cd..a1f4554726 100644 --- a/openpype/hosts/houdini/plugins/publish/collect_vray_rop.py +++ b/openpype/hosts/houdini/plugins/publish/collect_vray_rop.py @@ -45,7 +45,26 @@ class CollectVrayROPRenderProducts(pyblish.api.InstancePlugin): render_products = [] # TODO: add render elements if render element - beauty_product = self.get_beauty_render_product(default_prefix) + # Store whether we are splitting the render job in an export + render + export_job = rop.parm("render_export_mode").eval() == "2" + instance.data["exportJob"] = export_job + export_prefix = None + export_products = [] + if export_job: + export_prefix = evalParmNoFrame( + rop, "render_export_filepath", pad_character="0" + ) + beauty_export_product = self.get_render_product_name( + prefix=export_prefix, + suffix=None) + export_products.append(beauty_export_product) + self.log.debug( + "Found export product: {}".format(beauty_export_product) + ) + instance.data["ifdFile"] = beauty_export_product + instance.data["exportFiles"] = list(export_products) + + beauty_product = self.get_render_product_name(default_prefix) render_products.append(beauty_product) files_by_aov = { "RGB Color": self.generate_expected_files(instance, @@ -79,7 +98,7 @@ class CollectVrayROPRenderProducts(pyblish.api.InstancePlugin): instance.data["colorspaceDisplay"] = colorspace_data["display"] instance.data["colorspaceView"] = colorspace_data["view"] - def get_beauty_render_product(self, prefix, suffix=""): + def get_render_product_name(self, prefix, suffix=""): """Return the beauty output filename if render element enabled """ # Remove aov suffix from the product: `prefix.aov_suffix` -> `prefix` diff --git a/openpype/hosts/houdini/plugins/publish/extract_alembic.py b/openpype/hosts/houdini/plugins/publish/extract_alembic.py index bdd19b23d4..df2fdda241 100644 --- a/openpype/hosts/houdini/plugins/publish/extract_alembic.py +++ b/openpype/hosts/houdini/plugins/publish/extract_alembic.py @@ -14,8 +14,12 @@ class ExtractAlembic(publish.Extractor): label = "Extract Alembic" hosts = ["houdini"] families = ["abc", "camera"] + targets = ["local", "remote"] def process(self, instance): + if instance.data.get("farm"): + self.log.debug("Should be processed on farm, skipping.") + return ropnode = hou.node(instance.data["instance_node"]) diff --git a/openpype/hosts/houdini/plugins/publish/extract_ass.py b/openpype/hosts/houdini/plugins/publish/extract_ass.py index be60217055..28dd08f999 100644 --- a/openpype/hosts/houdini/plugins/publish/extract_ass.py +++ b/openpype/hosts/houdini/plugins/publish/extract_ass.py @@ -14,9 +14,12 @@ class ExtractAss(publish.Extractor): label = "Extract Ass" families = ["ass"] hosts = ["houdini"] + targets = ["local", "remote"] def process(self, instance): - + if instance.data.get("farm"): + self.log.debug("Should be processed on farm, skipping.") + return ropnode = hou.node(instance.data["instance_node"]) # Get the filename from the filename parameter diff --git a/openpype/hosts/houdini/plugins/publish/extract_bgeo.py b/openpype/hosts/houdini/plugins/publish/extract_bgeo.py index d13141b426..a3840f8f73 100644 --- a/openpype/hosts/houdini/plugins/publish/extract_bgeo.py +++ b/openpype/hosts/houdini/plugins/publish/extract_bgeo.py @@ -17,7 +17,9 @@ class ExtractBGEO(publish.Extractor): families = ["bgeo"] def process(self, instance): - + if instance.data.get("farm"): + self.log.debug("Should be processed on farm, skipping.") + return ropnode = hou.node(instance.data["instance_node"]) # Get the filename from the filename parameter diff --git a/openpype/hosts/houdini/plugins/publish/extract_mantra_ifd.py b/openpype/hosts/houdini/plugins/publish/extract_mantra_ifd.py new file mode 100644 index 0000000000..894260d1bf --- /dev/null +++ b/openpype/hosts/houdini/plugins/publish/extract_mantra_ifd.py @@ -0,0 +1,51 @@ +import os + +import pyblish.api + +from openpype.pipeline import publish + +import hou + + +class ExtractMantraIFD(publish.Extractor): + + order = pyblish.api.ExtractorOrder + label = "Extract Mantra ifd" + hosts = ["houdini"] + families = ["mantraifd"] + targets = ["local", "remote"] + + def process(self, instance): + if instance.data.get("farm"): + self.log.debug("Should be processed on farm, skipping.") + return + + ropnode = hou.node(instance.data.get("instance_node")) + output = ropnode.evalParm("soho_diskfile") + staging_dir = os.path.dirname(output) + instance.data["stagingDir"] = staging_dir + + files = instance.data["frames"] + missing_frames = [ + frame + for frame in instance.data["frames"] + if not os.path.exists( + os.path.normpath(os.path.join(staging_dir, frame))) + ] + if missing_frames: + raise RuntimeError("Failed to complete Mantra ifd extraction. " + "Missing output files: {}".format( + missing_frames)) + + if "representations" not in instance.data: + instance.data["representations"] = [] + + representation = { + 'name': 'ifd', + 'ext': 'ifd', + 'files': files, + "stagingDir": staging_dir, + "frameStart": instance.data["frameStart"], + "frameEnd": instance.data["frameEnd"], + } + instance.data["representations"].append(representation) diff --git a/openpype/hosts/houdini/plugins/publish/extract_redshift_proxy.py b/openpype/hosts/houdini/plugins/publish/extract_redshift_proxy.py index ef5991924f..218f3b9256 100644 --- a/openpype/hosts/houdini/plugins/publish/extract_redshift_proxy.py +++ b/openpype/hosts/houdini/plugins/publish/extract_redshift_proxy.py @@ -14,9 +14,12 @@ class ExtractRedshiftProxy(publish.Extractor): label = "Extract Redshift Proxy" families = ["redshiftproxy"] hosts = ["houdini"] + targets = ["local", "remote"] def process(self, instance): - + if instance.data.get("farm"): + self.log.debug("Should be processed on farm, skipping.") + return ropnode = hou.node(instance.data.get("instance_node")) # Get the filename from the filename parameter diff --git a/openpype/hosts/houdini/plugins/publish/extract_vdb_cache.py b/openpype/hosts/houdini/plugins/publish/extract_vdb_cache.py index 89af8e1756..8ac16704f0 100644 --- a/openpype/hosts/houdini/plugins/publish/extract_vdb_cache.py +++ b/openpype/hosts/houdini/plugins/publish/extract_vdb_cache.py @@ -16,7 +16,9 @@ class ExtractVDBCache(publish.Extractor): hosts = ["houdini"] def process(self, instance): - + if instance.data.get("farm"): + self.log.debug("Should be processed on farm, skipping.") + return ropnode = hou.node(instance.data["instance_node"]) # Get the filename from the filename parameter diff --git a/openpype/hosts/houdini/plugins/publish/increment_current_file.py b/openpype/hosts/houdini/plugins/publish/increment_current_file.py index 3569de7693..4788cca3cf 100644 --- a/openpype/hosts/houdini/plugins/publish/increment_current_file.py +++ b/openpype/hosts/houdini/plugins/publish/increment_current_file.py @@ -22,7 +22,8 @@ class IncrementCurrentFile(pyblish.api.ContextPlugin): "arnold_rop", "mantra_rop", "karma_rop", - "usdrender"] + "usdrender", + "publish.hou"] optional = True def process(self, context): diff --git a/openpype/hosts/houdini/plugins/publish/validate_houdini_license_category.py b/openpype/hosts/houdini/plugins/publish/validate_houdini_license_category.py index 5076acda60..108a700bbe 100644 --- a/openpype/hosts/houdini/plugins/publish/validate_houdini_license_category.py +++ b/openpype/hosts/houdini/plugins/publish/validate_houdini_license_category.py @@ -20,7 +20,7 @@ class ValidateHoudiniNotApprenticeLicense(pyblish.api.InstancePlugin): """ order = pyblish.api.ValidatorOrder - families = ["usd", "abc"] + families = ["usd", "abc", "fbx", "camera"] hosts = ["houdini"] label = "Houdini Apprentice License" diff --git a/openpype/hosts/houdini/plugins/publish/validate_subset_name.py b/openpype/hosts/houdini/plugins/publish/validate_subset_name.py index bb3648f361..7bed74ebb1 100644 --- a/openpype/hosts/houdini/plugins/publish/validate_subset_name.py +++ b/openpype/hosts/houdini/plugins/publish/validate_subset_name.py @@ -54,12 +54,13 @@ class ValidateSubsetName(pyblish.api.InstancePlugin, rop_node = hou.node(instance.data["instance_node"]) # Check subset name + asset_doc = instance.data["assetEntity"] subset_name = get_subset_name( family=instance.data["family"], variant=instance.data["variant"], task_name=instance.data["task"], - asset_doc=instance.data["assetEntity"], - dynamic_data={"asset": instance.data["asset"]} + asset_doc=asset_doc, + dynamic_data={"asset": asset_doc["name"]} ) if instance.data.get("subset") != subset_name: @@ -76,12 +77,13 @@ class ValidateSubsetName(pyblish.api.InstancePlugin, rop_node = hou.node(instance.data["instance_node"]) # Check subset name + asset_doc = instance.data["assetEntity"] subset_name = get_subset_name( family=instance.data["family"], variant=instance.data["variant"], task_name=instance.data["task"], - asset_doc=instance.data["assetEntity"], - dynamic_data={"asset": instance.data["asset"]} + asset_doc=asset_doc, + dynamic_data={"asset": asset_doc["name"]} ) instance.data["subset"] = subset_name diff --git a/openpype/hosts/houdini/startup/python2.7libs/pythonrc.py b/openpype/hosts/houdini/startup/python2.7libs/pythonrc.py index 683ea6721c..0b92fc2706 100644 --- a/openpype/hosts/houdini/startup/python2.7libs/pythonrc.py +++ b/openpype/hosts/houdini/startup/python2.7libs/pythonrc.py @@ -2,10 +2,12 @@ """OpenPype startup script.""" from openpype.pipeline import install_host from openpype.hosts.houdini.api import HoudiniHost +from openpype import AYON_SERVER_ENABLED def main(): - print("Installing OpenPype ...") + print("Installing {} ...".format( + "AYON" if AYON_SERVER_ENABLED else "OpenPype")) install_host(HoudiniHost()) diff --git a/openpype/hosts/houdini/startup/python3.10libs/pythonrc.py b/openpype/hosts/houdini/startup/python3.10libs/pythonrc.py new file mode 100644 index 0000000000..0b92fc2706 --- /dev/null +++ b/openpype/hosts/houdini/startup/python3.10libs/pythonrc.py @@ -0,0 +1,14 @@ +# -*- coding: utf-8 -*- +"""OpenPype startup script.""" +from openpype.pipeline import install_host +from openpype.hosts.houdini.api import HoudiniHost +from openpype import AYON_SERVER_ENABLED + + +def main(): + print("Installing {} ...".format( + "AYON" if AYON_SERVER_ENABLED else "OpenPype")) + install_host(HoudiniHost()) + + +main() diff --git a/openpype/hosts/houdini/startup/python3.7libs/pythonrc.py b/openpype/hosts/houdini/startup/python3.7libs/pythonrc.py index 683ea6721c..0b92fc2706 100644 --- a/openpype/hosts/houdini/startup/python3.7libs/pythonrc.py +++ b/openpype/hosts/houdini/startup/python3.7libs/pythonrc.py @@ -2,10 +2,12 @@ """OpenPype startup script.""" from openpype.pipeline import install_host from openpype.hosts.houdini.api import HoudiniHost +from openpype import AYON_SERVER_ENABLED def main(): - print("Installing OpenPype ...") + print("Installing {} ...".format( + "AYON" if AYON_SERVER_ENABLED else "OpenPype")) install_host(HoudiniHost()) diff --git a/openpype/hosts/houdini/startup/python3.9libs/pythonrc.py b/openpype/hosts/houdini/startup/python3.9libs/pythonrc.py index 683ea6721c..0b92fc2706 100644 --- a/openpype/hosts/houdini/startup/python3.9libs/pythonrc.py +++ b/openpype/hosts/houdini/startup/python3.9libs/pythonrc.py @@ -2,10 +2,12 @@ """OpenPype startup script.""" from openpype.pipeline import install_host from openpype.hosts.houdini.api import HoudiniHost +from openpype import AYON_SERVER_ENABLED def main(): - print("Installing OpenPype ...") + print("Installing {} ...".format( + "AYON" if AYON_SERVER_ENABLED else "OpenPype")) install_host(HoudiniHost()) diff --git a/openpype/hosts/houdini/vendor/husdoutputprocessors/__init__.py b/openpype/hosts/houdini/vendor/husdoutputprocessors/__init__.py deleted file mode 100644 index 69e3be50da..0000000000 --- a/openpype/hosts/houdini/vendor/husdoutputprocessors/__init__.py +++ /dev/null @@ -1 +0,0 @@ -__path__ = __import__('pkgutil').extend_path(__path__, __name__) diff --git a/openpype/hosts/houdini/vendor/husdoutputprocessors/avalon_uri_processor.py b/openpype/hosts/houdini/vendor/husdoutputprocessors/avalon_uri_processor.py deleted file mode 100644 index 310d057a11..0000000000 --- a/openpype/hosts/houdini/vendor/husdoutputprocessors/avalon_uri_processor.py +++ /dev/null @@ -1,152 +0,0 @@ -import os -import hou -import husdoutputprocessors.base as base - -import colorbleed.usdlib as usdlib - -from openpype.client import get_asset_by_name -from openpype.pipeline import Anatomy, get_current_project_name - - -class AvalonURIOutputProcessor(base.OutputProcessorBase): - """Process Avalon URIs into their full path equivalents. - - """ - - _parameters = None - _param_prefix = 'avalonurioutputprocessor_' - _parms = { - "use_publish_paths": _param_prefix + "use_publish_paths" - } - - def __init__(self): - """ There is only one object of each output processor class that is - ever created in a Houdini session. Therefore be very careful - about what data gets put in this object. - """ - self._use_publish_paths = False - self._cache = dict() - - def displayName(self): - return 'Avalon URI Output Processor' - - def parameters(self): - - if not self._parameters: - parameters = hou.ParmTemplateGroup() - use_publish_path = hou.ToggleParmTemplate( - name=self._parms["use_publish_paths"], - label='Resolve Reference paths to publish paths', - default_value=False, - help=("When enabled any paths for Layers, References or " - "Payloads are resolved to published master versions.\n" - "This is usually only used by the publishing pipeline, " - "but can be used for testing too.")) - parameters.append(use_publish_path) - self._parameters = parameters.asDialogScript() - - return self._parameters - - def beginSave(self, config_node, t): - parm = self._parms["use_publish_paths"] - self._use_publish_paths = config_node.parm(parm).evalAtTime(t) - self._cache.clear() - - def endSave(self): - self._use_publish_paths = None - self._cache.clear() - - def processAsset(self, - asset_path, - asset_path_for_save, - referencing_layer_path, - asset_is_layer, - for_save): - """ - Args: - asset_path (str): The incoming file path you want to alter or not. - asset_path_for_save (bool): Whether the current path is a - referenced path in the USD file. When True, return the path - you want inside USD file. - referencing_layer_path (str): ??? - asset_is_layer (bool): Whether this asset is a USD layer file. - If this is False, the asset is something else (for example, - a texture or volume file). - for_save (bool): Whether the asset path is for a file to be saved - out. If so, then return actual written filepath. - - Returns: - The refactored asset path. - - """ - - # Retrieve from cache if this query occurred before (optimization) - cache_key = (asset_path, asset_path_for_save, asset_is_layer, for_save) - if cache_key in self._cache: - return self._cache[cache_key] - - relative_template = "{asset}_{subset}.{ext}" - uri_data = usdlib.parse_avalon_uri(asset_path) - if uri_data: - - if for_save: - # Set save output path to a relative path so other - # processors can potentially manage it easily? - path = relative_template.format(**uri_data) - - print("Avalon URI Resolver: %s -> %s" % (asset_path, path)) - self._cache[cache_key] = path - return path - - if self._use_publish_paths: - # Resolve to an Avalon published asset for embedded paths - path = self._get_usd_master_path(**uri_data) - else: - path = relative_template.format(**uri_data) - - print("Avalon URI Resolver: %s -> %s" % (asset_path, path)) - self._cache[cache_key] = path - return path - - self._cache[cache_key] = asset_path - return asset_path - - def _get_usd_master_path(self, - asset, - subset, - ext): - """Get the filepath for a .usd file of a subset. - - This will return the path to an unversioned master file generated by - `usd_master_file.py`. - - """ - - PROJECT = get_current_project_name() - anatomy = Anatomy(PROJECT) - asset_doc = get_asset_by_name(PROJECT, asset) - if not asset_doc: - raise RuntimeError("Invalid asset name: '%s'" % asset) - - template_obj = anatomy.templates_obj["publish"]["path"] - path = template_obj.format_strict({ - "project": PROJECT, - "asset": asset_doc["name"], - "subset": subset, - "representation": ext, - "version": 0 # stub version zero - }) - - # Remove the version folder - subset_folder = os.path.dirname(os.path.dirname(path)) - master_folder = os.path.join(subset_folder, "master") - fname = "{0}.{1}".format(subset, ext) - - return os.path.join(master_folder, fname).replace("\\", "/") - - -output_processor = AvalonURIOutputProcessor() - - -def usdOutputProcessor(): - return output_processor diff --git a/openpype/hosts/houdini/vendor/husdoutputprocessors/stagingdir_processor.py b/openpype/hosts/houdini/vendor/husdoutputprocessors/stagingdir_processor.py deleted file mode 100644 index d8e36d5aa8..0000000000 --- a/openpype/hosts/houdini/vendor/husdoutputprocessors/stagingdir_processor.py +++ /dev/null @@ -1,90 +0,0 @@ -import hou -import husdoutputprocessors.base as base -import os - - -class StagingDirOutputProcessor(base.OutputProcessorBase): - """Output all USD Rop file nodes into the Staging Directory - - Ignore any folders and paths set in the Configured Layers - and USD Rop node, just take the filename and save into a - single directory. - - """ - theParameters = None - parameter_prefix = "stagingdiroutputprocessor_" - stagingdir_parm_name = parameter_prefix + "stagingDir" - - def __init__(self): - self.staging_dir = None - - def displayName(self): - return 'StagingDir Output Processor' - - def parameters(self): - if not self.theParameters: - parameters = hou.ParmTemplateGroup() - rootdirparm = hou.StringParmTemplate( - self.stagingdir_parm_name, - 'Staging Directory', 1, - string_type=hou.stringParmType.FileReference, - file_type=hou.fileType.Directory - ) - parameters.append(rootdirparm) - self.theParameters = parameters.asDialogScript() - return self.theParameters - - def beginSave(self, config_node, t): - - # Use the Root Directory parameter if it is set. - root_dir_parm = config_node.parm(self.stagingdir_parm_name) - if root_dir_parm: - self.staging_dir = root_dir_parm.evalAtTime(t) - - if not self.staging_dir: - out_file_parm = config_node.parm('lopoutput') - if out_file_parm: - self.staging_dir = out_file_parm.evalAtTime(t) - if self.staging_dir: - (self.staging_dir, filename) = os.path.split(self.staging_dir) - - def endSave(self): - self.staging_dir = None - - def processAsset(self, asset_path, - asset_path_for_save, - referencing_layer_path, - asset_is_layer, - for_save): - """ - Args: - asset_path (str): The incoming file path you want to alter or not. - asset_path_for_save (bool): Whether the current path is a - referenced path in the USD file. When True, return the path - you want inside USD file. - referencing_layer_path (str): ??? - asset_is_layer (bool): Whether this asset is a USD layer file. - If this is False, the asset is something else (for example, - a texture or volume file). - for_save (bool): Whether the asset path is for a file to be saved - out. If so, then return actual written filepath. - - Returns: - The refactored asset path. - - """ - - # Treat save paths as being relative to the output path. - if for_save and self.staging_dir: - # Whenever we're processing a Save Path make sure to - # resolve it to the Staging Directory - filename = os.path.basename(asset_path) - return os.path.join(self.staging_dir, filename) - - return asset_path - - -output_processor = StagingDirOutputProcessor() -def usdOutputProcessor(): - return output_processor - diff --git a/openpype/hosts/max/api/menu.py b/openpype/hosts/max/api/menu.py index 364f9cd5c5..caaa3e3730 100644 --- a/openpype/hosts/max/api/menu.py +++ b/openpype/hosts/max/api/menu.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- -"""3dsmax menu definition of OpenPype.""" +"""3dsmax menu definition of AYON.""" +import os from qtpy import QtWidgets, QtCore from pymxs import runtime as rt @@ -8,7 +9,7 @@ from openpype.hosts.max.api import lib class OpenPypeMenu(object): - """Object representing OpenPype menu. + """Object representing OpenPype/AYON menu. This is using "hack" to inject itself before "Help" menu of 3dsmax. For some reason `postLoadingMenus` event doesn't fire, and main menu @@ -50,17 +51,17 @@ class OpenPypeMenu(object): return list(self.main_widget.findChildren(QtWidgets.QMenuBar))[0] def get_or_create_openpype_menu( - self, name: str = "&OpenPype", + self, name: str = "&Openpype", before: str = "&Help") -> QtWidgets.QAction: - """Create OpenPype menu. + """Create AYON menu. Args: - name (str, Optional): OpenPypep menu name. + name (str, Optional): AYON menu name. before (str, Optional): Name of the 3dsmax main menu item to - add OpenPype menu before. + add AYON menu before. Returns: - QtWidgets.QAction: OpenPype menu action. + QtWidgets.QAction: AYON menu action. """ if self.menu is not None: @@ -77,15 +78,15 @@ class OpenPypeMenu(object): if before in item.title(): help_action = item.menuAction() - - op_menu = QtWidgets.QMenu("&OpenPype") + tab_menu_label = os.environ.get("AVALON_LABEL") or "AYON" + op_menu = QtWidgets.QMenu("&{}".format(tab_menu_label)) menu_bar.insertMenu(help_action, op_menu) self.menu = op_menu return op_menu def build_openpype_menu(self) -> QtWidgets.QAction: - """Build items in OpenPype menu.""" + """Build items in AYON menu.""" openpype_menu = self.get_or_create_openpype_menu() load_action = QtWidgets.QAction("Load...", openpype_menu) load_action.triggered.connect(self.load_callback) diff --git a/openpype/hosts/max/api/pipeline.py b/openpype/hosts/max/api/pipeline.py index e46c4cabe7..d0ae854dc8 100644 --- a/openpype/hosts/max/api/pipeline.py +++ b/openpype/hosts/max/api/pipeline.py @@ -175,7 +175,7 @@ def containerise(name: str, nodes: list, context, def load_custom_attribute_data(): - """Re-loading the Openpype/AYON custom parameter built by the creator + """Re-loading the AYON custom parameter built by the creator Returns: attribute: re-loading the custom OP attributes set in Maxscript @@ -213,7 +213,7 @@ def import_custom_attribute_data(container: str, selections: list): def update_custom_attribute_data(container: str, selections: list): - """Updating the Openpype/AYON custom parameter built by the creator + """Updating the AYON custom parameter built by the creator Args: container (str): target container which adds custom attributes diff --git a/openpype/hosts/max/api/preview_animation.py b/openpype/hosts/max/api/preview_animation.py index 6c7b8eaa80..74579b165f 100644 --- a/openpype/hosts/max/api/preview_animation.py +++ b/openpype/hosts/max/api/preview_animation.py @@ -198,8 +198,8 @@ def _render_preview_animation_max_pre_2024( res_width, res_height, filename=filepath ) dib = rt.gw.getViewportDib() - dib_width = rt.renderWidth - dib_height = rt.renderHeight + dib_width = float(dib.width) + dib_height = float(dib.height) # aspect ratio viewportRatio = dib_width / dib_height renderRatio = float(res_width / res_height) diff --git a/openpype/hosts/maya/api/lib.py b/openpype/hosts/maya/api/lib.py index c851a12690..ea83abafc2 100644 --- a/openpype/hosts/maya/api/lib.py +++ b/openpype/hosts/maya/api/lib.py @@ -71,8 +71,6 @@ DEFAULT_MATRIX = [1.0, 0.0, 0.0, 0.0, INT_FPS = {15, 24, 25, 30, 48, 50, 60, 44100, 48000} FLOAT_FPS = {23.98, 23.976, 29.97, 47.952, 59.94} -RENDERLIKE_INSTANCE_FAMILIES = ["rendering", "vrayscene"] - DISPLAY_LIGHTS_ENUM = [ {"label": "Use Project Settings", "value": "project_settings"}, @@ -2818,194 +2816,6 @@ class shelf(): cmds.shelfLayout(self.name, p="ShelfLayout") -def _get_render_instances(): - """Return all 'render-like' instances. - - This returns list of instance sets that needs to receive information - about render layer changes. - - Returns: - list: list of instances - - """ - objectset = cmds.ls("*.id", long=True, exactType="objectSet", - recursive=True, objectsOnly=True) - - instances = [] - for objset in objectset: - if not cmds.attributeQuery("id", node=objset, exists=True): - continue - - id_attr = "{}.id".format(objset) - if cmds.getAttr(id_attr) != "pyblish.avalon.instance": - continue - - has_family = cmds.attributeQuery("family", - node=objset, - exists=True) - if not has_family: - continue - - if cmds.getAttr( - "{}.family".format(objset)) in RENDERLIKE_INSTANCE_FAMILIES: - instances.append(objset) - - return instances - - -renderItemObserverList = [] - - -class RenderSetupListObserver: - """Observer to catch changes in render setup layers.""" - - def listItemAdded(self, item): - print("--- adding ...") - self._add_render_layer(item) - - def listItemRemoved(self, item): - print("--- removing ...") - self._remove_render_layer(item.name()) - - def _add_render_layer(self, item): - render_sets = _get_render_instances() - layer_name = item.name() - - for render_set in render_sets: - members = cmds.sets(render_set, query=True) or [] - - namespace_name = "_{}".format(render_set) - if not cmds.namespace(exists=namespace_name): - index = 1 - namespace_name = "_{}".format(render_set) - try: - cmds.namespace(rm=namespace_name) - except RuntimeError: - # namespace is not empty, so we leave it untouched - pass - orignal_namespace_name = namespace_name - while(cmds.namespace(exists=namespace_name)): - namespace_name = "{}{}".format( - orignal_namespace_name, index) - index += 1 - - namespace = cmds.namespace(add=namespace_name) - - if members: - # if set already have namespaced members, use the same - # namespace as others. - namespace = members[0].rpartition(":")[0] - else: - namespace = namespace_name - - render_layer_set_name = "{}:{}".format(namespace, layer_name) - if render_layer_set_name in members: - continue - print(" - creating set for {}".format(layer_name)) - maya_set = cmds.sets(n=render_layer_set_name, empty=True) - cmds.sets(maya_set, forceElement=render_set) - rio = RenderSetupItemObserver(item) - print("- adding observer for {}".format(item.name())) - item.addItemObserver(rio.itemChanged) - renderItemObserverList.append(rio) - - def _remove_render_layer(self, layer_name): - render_sets = _get_render_instances() - - for render_set in render_sets: - members = cmds.sets(render_set, query=True) - if not members: - continue - - # all sets under set should have the same namespace - namespace = members[0].rpartition(":")[0] - render_layer_set_name = "{}:{}".format(namespace, layer_name) - - if render_layer_set_name in members: - print(" - removing set for {}".format(layer_name)) - cmds.delete(render_layer_set_name) - - -class RenderSetupItemObserver: - """Handle changes in render setup items.""" - - def __init__(self, item): - self.item = item - self.original_name = item.name() - - def itemChanged(self, *args, **kwargs): - """Item changed callback.""" - if self.item.name() == self.original_name: - return - - render_sets = _get_render_instances() - - for render_set in render_sets: - members = cmds.sets(render_set, query=True) - if not members: - continue - - # all sets under set should have the same namespace - namespace = members[0].rpartition(":")[0] - render_layer_set_name = "{}:{}".format( - namespace, self.original_name) - - if render_layer_set_name in members: - print(" <> renaming {} to {}".format(self.original_name, - self.item.name())) - cmds.rename(render_layer_set_name, - "{}:{}".format( - namespace, self.item.name())) - self.original_name = self.item.name() - - -renderListObserver = RenderSetupListObserver() - - -def add_render_layer_change_observer(): - import maya.app.renderSetup.model.renderSetup as renderSetup - - rs = renderSetup.instance() - render_sets = _get_render_instances() - - layers = rs.getRenderLayers() - for render_set in render_sets: - members = cmds.sets(render_set, query=True) - if not members: - continue - # all sets under set should have the same namespace - namespace = members[0].rpartition(":")[0] - for layer in layers: - render_layer_set_name = "{}:{}".format(namespace, layer.name()) - if render_layer_set_name not in members: - continue - rio = RenderSetupItemObserver(layer) - print("- adding observer for {}".format(layer.name())) - layer.addItemObserver(rio.itemChanged) - renderItemObserverList.append(rio) - - -def add_render_layer_observer(): - import maya.app.renderSetup.model.renderSetup as renderSetup - - print("> adding renderSetup observer ...") - rs = renderSetup.instance() - rs.addListObserver(renderListObserver) - pass - - -def remove_render_layer_observer(): - import maya.app.renderSetup.model.renderSetup as renderSetup - - print("< removing renderSetup observer ...") - rs = renderSetup.instance() - try: - rs.removeListObserver(renderListObserver) - except ValueError: - # no observer set yet - pass - - def update_content_on_context_change(): """ This will update scene content to match new asset on context change diff --git a/openpype/hosts/maya/api/lib_rendersettings.py b/openpype/hosts/maya/api/lib_rendersettings.py index 8b57c2e481..1f964589a9 100644 --- a/openpype/hosts/maya/api/lib_rendersettings.py +++ b/openpype/hosts/maya/api/lib_rendersettings.py @@ -70,8 +70,8 @@ class RenderSettings(object): def set_default_renderer_settings(self, renderer=None): """Set basic settings based on renderer.""" # Not all hosts can import this module. - from maya import cmds - import maya.mel as mel + from maya import cmds # noqa: F401 + import maya.mel as mel # noqa: F401 if not renderer: renderer = cmds.getAttr( @@ -126,6 +126,10 @@ class RenderSettings(object): """Sets settings for Arnold.""" from mtoa.core import createOptions # noqa from mtoa.aovs import AOVInterface # noqa + # Not all hosts can import this module. + from maya import cmds # noqa: F401 + import maya.mel as mel # noqa: F401 + createOptions() render_settings = self._project_settings["maya"]["RenderSettings"] arnold_render_presets = render_settings["arnold_renderer"] # noqa @@ -172,6 +176,10 @@ class RenderSettings(object): def _set_redshift_settings(self, width, height): """Sets settings for Redshift.""" + # Not all hosts can import this module. + from maya import cmds # noqa: F401 + import maya.mel as mel # noqa: F401 + render_settings = self._project_settings["maya"]["RenderSettings"] redshift_render_presets = render_settings["redshift_renderer"] @@ -224,6 +232,10 @@ class RenderSettings(object): def _set_renderman_settings(self, width, height, aov_separator): """Sets settings for Renderman""" + # Not all hosts can import this module. + from maya import cmds # noqa: F401 + import maya.mel as mel # noqa: F401 + rman_render_presets = ( self._project_settings ["maya"] @@ -285,6 +297,11 @@ class RenderSettings(object): def _set_vray_settings(self, aov_separator, width, height): # type: (str, int, int) -> None """Sets important settings for Vray.""" + # Not all hosts can import this module. + from maya import cmds # noqa: F401 + import maya.mel as mel # noqa: F401 + + settings = cmds.ls(type="VRaySettingsNode") node = settings[0] if settings else cmds.createNode("VRaySettingsNode") render_settings = self._project_settings["maya"]["RenderSettings"] @@ -357,6 +374,10 @@ class RenderSettings(object): @staticmethod def _set_global_output_settings(): + # Not all hosts can import this module. + from maya import cmds # noqa: F401 + import maya.mel as mel # noqa: F401 + # enable animation cmds.setAttr("defaultRenderGlobals.outFormatControl", 0) cmds.setAttr("defaultRenderGlobals.animation", 1) @@ -364,6 +385,10 @@ class RenderSettings(object): cmds.setAttr("defaultRenderGlobals.extensionPadding", 4) def _additional_attribs_setter(self, additional_attribs): + # Not all hosts can import this module. + from maya import cmds # noqa: F401 + import maya.mel as mel # noqa: F401 + for item in additional_attribs: attribute, value = item attribute = str(attribute) # ensure str conversion from settings diff --git a/openpype/hosts/maya/api/pipeline.py b/openpype/hosts/maya/api/pipeline.py index 6b791c9665..1ecfdfaa40 100644 --- a/openpype/hosts/maya/api/pipeline.py +++ b/openpype/hosts/maya/api/pipeline.py @@ -580,20 +580,11 @@ def on_save(): lib.set_id(node, new_id, overwrite=False) -def _update_render_layer_observers(): - # Helper to trigger update for all renderlayer observer logic - lib.remove_render_layer_observer() - lib.add_render_layer_observer() - lib.add_render_layer_change_observer() - - def on_open(): """On scene open let's assume the containers have changed.""" from openpype.widgets import popup - utils.executeDeferred(_update_render_layer_observers) - # Validate FPS after update_task_from_path to # ensure it is using correct FPS for the asset lib.validate_fps() @@ -630,7 +621,6 @@ def on_new(): with lib.suspended_refresh(): lib.set_context_settings() - utils.executeDeferred(_update_render_layer_observers) _remove_workfile_lock() diff --git a/openpype/hosts/maya/api/plugin.py b/openpype/hosts/maya/api/plugin.py index 212c4df492..e684a91fe2 100644 --- a/openpype/hosts/maya/api/plugin.py +++ b/openpype/hosts/maya/api/plugin.py @@ -7,6 +7,7 @@ import six from maya import cmds from maya.app.renderSetup.model import renderSetup +from openpype import AYON_SERVER_ENABLED from openpype.lib import BoolDef, Logger from openpype.settings import get_project_settings from openpype.pipeline import ( @@ -449,14 +450,16 @@ class RenderlayerCreator(NewCreator, MayaCreatorBase): # this instance will not have the `instance_node` data yet # until it's been saved/persisted at least once. project_name = self.create_context.get_current_project_name() - + asset_name = self.create_context.get_current_asset_name() instance_data = { - "asset": self.create_context.get_current_asset_name(), "task": self.create_context.get_current_task_name(), "variant": layer.name(), } - asset_doc = get_asset_by_name(project_name, - instance_data["asset"]) + if AYON_SERVER_ENABLED: + instance_data["folderPath"] = asset_name + else: + instance_data["asset"] = asset_name + asset_doc = get_asset_by_name(project_name, asset_name) subset_name = self.get_subset_name( layer.name(), instance_data["task"], diff --git a/openpype/hosts/maya/plugins/create/create_multishot_layout.py b/openpype/hosts/maya/plugins/create/create_multishot_layout.py index 0b027c02ea..8f5c423202 100644 --- a/openpype/hosts/maya/plugins/create/create_multishot_layout.py +++ b/openpype/hosts/maya/plugins/create/create_multishot_layout.py @@ -45,10 +45,14 @@ class CreateMultishotLayout(plugin.MayaCreator): above is done. """ - current_folder = get_folder_by_name( - project_name=get_current_project_name(), - folder_name=get_current_asset_name(), - ) + project_name = get_current_project_name() + folder_path = get_current_asset_name() + if "/" in folder_path: + current_folder = get_folder_by_path(project_name, folder_path) + else: + current_folder = get_folder_by_name( + project_name, folder_name=folder_path + ) current_path_parts = current_folder["path"].split("/") @@ -154,7 +158,7 @@ class CreateMultishotLayout(plugin.MayaCreator): # Create layout instance by the layout creator instance_data = { - "asset": shot["name"], + "folderPath": shot["path"], "variant": layout_creator.get_default_variant() } if layout_task: diff --git a/openpype/hosts/maya/plugins/create/create_review.py b/openpype/hosts/maya/plugins/create/create_review.py index f60e2406bc..18d661b186 100644 --- a/openpype/hosts/maya/plugins/create/create_review.py +++ b/openpype/hosts/maya/plugins/create/create_review.py @@ -2,6 +2,7 @@ import json from maya import cmds +from openpype import AYON_SERVER_ENABLED from openpype.hosts.maya.api import ( lib, plugin @@ -43,7 +44,11 @@ class CreateReview(plugin.MayaCreator): members = cmds.ls(selection=True) project_name = self.project_name - asset_doc = get_asset_by_name(project_name, instance_data["asset"]) + if AYON_SERVER_ENABLED: + asset_name = instance_data["folderPath"] + else: + asset_name = instance_data["asset"] + asset_doc = get_asset_by_name(project_name, asset_name) task_name = instance_data["task"] preset = lib.get_capture_preset( task_name, diff --git a/openpype/hosts/maya/plugins/create/create_unreal_skeletalmesh.py b/openpype/hosts/maya/plugins/create/create_unreal_skeletalmesh.py index 3c9a79156a..b4151bac99 100644 --- a/openpype/hosts/maya/plugins/create/create_unreal_skeletalmesh.py +++ b/openpype/hosts/maya/plugins/create/create_unreal_skeletalmesh.py @@ -51,7 +51,7 @@ class CreateUnrealSkeletalMesh(plugin.MayaCreator): # We reorganize the geometry that was originally added into the # set into either 'joints_SET' or 'geometry_SET' based on the # joint_hints from project settings - members = cmds.sets(instance_node, query=True) + members = cmds.sets(instance_node, query=True) or [] cmds.sets(clear=instance_node) geometry_set = cmds.sets(name="geometry_SET", empty=True) diff --git a/openpype/hosts/maya/plugins/create/create_workfile.py b/openpype/hosts/maya/plugins/create/create_workfile.py index d84753cd7f..198f9c4a36 100644 --- a/openpype/hosts/maya/plugins/create/create_workfile.py +++ b/openpype/hosts/maya/plugins/create/create_workfile.py @@ -1,7 +1,8 @@ # -*- coding: utf-8 -*- """Creator plugin for creating workfiles.""" +from openpype import AYON_SERVER_ENABLED from openpype.pipeline import CreatedInstance, AutoCreator -from openpype.client import get_asset_by_name +from openpype.client import get_asset_by_name, get_asset_name_identifier from openpype.hosts.maya.api import plugin from maya import cmds @@ -29,16 +30,27 @@ class CreateWorkfile(plugin.MayaCreatorBase, AutoCreator): task_name = self.create_context.get_current_task_name() host_name = self.create_context.host_name + if current_instance is None: + current_instance_asset = None + elif AYON_SERVER_ENABLED: + current_instance_asset = current_instance["folderPath"] + else: + current_instance_asset = current_instance["asset"] + if current_instance is None: asset_doc = get_asset_by_name(project_name, asset_name) subset_name = self.get_subset_name( variant, task_name, asset_doc, project_name, host_name ) data = { - "asset": asset_name, "task": task_name, "variant": variant } + if AYON_SERVER_ENABLED: + data["folderPath"] = asset_name + else: + data["asset"] = asset_name + data.update( self.get_dynamic_data( variant, task_name, asset_doc, @@ -50,15 +62,20 @@ class CreateWorkfile(plugin.MayaCreatorBase, AutoCreator): ) self._add_instance_to_context(current_instance) elif ( - current_instance["asset"] != asset_name - or current_instance["task"] != task_name + current_instance_asset != asset_name + or current_instance["task"] != task_name ): # Update instance context if is not the same asset_doc = get_asset_by_name(project_name, asset_name) subset_name = self.get_subset_name( variant, task_name, asset_doc, project_name, host_name ) - current_instance["asset"] = asset_name + asset_name = get_asset_name_identifier(asset_doc) + + if AYON_SERVER_ENABLED: + current_instance["folderPath"] = asset_name + else: + current_instance["asset"] = asset_name current_instance["task"] = task_name current_instance["subset"] = subset_name diff --git a/openpype/hosts/maya/plugins/inventory/import_modelrender.py b/openpype/hosts/maya/plugins/inventory/import_modelrender.py index 4db8c4f2f6..3b30695146 100644 --- a/openpype/hosts/maya/plugins/inventory/import_modelrender.py +++ b/openpype/hosts/maya/plugins/inventory/import_modelrender.py @@ -33,7 +33,7 @@ class ImportModelRender(InventoryAction): ) def process(self, containers): - from maya import cmds + from maya import cmds # noqa: F401 project_name = get_current_project_name() for container in containers: @@ -66,7 +66,7 @@ class ImportModelRender(InventoryAction): None """ - from maya import cmds + from maya import cmds # noqa: F401 project_name = get_current_project_name() repre_docs = get_representations( @@ -85,12 +85,7 @@ class ImportModelRender(InventoryAction): if scene_type_regex.fullmatch(repre_name): look_repres.append(repre_doc) - # QUESTION should we care if there is more then one look - # representation? (since it's based on regex match) - look_repre = None - if look_repres: - look_repre = look_repres[0] - + look_repre = look_repres[0] if look_repres else None # QUESTION shouldn't be json representation validated too? if not look_repre: print("No model render sets for this model version..") diff --git a/openpype/hosts/maya/plugins/load/load_image.py b/openpype/hosts/maya/plugins/load/load_image.py index 3b1f5442ce..27c9ec7118 100644 --- a/openpype/hosts/maya/plugins/load/load_image.py +++ b/openpype/hosts/maya/plugins/load/load_image.py @@ -9,7 +9,7 @@ from openpype.pipeline import ( ) from openpype.pipeline.load.utils import get_representation_path_from_context from openpype.pipeline.colorspace import ( - get_imageio_colorspace_from_filepath, + get_imageio_file_rules_colorspace_from_filepath, get_imageio_config, get_imageio_file_rules ) @@ -285,10 +285,10 @@ class FileNodeLoader(load.LoaderPlugin): ) path = get_representation_path_from_context(context) - colorspace = get_imageio_colorspace_from_filepath( - path=path, - host_name=host_name, - project_name=project_name, + colorspace = get_imageio_file_rules_colorspace_from_filepath( + path, + host_name, + project_name, config_data=config_data, file_rules=file_rules, project_settings=project_settings diff --git a/openpype/hosts/maya/plugins/load/load_reference.py b/openpype/hosts/maya/plugins/load/load_reference.py index 0d7f08d3c3..a4ab6c79c1 100644 --- a/openpype/hosts/maya/plugins/load/load_reference.py +++ b/openpype/hosts/maya/plugins/load/load_reference.py @@ -265,6 +265,7 @@ class ReferenceLoader(openpype.hosts.maya.api.plugin.ReferenceLoader): class MayaUSDReferenceLoader(ReferenceLoader): """Reference USD file to native Maya nodes using MayaUSDImport reference""" + label = "Reference Maya USD" families = ["usd"] representations = ["usd"] extensions = {"usd", "usda", "usdc"} diff --git a/openpype/hosts/maya/plugins/publish/collect_look.py b/openpype/hosts/maya/plugins/publish/collect_look.py index db042963c6..72682f7800 100644 --- a/openpype/hosts/maya/plugins/publish/collect_look.py +++ b/openpype/hosts/maya/plugins/publish/collect_look.py @@ -45,11 +45,23 @@ FILE_NODES = { "PxrTexture": "filename" } +RENDER_SET_TYPES = [ + "VRayDisplacement", + "VRayLightMesh", + "VRayObjectProperties", + "RedshiftObjectId", + "RedshiftMeshParameters", +] + # Keep only node types that actually exist all_node_types = set(cmds.allNodeTypes()) for node_type in list(FILE_NODES.keys()): if node_type not in all_node_types: FILE_NODES.pop(node_type) + +for node_type in RENDER_SET_TYPES: + if node_type not in all_node_types: + RENDER_SET_TYPES.remove(node_type) del all_node_types # Cache pixar dependency node types so we can perform a type lookup against it @@ -69,9 +81,7 @@ def get_attributes(dictionary, attr, node=None): else: val = dictionary.get(attr, []) - if not isinstance(val, list): - return [val] - return val + return val if isinstance(val, list) else [val] def get_look_attrs(node): @@ -106,7 +116,7 @@ def get_look_attrs(node): def node_uses_image_sequence(node, node_path): - # type: (str) -> bool + # type: (str, str) -> bool """Return whether file node uses an image sequence or single image. Determine if a node uses an image sequence or just a single image, @@ -114,6 +124,7 @@ def node_uses_image_sequence(node, node_path): Args: node (str): Name of the Maya node + node_path (str): The file path of the node Returns: bool: True if node uses an image sequence @@ -247,7 +258,7 @@ def get_file_node_files(node): # For sequences get all files and filter to only existing files result = [] - for index, path in enumerate(paths): + for path in paths: if node_uses_image_sequence(node, path): glob_pattern = seq_to_glob(path) result.extend(glob.glob(glob_pattern)) @@ -358,6 +369,7 @@ class CollectLook(pyblish.api.InstancePlugin): for attr in shader_attrs: if cmds.attributeQuery(attr, node=look, exists=True): existing_attrs.append("{}.{}".format(look, attr)) + materials = cmds.listConnections(existing_attrs, source=True, destination=False) or [] @@ -367,30 +379,32 @@ class CollectLook(pyblish.api.InstancePlugin): self.log.debug("Found the following sets:\n{}".format(look_sets)) # Get the entire node chain of the look sets # history = cmds.listHistory(look_sets, allConnections=True) - history = cmds.listHistory(materials, allConnections=True) + # if materials list is empty, listHistory() will crash with + # RuntimeError + history = set() + if materials: + history = set( + cmds.listHistory(materials, allConnections=True)) # Since we retrieved history only of the connected materials # connected to the look sets above we now add direct history # for some of the look sets directly # handling render attribute sets - render_set_types = [ - "VRayDisplacement", - "VRayLightMesh", - "VRayObjectProperties", - "RedshiftObjectId", - "RedshiftMeshParameters", - ] - render_sets = cmds.ls(look_sets, type=render_set_types) - if render_sets: - history.extend( - cmds.listHistory(render_sets, - future=False, - pruneDagObjects=True) - or [] - ) + + # Maya (at least 2024) crashes with Warning when render set type + # isn't available. cmds.ls() will return empty list + if RENDER_SET_TYPES: + render_sets = cmds.ls(look_sets, type=RENDER_SET_TYPES) + if render_sets: + history.update( + cmds.listHistory(render_sets, + future=False, + pruneDagObjects=True) + or [] + ) # Ensure unique entries only - history = list(set(history)) + history = list(history) files = cmds.ls(history, # It's important only node types are passed that diff --git a/openpype/hosts/maya/plugins/publish/collect_review.py b/openpype/hosts/maya/plugins/publish/collect_review.py index 586939a3b8..0930da8f27 100644 --- a/openpype/hosts/maya/plugins/publish/collect_review.py +++ b/openpype/hosts/maya/plugins/publish/collect_review.py @@ -3,7 +3,7 @@ from maya import cmds, mel import pyblish.api from openpype.client import get_subset_by_name -from openpype.pipeline import legacy_io, KnownPublishError +from openpype.pipeline import KnownPublishError from openpype.hosts.maya.api import lib @@ -116,10 +116,10 @@ class CollectReview(pyblish.api.InstancePlugin): instance.data['remove'] = True else: - task = legacy_io.Session["AVALON_TASK"] - legacy_subset_name = task + 'Review' + project_name = instance.context.data["projectName"] asset_doc = instance.context.data['assetEntity'] - project_name = legacy_io.active_project() + task = instance.context.data["task"] + legacy_subset_name = task + 'Review' subset_doc = get_subset_by_name( project_name, legacy_subset_name, diff --git a/openpype/hosts/maya/plugins/publish/extract_redshift_proxy.py b/openpype/hosts/maya/plugins/publish/extract_redshift_proxy.py index 3868270b79..7fc8760a70 100644 --- a/openpype/hosts/maya/plugins/publish/extract_redshift_proxy.py +++ b/openpype/hosts/maya/plugins/publish/extract_redshift_proxy.py @@ -50,11 +50,11 @@ class ExtractRedshiftProxy(publish.Extractor): # Padding is taken from number of digits of the end_frame. # Not sure where Redshift is taking it. repr_files = [ - "{}.{}{}".format(root, str(frame).rjust(4, "0"), ext) # noqa: E501 + "{}.{}{}".format(os.path.basename(root), str(frame).rjust(4, "0"), ext) # noqa: E501 for frame in range( int(start_frame), int(end_frame) + 1, - int(instance.data["step"]), + int(instance.data["step"]) )] # vertex_colors = instance.data.get("vertexColors", False) diff --git a/openpype/hosts/maya/plugins/publish/extract_unreal_skeletalmesh_abc.py b/openpype/hosts/maya/plugins/publish/extract_unreal_skeletalmesh_abc.py index af82c24683..70d39d9709 100644 --- a/openpype/hosts/maya/plugins/publish/extract_unreal_skeletalmesh_abc.py +++ b/openpype/hosts/maya/plugins/publish/extract_unreal_skeletalmesh_abc.py @@ -13,16 +13,6 @@ from openpype.hosts.maya.api.lib import ( ) -@contextmanager -def renamed(original_name, renamed_name): - # type: (str, str) -> None - try: - cmds.rename(original_name, renamed_name) - yield - finally: - cmds.rename(renamed_name, original_name) - - class ExtractUnrealSkeletalMeshAbc(publish.Extractor): """Extract Unreal Skeletal Mesh as FBX from Maya. """ diff --git a/openpype/hosts/maya/plugins/publish/extract_unreal_skeletalmesh_fbx.py b/openpype/hosts/maya/plugins/publish/extract_unreal_skeletalmesh_fbx.py index 96175a07d7..4b36134694 100644 --- a/openpype/hosts/maya/plugins/publish/extract_unreal_skeletalmesh_fbx.py +++ b/openpype/hosts/maya/plugins/publish/extract_unreal_skeletalmesh_fbx.py @@ -62,6 +62,10 @@ class ExtractUnrealSkeletalMeshFbx(publish.Extractor): original_parent = to_extract[0].split("|")[1] parent_node = instance.data.get("asset") + # this needs to be done for AYON + # WARNING: since AYON supports duplicity of asset names, + # this needs to be refactored throughout the pipeline. + parent_node = parent_node.split("/")[-1] renamed_to_extract = [] for node in to_extract: diff --git a/openpype/hosts/maya/plugins/publish/validate_instance_in_context.py b/openpype/hosts/maya/plugins/publish/validate_instance_in_context.py index 4ded57137c..4222e63898 100644 --- a/openpype/hosts/maya/plugins/publish/validate_instance_in_context.py +++ b/openpype/hosts/maya/plugins/publish/validate_instance_in_context.py @@ -3,6 +3,7 @@ from __future__ import absolute_import import pyblish.api +from openpype import AYON_SERVER_ENABLED import openpype.hosts.maya.api.action from openpype.pipeline.publish import ( RepairAction, @@ -66,12 +67,16 @@ class ValidateInstanceInContext(pyblish.api.InstancePlugin, def repair(cls, instance): context_asset = cls.get_context_asset(instance) instance_node = instance.data["instance_node"] + if AYON_SERVER_ENABLED: + asset_name_attr = "folderPath" + else: + asset_name_attr = "asset" cmds.setAttr( - "{}.asset".format(instance_node), + "{}.{}".format(instance_node, asset_name_attr), context_asset, type="string" ) @staticmethod def get_context_asset(instance): - return instance.context.data["assetEntity"]["name"] + return instance.context.data["asset"] diff --git a/openpype/hosts/maya/plugins/publish/validate_look_default_shaders_connections.py b/openpype/hosts/maya/plugins/publish/validate_look_default_shaders_connections.py index 0109f6ebd5..c3edf5f1c3 100644 --- a/openpype/hosts/maya/plugins/publish/validate_look_default_shaders_connections.py +++ b/openpype/hosts/maya/plugins/publish/validate_look_default_shaders_connections.py @@ -3,60 +3,76 @@ from maya import cmds import pyblish.api from openpype.pipeline.publish import ( ValidateContentsOrder, + RepairContextAction, PublishValidationError ) -class ValidateLookDefaultShadersConnections(pyblish.api.InstancePlugin): +class ValidateLookDefaultShadersConnections(pyblish.api.ContextPlugin): """Validate default shaders in the scene have their default connections. - For example the lambert1 could potentially be disconnected from the - initialShadingGroup. As such it's not lambert1 that will be identified - as the default shader which can have unpredictable results. + For example the standardSurface1 or lambert1 (maya 2023 and before) could + potentially be disconnected from the initialShadingGroup. As such it's not + lambert1 that will be identified as the default shader which can have + unpredictable results. To fix the default connections need to be made again. See the logs for more details on which connections are missing. """ - order = ValidateContentsOrder + order = pyblish.api.ValidatorOrder - 0.4999 families = ['look'] hosts = ['maya'] label = 'Look Default Shader Connections' + actions = [RepairContextAction] # The default connections to check - DEFAULTS = [("initialShadingGroup.surfaceShader", "lambert1"), - ("initialParticleSE.surfaceShader", "lambert1"), - ("initialParticleSE.volumeShader", "particleCloud1") - ] + DEFAULTS = { + "initialShadingGroup.surfaceShader": ["standardSurface1.outColor", + "lambert1.outColor"], + "initialParticleSE.surfaceShader": ["standardSurface1.outColor", + "lambert1.outColor"], + "initialParticleSE.volumeShader": ["particleCloud1.outColor"] + } - def process(self, instance): + def process(self, context): - # Ensure check is run only once. We don't use ContextPlugin because - # of a bug where the ContextPlugin will always be visible. Even when - # the family is not present in an instance. - key = "__validate_look_default_shaders_connections_checked" - context = instance.context - is_run = context.data.get(key, False) - if is_run: - return - else: - context.data[key] = True + if self.get_invalid(): + raise PublishValidationError( + "Default shaders in your scene do not have their " + "default shader connections. Please repair them to continue." + ) + + @classmethod + def get_invalid(cls): # Process as usual invalid = list() - for plug, input_node in self.DEFAULTS: + for plug, valid_inputs in cls.DEFAULTS.items(): inputs = cmds.listConnections(plug, source=True, - destination=False) or None - - if not inputs or inputs[0] != input_node: - self.log.error("{0} is not connected to {1}. " - "This can result in unexpected behavior. " - "Please reconnect to continue.".format( - plug, - input_node)) + destination=False, + plugs=True) or None + if not inputs or inputs[0] not in valid_inputs: + cls.log.error( + "{0} is not connected to {1}. This can result in " + "unexpected behavior. Please reconnect to continue." + "".format(plug, " or ".join(valid_inputs)) + ) invalid.append(plug) - if invalid: - raise PublishValidationError("Invalid connections.") + return invalid + + @classmethod + def repair(cls, context): + invalid = cls.get_invalid() + for plug in invalid: + valid_inputs = cls.DEFAULTS[plug] + for valid_input in valid_inputs: + if cmds.objExists(valid_input): + cls.log.info( + "Connecting {} -> {}".format(valid_input, plug) + ) + cmds.connectAttr(valid_input, plug, force=True) + break diff --git a/openpype/hosts/maya/plugins/publish/validate_model_name.py b/openpype/hosts/maya/plugins/publish/validate_model_name.py index f4c1aa39c7..11f59bb439 100644 --- a/openpype/hosts/maya/plugins/publish/validate_model_name.py +++ b/openpype/hosts/maya/plugins/publish/validate_model_name.py @@ -67,13 +67,15 @@ class ValidateModelName(pyblish.api.InstancePlugin, regex = cls.top_level_regex r = re.compile(regex) m = r.match(top_group) + project_name = instance.context.data["projectName"] + current_asset_name = instance.context.data["asset"] if m is None: cls.log.error("invalid name on: {}".format(top_group)) cls.log.error("name doesn't match regex {}".format(regex)) invalid.append(top_group) else: if "asset" in r.groupindex: - if m.group("asset") != legacy_io.Session["AVALON_ASSET"]: + if m.group("asset") != current_asset_name: cls.log.error("Invalid asset name in top level group.") return top_group if "subset" in r.groupindex: @@ -81,7 +83,7 @@ class ValidateModelName(pyblish.api.InstancePlugin, cls.log.error("Invalid subset name in top level group.") return top_group if "project" in r.groupindex: - if m.group("project") != legacy_io.Session["AVALON_PROJECT"]: + if m.group("project") != project_name: cls.log.error("Invalid project name in top level group.") return top_group diff --git a/openpype/hosts/maya/plugins/publish/validate_rendersettings.py b/openpype/hosts/maya/plugins/publish/validate_rendersettings.py index 3409b4ec91..f2a98eab32 100644 --- a/openpype/hosts/maya/plugins/publish/validate_rendersettings.py +++ b/openpype/hosts/maya/plugins/publish/validate_rendersettings.py @@ -371,7 +371,6 @@ class ValidateRenderSettings(pyblish.api.InstancePlugin): continue for node in data["nodes"]: lib.set_attribute(data["attribute"], data["values"][0], node) - with lib.renderlayer(layer_node): # Repair animation must be enabled @@ -392,13 +391,11 @@ class ValidateRenderSettings(pyblish.api.InstancePlugin): if renderer != "renderman": prefix_attr = RenderSettings.get_image_prefix_attr(renderer) fname_prefix = default_prefix - cmds.setAttr("{}.{}".format(node, prefix_attr), - fname_prefix, type="string") + cmds.setAttr(prefix_attr, fname_prefix, type="string") # Repair padding padding_attr = RenderSettings.get_padding_attr(renderer) - cmds.setAttr("{}.{}".format(node, padding_attr), - cls.DEFAULT_PADDING) + cmds.setAttr(padding_attr, cls.DEFAULT_PADDING) else: # renderman handles stuff differently cmds.setAttr("rmanGlobals.imageFileFormat", diff --git a/openpype/hosts/maya/plugins/publish/validate_shader_name.py b/openpype/hosts/maya/plugins/publish/validate_shader_name.py index 36bb2c1fee..d6486dea7f 100644 --- a/openpype/hosts/maya/plugins/publish/validate_shader_name.py +++ b/openpype/hosts/maya/plugins/publish/validate_shader_name.py @@ -51,7 +51,7 @@ class ValidateShaderName(pyblish.api.InstancePlugin, descendants = cmds.ls(descendants, noIntermediate=True, long=True) shapes = cmds.ls(descendants, type=["nurbsSurface", "mesh"], long=True) - asset_name = instance.data.get("asset", None) + asset_name = instance.data.get("asset") # Check the number of connected shadingEngines per shape regex_compile = re.compile(cls.regex) diff --git a/openpype/hosts/maya/plugins/publish/validate_unreal_staticmesh_naming.py b/openpype/hosts/maya/plugins/publish/validate_unreal_staticmesh_naming.py index 58fa9d02bd..42d3dc3ac8 100644 --- a/openpype/hosts/maya/plugins/publish/validate_unreal_staticmesh_naming.py +++ b/openpype/hosts/maya/plugins/publish/validate_unreal_staticmesh_naming.py @@ -102,7 +102,8 @@ class ValidateUnrealStaticMeshName(pyblish.api.InstancePlugin, cl_r = re.compile(regex_collision) - mesh_name = "{}{}".format(instance.data["asset"], + asset_name = instance.data["assetEntity"]["name"] + mesh_name = "{}{}".format(asset_name, instance.data.get("variant", [])) for obj in collision_set: diff --git a/openpype/hosts/maya/tools/mayalookassigner/commands.py b/openpype/hosts/maya/tools/mayalookassigner/commands.py index 5cc4f84931..86df502ecd 100644 --- a/openpype/hosts/maya/tools/mayalookassigner/commands.py +++ b/openpype/hosts/maya/tools/mayalookassigner/commands.py @@ -4,7 +4,7 @@ from collections import defaultdict import maya.cmds as cmds -from openpype.client import get_assets +from openpype.client import get_assets, get_asset_name_identifier from openpype.pipeline import ( remove_container, registered_host, @@ -128,7 +128,8 @@ def create_items_from_nodes(nodes): project_name = get_current_project_name() asset_ids = set(id_hashes.keys()) - asset_docs = get_assets(project_name, asset_ids, fields=["name"]) + fields = {"_id", "name", "data.parents"} + asset_docs = get_assets(project_name, asset_ids, fields=fields) asset_docs_by_id = { str(asset_doc["_id"]): asset_doc for asset_doc in asset_docs @@ -156,8 +157,9 @@ def create_items_from_nodes(nodes): namespace = get_namespace_from_node(node) namespaces.add(namespace) + label = get_asset_name_identifier(asset_doc) asset_view_items.append({ - "label": asset_doc["name"], + "label": label, "asset": asset_doc, "looks": looks, "namespaces": namespaces diff --git a/openpype/hosts/maya/tools/mayalookassigner/widgets.py b/openpype/hosts/maya/tools/mayalookassigner/widgets.py index 82c37e2104..ef29a4c726 100644 --- a/openpype/hosts/maya/tools/mayalookassigner/widgets.py +++ b/openpype/hosts/maya/tools/mayalookassigner/widgets.py @@ -3,6 +3,7 @@ from collections import defaultdict from qtpy import QtWidgets, QtCore +from openpype.client import get_asset_name_identifier from openpype.tools.utils.models import TreeModel from openpype.tools.utils.lib import ( preserve_expanded_rows, @@ -126,7 +127,7 @@ class AssetOutliner(QtWidgets.QWidget): asset_namespaces = defaultdict(set) for item in items: asset_id = str(item["asset"]["_id"]) - asset_name = item["asset"]["name"] + asset_name = get_asset_name_identifier(item["asset"]) asset_namespaces[asset_name].add(item.get("namespace")) if asset_name in assets: diff --git a/openpype/hosts/nuke/api/lib.py b/openpype/hosts/nuke/api/lib.py index de5d13d347..88c587faf6 100644 --- a/openpype/hosts/nuke/api/lib.py +++ b/openpype/hosts/nuke/api/lib.py @@ -13,6 +13,7 @@ from collections import OrderedDict import nuke from qtpy import QtCore, QtWidgets +from openpype import AYON_SERVER_ENABLED from openpype.client import ( get_project, get_asset_by_name, @@ -1107,7 +1108,9 @@ def format_anatomy(data): Return: path (str) ''' - anatomy = Anatomy() + + project_name = get_current_project_name() + anatomy = Anatomy(project_name) log.debug("__ anatomy.templates: {}".format(anatomy.templates)) padding = None @@ -1125,8 +1128,10 @@ def format_anatomy(data): file = script_name() data["version"] = get_version_from_path(file) - project_name = anatomy.project_name - asset_name = data["asset"] + if AYON_SERVER_ENABLED: + asset_name = data["folderPath"] + else: + asset_name = data["asset"] task_name = data["task"] host_name = get_current_host_name() context_data = get_template_data_with_names( diff --git a/openpype/hosts/nuke/api/plugin.py b/openpype/hosts/nuke/api/plugin.py index 301b9533a9..15d7bfc4b9 100644 --- a/openpype/hosts/nuke/api/plugin.py +++ b/openpype/hosts/nuke/api/plugin.py @@ -21,6 +21,11 @@ from openpype.pipeline import ( CreatedInstance, get_current_task_name ) +from openpype.pipeline.colorspace import ( + get_display_view_colorspace_name, + get_colorspace_settings_from_publish_context, + set_colorspace_data_to_representation +) from openpype.lib.transcoding import ( VIDEO_EXTENSIONS ) @@ -612,7 +617,7 @@ class ExporterReview(object): def get_representation_data( self, tags=None, range=False, - custom_tags=None + custom_tags=None, colorspace=None ): """ Add representation data to self.data @@ -652,6 +657,14 @@ class ExporterReview(object): if self.publish_on_farm: repre["tags"].append("publish_on_farm") + # add colorspace data to representation + if colorspace: + set_colorspace_data_to_representation( + repre, + self.instance.context.data, + colorspace=colorspace, + log=self.log + ) self.data["representations"].append(repre) def get_imageio_baking_profile(self): @@ -866,6 +879,13 @@ class ExporterReviewMov(ExporterReview): return path def generate_mov(self, farm=False, **kwargs): + # colorspace data + colorspace = None + # get colorspace settings + # get colorspace data from context + config_data, _ = get_colorspace_settings_from_publish_context( + self.instance.context.data) + add_tags = [] self.publish_on_farm = farm read_raw = kwargs["read_raw"] @@ -951,6 +971,14 @@ class ExporterReviewMov(ExporterReview): # assign viewer dag_node["view"].setValue(viewer) + if config_data: + # convert display and view to colorspace + colorspace = get_display_view_colorspace_name( + config_path=config_data["path"], + display=display, + view=viewer + ) + self._connect_to_above_nodes(dag_node, subset, "OCIODisplay... `{}`") # Write node write_node = nuke.createNode("Write") @@ -996,9 +1024,10 @@ class ExporterReviewMov(ExporterReview): # ---------- generate representation data self.get_representation_data( - tags=["review", "delete"] + add_tags, + tags=["review", "need_thumbnail", "delete"] + add_tags, custom_tags=add_custom_tags, - range=True + range=True, + colorspace=colorspace ) self.log.debug("Representation... `{}`".format(self.data)) diff --git a/openpype/hosts/nuke/plugins/publish/extract_slate_frame.py b/openpype/hosts/nuke/plugins/publish/extract_slate_frame.py index 7befb7b7f3..5816434f2b 100644 --- a/openpype/hosts/nuke/plugins/publish/extract_slate_frame.py +++ b/openpype/hosts/nuke/plugins/publish/extract_slate_frame.py @@ -276,7 +276,7 @@ class ExtractSlateFrame(publish.Extractor): if not matching_repre: self.log.info( - "Matching reresentation was not found." + "Matching representation was not found." " Representation files were not filled with slate." ) return @@ -294,7 +294,7 @@ class ExtractSlateFrame(publish.Extractor): self.log.debug( "__ matching_repre: {}".format(pformat(matching_repre))) - self.log.warning("Added slate frame to representation files") + self.log.info("Added slate frame to representation files") def add_comment_slate_node(self, instance, node): diff --git a/openpype/hosts/nuke/plugins/publish/extract_thumbnail.py b/openpype/hosts/nuke/plugins/publish/extract_thumbnail.py deleted file mode 100644 index de7567c1b1..0000000000 --- a/openpype/hosts/nuke/plugins/publish/extract_thumbnail.py +++ /dev/null @@ -1,216 +0,0 @@ -import sys -import os -import nuke -import pyblish.api - -from openpype.pipeline import publish -from openpype.hosts.nuke import api as napi -from openpype.hosts.nuke.api.lib import set_node_knobs_from_settings - - -# Python 2/3 compatibility -if sys.version_info[0] >= 3: - unicode = str - - -class ExtractThumbnail(publish.Extractor): - """Extracts movie and thumbnail with baked in luts - - must be run after extract_render_local.py - - """ - - order = pyblish.api.ExtractorOrder + 0.011 - label = "Extract Thumbnail" - - families = ["review"] - hosts = ["nuke"] - - # settings - use_rendered = False - bake_viewer_process = True - bake_viewer_input_process = True - nodes = {} - reposition_nodes = None - - def process(self, instance): - if instance.data.get("farm"): - return - - with napi.maintained_selection(): - self.log.debug("instance: {}".format(instance)) - self.log.debug("instance.data[families]: {}".format( - instance.data["families"])) - - if instance.data.get("bakePresets"): - for o_name, o_data in instance.data["bakePresets"].items(): - self.render_thumbnail(instance, o_name, **o_data) - else: - viewer_process_switches = { - "bake_viewer_process": True, - "bake_viewer_input_process": True - } - self.render_thumbnail( - instance, None, **viewer_process_switches) - - def render_thumbnail(self, instance, output_name=None, **kwargs): - first_frame = instance.data["frameStartHandle"] - last_frame = instance.data["frameEndHandle"] - colorspace = instance.data["colorspace"] - - # find frame range and define middle thumb frame - mid_frame = int((last_frame - first_frame) / 2) - - # solve output name if any is set - output_name = output_name or "" - - bake_viewer_process = kwargs["bake_viewer_process"] - bake_viewer_input_process_node = kwargs[ - "bake_viewer_input_process"] - - node = instance.data["transientData"]["node"] # group node - self.log.debug("Creating staging dir...") - - if "representations" not in instance.data: - instance.data["representations"] = [] - - staging_dir = os.path.normpath( - os.path.dirname(instance.data['path'])) - - instance.data["stagingDir"] = staging_dir - - self.log.debug( - "StagingDir `{0}`...".format(instance.data["stagingDir"])) - - temporary_nodes = [] - - # try to connect already rendered images - previous_node = node - collection = instance.data.get("collection", None) - self.log.debug("__ collection: `{}`".format(collection)) - - if collection: - # get path - fhead = collection.format("{head}") - - thumb_fname = list(collection)[mid_frame] - else: - fname = thumb_fname = os.path.basename( - instance.data.get("path", None)) - fhead = os.path.splitext(fname)[0] + "." - - self.log.debug("__ fhead: `{}`".format(fhead)) - - if "#" in fhead: - fhead = fhead.replace("#", "")[:-1] - - path_render = os.path.join( - staging_dir, thumb_fname).replace("\\", "/") - self.log.debug("__ path_render: `{}`".format(path_render)) - - if self.use_rendered and os.path.isfile(path_render): - # check if file exist otherwise connect to write node - rnode = nuke.createNode("Read") - rnode["file"].setValue(path_render) - rnode["colorspace"].setValue(colorspace) - - # turn it raw if none of baking is ON - if all([ - not self.bake_viewer_input_process, - not self.bake_viewer_process - ]): - rnode["raw"].setValue(True) - - temporary_nodes.append(rnode) - previous_node = rnode - - if self.reposition_nodes is None: - # [deprecated] create reformat node old way - reformat_node = nuke.createNode("Reformat") - ref_node = self.nodes.get("Reformat", None) - if ref_node: - for k, v in ref_node: - self.log.debug("k, v: {0}:{1}".format(k, v)) - if isinstance(v, unicode): - v = str(v) - reformat_node[k].setValue(v) - - reformat_node.setInput(0, previous_node) - previous_node = reformat_node - temporary_nodes.append(reformat_node) - else: - # create reformat node new way - for repo_node in self.reposition_nodes: - node_class = repo_node["node_class"] - knobs = repo_node["knobs"] - node = nuke.createNode(node_class) - set_node_knobs_from_settings(node, knobs) - - # connect in order - node.setInput(0, previous_node) - previous_node = node - temporary_nodes.append(node) - - # only create colorspace baking if toggled on - if bake_viewer_process: - if bake_viewer_input_process_node: - # get input process and connect it to baking - ipn = napi.get_view_process_node() - if ipn is not None: - ipn.setInput(0, previous_node) - previous_node = ipn - temporary_nodes.append(ipn) - - dag_node = nuke.createNode("OCIODisplay") - dag_node.setInput(0, previous_node) - previous_node = dag_node - temporary_nodes.append(dag_node) - - thumb_name = "thumbnail" - # only add output name and - # if there are more than one bake preset - if ( - output_name - and len(instance.data.get("bakePresets", {}).keys()) > 1 - ): - thumb_name = "{}_{}".format(output_name, thumb_name) - - # create write node - write_node = nuke.createNode("Write") - file = fhead[:-1] + thumb_name + ".jpg" - thumb_path = os.path.join(staging_dir, file).replace("\\", "/") - - # add thumbnail to cleanup - instance.context.data["cleanupFullPaths"].append(thumb_path) - - # make sure only one thumbnail path is set - # and it is existing file - instance_thumb_path = instance.data.get("thumbnailPath") - if not instance_thumb_path or not os.path.isfile(instance_thumb_path): - instance.data["thumbnailPath"] = thumb_path - - write_node["file"].setValue(thumb_path) - write_node["file_type"].setValue("jpg") - write_node["raw"].setValue(1) - write_node.setInput(0, previous_node) - temporary_nodes.append(write_node) - - repre = { - 'name': thumb_name, - 'ext': "jpg", - "outputName": thumb_name, - 'files': file, - "stagingDir": staging_dir, - "tags": ["thumbnail", "publish_on_farm", "delete"] - } - instance.data["representations"].append(repre) - - # Render frames - nuke.execute(write_node.name(), mid_frame, mid_frame) - - self.log.debug( - "representations: {}".format(instance.data["representations"])) - - # Clean up - for node in temporary_nodes: - nuke.delete(node) diff --git a/openpype/hosts/nuke/plugins/publish/validate_write_nodes.py b/openpype/hosts/nuke/plugins/publish/validate_write_nodes.py index 9c8bfae388..0539c1188f 100644 --- a/openpype/hosts/nuke/plugins/publish/validate_write_nodes.py +++ b/openpype/hosts/nuke/plugins/publish/validate_write_nodes.py @@ -111,7 +111,6 @@ class ValidateNukeWriteNode( for value in values: if type(node_value) in (int, float): try: - if isinstance(value, list): value = color_gui_to_int(value) else: @@ -130,7 +129,7 @@ class ValidateNukeWriteNode( and key != "file" and key != "tile_color" ): - check.append([key, value, write_node[key].value()]) + check.append([key, node_value, write_node[key].value()]) if check: self._make_error(check) diff --git a/openpype/hosts/photoshop/lib.py b/openpype/hosts/photoshop/lib.py index 9f603a70d2..5c8dff947d 100644 --- a/openpype/hosts/photoshop/lib.py +++ b/openpype/hosts/photoshop/lib.py @@ -1,5 +1,6 @@ import re +from openpype import AYON_SERVER_ENABLED import openpype.hosts.photoshop.api as api from openpype.client import get_asset_by_name from openpype.lib import prepare_template_data @@ -43,6 +44,14 @@ class PSAutoCreator(AutoCreator): asset_name = context.get_current_asset_name() task_name = context.get_current_task_name() host_name = context.host_name + + if existing_instance is None: + existing_instance_asset = None + elif AYON_SERVER_ENABLED: + existing_instance_asset = existing_instance["folderPath"] + else: + existing_instance_asset = existing_instance["asset"] + if existing_instance is None: asset_doc = get_asset_by_name(project_name, asset_name) subset_name = self.get_subset_name( @@ -50,10 +59,13 @@ class PSAutoCreator(AutoCreator): project_name, host_name ) data = { - "asset": asset_name, "task": task_name, "variant": self.default_variant } + if AYON_SERVER_ENABLED: + data["folderPath"] = asset_name + else: + data["asset"] = asset_name data.update(self.get_dynamic_data( self.default_variant, task_name, asset_doc, project_name, host_name, None @@ -70,7 +82,7 @@ class PSAutoCreator(AutoCreator): new_instance.data_to_store()) elif ( - existing_instance["asset"] != asset_name + existing_instance_asset != asset_name or existing_instance["task"] != task_name ): asset_doc = get_asset_by_name(project_name, asset_name) @@ -78,7 +90,10 @@ class PSAutoCreator(AutoCreator): self.default_variant, task_name, asset_doc, project_name, host_name ) - existing_instance["asset"] = asset_name + if AYON_SERVER_ENABLED: + existing_instance["folderPath"] = asset_name + else: + existing_instance["asset"] = asset_name existing_instance["task"] = task_name existing_instance["subset"] = subset_name diff --git a/openpype/hosts/photoshop/plugins/create/create_flatten_image.py b/openpype/hosts/photoshop/plugins/create/create_flatten_image.py index afde77fdb4..24be9df0e0 100644 --- a/openpype/hosts/photoshop/plugins/create/create_flatten_image.py +++ b/openpype/hosts/photoshop/plugins/create/create_flatten_image.py @@ -1,5 +1,6 @@ from openpype.pipeline import CreatedInstance +from openpype import AYON_SERVER_ENABLED from openpype.lib import BoolDef import openpype.hosts.photoshop.api as api from openpype.hosts.photoshop.lib import PSAutoCreator, clean_subset_name @@ -37,6 +38,13 @@ class AutoImageCreator(PSAutoCreator): host_name = context.host_name asset_doc = get_asset_by_name(project_name, asset_name) + if existing_instance is None: + existing_instance_asset = None + elif AYON_SERVER_ENABLED: + existing_instance_asset = existing_instance["folderPath"] + else: + existing_instance_asset = existing_instance["asset"] + if existing_instance is None: subset_name = self.get_subset_name( self.default_variant, task_name, asset_doc, @@ -44,9 +52,12 @@ class AutoImageCreator(PSAutoCreator): ) data = { - "asset": asset_name, "task": task_name, } + if AYON_SERVER_ENABLED: + data["folderPath"] = asset_name + else: + data["asset"] = asset_name if not self.active_on_create: data["active"] = False @@ -62,15 +73,17 @@ class AutoImageCreator(PSAutoCreator): new_instance.data_to_store()) elif ( # existing instance from different context - existing_instance["asset"] != asset_name + existing_instance_asset != asset_name or existing_instance["task"] != task_name ): subset_name = self.get_subset_name( self.default_variant, task_name, asset_doc, project_name, host_name ) - - existing_instance["asset"] = asset_name + if AYON_SERVER_ENABLED: + existing_instance["folderPath"] = asset_name + else: + existing_instance["asset"] = asset_name existing_instance["task"] = task_name existing_instance["subset"] = subset_name diff --git a/openpype/hosts/photoshop/plugins/publish/collect_auto_image.py b/openpype/hosts/photoshop/plugins/publish/collect_auto_image.py index d4b5f480b1..4d7838c510 100644 --- a/openpype/hosts/photoshop/plugins/publish/collect_auto_image.py +++ b/openpype/hosts/photoshop/plugins/publish/collect_auto_image.py @@ -1,5 +1,6 @@ import pyblish.api +from openpype.client import get_asset_name_identifier from openpype.hosts.photoshop import api as photoshop from openpype.pipeline.create import get_subset_name @@ -27,7 +28,7 @@ class CollectAutoImage(pyblish.api.ContextPlugin): task_name = context.data["task"] host_name = context.data["hostName"] asset_doc = context.data["assetEntity"] - asset_name = asset_doc["name"] + asset_name = get_asset_name_identifier(asset_doc) auto_creator = proj_settings.get( "photoshop", {}).get( diff --git a/openpype/hosts/photoshop/plugins/publish/collect_auto_review.py b/openpype/hosts/photoshop/plugins/publish/collect_auto_review.py index 8964582a45..e5a2f326d7 100644 --- a/openpype/hosts/photoshop/plugins/publish/collect_auto_review.py +++ b/openpype/hosts/photoshop/plugins/publish/collect_auto_review.py @@ -7,6 +7,7 @@ Provides: """ import pyblish.api +from openpype.client import get_asset_name_identifier from openpype.hosts.photoshop import api as photoshop from openpype.pipeline.create import get_subset_name @@ -65,7 +66,8 @@ class CollectAutoReview(pyblish.api.ContextPlugin): task_name = context.data["task"] host_name = context.data["hostName"] asset_doc = context.data["assetEntity"] - asset_name = asset_doc["name"] + + asset_name = get_asset_name_identifier(asset_doc) subset_name = get_subset_name( family, diff --git a/openpype/hosts/photoshop/plugins/publish/collect_auto_workfile.py b/openpype/hosts/photoshop/plugins/publish/collect_auto_workfile.py index d3cc8d44d0..9ccb8f4f85 100644 --- a/openpype/hosts/photoshop/plugins/publish/collect_auto_workfile.py +++ b/openpype/hosts/photoshop/plugins/publish/collect_auto_workfile.py @@ -1,6 +1,7 @@ import os import pyblish.api +from openpype.client import get_asset_name_identifier from openpype.hosts.photoshop import api as photoshop from openpype.pipeline.create import get_subset_name @@ -69,8 +70,8 @@ class CollectAutoWorkfile(pyblish.api.ContextPlugin): task_name = context.data["task"] host_name = context.data["hostName"] asset_doc = context.data["assetEntity"] - asset_name = asset_doc["name"] + asset_name = get_asset_name_identifier(asset_doc) subset_name = get_subset_name( family, variant, diff --git a/openpype/hosts/resolve/api/lib.py b/openpype/hosts/resolve/api/lib.py index aef9caca78..3866477c77 100644 --- a/openpype/hosts/resolve/api/lib.py +++ b/openpype/hosts/resolve/api/lib.py @@ -298,7 +298,7 @@ def create_timeline_item( if source_end: clip_data["endFrame"] = source_end if timecode_in: - clip_data["recordFrame"] = timecode_in + clip_data["recordFrame"] = timeline_in # add to timeline media_pool.AppendToTimeline([clip_data]) diff --git a/openpype/hosts/resolve/api/menu.py b/openpype/hosts/resolve/api/menu.py index 9c6fe4957c..2210178a67 100644 --- a/openpype/hosts/resolve/api/menu.py +++ b/openpype/hosts/resolve/api/menu.py @@ -7,6 +7,9 @@ from openpype.tools.utils import host_tools from openpype.pipeline import registered_host +MENU_LABEL = os.environ["AVALON_LABEL"] + + def load_stylesheet(): path = os.path.join(os.path.dirname(__file__), "menu_style.qss") if not os.path.exists(path): @@ -39,7 +42,7 @@ class OpenPypeMenu(QtWidgets.QWidget): def __init__(self, *args, **kwargs): super(OpenPypeMenu, self).__init__(*args, **kwargs) - self.setObjectName("OpenPypeMenu") + self.setObjectName(f"{MENU_LABEL}Menu") self.setWindowFlags( QtCore.Qt.Window @@ -49,7 +52,7 @@ class OpenPypeMenu(QtWidgets.QWidget): | QtCore.Qt.WindowStaysOnTopHint ) - self.setWindowTitle("OpenPype") + self.setWindowTitle(f"{MENU_LABEL}") save_current_btn = QtWidgets.QPushButton("Save current file", self) workfiles_btn = QtWidgets.QPushButton("Workfiles ...", self) create_btn = QtWidgets.QPushButton("Create ...", self) diff --git a/openpype/hosts/resolve/api/plugin.py b/openpype/hosts/resolve/api/plugin.py index 5c4a92df89..a00933405f 100644 --- a/openpype/hosts/resolve/api/plugin.py +++ b/openpype/hosts/resolve/api/plugin.py @@ -1,10 +1,11 @@ import re import uuid +import copy + import qargparse from qtpy import QtWidgets, QtCore from openpype.settings import get_current_project_settings -from openpype.pipeline.context_tools import get_current_project_asset from openpype.pipeline import ( LegacyCreator, LoaderPlugin, @@ -18,7 +19,7 @@ from .menu import load_stylesheet class CreatorWidget(QtWidgets.QDialog): # output items - items = dict() + items = {} def __init__(self, name, info, ui_inputs, parent=None): super(CreatorWidget, self).__init__(parent) @@ -100,7 +101,7 @@ class CreatorWidget(QtWidgets.QDialog): self.close() def value(self, data, new_data=None): - new_data = new_data or dict() + new_data = new_data or {} for k, v in data.items(): new_data[k] = { "target": None, @@ -289,7 +290,7 @@ class Spacer(QtWidgets.QWidget): class ClipLoader: active_bin = None - data = dict() + data = {} def __init__(self, loader_obj, context, **options): """ Initialize object @@ -386,8 +387,8 @@ class ClipLoader: joint `data` key with asset.data dict into the representation """ - asset_name = self.context["representation"]["context"]["asset"] - self.data["assetData"] = get_current_project_asset(asset_name)["data"] + + self.data["assetData"] = copy.deepcopy(self.context["asset"]["data"]) def load(self, files): """Load clip into timeline @@ -405,26 +406,42 @@ class ClipLoader: self.active_bin ) _clip_property = media_pool_item.GetClipProperty + source_in = int(_clip_property("Start")) + source_out = int(_clip_property("End")) + source_duration = int(_clip_property("Frames")) - # get handles - handle_start = self.data["versionData"].get("handleStart") - handle_end = self.data["versionData"].get("handleEnd") - if handle_start is None: - handle_start = int(self.data["assetData"]["handleStart"]) - if handle_end is None: - handle_end = int(self.data["assetData"]["handleEnd"]) + if not self.with_handles: + # Load file without the handles of the source media + # We remove the handles from the source in and source out + # so that the handles are excluded in the timeline + handle_start = 0 + handle_end = 0 - # check frame duration from versionData or assetData - frame_start = self.data["versionData"].get("frameStart") - if frame_start is None: - frame_start = self.data["assetData"]["frameStart"] + # get version data frame data from db + version_data = self.data["versionData"] + frame_start = version_data.get("frameStart") + frame_end = version_data.get("frameEnd") - # check frame duration from versionData or assetData - frame_end = self.data["versionData"].get("frameEnd") - if frame_end is None: - frame_end = self.data["assetData"]["frameEnd"] - - db_frame_duration = int(frame_end) - int(frame_start) + 1 + # The version data usually stored the frame range + handles of the + # media however certain representations may be shorter because they + # exclude those handles intentionally. Unfortunately the + # representation does not store that in the database currently; + # so we should compensate for those cases. If the media is shorter + # than the frame range specified in the database we assume it is + # without handles and thus we do not need to remove the handles + # from source and out + if frame_start is not None and frame_end is not None: + # Version has frame range data, so we can compare media length + handle_start = version_data.get("handleStart", 0) + handle_end = version_data.get("handleEnd", 0) + frame_start_handle = frame_start - handle_start + frame_end_handle = frame_start + handle_end + database_frame_duration = int( + frame_end_handle - frame_start_handle + 1 + ) + if source_duration >= database_frame_duration: + source_in += handle_start + source_out -= handle_end # get timeline in timeline_start = self.active_timeline.GetStartFrame() @@ -436,24 +453,6 @@ class ClipLoader: timeline_in = int( timeline_start + self.data["assetData"]["clipIn"]) - source_in = int(_clip_property("Start")) - source_out = int(_clip_property("End")) - source_duration = int(_clip_property("Frames")) - - # check if source duration is shorter than db frame duration - source_with_handles = True - if source_duration < db_frame_duration: - source_with_handles = False - - # only exclude handles if source has no handles or - # if user wants to load without handles - if ( - not self.with_handles - or not source_with_handles - ): - source_in += handle_start - source_out -= handle_end - # make track item from source in bin as item timeline_item = lib.create_timeline_item( media_pool_item, @@ -587,8 +586,8 @@ class PublishClip: Returns: hiero.core.TrackItem: hiero track item object with openpype tag """ - vertical_clip_match = dict() - tag_data = dict() + vertical_clip_match = {} + tag_data = {} types = { "shot": "shot", "folder": "folder", @@ -664,15 +663,23 @@ class PublishClip: new_name = self.tag_data.pop("newClipName") if self.rename: - self.tag_data["asset"] = new_name + self.tag_data["asset_name"] = new_name else: - self.tag_data["asset"] = self.ti_name + self.tag_data["asset_name"] = self.ti_name + # AYON unique identifier + folder_path = "/{}/{}".format( + self.tag_data["hierarchy"], + self.tag_data["asset_name"] + ) + self.tag_data["folder_path"] = folder_path + + # create new name for track item if not lib.pype_marker_workflow: # create compound clip workflow lib.create_compound_clip( self.timeline_item_data, - self.tag_data["asset"], + self.tag_data["asset_name"], self.mp_folder ) @@ -764,7 +771,7 @@ class PublishClip: # increasing steps by index of rename iteration self.count_steps *= self.rename_index - hierarchy_formatting_data = dict() + hierarchy_formatting_data = {} _data = self.timeline_item_default_data.copy() if self.ui_inputs: # adding tag metadata from ui @@ -853,14 +860,13 @@ class PublishClip: "parents": self.parents, "hierarchyData": hierarchy_formatting_data, "subset": self.subset, - "family": self.subset_family, - "families": ["clip"] + "family": self.subset_family } def _convert_to_entity(self, key): """ Converting input key to key with type. """ # convert to entity type - entity_type = self.types.get(key, None) + entity_type = self.types.get(key) assert entity_type, "Missing entity type for `{}`".format( key diff --git a/openpype/hosts/resolve/plugins/publish/extract_workfile.py b/openpype/hosts/resolve/plugins/publish/extract_workfile.py index 535f879b58..db63487405 100644 --- a/openpype/hosts/resolve/plugins/publish/extract_workfile.py +++ b/openpype/hosts/resolve/plugins/publish/extract_workfile.py @@ -26,6 +26,7 @@ class ExtractWorkfile(publish.Extractor): resolve_workfile_ext = ".drp" drp_file_name = name + resolve_workfile_ext + drp_file_path = os.path.normpath( os.path.join(staging_dir, drp_file_name)) diff --git a/openpype/hosts/resolve/plugins/publish/precollect_instances.py b/openpype/hosts/resolve/plugins/publish/precollect_instances.py index 8ec169ad65..bca6734848 100644 --- a/openpype/hosts/resolve/plugins/publish/precollect_instances.py +++ b/openpype/hosts/resolve/plugins/publish/precollect_instances.py @@ -9,6 +9,7 @@ from openpype.hosts.resolve.api.lib import ( get_publish_attribute, get_otio_clip_instance_data, ) +from openpype import AYON_SERVER_ENABLED class PrecollectInstances(pyblish.api.ContextPlugin): @@ -29,7 +30,7 @@ class PrecollectInstances(pyblish.api.ContextPlugin): for timeline_item_data in selected_timeline_items: - data = dict() + data = {} timeline_item = timeline_item_data["clip"]["item"] # get pype tag data @@ -60,24 +61,24 @@ class PrecollectInstances(pyblish.api.ContextPlugin): if k not in ("id", "applieswhole", "label") }) - asset = tag_data["asset"] + if AYON_SERVER_ENABLED: + asset = tag_data["folder_path"] + else: + asset = tag_data["asset_name"] + subset = tag_data["subset"] - # insert family into families - family = tag_data["family"] - families = [str(f) for f in tag_data["families"]] - families.insert(0, str(family)) - data.update({ - "name": "{} {} {}".format(asset, subset, families), + "name": "{}_{}".format(asset, subset), + "label": "{} {}".format(asset, subset), "asset": asset, "item": timeline_item, - "families": families, "publish": get_publish_attribute(timeline_item), "fps": context.data["fps"], "handleStart": handle_start, "handleEnd": handle_end, - "newAssetPublishing": True + "newAssetPublishing": True, + "families": ["clip"], }) # otio clip data @@ -135,7 +136,8 @@ class PrecollectInstances(pyblish.api.ContextPlugin): family = "shot" data.update({ - "name": "{} {} {}".format(asset, subset, family), + "name": "{}_{}".format(asset, subset), + "label": "{} {}".format(asset, subset), "subset": subset, "asset": asset, "family": family, diff --git a/openpype/hosts/resolve/plugins/publish/precollect_workfile.py b/openpype/hosts/resolve/plugins/publish/precollect_workfile.py index a2f3eaed7a..ccc5fd86ff 100644 --- a/openpype/hosts/resolve/plugins/publish/precollect_workfile.py +++ b/openpype/hosts/resolve/plugins/publish/precollect_workfile.py @@ -1,7 +1,9 @@ import pyblish.api from pprint import pformat +from openpype import AYON_SERVER_ENABLED from openpype.pipeline import get_current_asset_name + from openpype.hosts.resolve import api as rapi from openpype.hosts.resolve.otio import davinci_export @@ -13,9 +15,12 @@ class PrecollectWorkfile(pyblish.api.ContextPlugin): order = pyblish.api.CollectorOrder - 0.5 def process(self, context): + current_asset_name = asset_name = get_current_asset_name() - asset = get_current_asset_name() - subset = "workfile" + if AYON_SERVER_ENABLED: + asset_name = current_asset_name.split("/")[-1] + + subset = "workfileMain" project = rapi.get_current_project() fps = project.GetSetting("timelineFrameRate") video_tracks = rapi.get_video_track_names() @@ -24,9 +29,10 @@ class PrecollectWorkfile(pyblish.api.ContextPlugin): otio_timeline = davinci_export.create_otio_timeline(project) instance_data = { - "name": "{}_{}".format(asset, subset), - "asset": asset, - "subset": "{}{}".format(asset, subset.capitalize()), + "name": "{}_{}".format(asset_name, subset), + "label": "{} {}".format(current_asset_name, subset), + "asset": current_asset_name, + "subset": subset, "item": project, "family": "workfile", "families": [] diff --git a/openpype/hosts/resolve/utility_scripts/AYON__Menu.py b/openpype/hosts/resolve/utility_scripts/AYON__Menu.py new file mode 100644 index 0000000000..4f14927074 --- /dev/null +++ b/openpype/hosts/resolve/utility_scripts/AYON__Menu.py @@ -0,0 +1,22 @@ +import os +import sys + +from openpype.pipeline import install_host +from openpype.lib import Logger + +log = Logger.get_logger(__name__) + + +def main(env): + from openpype.hosts.resolve.api import ResolveHost, launch_pype_menu + + # activate resolve from openpype + host = ResolveHost() + install_host(host) + + launch_pype_menu() + + +if __name__ == "__main__": + result = main(os.environ) + sys.exit(not bool(result)) diff --git a/openpype/hosts/resolve/utils.py b/openpype/hosts/resolve/utils.py index 5e3003862f..9b91a14267 100644 --- a/openpype/hosts/resolve/utils.py +++ b/openpype/hosts/resolve/utils.py @@ -2,6 +2,7 @@ import os import shutil from openpype.lib import Logger, is_running_from_build +from openpype import AYON_SERVER_ENABLED RESOLVE_ROOT_DIR = os.path.dirname(os.path.abspath(__file__)) @@ -54,6 +55,14 @@ def setup(env): src = os.path.join(directory, script) dst = os.path.join(util_scripts_dir, script) + # TODO: remove this once we have a proper solution + if AYON_SERVER_ENABLED: + if "OpenPype__Menu.py" == script: + continue + else: + if "AYON__Menu.py" == script: + continue + # TODO: Make this a less hacky workaround if script == "openpype_startup.scriptlib": # Handle special case for scriptlib that needs to be a folder diff --git a/openpype/hosts/standalonepublisher/plugins/publish/collect_harmony_scenes.py b/openpype/hosts/standalonepublisher/plugins/publish/collect_harmony_scenes.py index 48c36aa067..c435ca2096 100644 --- a/openpype/hosts/standalonepublisher/plugins/publish/collect_harmony_scenes.py +++ b/openpype/hosts/standalonepublisher/plugins/publish/collect_harmony_scenes.py @@ -60,6 +60,9 @@ class CollectHarmonyScenes(pyblish.api.InstancePlugin): # updating hierarchy data anatomy_data_new.update({ "asset": asset_data["name"], + "folder": { + "name": asset_data["name"], + }, "task": { "name": task, "type": task_type, diff --git a/openpype/hosts/standalonepublisher/plugins/publish/collect_harmony_zips.py b/openpype/hosts/standalonepublisher/plugins/publish/collect_harmony_zips.py index 40a969f8df..d90215e767 100644 --- a/openpype/hosts/standalonepublisher/plugins/publish/collect_harmony_zips.py +++ b/openpype/hosts/standalonepublisher/plugins/publish/collect_harmony_zips.py @@ -56,6 +56,9 @@ class CollectHarmonyZips(pyblish.api.InstancePlugin): anatomy_data_new.update( { "asset": asset_data["name"], + "folder": { + "name": asset_data["name"], + }, "task": { "name": task, "type": task_type, diff --git a/openpype/hosts/standalonepublisher/plugins/publish/collect_original_basename.py b/openpype/hosts/standalonepublisher/plugins/publish/collect_original_basename.py deleted file mode 100644 index b83a924d33..0000000000 --- a/openpype/hosts/standalonepublisher/plugins/publish/collect_original_basename.py +++ /dev/null @@ -1,18 +0,0 @@ -# -*- coding: utf-8 -*- -"""Collect original base name for use in templates.""" -from pathlib import Path - -import pyblish.api - - -class CollectOriginalBasename(pyblish.api.InstancePlugin): - """Collect original file base name.""" - - order = pyblish.api.CollectorOrder + 0.498 - label = "Collect Base Name" - hosts = ["standalonepublisher"] - families = ["simpleUnrealTexture"] - - def process(self, instance): - file_name = Path(instance.data["representations"][0]["files"]) - instance.data["originalBasename"] = file_name.stem diff --git a/openpype/hosts/standalonepublisher/plugins/publish/validate_simple_unreal_texture_naming.py b/openpype/hosts/standalonepublisher/plugins/publish/validate_simple_unreal_texture_naming.py deleted file mode 100644 index c123bef4f8..0000000000 --- a/openpype/hosts/standalonepublisher/plugins/publish/validate_simple_unreal_texture_naming.py +++ /dev/null @@ -1,29 +0,0 @@ -# -*- coding: utf-8 -*- -"""Validator for correct file naming.""" -import re -import pyblish.api - -from openpype.pipeline.publish import ( - ValidateContentsOrder, - PublishXmlValidationError, -) - - -class ValidateSimpleUnrealTextureNaming(pyblish.api.InstancePlugin): - label = "Validate Unreal Texture Names" - hosts = ["standalonepublisher"] - families = ["simpleUnrealTexture"] - order = ValidateContentsOrder - regex = "^T_{asset}.*" - - def process(self, instance): - file_name = instance.data.get("originalBasename") - self.log.info(file_name) - pattern = self.regex.format(asset=instance.data.get("asset")) - if not re.match(pattern, file_name): - msg = f"Invalid file name {file_name}" - raise PublishXmlValidationError( - self, msg, formatting_data={ - "invalid_file": file_name, - "asset": instance.data.get("asset") - }) diff --git a/openpype/hosts/substancepainter/api/lib.py b/openpype/hosts/substancepainter/api/lib.py index 2cd08f862e..1cb480b552 100644 --- a/openpype/hosts/substancepainter/api/lib.py +++ b/openpype/hosts/substancepainter/api/lib.py @@ -583,18 +583,9 @@ def prompt_new_file_with_mesh(mesh_filepath): file_dialog.setDirectory(os.path.dirname(mesh_filepath)) url = QtCore.QUrl.fromLocalFile(os.path.basename(mesh_filepath)) file_dialog.selectUrl(url) - - # Give the explorer window time to refresh to the folder and select - # the file - while not file_dialog.selectedFiles(): - app.processEvents(QtCore.QEventLoop.ExcludeUserInputEvents, 1000) - print(f"Selected: {file_dialog.selectedFiles()}") - - # Set it again now we know the path is refreshed - without this - # accepting the dialog will often not trigger the correct filepath - file_dialog.setDirectory(os.path.dirname(mesh_filepath)) - url = QtCore.QUrl.fromLocalFile(os.path.basename(mesh_filepath)) - file_dialog.selectUrl(url) + # TODO: find a way to improve the process event to + # load more complicated mesh + app.processEvents(QtCore.QEventLoop.ExcludeUserInputEvents, 3000) file_dialog.done(file_dialog.Accepted) app.processEvents(QtCore.QEventLoop.AllEvents) @@ -628,7 +619,12 @@ def prompt_new_file_with_mesh(mesh_filepath): mesh_filename_label = mesh_filename.findChild(QtWidgets.QLabel) if not mesh_filename_label.text(): dialog.close() - raise RuntimeError(f"Failed to set mesh path: {mesh_filepath}") + substance_painter.logging.warning( + "Failed to set mesh path with the prompt dialog:" + f"{mesh_filepath}\n\n" + "Creating new project directly with the mesh path instead.") + else: + dialog.done(dialog.Accepted) new_action = _get_new_project_action() if not new_action: diff --git a/openpype/hosts/substancepainter/plugins/create/create_workfile.py b/openpype/hosts/substancepainter/plugins/create/create_workfile.py index d7f31f9dcf..c73277e405 100644 --- a/openpype/hosts/substancepainter/plugins/create/create_workfile.py +++ b/openpype/hosts/substancepainter/plugins/create/create_workfile.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- """Creator plugin for creating workfiles.""" +from openpype import AYON_SERVER_ENABLED from openpype.pipeline import CreatedInstance, AutoCreator from openpype.client import get_asset_by_name @@ -41,6 +42,13 @@ class CreateWorkfile(AutoCreator): if instance.creator_identifier == self.identifier ), None) + if current_instance is None: + current_instance_asset = None + elif AYON_SERVER_ENABLED: + current_instance_asset = current_instance["folderPath"] + else: + current_instance_asset = current_instance["asset"] + if current_instance is None: self.log.info("Auto-creating workfile instance...") asset_doc = get_asset_by_name(project_name, asset_name) @@ -48,22 +56,28 @@ class CreateWorkfile(AutoCreator): variant, task_name, asset_doc, project_name, host_name ) data = { - "asset": asset_name, "task": task_name, "variant": variant } + if AYON_SERVER_ENABLED: + data["folderPath"] = asset_name + else: + data["asset"] = asset_name current_instance = self.create_instance_in_context(subset_name, data) elif ( - current_instance["asset"] != asset_name - or current_instance["task"] != task_name + current_instance_asset != asset_name + or current_instance["task"] != task_name ): # Update instance context if is not the same asset_doc = get_asset_by_name(project_name, asset_name) subset_name = self.get_subset_name( variant, task_name, asset_doc, project_name, host_name ) - current_instance["asset"] = asset_name + if AYON_SERVER_ENABLED: + current_instance["folderPath"] = asset_name + else: + current_instance["asset"] = asset_name current_instance["task"] = task_name current_instance["subset"] = subset_name diff --git a/openpype/hosts/substancepainter/plugins/load/load_mesh.py b/openpype/hosts/substancepainter/plugins/load/load_mesh.py index 57db869a11..08c1d5c391 100644 --- a/openpype/hosts/substancepainter/plugins/load/load_mesh.py +++ b/openpype/hosts/substancepainter/plugins/load/load_mesh.py @@ -44,14 +44,22 @@ class SubstanceLoadProjectMesh(load.LoaderPlugin): # Get user inputs import_cameras = data.get("import_cameras", True) preserve_strokes = data.get("preserve_strokes", True) - + sp_settings = substance_painter.project.Settings( + import_cameras=import_cameras + ) if not substance_painter.project.is_open(): # Allow to 'initialize' a new project path = self.filepath_from_context(context) + # TODO: improve the prompt dialog function to not + # only works for simple polygon scene result = prompt_new_file_with_mesh(mesh_filepath=path) if not result: - self.log.info("User cancelled new project prompt.") - return + self.log.info("User cancelled new project prompt." + "Creating new project directly from" + " Substance Painter API Instead.") + settings = substance_painter.project.create( + mesh_file_path=path, settings=sp_settings + ) else: # Reload the mesh diff --git a/openpype/hosts/traypublisher/api/editorial.py b/openpype/hosts/traypublisher/api/editorial.py index e8f76bd314..613f1de768 100644 --- a/openpype/hosts/traypublisher/api/editorial.py +++ b/openpype/hosts/traypublisher/api/editorial.py @@ -53,11 +53,11 @@ class ShotMetadataSolver: try: # format to new shot name return shot_rename_template.format(**data) - except KeyError as _E: + except KeyError as _error: raise CreatorError(( "Make sure all keys in settings are correct:: \n\n" f"From template string {shot_rename_template} > " - f"`{_E}` has no equivalent in \n" + f"`{_error}` has no equivalent in \n" f"{list(data.keys())} input formatting keys!" )) @@ -100,7 +100,7 @@ class ShotMetadataSolver: "at your project settings..." )) - # QUESTION:how to refactory `match[-1]` to some better way? + # QUESTION:how to refactor `match[-1]` to some better way? output_data[token_key] = match[-1] return output_data @@ -130,10 +130,10 @@ class ShotMetadataSolver: parent_token["name"]: parent_token["value"].format(**data) for parent_token in hierarchy_parents } - except KeyError as _E: + except KeyError as _error: raise CreatorError(( "Make sure all keys in settings are correct : \n" - f"`{_E}` has no equivalent in \n{list(data.keys())}" + f"`{_error}` has no equivalent in \n{list(data.keys())}" )) _parent_tokens_type = { @@ -147,10 +147,10 @@ class ShotMetadataSolver: try: parent_name = _parent.format( **_parent_tokens_formatting_data) - except KeyError as _E: + except KeyError as _error: raise CreatorError(( "Make sure all keys in settings are correct : \n\n" - f"`{_E}` from template string " + f"`{_error}` from template string " f"{shot_hierarchy['parents_path']}, " f" has no equivalent in \n" f"{list(_parent_tokens_formatting_data.keys())} parents" @@ -319,8 +319,16 @@ class ShotMetadataSolver: tasks = self._generate_tasks_from_settings( project_doc) + # generate hierarchy path from parents + hierarchy_path = self._create_hierarchy_path(parents) + if hierarchy_path: + folder_path = f"/{hierarchy_path}/{shot_name}" + else: + folder_path = f"/{shot_name}" + return shot_name, { - "hierarchy": self._create_hierarchy_path(parents), + "hierarchy": hierarchy_path, + "folderPath": folder_path, "parents": parents, "tasks": tasks } diff --git a/openpype/hosts/traypublisher/api/plugin.py b/openpype/hosts/traypublisher/api/plugin.py index 36e041a32c..14c66fa08f 100644 --- a/openpype/hosts/traypublisher/api/plugin.py +++ b/openpype/hosts/traypublisher/api/plugin.py @@ -1,7 +1,9 @@ +from openpype import AYON_SERVER_ENABLED from openpype.client import ( get_assets, get_subsets, get_last_versions, + get_asset_name_identifier, ) from openpype.lib.attribute_definitions import ( FileDef, @@ -114,7 +116,10 @@ class SettingsCreator(TrayPublishCreator): # Fill 'version_to_use' if version control is enabled if self.allow_version_control: - asset_name = data["asset"] + if AYON_SERVER_ENABLED: + asset_name = data["folderPath"] + else: + asset_name = data["asset"] subset_docs_by_asset_id = self._prepare_next_versions( [asset_name], [subset_name]) version = subset_docs_by_asset_id[asset_name].get(subset_name) @@ -162,10 +167,10 @@ class SettingsCreator(TrayPublishCreator): asset_docs = get_assets( self.project_name, asset_names=asset_names, - fields=["_id", "name"] + fields=["_id", "name", "data.parents"] ) asset_names_by_id = { - asset_doc["_id"]: asset_doc["name"] + asset_doc["_id"]: get_asset_name_identifier(asset_doc) for asset_doc in asset_docs } subset_docs = list(get_subsets( diff --git a/openpype/hosts/traypublisher/plugins/create/create_colorspace_look.py b/openpype/hosts/traypublisher/plugins/create/create_colorspace_look.py index 5628d0973f..ac4c72a0ce 100644 --- a/openpype/hosts/traypublisher/plugins/create/create_colorspace_look.py +++ b/openpype/hosts/traypublisher/plugins/create/create_colorspace_look.py @@ -6,6 +6,7 @@ production type `ociolook`. All files are published as representation. """ from pathlib import Path +from openpype import AYON_SERVER_ENABLED from openpype.client import get_asset_by_name from openpype.lib.attribute_definitions import ( FileDef, EnumDef, TextDef, UISeparatorDef @@ -54,8 +55,12 @@ This creator publishes color space look file (LUT). # this should never happen raise CreatorError("Missing files from representation") + if AYON_SERVER_ENABLED: + asset_name = instance_data["folderPath"] + else: + asset_name = instance_data["asset"] asset_doc = get_asset_by_name( - self.project_name, instance_data["asset"]) + self.project_name, asset_name) subset_name = self.get_subset_name( variant=instance_data["variant"], diff --git a/openpype/hosts/traypublisher/plugins/create/create_editorial.py b/openpype/hosts/traypublisher/plugins/create/create_editorial.py index a2746f115f..dce4a051fd 100644 --- a/openpype/hosts/traypublisher/plugins/create/create_editorial.py +++ b/openpype/hosts/traypublisher/plugins/create/create_editorial.py @@ -1,6 +1,7 @@ import os from copy import deepcopy import opentimelineio as otio +from openpype import AYON_SERVER_ENABLED from openpype.client import ( get_asset_by_name, get_project @@ -101,14 +102,23 @@ class EditorialShotInstanceCreator(EditorialClipInstanceCreatorBase): label = "Editorial Shot" def get_instance_attr_defs(self): - attr_defs = [ - TextDef( - "asset_name", - label="Asset name", + instance_attributes = [] + if AYON_SERVER_ENABLED: + instance_attributes.append( + TextDef( + "folderPath", + label="Folder path" + ) ) - ] - attr_defs.extend(CLIP_ATTR_DEFS) - return attr_defs + else: + instance_attributes.append( + TextDef( + "shotName", + label="Shot name" + ) + ) + instance_attributes.extend(CLIP_ATTR_DEFS) + return instance_attributes class EditorialPlateInstanceCreator(EditorialClipInstanceCreatorBase): @@ -214,8 +224,11 @@ or updating already created. Publishing will create OTIO file. i["family"] for i in self._creator_settings["family_presets"] ] } - # Create otio editorial instance - asset_name = instance_data["asset"] + if AYON_SERVER_ENABLED: + asset_name = instance_data["folderPath"] + else: + asset_name = instance_data["asset"] + asset_doc = get_asset_by_name(self.project_name, asset_name) if pre_create_data["fps"] == "from_selection": @@ -595,19 +608,23 @@ or updating already created. Publishing will create OTIO file. Returns: str: label string """ - shot_name = instance_data["shotName"] + if AYON_SERVER_ENABLED: + asset_name = instance_data["creator_attributes"]["folderPath"] + else: + asset_name = instance_data["creator_attributes"]["shotName"] + variant_name = instance_data["variant"] family = preset["family"] - # get variant name from preset or from inharitance + # get variant name from preset or from inheritance _variant_name = preset.get("variant") or variant_name # subset name subset_name = "{}{}".format( family, _variant_name.capitalize() ) - label = "{}_{}".format( - shot_name, + label = "{} {}".format( + asset_name, subset_name ) @@ -646,7 +663,7 @@ or updating already created. Publishing will create OTIO file. variant_name = instance_data["variant"] # basic unique asset name - clip_name = os.path.splitext(otio_clip.name)[0].lower() + clip_name = os.path.splitext(otio_clip.name)[0] project_doc = get_project(self.project_name) shot_name, shot_metadata = self._shot_metadata_solver.generate_data( @@ -666,7 +683,10 @@ or updating already created. Publishing will create OTIO file. } ) - self._validate_name_uniqueness(shot_name) + # It should be validated only in openpype since we are supporting + # publishing to AYON with folder path and uniqueness is not an issue + if not AYON_SERVER_ENABLED: + self._validate_name_uniqueness(shot_name) timing_data = self._get_timing_data( otio_clip, @@ -677,35 +697,43 @@ or updating already created. Publishing will create OTIO file. # create creator attributes creator_attributes = { - "asset_name": shot_name, - "Parent hierarchy path": shot_metadata["hierarchy"], + "workfile_start_frame": workfile_start_frame, "fps": fps, "handle_start": int(handle_start), "handle_end": int(handle_end) } + # add timing data creator_attributes.update(timing_data) - # create shared new instance data + # create base instance data base_instance_data = { "shotName": shot_name, "variant": variant_name, - - # HACK: just for temporal bug workaround - # TODO: should loockup shot name for update - "asset": parent_asset_name, "task": "", - "newAssetPublishing": True, - - # parent time properties "trackStartFrame": track_start_frame, "timelineOffset": timeline_offset, - "isEditorial": True, # creator_attributes "creator_attributes": creator_attributes } + # update base instance data with context data + # and also update creator attributes with context data + if AYON_SERVER_ENABLED: + # TODO: this is here just to be able to publish + # to AYON with folder path + creator_attributes["folderPath"] = shot_metadata.pop("folderPath") + base_instance_data["folderPath"] = parent_asset_name + else: + creator_attributes.update({ + "shotName": shot_name, + "Parent hierarchy path": shot_metadata["hierarchy"] + }) + + base_instance_data["asset"] = parent_asset_name + # add creator attributes to shared instance data + base_instance_data["creator_attributes"] = creator_attributes # add hierarchy shot metadata base_instance_data.update(shot_metadata) diff --git a/openpype/hosts/traypublisher/plugins/create/create_movie_batch.py b/openpype/hosts/traypublisher/plugins/create/create_movie_batch.py index 3454b6e135..8fa65c7fff 100644 --- a/openpype/hosts/traypublisher/plugins/create/create_movie_batch.py +++ b/openpype/hosts/traypublisher/plugins/create/create_movie_batch.py @@ -2,6 +2,8 @@ import copy import os import re +from openpype import AYON_SERVER_ENABLED +from openpype.client import get_asset_name_identifier from openpype.lib import ( FileDef, BoolDef, @@ -64,8 +66,13 @@ class BatchMovieCreator(TrayPublishCreator): subset_name, task_name = self._get_subset_and_task( asset_doc, data["variant"], self.project_name) + asset_name = get_asset_name_identifier(asset_doc) + instance_data["task"] = task_name - instance_data["asset"] = asset_doc["name"] + if AYON_SERVER_ENABLED: + instance_data["folderPath"] = asset_name + else: + instance_data["asset"] = asset_name # Create new instance new_instance = CreatedInstance(self.family, subset_name, diff --git a/openpype/hosts/traypublisher/plugins/publish/collect_sequence_frame_data.py b/openpype/hosts/traypublisher/plugins/publish/collect_sequence_frame_data.py index 92cedf6b5b..5e60a94927 100644 --- a/openpype/hosts/traypublisher/plugins/publish/collect_sequence_frame_data.py +++ b/openpype/hosts/traypublisher/plugins/publish/collect_sequence_frame_data.py @@ -28,9 +28,9 @@ class CollectSequenceFrameData( return # editorial would fail since they might not be in database yet - is_editorial = instance.data.get("isEditorial") - if is_editorial: - self.log.debug("Instance is Editorial. Skipping.") + new_asset_publishing = instance.data.get("newAssetPublishing") + if new_asset_publishing: + self.log.debug("Instance is creating new asset. Skipping.") return frame_data = self.get_frame_data_from_repre_sequence(instance) diff --git a/openpype/hosts/traypublisher/plugins/publish/collect_shot_instances.py b/openpype/hosts/traypublisher/plugins/publish/collect_shot_instances.py index 78c1f14e4e..e00ac64244 100644 --- a/openpype/hosts/traypublisher/plugins/publish/collect_shot_instances.py +++ b/openpype/hosts/traypublisher/plugins/publish/collect_shot_instances.py @@ -2,6 +2,8 @@ from pprint import pformat import pyblish.api import opentimelineio as otio +from openpype import AYON_SERVER_ENABLED + class CollectShotInstance(pyblish.api.InstancePlugin): """ Collect shot instances @@ -119,8 +121,7 @@ class CollectShotInstance(pyblish.api.InstancePlugin): frame_end = _cr_attrs["frameEnd"] frame_dur = frame_end - frame_start - return { - "asset": _cr_attrs["asset_name"], + data = { "fps": float(_cr_attrs["fps"]), "handleStart": _cr_attrs["handle_start"], "handleEnd": _cr_attrs["handle_end"], @@ -133,6 +134,12 @@ class CollectShotInstance(pyblish.api.InstancePlugin): "sourceOut": _cr_attrs["sourceOut"], "workfileFrameStart": workfile_start_frame } + if AYON_SERVER_ENABLED: + data["asset"] = _cr_attrs["folderPath"] + else: + data["asset"] = _cr_attrs["shotName"] + + return data def _solve_hierarchy_context(self, instance): """ Adding hierarchy data to context shared data. @@ -148,7 +155,7 @@ class CollectShotInstance(pyblish.api.InstancePlugin): else {} ) - name = instance.data["asset"] + asset_name = instance.data["asset"] # get handles handle_start = int(instance.data["handleStart"]) @@ -170,7 +177,7 @@ class CollectShotInstance(pyblish.api.InstancePlugin): parents = instance.data.get('parents', []) - actual = {name: in_info} + actual = {asset_name: in_info} for parent in reversed(parents): parent_name = parent["entity_name"] diff --git a/openpype/hosts/traypublisher/plugins/publish/validate_frame_ranges.py b/openpype/hosts/traypublisher/plugins/publish/validate_frame_ranges.py index 4977a13374..56389a927f 100644 --- a/openpype/hosts/traypublisher/plugins/publish/validate_frame_ranges.py +++ b/openpype/hosts/traypublisher/plugins/publish/validate_frame_ranges.py @@ -31,9 +31,9 @@ class ValidateFrameRange(OptionalPyblishPluginMixin, return # editorial would fail since they might not be in database yet - is_editorial = instance.data.get("isEditorial") - if is_editorial: - self.log.debug("Instance is Editorial. Skipping.") + new_asset_publishing = instance.data.get("newAssetPublishing") + if new_asset_publishing: + self.log.debug("Instance is creating new asset. Skipping.") return if (self.skip_timelines_check and @@ -41,6 +41,7 @@ class ValidateFrameRange(OptionalPyblishPluginMixin, for pattern in self.skip_timelines_check)): self.log.info("Skipping for {} task".format(instance.data["task"])) + asset_doc = instance.data["assetEntity"] asset_data = asset_doc["data"] frame_start = asset_data["frameStart"] frame_end = asset_data["frameEnd"] diff --git a/openpype/hosts/tvpaint/plugins/create/create_render.py b/openpype/hosts/tvpaint/plugins/create/create_render.py index b7a7c208d9..667103432e 100644 --- a/openpype/hosts/tvpaint/plugins/create/create_render.py +++ b/openpype/hosts/tvpaint/plugins/create/create_render.py @@ -37,7 +37,8 @@ Todos: import collections from typing import Any, Optional, Union -from openpype.client import get_asset_by_name +from openpype import AYON_SERVER_ENABLED +from openpype.client import get_asset_by_name, get_asset_name_identifier from openpype.lib import ( prepare_template_data, AbstractAttrDef, @@ -784,18 +785,25 @@ class TVPaintAutoDetectRenderCreator(TVPaintCreator): project_name, host_name=self.create_context.host_name, ) + asset_name = get_asset_name_identifier(asset_doc) if existing_instance is not None: - existing_instance["asset"] = asset_doc["name"] + if AYON_SERVER_ENABLED: + existing_instance["folderPath"] = asset_name + else: + existing_instance["asset"] = asset_name existing_instance["task"] = task_name existing_instance["subset"] = subset_name return existing_instance instance_data: dict[str, str] = { - "asset": asset_doc["name"], "task": task_name, "family": creator.family, "variant": variant } + if AYON_SERVER_ENABLED: + instance_data["folderPath"] = asset_name + else: + instance_data["asset"] = asset_name pre_create_data: dict[str, str] = { "group_id": group_id, "mark_for_review": mark_for_review @@ -820,6 +828,8 @@ class TVPaintAutoDetectRenderCreator(TVPaintCreator): for layer_name in render_pass["layer_names"]: render_pass_by_layer_name[layer_name] = render_pass + asset_name = get_asset_name_identifier(asset_doc) + for layer in layers: layer_name = layer["name"] variant = layer_name @@ -838,17 +848,25 @@ class TVPaintAutoDetectRenderCreator(TVPaintCreator): ) if render_pass is not None: - render_pass["asset"] = asset_doc["name"] + if AYON_SERVER_ENABLED: + render_pass["folderPath"] = asset_name + else: + render_pass["asset"] = asset_name + render_pass["task"] = task_name render_pass["subset"] = subset_name continue instance_data: dict[str, str] = { - "asset": asset_doc["name"], "task": task_name, "family": creator.family, "variant": variant } + if AYON_SERVER_ENABLED: + instance_data["folderPath"] = asset_name + else: + instance_data["asset"] = asset_name + pre_create_data: dict[str, Any] = { "render_layer_instance_id": render_layer_instance.id, "layer_names": [layer_name], @@ -882,9 +900,13 @@ class TVPaintAutoDetectRenderCreator(TVPaintCreator): def create(self, subset_name, instance_data, pre_create_data): project_name: str = self.create_context.get_current_project_name() - asset_name: str = instance_data["asset"] + if AYON_SERVER_ENABLED: + asset_name: str = instance_data["folderPath"] + else: + asset_name: str = instance_data["asset"] task_name: str = instance_data["task"] - asset_doc: dict[str, Any] = get_asset_by_name(project_name, asset_name) + asset_doc: dict[str, Any] = get_asset_by_name( + project_name, asset_name) render_layers_by_group_id: dict[int, CreatedInstance] = {} render_passes_by_render_layer_id: dict[int, list[CreatedInstance]] = ( @@ -1061,7 +1083,6 @@ class TVPaintSceneRenderCreator(TVPaintAutoCreator): host_name ) data = { - "asset": asset_name, "task": task_name, "variant": self.default_variant, "creator_attributes": { @@ -1073,6 +1094,10 @@ class TVPaintSceneRenderCreator(TVPaintAutoCreator): self.default_pass_name ) } + if AYON_SERVER_ENABLED: + data["folderPath"] = asset_name + else: + data["asset"] = asset_name if not self.active_on_create: data["active"] = False @@ -1101,8 +1126,14 @@ class TVPaintSceneRenderCreator(TVPaintAutoCreator): asset_name = create_context.get_current_asset_name() task_name = create_context.get_current_task_name() + existing_name = None + if AYON_SERVER_ENABLED: + existing_name = existing_instance.get("folderPath") + if existing_name is None: + existing_name = existing_instance["asset"] + if ( - existing_instance["asset"] != asset_name + existing_name != asset_name or existing_instance["task"] != task_name ): asset_doc = get_asset_by_name(project_name, asset_name) @@ -1114,7 +1145,10 @@ class TVPaintSceneRenderCreator(TVPaintAutoCreator): host_name, existing_instance ) - existing_instance["asset"] = asset_name + if AYON_SERVER_ENABLED: + existing_instance["folderPath"] = asset_name + else: + existing_instance["asset"] = asset_name existing_instance["task"] = task_name existing_instance["subset"] = subset_name diff --git a/openpype/hosts/tvpaint/plugins/create/create_review.py b/openpype/hosts/tvpaint/plugins/create/create_review.py index 7bb7510a8e..5caf20f27d 100644 --- a/openpype/hosts/tvpaint/plugins/create/create_review.py +++ b/openpype/hosts/tvpaint/plugins/create/create_review.py @@ -1,3 +1,4 @@ +from openpype import AYON_SERVER_ENABLED from openpype.client import get_asset_by_name from openpype.pipeline import CreatedInstance from openpype.hosts.tvpaint.api.plugin import TVPaintAutoCreator @@ -33,6 +34,13 @@ class TVPaintReviewCreator(TVPaintAutoCreator): asset_name = create_context.get_current_asset_name() task_name = create_context.get_current_task_name() + if existing_instance is None: + existing_asset_name = None + elif AYON_SERVER_ENABLED: + existing_asset_name = existing_instance["folderPath"] + else: + existing_asset_name = existing_instance["asset"] + if existing_instance is None: asset_doc = get_asset_by_name(project_name, asset_name) subset_name = self.get_subset_name( @@ -43,10 +51,14 @@ class TVPaintReviewCreator(TVPaintAutoCreator): host_name ) data = { - "asset": asset_name, "task": task_name, "variant": self.default_variant } + if AYON_SERVER_ENABLED: + data["folderPath"] = asset_name + else: + data["asset"] = asset_name + if not self.active_on_create: data["active"] = False @@ -59,7 +71,7 @@ class TVPaintReviewCreator(TVPaintAutoCreator): self._add_instance_to_context(new_instance) elif ( - existing_instance["asset"] != asset_name + existing_asset_name != asset_name or existing_instance["task"] != task_name ): asset_doc = get_asset_by_name(project_name, asset_name) @@ -71,6 +83,9 @@ class TVPaintReviewCreator(TVPaintAutoCreator): host_name, existing_instance ) - existing_instance["asset"] = asset_name + if AYON_SERVER_ENABLED: + existing_instance["folderPath"] = asset_name + else: + existing_instance["asset"] = asset_name existing_instance["task"] = task_name existing_instance["subset"] = subset_name diff --git a/openpype/hosts/tvpaint/plugins/create/create_workfile.py b/openpype/hosts/tvpaint/plugins/create/create_workfile.py index c3982c0eca..4ce5d7fc96 100644 --- a/openpype/hosts/tvpaint/plugins/create/create_workfile.py +++ b/openpype/hosts/tvpaint/plugins/create/create_workfile.py @@ -1,3 +1,4 @@ +from openpype import AYON_SERVER_ENABLED from openpype.client import get_asset_by_name from openpype.pipeline import CreatedInstance from openpype.hosts.tvpaint.api.plugin import TVPaintAutoCreator @@ -29,6 +30,13 @@ class TVPaintWorkfileCreator(TVPaintAutoCreator): asset_name = create_context.get_current_asset_name() task_name = create_context.get_current_task_name() + if existing_instance is None: + existing_asset_name = None + elif AYON_SERVER_ENABLED: + existing_asset_name = existing_instance["folderPath"] + else: + existing_asset_name = existing_instance["asset"] + if existing_instance is None: asset_doc = get_asset_by_name(project_name, asset_name) subset_name = self.get_subset_name( @@ -39,10 +47,13 @@ class TVPaintWorkfileCreator(TVPaintAutoCreator): host_name ) data = { - "asset": asset_name, "task": task_name, "variant": self.default_variant } + if AYON_SERVER_ENABLED: + data["folderPath"] = asset_name + else: + data["asset"] = asset_name new_instance = CreatedInstance( self.family, subset_name, data, self @@ -53,7 +64,7 @@ class TVPaintWorkfileCreator(TVPaintAutoCreator): self._add_instance_to_context(new_instance) elif ( - existing_instance["asset"] != asset_name + existing_asset_name != asset_name or existing_instance["task"] != task_name ): asset_doc = get_asset_by_name(project_name, asset_name) @@ -65,6 +76,9 @@ class TVPaintWorkfileCreator(TVPaintAutoCreator): host_name, existing_instance ) - existing_instance["asset"] = asset_name + if AYON_SERVER_ENABLED: + existing_instance["folderPath"] = asset_name + else: + existing_instance["asset"] = asset_name existing_instance["task"] = task_name existing_instance["subset"] = subset_name diff --git a/openpype/hosts/tvpaint/plugins/publish/collect_render_instances.py b/openpype/hosts/tvpaint/plugins/publish/collect_render_instances.py index e89fbf7882..577e6e30e2 100644 --- a/openpype/hosts/tvpaint/plugins/publish/collect_render_instances.py +++ b/openpype/hosts/tvpaint/plugins/publish/collect_render_instances.py @@ -73,7 +73,7 @@ class CollectRenderInstances(pyblish.api.InstancePlugin): render_layer_id = creator_attributes["render_layer_instance_id"] for in_data in instance.context.data["workfileInstances"]: if ( - in_data["creator_identifier"] == "render.layer" + in_data.get("creator_identifier") == "render.layer" and in_data["instance_id"] == render_layer_id ): render_layer_data = in_data diff --git a/openpype/hosts/tvpaint/plugins/publish/validate_asset_name.py b/openpype/hosts/tvpaint/plugins/publish/validate_asset_name.py index 9347960d3f..dc29e6c278 100644 --- a/openpype/hosts/tvpaint/plugins/publish/validate_asset_name.py +++ b/openpype/hosts/tvpaint/plugins/publish/validate_asset_name.py @@ -1,4 +1,5 @@ import pyblish.api +from openpype import AYON_SERVER_ENABLED from openpype.pipeline import ( PublishXmlValidationError, OptionalPyblishPluginMixin, @@ -24,12 +25,19 @@ class FixAssetNames(pyblish.api.Action): old_instance_items = list_instances() new_instance_items = [] for instance_item in old_instance_items: - instance_asset_name = instance_item.get("asset") + if AYON_SERVER_ENABLED: + instance_asset_name = instance_item.get("folderPath") + else: + instance_asset_name = instance_item.get("asset") + if ( instance_asset_name and instance_asset_name != context_asset_name ): - instance_item["asset"] = context_asset_name + if AYON_SERVER_ENABLED: + instance_item["folderPath"] = context_asset_name + else: + instance_item["asset"] = context_asset_name new_instance_items.append(instance_item) write_instances(new_instance_items) diff --git a/openpype/lib/__init__.py b/openpype/lib/__init__.py index f1eb564e5e..b3b12ac250 100644 --- a/openpype/lib/__init__.py +++ b/openpype/lib/__init__.py @@ -111,6 +111,7 @@ from .transcoding import ( get_ffmpeg_format_args, convert_ffprobe_fps_value, convert_ffprobe_fps_to_float, + get_rescaled_command_arguments, ) from .local_settings import ( @@ -232,6 +233,7 @@ __all__ = [ "get_ffmpeg_format_args", "convert_ffprobe_fps_value", "convert_ffprobe_fps_to_float", + "get_rescaled_command_arguments", "IniSettingRegistry", "JSONSettingRegistry", diff --git a/openpype/lib/applications.py b/openpype/lib/applications.py index ff5e27c122..4d75a01e1d 100644 --- a/openpype/lib/applications.py +++ b/openpype/lib/applications.py @@ -12,6 +12,7 @@ from abc import ABCMeta, abstractmethod import six from openpype import AYON_SERVER_ENABLED, PACKAGE_DIR +from openpype.client import get_asset_name_identifier from openpype.settings import ( get_system_settings, get_project_settings, @@ -1728,7 +1729,9 @@ def prepare_context_environments(data, env_group=None, modules_manager=None): "AVALON_APP_NAME": app.full_name } if asset_doc: - context_env["AVALON_ASSET"] = asset_doc["name"] + asset_name = get_asset_name_identifier(asset_doc) + context_env["AVALON_ASSET"] = asset_name + if task_name: context_env["AVALON_TASK"] = task_name diff --git a/openpype/lib/openpype_version.py b/openpype/lib/openpype_version.py index 1c8356d5fe..5618eb0c2e 100644 --- a/openpype/lib/openpype_version.py +++ b/openpype/lib/openpype_version.py @@ -140,7 +140,7 @@ def is_running_staging(): latest_version = get_latest_version(local=False, remote=True) staging_version = latest_version - if current_version == production_version: + if current_version == staging_version: return True return is_staging_enabled() diff --git a/openpype/lib/transcoding.py b/openpype/lib/transcoding.py index 97c8dd41ab..316dedbd3d 100644 --- a/openpype/lib/transcoding.py +++ b/openpype/lib/transcoding.py @@ -536,7 +536,7 @@ def convert_for_ffmpeg( input_frame_end=None, logger=None ): - """Contert source file to format supported in ffmpeg. + """Convert source file to format supported in ffmpeg. Currently can convert only exrs. @@ -592,29 +592,7 @@ def convert_for_ffmpeg( oiio_cmd.extend(["--compression", compression]) # Collect channels to export - channel_names = input_info["channelnames"] - review_channels = get_convert_rgb_channels(channel_names) - if review_channels is None: - raise ValueError( - "Couldn't find channels that can be used for conversion." - ) - - red, green, blue, alpha = review_channels - input_channels = [red, green, blue] - channels_arg = "R={},G={},B={}".format(red, green, blue) - if alpha is not None: - channels_arg += ",A={}".format(alpha) - input_channels.append(alpha) - input_channels_str = ",".join(input_channels) - - subimages = input_info.get("subimages") - input_arg = "-i" - if subimages is None or subimages == 1: - # Tell oiiotool which channels should be loaded - # - other channels are not loaded to memory so helps to avoid memory - # leak issues - # - this option is crashing if used on multipart/subimages exrs - input_arg += ":ch={}".format(input_channels_str) + input_arg, channels_arg = get_oiio_input_and_channel_args(input_info) oiio_cmd.extend([ input_arg, first_input_path, @@ -635,7 +613,7 @@ def convert_for_ffmpeg( continue # Remove attributes that have string value longer than allowed length - # for ffmpeg or when contain unallowed symbols + # for ffmpeg or when contain prohibited symbols erase_reason = "Missing reason" erase_attribute = False if len(attr_value) > MAX_FFMPEG_STRING_LEN: @@ -695,7 +673,7 @@ def convert_input_paths_for_ffmpeg( Args: input_paths (str): Paths that should be converted. It is expected that - contains single file or image sequence of samy type. + contains single file or image sequence of same type. output_dir (str): Path to directory where output will be rendered. Must not be same as input's directory. logger (logging.Logger): Logger used for logging. @@ -709,6 +687,7 @@ def convert_input_paths_for_ffmpeg( first_input_path = input_paths[0] ext = os.path.splitext(first_input_path)[1].lower() + if ext != ".exr": raise ValueError(( "Function 'convert_for_ffmpeg' currently support only" @@ -724,30 +703,7 @@ def convert_input_paths_for_ffmpeg( compression = "none" # Collect channels to export - channel_names = input_info["channelnames"] - review_channels = get_convert_rgb_channels(channel_names) - if review_channels is None: - raise ValueError( - "Couldn't find channels that can be used for conversion." - ) - - red, green, blue, alpha = review_channels - input_channels = [red, green, blue] - # TODO find subimage inder where rgba is available for multipart exrs - channels_arg = "R={},G={},B={}".format(red, green, blue) - if alpha is not None: - channels_arg += ",A={}".format(alpha) - input_channels.append(alpha) - input_channels_str = ",".join(input_channels) - - subimages = input_info.get("subimages") - input_arg = "-i" - if subimages is None or subimages == 1: - # Tell oiiotool which channels should be loaded - # - other channels are not loaded to memory so helps to avoid memory - # leak issues - # - this option is crashing if used on multipart exrs - input_arg += ":ch={}".format(input_channels_str) + input_arg, channels_arg = get_oiio_input_and_channel_args(input_info) for input_path in input_paths: # Prepare subprocess arguments @@ -774,7 +730,7 @@ def convert_input_paths_for_ffmpeg( continue # Remove attributes that have string value longer than allowed - # length for ffmpeg or when containing unallowed symbols + # length for ffmpeg or when containing prohibited symbols erase_reason = "Missing reason" erase_attribute = False if len(attr_value) > MAX_FFMPEG_STRING_LEN: @@ -1021,9 +977,7 @@ def _ffmpeg_h264_codec_args(stream_data, source_ffmpeg_cmd): if pix_fmt: output.extend(["-pix_fmt", pix_fmt]) - output.extend(["-intra"]) - output.extend(["-g", "1"]) - + output.extend(["-intra", "-g", "1"]) return output @@ -1150,7 +1104,7 @@ def convert_colorspace( view=None, display=None, additional_command_args=None, - logger=None + logger=None, ): """Convert source file from one color space to another. @@ -1169,6 +1123,7 @@ def convert_colorspace( view (str): name for viewer space (ocio valid) both 'view' and 'display' must be filled (if 'target_colorspace') display (str): name for display-referred reference space (ocio valid) + both 'view' and 'display' must be filled (if 'target_colorspace') additional_command_args (list): arguments for oiiotool (like binary depth for .dpx) logger (logging.Logger): Logger used for logging. @@ -1178,14 +1133,28 @@ def convert_colorspace( if logger is None: logger = logging.getLogger(__name__) + input_info = get_oiio_info_for_input(input_path, logger=logger) + + # Collect channels to export + input_arg, channels_arg = get_oiio_input_and_channel_args(input_info) + + # Prepare subprocess arguments oiio_cmd = get_oiio_tool_args( "oiiotool", - input_path, # Don't add any additional attributes "--nosoftwareattrib", "--colorconfig", config_path ) + oiio_cmd.extend([ + input_arg, input_path, + # Tell oiiotool which channels should be put to top stack + # (and output) + "--ch", channels_arg, + # Use first subimage + "--subimage", "0" + ]) + if all([target_colorspace, view, display]): raise ValueError("Colorspace and both screen and display" " cannot be set together." @@ -1226,3 +1195,221 @@ def split_cmd_args(in_args): continue splitted_args.extend(arg.split(" ")) return splitted_args + + +def get_rescaled_command_arguments( + application, + input_path, + target_width, + target_height, + target_par=None, + bg_color=None, + log=None +): + """Get command arguments for rescaling input to target size. + + Args: + application (str): Application for which command should be created. + Currently supported are "ffmpeg" and "oiiotool". + input_path (str): Path to input file. + target_width (int): Width of target. + target_height (int): Height of target. + target_par (Optional[float]): Pixel aspect ratio of target. + bg_color (Optional[list[int]]): List of 8bit int values for + background color. Should be in range 0 - 255. + log (Optional[logging.Logger]): Logger used for logging. + + Returns: + list[str]: List of command arguments. + """ + command_args = [] + target_par = target_par or 1.0 + input_par = 1.0 + + # ffmpeg command + input_file_metadata = get_ffprobe_data(input_path, logger=log) + stream = input_file_metadata["streams"][0] + input_width = int(stream["width"]) + input_height = int(stream["height"]) + stream_input_par = stream.get("sample_aspect_ratio") + if stream_input_par: + input_par = ( + float(stream_input_par.split(":")[0]) + / float(stream_input_par.split(":")[1]) + ) + # recalculating input and target width + input_width = int(input_width * input_par) + target_width = int(target_width * target_par) + + # calculate aspect ratios + target_aspect = float(target_width) / target_height + input_aspect = float(input_width) / input_height + + # calculate scale size + scale_size = float(input_width) / target_width + if input_aspect < target_aspect: + scale_size = float(input_height) / target_height + + # calculate rescaled width and height + rescaled_width = int(input_width / scale_size) + rescaled_height = int(input_height / scale_size) + + # calculate width and height shift + rescaled_width_shift = int((target_width - rescaled_width) / 2) + rescaled_height_shift = int((target_height - rescaled_height) / 2) + + if application == "ffmpeg": + # create scale command + scale = "scale={0}:{1}".format(input_width, input_height) + pad = "pad={0}:{1}:({2}-iw)/2:({3}-ih)/2".format( + target_width, + target_height, + target_width, + target_height + ) + if input_width > target_width or input_height > target_height: + scale = "scale={0}:{1}".format(rescaled_width, rescaled_height) + pad = "pad={0}:{1}:{2}:{3}".format( + target_width, + target_height, + rescaled_width_shift, + rescaled_height_shift + ) + + if bg_color: + color = convert_color_values(application, bg_color) + pad += ":{0}".format(color) + command_args.extend(["-vf", "{0},{1}".format(scale, pad)]) + + elif application == "oiiotool": + input_info = get_oiio_info_for_input(input_path, logger=log) + # Collect channels to export + _, channels_arg = get_oiio_input_and_channel_args( + input_info, alpha_default=1.0) + + command_args.extend([ + # Tell oiiotool which channels should be put to top stack + # (and output) + "--ch", channels_arg, + # Use first subimage + "--subimage", "0" + ]) + + if input_par != 1.0: + command_args.extend(["--pixelaspect", "1"]) + + width_shift = int((target_width - input_width) / 2) + height_shift = int((target_height - input_height) / 2) + + # default resample is not scaling source image + resample = [ + "--resize", + "{0}x{1}".format(input_width, input_height), + "--origin", + "+{0}+{1}".format(width_shift, height_shift), + ] + # scaled source image to target size + if input_width > target_width or input_height > target_height: + # form resample command + resample = [ + "--resize:filter=lanczos3", + "{0}x{1}".format(rescaled_width, rescaled_height), + "--origin", + "+{0}+{1}".format(rescaled_width_shift, rescaled_height_shift), + ] + command_args.extend(resample) + + fullsize = [ + "--fullsize", + "{0}x{1}".format(target_width, target_height) + ] + if bg_color: + color = convert_color_values(application, bg_color) + + fullsize.extend([ + "--pattern", + "constant:color={0}".format(color), + "{0}x{1}".format(target_width, target_height), + "4", # 4 channels + "--over" + ]) + command_args.extend(fullsize) + + else: + raise ValueError( + "\"application\" input argument should " + "be either \"ffmpeg\" or \"oiiotool\"" + ) + + return command_args + + +def convert_color_values(application, color_value): + """Get color mapping for ffmpeg and oiiotool. + Args: + application (str): Application for which command should be created. + color_value (list[int]): List of 8bit int values for RGBA. + Returns: + str: ffmpeg returns hex string, oiiotool is string with floats. + """ + red, green, blue, alpha = color_value + + if application == "ffmpeg": + return "{0:0>2X}{1:0>2X}{2:0>2X}@{3}".format( + red, green, blue, (alpha / 255.0) + ) + elif application == "oiiotool": + red = float(red / 255) + green = float(green / 255) + blue = float(blue / 255) + alpha = float(alpha / 255) + + return "{0:.3f},{1:.3f},{2:.3f},{3:.3f}".format( + red, green, blue, alpha) + else: + raise ValueError( + "\"application\" input argument should " + "be either \"ffmpeg\" or \"oiiotool\"" + ) + + +def get_oiio_input_and_channel_args(oiio_input_info, alpha_default=None): + """Get input and channel arguments for oiiotool. + Args: + oiio_input_info (dict): Information about input from oiio tool. + Should be output of function `get_oiio_info_for_input`. + alpha_default (float, optional): Default value for alpha channel. + Returns: + tuple[str, str]: Tuple of input and channel arguments. + """ + channel_names = oiio_input_info["channelnames"] + review_channels = get_convert_rgb_channels(channel_names) + + if review_channels is None: + raise ValueError( + "Couldn't find channels that can be used for conversion." + ) + + red, green, blue, alpha = review_channels + input_channels = [red, green, blue] + + channels_arg = "R={0},G={1},B={2}".format(red, green, blue) + if alpha is not None: + channels_arg += ",A={}".format(alpha) + input_channels.append(alpha) + elif alpha_default: + channels_arg += ",A={}".format(float(alpha_default)) + input_channels.append("A") + + input_channels_str = ",".join(input_channels) + + subimages = oiio_input_info.get("subimages") + input_arg = "-i" + if subimages is None or subimages == 1: + # Tell oiiotool which channels should be loaded + # - other channels are not loaded to memory so helps to avoid memory + # leak issues + # - this option is crashing if used on multipart exrs + input_arg += ":ch={}".format(input_channels_str) + + return input_arg, channels_arg diff --git a/openpype/modules/__init__.py b/openpype/modules/__init__.py index 1f345feea9..3097805353 100644 --- a/openpype/modules/__init__.py +++ b/openpype/modules/__init__.py @@ -10,6 +10,7 @@ from .interfaces import ( ) from .base import ( + AYONAddon, OpenPypeModule, OpenPypeAddOn, @@ -35,6 +36,7 @@ __all__ = ( "ISettingsChangeListener", "IHostAddon", + "AYONAddon", "OpenPypeModule", "OpenPypeAddOn", diff --git a/openpype/modules/asset_reporter/__init__.py b/openpype/modules/asset_reporter/__init__.py new file mode 100644 index 0000000000..6267b4824b --- /dev/null +++ b/openpype/modules/asset_reporter/__init__.py @@ -0,0 +1,8 @@ +from .module import ( + AssetReporterAction +) + + +__all__ = ( + "AssetReporterAction", +) diff --git a/openpype/modules/asset_reporter/module.py b/openpype/modules/asset_reporter/module.py new file mode 100644 index 0000000000..8c754cc3c0 --- /dev/null +++ b/openpype/modules/asset_reporter/module.py @@ -0,0 +1,27 @@ +import os.path + +from openpype import AYON_SERVER_ENABLED +from openpype.modules import OpenPypeModule, ITrayAction +from openpype.lib import run_detached_process, get_openpype_execute_args + + +class AssetReporterAction(OpenPypeModule, ITrayAction): + + label = "Asset Usage Report" + name = "asset_reporter" + + def tray_init(self): + pass + + def initialize(self, modules_settings): + self.enabled = not AYON_SERVER_ENABLED + + def on_action_trigger(self): + args = get_openpype_execute_args() + args += ["run", + os.path.join( + os.path.dirname(__file__), + "window.py")] + + print(" ".join(args)) + run_detached_process(args) diff --git a/openpype/modules/asset_reporter/window.py b/openpype/modules/asset_reporter/window.py new file mode 100644 index 0000000000..ed3bc298e1 --- /dev/null +++ b/openpype/modules/asset_reporter/window.py @@ -0,0 +1,418 @@ +"""Tool for generating asset usage report. + +This tool is used to generate asset usage report for a project. +It is using links between published version to find out where +the asset is used. + +""" + +import csv +import time + +import appdirs +import qtawesome +from pymongo.collection import Collection +from qtpy import QtCore, QtWidgets +from qtpy.QtGui import QClipboard, QColor + +from openpype import style +from openpype.client import OpenPypeMongoConnection +from openpype.lib import JSONSettingRegistry +from openpype.tools.utils import PlaceholderLineEdit, get_openpype_qt_app +from openpype.tools.utils.constants import PROJECT_NAME_ROLE +from openpype.tools.utils.models import ProjectModel, ProjectSortFilterProxy + + +class AssetReporterRegistry(JSONSettingRegistry): + """Class handling OpenPype general settings registry. + + This is used to store last selected project. + + Attributes: + vendor (str): Name used for path construction. + product (str): Additional name used for path construction. + + """ + + def __init__(self): + self.vendor = "ynput" + self.product = "openpype" + name = "asset_usage_reporter" + path = appdirs.user_data_dir(self.product, self.vendor) + super(AssetReporterRegistry, self).__init__(name, path) + + +class OverlayWidget(QtWidgets.QFrame): + """Overlay widget for choosing project. + + This code is taken from the Tray Publisher tool. + """ + project_selected = QtCore.Signal(str) + + def __init__(self, publisher_window): + super(OverlayWidget, self).__init__(publisher_window) + self.setObjectName("OverlayFrame") + + middle_frame = QtWidgets.QFrame(self) + middle_frame.setObjectName("ChooseProjectFrame") + + content_widget = QtWidgets.QWidget(middle_frame) + + header_label = QtWidgets.QLabel("Choose project", content_widget) + header_label.setObjectName("ChooseProjectLabel") + # Create project models and view + projects_model = ProjectModel() + projects_proxy = ProjectSortFilterProxy() + projects_proxy.setSourceModel(projects_model) + projects_proxy.setFilterKeyColumn(0) + + projects_view = QtWidgets.QListView(content_widget) + projects_view.setObjectName("ChooseProjectView") + projects_view.setModel(projects_proxy) + projects_view.setEditTriggers( + QtWidgets.QAbstractItemView.NoEditTriggers + ) + + confirm_btn = QtWidgets.QPushButton("Confirm", content_widget) + cancel_btn = QtWidgets.QPushButton("Cancel", content_widget) + cancel_btn.setVisible(False) + btns_layout = QtWidgets.QHBoxLayout() + btns_layout.addStretch(1) + btns_layout.addWidget(cancel_btn, 0) + btns_layout.addWidget(confirm_btn, 0) + + txt_filter = PlaceholderLineEdit(content_widget) + txt_filter.setPlaceholderText("Quick filter projects..") + txt_filter.setClearButtonEnabled(True) + txt_filter.addAction(qtawesome.icon("fa.filter", color="gray"), + QtWidgets.QLineEdit.LeadingPosition) + + content_layout = QtWidgets.QVBoxLayout(content_widget) + content_layout.setContentsMargins(0, 0, 0, 0) + content_layout.setSpacing(20) + content_layout.addWidget(header_label, 0) + content_layout.addWidget(txt_filter, 0) + content_layout.addWidget(projects_view, 1) + content_layout.addLayout(btns_layout, 0) + + middle_layout = QtWidgets.QHBoxLayout(middle_frame) + middle_layout.setContentsMargins(30, 30, 10, 10) + middle_layout.addWidget(content_widget) + + main_layout = QtWidgets.QHBoxLayout(self) + main_layout.setContentsMargins(10, 10, 10, 10) + main_layout.addStretch(1) + main_layout.addWidget(middle_frame, 2) + main_layout.addStretch(1) + + projects_view.doubleClicked.connect(self._on_double_click) + confirm_btn.clicked.connect(self._on_confirm_click) + cancel_btn.clicked.connect(self._on_cancel_click) + txt_filter.textChanged.connect(self._on_text_changed) + + self._projects_view = projects_view + self._projects_model = projects_model + self._projects_proxy = projects_proxy + self._cancel_btn = cancel_btn + self._confirm_btn = confirm_btn + self._txt_filter = txt_filter + + self._publisher_window = publisher_window + self._project_name = None + + def showEvent(self, event): + self._projects_model.refresh() + # Sort projects after refresh + self._projects_proxy.sort(0) + + setting_registry = AssetReporterRegistry() + try: + project_name = str(setting_registry.get_item("project_name")) + except ValueError: + project_name = None + + if project_name: + index = None + src_index = self._projects_model.find_project(project_name) + if src_index is not None: + index = self._projects_proxy.mapFromSource(src_index) + + if index is not None: + selection_model = self._projects_view.selectionModel() + selection_model.select( + index, + QtCore.QItemSelectionModel.SelectCurrent + ) + self._projects_view.setCurrentIndex(index) + + self._cancel_btn.setVisible(self._project_name is not None) + super(OverlayWidget, self).showEvent(event) + + def _on_double_click(self): + self.set_selected_project() + + def _on_confirm_click(self): + self.set_selected_project() + + def _on_cancel_click(self): + self._set_project(self._project_name) + + def _on_text_changed(self): + self._projects_proxy.setFilterRegularExpression( + self._txt_filter.text()) + + def set_selected_project(self): + index = self._projects_view.currentIndex() + + if project_name := index.data(PROJECT_NAME_ROLE): + self._set_project(project_name) + + def _set_project(self, project_name): + self._project_name = project_name + self.setVisible(False) + self.project_selected.emit(project_name) + + setting_registry = AssetReporterRegistry() + setting_registry.set_item("project_name", project_name) + + +class AssetReporterWindow(QtWidgets.QDialog): + default_width = 1000 + default_height = 800 + _content = None + + def __init__(self, parent=None, controller=None, reset_on_show=None): + super(AssetReporterWindow, self).__init__(parent) + + self._result = {} + self.setObjectName("AssetReporterWindow") + + self.setWindowTitle("Asset Usage Reporter") + + if parent is None: + on_top_flag = QtCore.Qt.WindowStaysOnTopHint + else: + on_top_flag = QtCore.Qt.Dialog + + self.setWindowFlags( + QtCore.Qt.WindowTitleHint + | QtCore.Qt.WindowMaximizeButtonHint + | QtCore.Qt.WindowMinimizeButtonHint + | QtCore.Qt.WindowCloseButtonHint + | on_top_flag + ) + self.table = QtWidgets.QTableWidget(self) + self.table.setColumnCount(3) + self.table.setColumnWidth(0, 400) + self.table.setColumnWidth(1, 300) + self.table.setHorizontalHeaderLabels(["Subset", "Used in", "Version"]) + + # self.text_area = QtWidgets.QTextEdit(self) + self.copy_button = QtWidgets.QPushButton('Copy to Clipboard', self) + self.save_button = QtWidgets.QPushButton('Save to CSV File', self) + + self.copy_button.clicked.connect(self.copy_to_clipboard) + self.save_button.clicked.connect(self.save_to_file) + + layout = QtWidgets.QVBoxLayout(self) + layout.addWidget(self.table) + # layout.addWidget(self.text_area) + layout.addWidget(self.copy_button) + layout.addWidget(self.save_button) + + self.resize(self.default_width, self.default_height) + self.setStyleSheet(style.load_stylesheet()) + + overlay_widget = OverlayWidget(self) + overlay_widget.project_selected.connect(self._on_project_select) + self._overlay_widget = overlay_widget + + def _on_project_select(self, project_name: str): + """Generate table when project is selected. + + This will generate the table and fill it with data. + Source data are held in memory in `_result` attribute that + is used to transform them into clipboard or csv file. + """ + self._project_name = project_name + self.process() + if not self._result: + self.set_content("no result generated") + return + + rows = sum(len(value) for key, value in self._result.items()) + self.table.setRowCount(rows) + + row = 0 + content = [] + for key, value in self._result.items(): + item = QtWidgets.QTableWidgetItem(key) + # this doesn't work as it is probably overriden by stylesheet? + # item.setBackground(QColor(32, 32, 32)) + self.table.setItem(row, 0, item) + for source in value: + self.table.setItem( + row, 1, QtWidgets.QTableWidgetItem(source["name"])) + self.table.setItem( + row, 2, QtWidgets.QTableWidgetItem( + str(source["version"]))) + row += 1 + + # generate clipboard content + content.append(key) + content.extend( + f"\t{source['name']} (v{source['version']})" for source in value # noqa: E501 + ) + self.set_content("\n".join(content)) + + def copy_to_clipboard(self): + clipboard = QtWidgets.QApplication.clipboard() + clipboard.setText(self._content, QClipboard.Clipboard) + + def save_to_file(self): + file_name, _ = QtWidgets.QFileDialog.getSaveFileName(self, 'Save File') + if file_name: + self._write_csv(file_name) + + def set_content(self, content): + self._content = content + + def get_content(self): + return self._content + + def _resize_overlay(self): + self._overlay_widget.resize( + self.width(), + self.height() + ) + + def resizeEvent(self, event): + super(AssetReporterWindow, self).resizeEvent(event) + self._resize_overlay() + + def _get_subset(self, version_id, project: Collection): + pipeline = [ + { + "$match": { + "_id": version_id + }, + }, { + "$lookup": { + "from": project.name, + "localField": "parent", + "foreignField": "_id", + "as": "parents" + } + } + ] + + result = project.aggregate(pipeline) + doc = next(result) + # print(doc) + return { + "name": f'{"/".join(doc["parents"][0]["data"]["parents"])}/{doc["parents"][0]["name"]}/{doc["name"]}', # noqa: E501 + "family": doc["data"].get("family") or doc["data"].get("families")[0] # noqa: E501 + } + + def process(self): + """Generate asset usage report data. + + This is the main method of the tool. It is using MongoDB + aggregation pipeline to find all published versions that + are used as input for other published versions. Then it + generates a map of assets and their usage. + + """ + start = time.perf_counter() + project = self._project_name + + # get all versions of published workfiles that has non-empty + # inputLinks and connect it with their respective documents + # using ID. + pipeline = [ + { + "$match": { + "data.inputLinks": { + "$exists": True, + "$ne": [] + }, + "data.families": {"$in": ["workfile"]} + } + }, { + "$lookup": { + "from": project, + "localField": "data.inputLinks.id", + "foreignField": "_id", + "as": "linked_docs" + } + } + ] + + client = OpenPypeMongoConnection.get_mongo_client() + db = client["avalon"] + + result = db[project].aggregate(pipeline) + + asset_map = [] + # this is creating the map - for every workfile and its linked + # documents, create a dictionary with "source" and "refs" keys + # and resolve the subset name and version from the document + for doc in result: + source = { + "source": self._get_subset(doc["parent"], db[project]), + } + source["source"].update({"version": doc["name"]}) + refs = [] + version = '' + for linked in doc["linked_docs"]: + try: + version = f'v{linked["name"]}' + except KeyError: + if linked["type"] == "hero_version": + version = "hero" + finally: + refs.append({ + "subset": self._get_subset( + linked["parent"], db[project]), + "version": version + }) + + source["refs"] = refs + asset_map.append(source) + + grouped = {} + + # this will group the assets by subset name and version + for asset in asset_map: + for ref in asset["refs"]: + key = f'{ref["subset"]["name"]} ({ref["version"]})' + if key in grouped: + grouped[key].append(asset["source"]) + else: + grouped[key] = [asset["source"]] + self._result = grouped + + end = time.perf_counter() + + print(f"Finished in {end - start:0.4f} seconds", 2) + + def _write_csv(self, file_name: str) -> None: + """Write CSV file with results.""" + with open(file_name, "w", newline="") as csvfile: + writer = csv.writer(csvfile, delimiter=";") + writer.writerow(["Subset", "Used in", "Version"]) + for key, value in self._result.items(): + writer.writerow([key, "", ""]) + for source in value: + writer.writerow(["", source["name"], source["version"]]) + + +def main(): + app_instance = get_openpype_qt_app() + window = AssetReporterWindow() + window.show() + app_instance.exec_() + + +if __name__ == "__main__": + main() diff --git a/openpype/modules/base.py b/openpype/modules/base.py index 4636906cec..1a2513b4b4 100644 --- a/openpype/modules/base.py +++ b/openpype/modules/base.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -"""Base class for Pype Modules.""" +"""Base class for AYON addons.""" import copy import os import sys @@ -11,6 +11,7 @@ import platform import threading import collections import traceback + from uuid import uuid4 from abc import ABCMeta, abstractmethod @@ -29,9 +30,12 @@ from openpype.settings import ( from openpype.settings.lib import ( get_studio_system_settings_overrides, - load_json_file + load_json_file, +) +from openpype.settings.ayon_settings import ( + is_dev_mode_enabled, + get_ayon_settings, ) -from openpype.settings.ayon_settings import is_dev_mode_enabled from openpype.lib import ( Logger, @@ -47,11 +51,11 @@ from .interfaces import ( ITrayService ) -# Files that will be always ignored on modules import +# Files that will be always ignored on addons import IGNORED_FILENAMES = ( "__pycache__", ) -# Files ignored on modules import from "./openpype/modules" +# Files ignored on addons import from "./openpype/modules" IGNORED_DEFAULT_FILENAMES = ( "__init__.py", "base.py", @@ -59,8 +63,8 @@ IGNORED_DEFAULT_FILENAMES = ( "example_addons", "default_modules", ) -# Modules that won't be loaded in AYON mode from "./openpype/modules" -# - the same modules are ignored in "./server_addon/create_ayon_addons.py" +# Addons that won't be loaded in AYON mode from "./openpype/modules" +# - the same addons are ignored in "./server_addon/create_ayon_addons.py" IGNORED_FILENAMES_IN_AYON = { "ftrack", "shotgrid", @@ -68,6 +72,10 @@ IGNORED_FILENAMES_IN_AYON = { "slack", "kitsu", } +IGNORED_HOSTS_IN_AYON = { + "flame", + "harmony", +} # Inherit from `object` for Python 2 hosts @@ -466,7 +474,7 @@ def _load_ayon_addons(openpype_modules, modules_key, log): attr = getattr(mod, attr_name) if ( inspect.isclass(attr) - and issubclass(attr, OpenPypeModule) + and issubclass(attr, AYONAddon) ): imported_modules.append(mod) break @@ -536,6 +544,11 @@ def _load_modules(): addons_dir = os.path.join(os.path.dirname(current_dir), "addons") module_dirs.append(addons_dir) + ignored_host_names = set(IGNORED_HOSTS_IN_AYON) + ignored_current_dir_filenames = set(IGNORED_DEFAULT_FILENAMES) + if AYON_SERVER_ENABLED: + ignored_current_dir_filenames |= IGNORED_FILENAMES_IN_AYON + processed_paths = set() for dirpath in frozenset(module_dirs): # Skip already processed paths @@ -551,9 +564,6 @@ def _load_modules(): is_in_current_dir = dirpath == current_dir is_in_host_dir = dirpath == hosts_dir - ignored_current_dir_filenames = set(IGNORED_DEFAULT_FILENAMES) - if AYON_SERVER_ENABLED: - ignored_current_dir_filenames |= IGNORED_FILENAMES_IN_AYON for filename in os.listdir(dirpath): # Ignore filenames @@ -566,6 +576,12 @@ def _load_modules(): ): continue + if ( + is_in_host_dir + and filename in ignored_host_names + ): + continue + fullpath = os.path.join(dirpath, filename) basename, ext = os.path.splitext(filename) @@ -633,26 +649,22 @@ def _load_modules(): @six.add_metaclass(ABCMeta) -class OpenPypeModule: - """Base class of pype module. +class AYONAddon(object): + """Base class of AYON addon. Attributes: - id (UUID): Module's id. - enabled (bool): Is module enabled. - name (str): Module name. - manager (ModulesManager): Manager that created the module. + id (UUID): Addon object id. + enabled (bool): Is addon enabled. + name (str): Addon name. + + Args: + manager (ModulesManager): Manager object who discovered addon. + settings (dict[str, Any]): AYON settings. """ - # Disable by default - enabled = False + enabled = True _id = None - @property - @abstractmethod - def name(self): - """Module's name.""" - pass - def __init__(self, manager, settings): self.manager = manager @@ -662,22 +674,45 @@ class OpenPypeModule: @property def id(self): + """Random id of addon object. + + Returns: + str: Object id. + """ + if self._id is None: self._id = uuid4() return self._id + @property @abstractmethod - def initialize(self, module_settings): - """Initialization of module attributes. + def name(self): + """Addon name. - It is not recommended to override __init__ that's why specific method - was implemented. + Returns: + str: Addon name. """ pass - def connect_with_modules(self, enabled_modules): - """Connect with other enabled modules.""" + def initialize(self, settings): + """Initialization of module attributes. + + It is not recommended to override __init__ that's why specific method + was implemented. + + Args: + settings (dict[str, Any]): Settings. + """ + + pass + + def connect_with_modules(self, enabled_addons): + """Connect with other enabled addons. + + Args: + enabled_addons (list[AYONAddon]): Addons that are enabled. + """ pass @@ -685,6 +720,9 @@ class OpenPypeModule: """Get global environments values of module. Environment variables that can be get only from system settings. + + Returns: + dict[str, str]: Environment variables. """ return {} @@ -697,7 +735,7 @@ class OpenPypeModule: Args: application (Application): Application that is launched. - env (dict): Current environment variables. + env (dict[str, str]): Current environment variables. """ pass @@ -713,7 +751,8 @@ class OpenPypeModule: to receive from 'host' object. Args: - host (ModuleType): Access to installed/registered host object. + host (Union[ModuleType, HostBase]): Access to installed/registered + host object. host_name (str): Name of host. project_name (str): Project name which is main part of host context. @@ -727,47 +766,66 @@ class OpenPypeModule: The best practise is to create click group for whole module which is used to separate commands. - class MyPlugin(OpenPypeModule): - ... - def cli(self, module_click_group): - module_click_group.add_command(cli_main) + Example: + class MyPlugin(AYONAddon): + ... + def cli(self, module_click_group): + module_click_group.add_command(cli_main) - @click.group(, help="") - def cli_main(): - pass + @click.group(, help="") + def cli_main(): + pass - @cli_main.command() - def mycommand(): - print("my_command") + @cli_main.command() + def mycommand(): + print("my_command") + + Args: + module_click_group (click.Group): Group to which can be added + commands. """ pass +class OpenPypeModule(AYONAddon): + """Base class of OpenPype module. + + Instead of 'AYONAddon' are passed in module settings. + + Args: + manager (ModulesManager): Manager object who discovered addon. + settings (dict[str, Any]): OpenPype settings. + """ + + # Disable by default + enabled = False + + class OpenPypeAddOn(OpenPypeModule): # Enable Addon by default enabled = True - def initialize(self, module_settings): - """Initialization is not be required for most of addons.""" - pass - class ModulesManager: """Manager of Pype modules helps to load and prepare them to work. Args: - modules_settings(dict): To be able create module manager with specified - data. For settings changes callbacks and testing purposes. + system_settings (Optional[dict[str, Any]]): OpenPype system settings. + ayon_settings (Optional[dict[str, Any]]): AYON studio settings. """ + # Helper attributes for report _report_total_key = "Total" + _system_settings = None + _ayon_settings = None - def __init__(self, _system_settings=None): + def __init__(self, system_settings=None, ayon_settings=None): self.log = logging.getLogger(self.__class__.__name__) - self._system_settings = _system_settings + self._system_settings = system_settings + self._ayon_settings = ayon_settings self.modules = [] self.modules_by_id = {} @@ -789,8 +847,9 @@ class ModulesManager: default (Any): Default output if module is not available. Returns: - Union[OpenPypeModule, None]: Module found by name or None. + Union[AYONAddon, None]: Module found by name or None. """ + return self.modules_by_name.get(module_name, default) def get_enabled_module(self, module_name, default=None): @@ -804,7 +863,7 @@ class ModulesManager: not enabled. Returns: - Union[OpenPypeModule, None]: Enabled module found by name or None. + Union[AYONAddon, None]: Enabled module found by name or None. """ module = self.get(module_name) @@ -819,11 +878,20 @@ class ModulesManager: import openpype_modules - self.log.debug("*** Pype modules initialization.") + self.log.debug("*** {} initialization.".format( + "AYON addons" + if AYON_SERVER_ENABLED + else "OpenPype modules" + )) # Prepare settings for modules - system_settings = getattr(self, "_system_settings", None) + system_settings = self._system_settings if system_settings is None: system_settings = get_system_settings() + + ayon_settings = self._ayon_settings + if AYON_SERVER_ENABLED and ayon_settings is None: + ayon_settings = get_ayon_settings() + modules_settings = system_settings["modules"] report = {} @@ -836,12 +904,13 @@ class ModulesManager: for name in dir(module): modules_item = getattr(module, name, None) # Filter globals that are not classes which inherit from - # OpenPypeModule + # AYONAddon if ( not inspect.isclass(modules_item) + or modules_item is AYONAddon or modules_item is OpenPypeModule or modules_item is OpenPypeAddOn - or not issubclass(modules_item, OpenPypeModule) + or not issubclass(modules_item, AYONAddon) ): continue @@ -866,10 +935,14 @@ class ModulesManager: module_classes.append(modules_item) for modules_item in module_classes: + is_openpype_module = issubclass(modules_item, OpenPypeModule) + settings = ( + modules_settings if is_openpype_module else ayon_settings + ) + name = modules_item.__name__ try: - name = modules_item.__name__ # Try initialize module - module = modules_item(self, modules_settings) + module = modules_item(self, settings) # Store initialized object self.modules.append(module) self.modules_by_id[module.id] = module @@ -924,8 +997,9 @@ class ModulesManager: """Enabled modules initialized by the manager. Returns: - list: Initialized and enabled modules. + list[AYONAddon]: Initialized and enabled modules. """ + return [ module for module in self.modules @@ -1108,7 +1182,7 @@ class ModulesManager: host_name (str): Host name for which is found host module. Returns: - OpenPypeModule: Found host module by name. + AYONAddon: Found host module by name. None: There was not found module inheriting IHostAddon which has host name set to passed 'host_name'. """ @@ -1129,12 +1203,11 @@ class ModulesManager: inheriting 'IHostAddon'. """ - host_names = { + return { module.host_name for module in self.get_enabled_modules() if isinstance(module, IHostAddon) } - return host_names def print_report(self): """Print out report of time spent on modules initialization parts. @@ -1290,6 +1363,10 @@ class TrayModulesManager(ModulesManager): callback can be defined with `doubleclick_callback` attribute. Missing feature how to define default callback. + + Args: + addon (AYONAddon): Addon object. + callback (FunctionType): Function callback. """ callback_name = "_".join([module.name, callback.__name__]) if callback_name not in self.doubleclick_callbacks: @@ -1310,11 +1387,17 @@ class TrayModulesManager(ModulesManager): self.tray_menu(tray_menu) def get_enabled_tray_modules(self): - output = [] - for module in self.modules: - if module.enabled and isinstance(module, ITrayModule): - output.append(module) - return output + """Enabled tray modules. + + Returns: + list[AYONAddon]: Enabled addons that inherit from tray interface. + """ + + return [ + module + for module in self.modules + if module.enabled and isinstance(module, ITrayModule) + ] def restart_tray(self): if self.tray_manager: diff --git a/openpype/modules/deadline/abstract_submit_deadline.py b/openpype/modules/deadline/abstract_submit_deadline.py index 23e959d84c..187feb9b1a 100644 --- a/openpype/modules/deadline/abstract_submit_deadline.py +++ b/openpype/modules/deadline/abstract_submit_deadline.py @@ -460,7 +460,21 @@ class AbstractSubmitDeadline(pyblish.api.InstancePlugin, self.plugin_info = self.get_plugin_info() self.aux_files = self.get_aux_files() - self.process_submission() + job_id = self.process_submission() + self.log.info("Submitted job to Deadline: {}.".format(job_id)) + + # TODO: Find a way that's more generic and not render type specific + if "exportJob" in instance.data: + self.log.info("Splitting export and render in two jobs") + self.log.info("Export job id: %s", job_id) + render_job_info = self.get_job_info(dependency_job_ids=[job_id]) + render_plugin_info = self.get_plugin_info(job_type="render") + payload = self.assemble_payload( + job_info=render_job_info, + plugin_info=render_plugin_info + ) + render_job_id = self.submit(payload) + self.log.info("Render job id: %s", render_job_id) def process_submission(self): """Process data for submission. diff --git a/openpype/modules/deadline/plugins/publish/collect_default_deadline_server.py b/openpype/modules/deadline/plugins/publish/collect_default_deadline_server.py index 58721efad3..cd4cde2519 100644 --- a/openpype/modules/deadline/plugins/publish/collect_default_deadline_server.py +++ b/openpype/modules/deadline/plugins/publish/collect_default_deadline_server.py @@ -2,6 +2,8 @@ """Collect default Deadline server.""" import pyblish.api +from openpype import AYON_SERVER_ENABLED + class CollectDefaultDeadlineServer(pyblish.api.ContextPlugin): """Collect default Deadline Webservice URL. @@ -30,24 +32,26 @@ class CollectDefaultDeadlineServer(pyblish.api.ContextPlugin): self.log.error("Cannot get OpenPype Deadline module.") raise AssertionError("OpenPype Deadline module not found.") - # get default deadline webservice url from deadline module - self.log.debug(deadline_module.deadline_urls) - context.data["defaultDeadline"] = deadline_module.deadline_urls["default"] # noqa: E501 + deadline_settings = context.data["project_settings"]["deadline"] + deadline_server_name = None + if AYON_SERVER_ENABLED: + deadline_server_name = deadline_settings["deadline_server"] + else: + deadline_servers = deadline_settings["deadline_servers"] + if deadline_servers: + deadline_server_name = deadline_servers[0] - context.data["deadlinePassMongoUrl"] = self.pass_mongo_url + context.data["deadlinePassMongoUrl"] = self.pass_mongo_url - deadline_servers = (context.data - ["project_settings"] - ["deadline"] - ["deadline_servers"]) - if deadline_servers: - deadline_server_name = deadline_servers[0] + deadline_webservice = None + if deadline_server_name: deadline_webservice = deadline_module.deadline_urls.get( deadline_server_name) - if deadline_webservice: - context.data["defaultDeadline"] = deadline_webservice - self.log.debug("Overriding from project settings with {}".format( # noqa: E501 - deadline_webservice)) - context.data["defaultDeadline"] = \ - context.data["defaultDeadline"].strip().rstrip("/") + default_deadline_webservice = deadline_module.deadline_urls["default"] + deadline_webservice = ( + deadline_webservice + or default_deadline_webservice + ) + + context.data["defaultDeadline"] = deadline_webservice.strip().rstrip("/") # noqa diff --git a/openpype/modules/deadline/plugins/publish/submit_blender_deadline.py b/openpype/modules/deadline/plugins/publish/submit_blender_deadline.py index 094f2b1821..8f9e9a7425 100644 --- a/openpype/modules/deadline/plugins/publish/submit_blender_deadline.py +++ b/openpype/modules/deadline/plugins/publish/submit_blender_deadline.py @@ -6,8 +6,14 @@ import getpass import attr from datetime import datetime -from openpype.lib import is_running_from_build +from openpype.lib import ( + is_running_from_build, + BoolDef, + NumberDef, + TextDef, +) from openpype.pipeline import legacy_io +from openpype.pipeline.publish import OpenPypePyblishPluginMixin from openpype.pipeline.farm.tools import iter_expected_files from openpype.tests.lib import is_in_tests @@ -22,10 +28,11 @@ class BlenderPluginInfo(): SaveFile = attr.ib(default=True) -class BlenderSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline): +class BlenderSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline, + OpenPypePyblishPluginMixin): label = "Submit Render to Deadline" hosts = ["blender"] - families = ["render.farm"] + families = ["render"] use_published = True priority = 50 @@ -33,6 +40,7 @@ class BlenderSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline): jobInfo = {} pluginInfo = {} group = None + job_delay = "00:00:00:00" def get_job_info(self): job_info = DeadlineJobInfo(Plugin="Blender") @@ -67,8 +75,7 @@ class BlenderSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline): job_info.Pool = instance.data.get("primaryPool") job_info.SecondaryPool = instance.data.get("secondaryPool") - job_info.Comment = context.data.get("comment") - job_info.Priority = instance.data.get("priority", self.priority) + job_info.Comment = instance.data.get("comment") if self.group != "none" and self.group: job_info.Group = self.group @@ -83,8 +90,10 @@ class BlenderSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline): machine_list_key = "Blacklist" render_globals[machine_list_key] = machine_list - job_info.Priority = attr_values.get("priority") - job_info.ChunkSize = attr_values.get("chunkSize") + job_info.ChunkSize = attr_values.get("chunkSize", self.chunk_size) + job_info.Priority = attr_values.get("priority", self.priority) + job_info.ScheduledType = "Once" + job_info.JobDelay = attr_values.get("job_delay", self.job_delay) # Add options from RenderGlobals render_globals = instance.data.get("renderGlobals", {}) @@ -180,3 +189,39 @@ class BlenderSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline): the metadata and the rendered files are in the same location. """ return super().from_published_scene(False) + + @classmethod + def get_attribute_defs(cls): + defs = super(BlenderSubmitDeadline, cls).get_attribute_defs() + defs.extend([ + BoolDef("use_published", + default=cls.use_published, + label="Use Published Scene"), + + NumberDef("priority", + minimum=1, + maximum=250, + decimals=0, + default=cls.priority, + label="Priority"), + + NumberDef("chunkSize", + minimum=1, + maximum=50, + decimals=0, + default=cls.chunk_size, + label="Frame Per Task"), + + TextDef("group", + default=cls.group, + label="Group Name"), + + TextDef("job_delay", + default=cls.job_delay, + label="Job Delay", + placeholder="dd:hh:mm:ss", + tooltip="Delay the job by the specified amount of time. " + "Timecode: dd:hh:mm:ss."), + ]) + + return defs diff --git a/openpype/modules/deadline/plugins/publish/submit_houdini_cache_deadline.py b/openpype/modules/deadline/plugins/publish/submit_houdini_cache_deadline.py new file mode 100644 index 0000000000..ada69575a8 --- /dev/null +++ b/openpype/modules/deadline/plugins/publish/submit_houdini_cache_deadline.py @@ -0,0 +1,194 @@ +import os +import getpass +from datetime import datetime + +import attr +import pyblish.api +from openpype.lib import ( + TextDef, + NumberDef, +) +from openpype.pipeline import ( + legacy_io, + OpenPypePyblishPluginMixin +) +from openpype.tests.lib import is_in_tests +from openpype.lib import is_running_from_build +from openpype_modules.deadline import abstract_submit_deadline +from openpype_modules.deadline.abstract_submit_deadline import DeadlineJobInfo + + +@attr.s +class HoudiniPluginInfo(object): + Build = attr.ib(default=None) + IgnoreInputs = attr.ib(default=True) + ScriptJob = attr.ib(default=True) + SceneFile = attr.ib(default=None) # Input + SaveFile = attr.ib(default=True) + ScriptFilename = attr.ib(default=None) + OutputDriver = attr.ib(default=None) + Version = attr.ib(default=None) # Mandatory for Deadline + ProjectPath = attr.ib(default=None) + + +class HoudiniCacheSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline, # noqa + OpenPypePyblishPluginMixin): + """Submit Houdini scene to perform a local publish in Deadline. + + Publishing in Deadline can be helpful for scenes that publish very slow. + This way it can process in the background on another machine without the + Artist having to wait for the publish to finish on their local machine. + + Submission is done through the Deadline Web Service as + supplied via the environment variable AVALON_DEADLINE. + + """ + + label = "Submit Scene to Deadline" + order = pyblish.api.IntegratorOrder + hosts = ["houdini"] + families = ["publish.hou"] + targets = ["local"] + + priority = 50 + jobInfo = {} + pluginInfo = {} + group = None + + def get_job_info(self): + job_info = DeadlineJobInfo(Plugin="Houdini") + + job_info.update(self.jobInfo) + instance = self._instance + context = instance.context + assert all( + result["success"] for result in context.data["results"] + ), "Errors found, aborting integration.." + + # Deadline connection + AVALON_DEADLINE = legacy_io.Session.get( + "AVALON_DEADLINE", "http://localhost:8082" + ) + assert AVALON_DEADLINE, "Requires AVALON_DEADLINE" + + project_name = instance.context.data["projectName"] + filepath = context.data["currentFile"] + scenename = os.path.basename(filepath) + job_name = "{scene} - {instance} [PUBLISH]".format( + scene=scenename, instance=instance.name) + batch_name = "{code} - {scene}".format(code=project_name, + scene=scenename) + if is_in_tests(): + batch_name += datetime.now().strftime("%d%m%Y%H%M%S") + + job_info.Name = job_name + job_info.BatchName = batch_name + job_info.Plugin = instance.data["plugin"] + job_info.UserName = context.data.get("deadlineUser", getpass.getuser()) + rop_node = self.get_rop_node(instance) + if rop_node.type().name() != "alembic": + frames = "{start}-{end}x{step}".format( + start=int(instance.data["frameStart"]), + end=int(instance.data["frameEnd"]), + step=int(instance.data["byFrameStep"]), + ) + + job_info.Frames = frames + + job_info.Pool = instance.data.get("primaryPool") + job_info.SecondaryPool = instance.data.get("secondaryPool") + + attr_values = self.get_attr_values_from_data(instance.data) + + job_info.ChunkSize = instance.data["chunkSize"] + job_info.Comment = context.data.get("comment") + job_info.Priority = attr_values.get("priority", self.priority) + job_info.Group = attr_values.get("group", self.group) + + keys = [ + "FTRACK_API_KEY", + "FTRACK_API_USER", + "FTRACK_SERVER", + "OPENPYPE_SG_USER", + "AVALON_PROJECT", + "AVALON_ASSET", + "AVALON_TASK", + "AVALON_APP_NAME", + "OPENPYPE_DEV", + "OPENPYPE_LOG_NO_COLORS", + ] + + # Add OpenPype version if we are running from build. + if is_running_from_build(): + keys.append("OPENPYPE_VERSION") + # Add mongo url if it's enabled + if self._instance.context.data.get("deadlinePassMongoUrl"): + keys.append("OPENPYPE_MONGO") + + environment = dict({key: os.environ[key] for key in keys + if key in os.environ}, **legacy_io.Session) + + for key in keys: + value = environment.get(key) + if not value: + continue + job_info.EnvironmentKeyValue[key] = value + # to recognize render jobs + job_info.add_render_job_env_var() + + return job_info + + def get_plugin_info(self): + # Not all hosts can import this module. + import hou + + instance = self._instance + version = hou.applicationVersionString() + version = ".".join(version.split(".")[:2]) + rop = self.get_rop_node(instance) + plugin_info = HoudiniPluginInfo( + Build=None, + IgnoreInputs=True, + ScriptJob=True, + SceneFile=self.scene_path, + SaveFile=True, + OutputDriver=rop.path(), + Version=version, + ProjectPath=os.path.dirname(self.scene_path) + ) + + plugin_payload = attr.asdict(plugin_info) + + return plugin_payload + + def process(self, instance): + super(HoudiniCacheSubmitDeadline, self).process(instance) + output_dir = os.path.dirname(instance.data["files"][0]) + instance.data["outputDir"] = output_dir + instance.data["toBeRenderedOn"] = "deadline" + + def get_rop_node(self, instance): + # Not all hosts can import this module. + import hou + + rop = instance.data.get("instance_node") + rop_node = hou.node(rop) + + return rop_node + + @classmethod + def get_attribute_defs(cls): + defs = super(HoudiniCacheSubmitDeadline, cls).get_attribute_defs() + defs.extend([ + NumberDef("priority", + minimum=1, + maximum=250, + decimals=0, + default=cls.priority, + label="Priority"), + TextDef("group", + default=cls.group, + label="Group Name"), + ]) + + return defs diff --git a/openpype/modules/deadline/plugins/publish/submit_houdini_render_deadline.py b/openpype/modules/deadline/plugins/publish/submit_houdini_render_deadline.py index abc650204b..0c75f632cb 100644 --- a/openpype/modules/deadline/plugins/publish/submit_houdini_render_deadline.py +++ b/openpype/modules/deadline/plugins/publish/submit_houdini_render_deadline.py @@ -5,12 +5,15 @@ from datetime import datetime import pyblish.api -from openpype.pipeline import legacy_io +from openpype.pipeline import legacy_io, OpenPypePyblishPluginMixin from openpype.tests.lib import is_in_tests from openpype_modules.deadline import abstract_submit_deadline from openpype_modules.deadline.abstract_submit_deadline import DeadlineJobInfo -from openpype.lib import is_running_from_build - +from openpype.lib import ( + is_running_from_build, + BoolDef, + NumberDef +) @attr.s class DeadlinePluginInfo(): @@ -20,8 +23,29 @@ class DeadlinePluginInfo(): IgnoreInputs = attr.ib(default=True) -class HoudiniSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline): - """Submit Solaris USD Render ROPs to Deadline. +@attr.s +class ArnoldRenderDeadlinePluginInfo(): + InputFile = attr.ib(default=None) + Verbose = attr.ib(default=4) + + +@attr.s +class MantraRenderDeadlinePluginInfo(): + SceneFile = attr.ib(default=None) + Version = attr.ib(default=None) + + +@attr.s +class VrayRenderPluginInfo(): + InputFilename = attr.ib(default=None) + SeparateFilesPerFrame = attr.ib(default=True) + + +class HoudiniSubmitDeadline( + abstract_submit_deadline.AbstractSubmitDeadline, + OpenPypePyblishPluginMixin +): + """Submit Render ROPs to Deadline. Renders are submitted to a Deadline Web Service as supplied via the environment variable AVALON_DEADLINE. @@ -45,21 +69,95 @@ class HoudiniSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline): targets = ["local"] use_published = True - def get_job_info(self): - job_info = DeadlineJobInfo(Plugin="Houdini") + # presets + priority = 50 + chunk_size = 1 + export_priority = 50 + export_chunk_size = 10 + group = "" + export_group = "" + + @classmethod + def get_attribute_defs(cls): + return [ + NumberDef( + "priority", + label="Priority", + default=cls.priority, + decimals=0 + ), + NumberDef( + "chunk", + label="Frames Per Task", + default=cls.chunk_size, + decimals=0, + minimum=1, + maximum=1000 + ), + NumberDef( + "export_priority", + label="Export Priority", + default=cls.priority, + decimals=0 + ), + NumberDef( + "export_chunk", + label="Export Frames Per Task", + default=cls.export_chunk_size, + decimals=0, + minimum=1, + maximum=1000 + ), + BoolDef( + "suspend_publish", + default=False, + label="Suspend publish" + ) + ] + + def get_job_info(self, dependency_job_ids=None): instance = self._instance context = instance.context + attribute_values = self.get_attr_values_from_data(instance.data) + + # Whether Deadline render submission is being split in two + # (extract + render) + split_render_job = instance.data["exportJob"] + + # If there's some dependency job ids we can assume this is a render job + # and not an export job + is_export_job = True + if dependency_job_ids: + is_export_job = False + + if split_render_job and not is_export_job: + # Convert from family to Deadline plugin name + # i.e., arnold_rop -> Arnold + plugin = instance.data["family"].replace("_rop", "").capitalize() + else: + plugin = "Houdini" + + job_info = DeadlineJobInfo(Plugin=plugin) + filepath = context.data["currentFile"] filename = os.path.basename(filepath) - job_info.Name = "{} - {}".format(filename, instance.name) job_info.BatchName = filename - job_info.Plugin = "Houdini" + job_info.UserName = context.data.get( "deadlineUser", getpass.getuser()) + if split_render_job and is_export_job: + job_info.Priority = attribute_values.get( + "export_priority", self.export_priority + ) + else: + job_info.Priority = attribute_values.get( + "priority", self.priority + ) + if is_in_tests(): job_info.BatchName += datetime.now().strftime("%d%m%Y%H%M%S") @@ -73,9 +171,23 @@ class HoudiniSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline): ) job_info.Frames = frames + # Make sure we make job frame dependent so render tasks pick up a soon + # as export tasks are done + if split_render_job and not is_export_job: + job_info.IsFrameDependent = True + job_info.Pool = instance.data.get("primaryPool") job_info.SecondaryPool = instance.data.get("secondaryPool") - job_info.ChunkSize = instance.data.get("chunkSize", 10) + job_info.Group = self.group + if split_render_job and is_export_job: + job_info.ChunkSize = attribute_values.get( + "export_chunk", self.export_chunk_size + ) + else: + job_info.ChunkSize = attribute_values.get( + "chunk", self.chunk_size + ) + job_info.Comment = context.data.get("comment") keys = [ @@ -101,6 +213,7 @@ class HoudiniSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline): environment = dict({key: os.environ[key] for key in keys if key in os.environ}, **legacy_io.Session) + for key in keys: value = environment.get(key) if value: @@ -115,25 +228,51 @@ class HoudiniSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline): job_info.OutputDirectory += dirname.replace("\\", "/") job_info.OutputFilename += fname + # Add dependencies if given + if dependency_job_ids: + job_info.JobDependencies = ",".join(dependency_job_ids) + return job_info - def get_plugin_info(self): + def get_plugin_info(self, job_type=None): # Not all hosts can import this module. import hou instance = self._instance context = instance.context - # Output driver to render - driver = hou.node(instance.data["instance_node"]) hou_major_minor = hou.applicationVersionString().rsplit(".", 1)[0] - plugin_info = DeadlinePluginInfo( - SceneFile=context.data["currentFile"], - OutputDriver=driver.path(), - Version=hou_major_minor, - IgnoreInputs=True - ) + # Output driver to render + if job_type == "render": + family = instance.data.get("family") + if family == "arnold_rop": + plugin_info = ArnoldRenderDeadlinePluginInfo( + InputFile=instance.data["ifdFile"] + ) + elif family == "mantra_rop": + plugin_info = MantraRenderDeadlinePluginInfo( + SceneFile=instance.data["ifdFile"], + Version=hou_major_minor, + ) + elif family == "vray_rop": + plugin_info = VrayRenderPluginInfo( + InputFilename=instance.data["ifdFile"], + ) + else: + self.log.error( + "Family '%s' not supported yet to split render job", + family + ) + return + else: + driver = hou.node(instance.data["instance_node"]) + plugin_info = DeadlinePluginInfo( + SceneFile=context.data["currentFile"], + OutputDriver=driver.path(), + Version=hou_major_minor, + IgnoreInputs=True + ) return attr.asdict(plugin_info) diff --git a/openpype/modules/deadline/plugins/publish/submit_maya_deadline.py b/openpype/modules/deadline/plugins/publish/submit_maya_deadline.py index 7d532923ff..26a605a744 100644 --- a/openpype/modules/deadline/plugins/publish/submit_maya_deadline.py +++ b/openpype/modules/deadline/plugins/publish/submit_maya_deadline.py @@ -132,6 +132,8 @@ class MayaSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline, cls.group = settings.get("group", cls.group) cls.strict_error_checking = settings.get("strict_error_checking", cls.strict_error_checking) + cls.jobInfo = settings.get("jobInfo", cls.jobInfo) + cls.pluginInfo = settings.get("pluginInfo", cls.pluginInfo) def get_job_info(self): job_info = DeadlineJobInfo(Plugin="MayaBatch") @@ -648,7 +650,7 @@ class MayaSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline, return job_info, attr.asdict(plugin_info) def _get_arnold_render_payload(self, data): - + from maya import cmds # Job Info job_info = copy.deepcopy(self.job_info) job_info.Name = self._job_info_label("Render") diff --git a/openpype/modules/deadline/plugins/publish/submit_nuke_deadline.py b/openpype/modules/deadline/plugins/publish/submit_nuke_deadline.py index fb3ab2710d..d03416ca00 100644 --- a/openpype/modules/deadline/plugins/publish/submit_nuke_deadline.py +++ b/openpype/modules/deadline/plugins/publish/submit_nuke_deadline.py @@ -370,10 +370,6 @@ class NukeSubmitDeadline(pyblish.api.InstancePlugin, environment = dict({key: os.environ[key] for key in keys if key in os.environ}, **legacy_io.Session) - for _path in os.environ: - if _path.lower().startswith('openpype_'): - environment[_path] = os.environ[_path] - # to recognize render jobs if AYON_SERVER_ENABLED: environment["AYON_BUNDLE_NAME"] = os.environ["AYON_BUNDLE_NAME"] @@ -402,7 +398,7 @@ class NukeSubmitDeadline(pyblish.api.InstancePlugin, self.log.debug("Submitting..") self.log.debug(json.dumps(payload, indent=4, sort_keys=True)) - # adding expectied files to instance.data + # adding expected files to instance.data self.expected_files( instance, render_path, @@ -458,7 +454,7 @@ class NukeSubmitDeadline(pyblish.api.InstancePlugin, def expected_files( self, instance, - path, + filepath, start_frame, end_frame ): @@ -467,21 +463,44 @@ class NukeSubmitDeadline(pyblish.api.InstancePlugin, if not instance.data.get("expectedFiles"): instance.data["expectedFiles"] = [] - dirname = os.path.dirname(path) - file = os.path.basename(path) + dirname = os.path.dirname(filepath) + file = os.path.basename(filepath) + # since some files might be already tagged as publish_on_farm + # we need to avoid adding them to expected files since those would be + # duplicated into metadata.json file + representations = instance.data.get("representations", []) + # check if file is not in representations with publish_on_farm tag + for repre in representations: + # Skip if 'publish_on_farm' not available + if "publish_on_farm" not in repre.get("tags", []): + continue + + # in case where single file (video, image) is already in + # representation file. Will be added to expected files via + # submit_publish_job.py + if file in repre.get("files", []): + self.log.debug( + "Skipping expected file: {}".format(filepath)) + return + + # in case path is hashed sequence expression + # (e.g. /path/to/file.####.png) if "#" in file: pparts = file.split("#") padding = "%0{}d".format(len(pparts) - 1) file = pparts[0] + padding + pparts[-1] + # in case input path was single file (video or image) if "%" not in file: - instance.data["expectedFiles"].append(path) + instance.data["expectedFiles"].append(filepath) return + # shift start frame by 1 if slate is present if instance.data.get("slate"): start_frame -= 1 + # add sequence files to expected files for i in range(start_frame, (end_frame + 1)): instance.data["expectedFiles"].append( os.path.join(dirname, (file % i)).replace("\\", "/")) diff --git a/openpype/modules/deadline/plugins/publish/submit_publish_cache_job.py b/openpype/modules/deadline/plugins/publish/submit_publish_cache_job.py new file mode 100644 index 0000000000..b2ebebc303 --- /dev/null +++ b/openpype/modules/deadline/plugins/publish/submit_publish_cache_job.py @@ -0,0 +1,506 @@ +# -*- coding: utf-8 -*- +"""Submit publishing job to farm.""" +import os +import json +import re +from copy import deepcopy +import requests + +import pyblish.api + +from openpype import AYON_SERVER_ENABLED +from openpype.client import ( + get_last_version_by_subset_name, +) +from openpype.pipeline import publish, legacy_io +from openpype.lib import EnumDef, is_running_from_build +from openpype.tests.lib import is_in_tests +from openpype.pipeline.version_start import get_versioning_start + +from openpype.pipeline.farm.pyblish_functions import ( + create_skeleton_instance_cache, + create_instances_for_cache, + attach_instances_to_subset, + prepare_cache_representations, + create_metadata_path +) + + +class ProcessSubmittedCacheJobOnFarm(pyblish.api.InstancePlugin, + publish.OpenPypePyblishPluginMixin, + publish.ColormanagedPyblishPluginMixin): + """Process Cache Job submitted on farm + This is replicated version of submit publish job + specifically for cache(s). + + These jobs are dependent on a deadline job + submission prior to this plug-in. + + - In case of Deadline, it creates dependent job on farm publishing + rendered image sequence. + + Options in instance.data: + - deadlineSubmissionJob (dict, Required): The returned .json + data from the job submission to deadline. + + - outputDir (str, Required): The output directory where the metadata + file should be generated. It's assumed that this will also be + final folder containing the output files. + + - ext (str, Optional): The extension (including `.`) that is required + in the output filename to be picked up for image sequence + publishing. + + - expectedFiles (list or dict): explained below + + """ + + label = "Submit cache jobs to Deadline" + order = pyblish.api.IntegratorOrder + 0.2 + icon = "tractor" + + targets = ["local"] + + hosts = ["houdini"] + + families = ["publish.hou"] + + environ_job_filter = [ + "OPENPYPE_METADATA_FILE" + ] + + environ_keys = [ + "FTRACK_API_USER", + "FTRACK_API_KEY", + "FTRACK_SERVER", + "AVALON_APP_NAME", + "OPENPYPE_USERNAME", + "OPENPYPE_SG_USER", + "KITSU_LOGIN", + "KITSU_PWD" + ] + + # custom deadline attributes + deadline_department = "" + deadline_pool = "" + deadline_pool_secondary = "" + deadline_group = "" + deadline_chunk_size = 1 + deadline_priority = None + + # regex for finding frame number in string + R_FRAME_NUMBER = re.compile(r'.+\.(?P[0-9]+)\..+') + + plugin_pype_version = "3.0" + + # script path for publish_filesequence.py + publishing_script = None + + def _submit_deadline_post_job(self, instance, job): + """Submit publish job to Deadline. + + Deadline specific code separated from :meth:`process` for sake of + more universal code. Muster post job is sent directly by Muster + submitter, so this type of code isn't necessary for it. + + Returns: + (str): deadline_publish_job_id + """ + data = instance.data.copy() + subset = data["subset"] + job_name = "Publish - {subset}".format(subset=subset) + + anatomy = instance.context.data['anatomy'] + + # instance.data.get("subset") != instances[0]["subset"] + # 'Main' vs 'renderMain' + override_version = None + instance_version = instance.data.get("version") # take this if exists + if instance_version != 1: + override_version = instance_version + + output_dir = self._get_publish_folder( + anatomy, + deepcopy(instance.data["anatomyData"]), + instance.data.get("asset"), + instance.data["subset"], + instance.context, + instance.data["family"], + override_version + ) + + # Transfer the environment from the original job to this dependent + # job so they use the same environment + metadata_path, rootless_metadata_path = \ + create_metadata_path(instance, anatomy) + + environment = { + "AVALON_PROJECT": instance.context.data["projectName"], + "AVALON_ASSET": instance.context.data["asset"], + "AVALON_TASK": instance.context.data["task"], + "OPENPYPE_USERNAME": instance.context.data["user"], + "OPENPYPE_LOG_NO_COLORS": "1", + "IS_TEST": str(int(is_in_tests())) + } + + if AYON_SERVER_ENABLED: + environment["AYON_PUBLISH_JOB"] = "1" + environment["AYON_RENDER_JOB"] = "0" + environment["AYON_REMOTE_PUBLISH"] = "0" + environment["AYON_BUNDLE_NAME"] = os.environ["AYON_BUNDLE_NAME"] + deadline_plugin = "Ayon" + else: + environment["OPENPYPE_PUBLISH_JOB"] = "1" + environment["OPENPYPE_RENDER_JOB"] = "0" + environment["OPENPYPE_REMOTE_PUBLISH"] = "0" + deadline_plugin = "OpenPype" + # Add OpenPype version if we are running from build. + if is_running_from_build(): + self.environ_keys.append("OPENPYPE_VERSION") + + # add environments from self.environ_keys + for env_key in self.environ_keys: + if os.getenv(env_key): + environment[env_key] = os.environ[env_key] + + # pass environment keys from self.environ_job_filter + job_environ = job["Props"].get("Env", {}) + for env_j_key in self.environ_job_filter: + if job_environ.get(env_j_key): + environment[env_j_key] = job_environ[env_j_key] + + # Add mongo url if it's enabled + if instance.context.data.get("deadlinePassMongoUrl"): + mongo_url = os.environ.get("OPENPYPE_MONGO") + if mongo_url: + environment["OPENPYPE_MONGO"] = mongo_url + + priority = self.deadline_priority or instance.data.get("priority", 50) + + instance_settings = self.get_attr_values_from_data(instance.data) + initial_status = instance_settings.get("publishJobState", "Active") + # TODO: Remove this backwards compatibility of `suspend_publish` + if instance.data.get("suspend_publish"): + initial_status = "Suspended" + + args = [ + "--headless", + 'publish', + '"{}"'.format(rootless_metadata_path), + "--targets", "deadline", + "--targets", "farm" + ] + + if is_in_tests(): + args.append("--automatic-tests") + + # Generate the payload for Deadline submission + secondary_pool = ( + self.deadline_pool_secondary or instance.data.get("secondaryPool") + ) + payload = { + "JobInfo": { + "Plugin": deadline_plugin, + "BatchName": job["Props"]["Batch"], + "Name": job_name, + "UserName": job["Props"]["User"], + "Comment": instance.context.data.get("comment", ""), + + "Department": self.deadline_department, + "ChunkSize": self.deadline_chunk_size, + "Priority": priority, + "InitialStatus": initial_status, + + "Group": self.deadline_group, + "Pool": self.deadline_pool or instance.data.get("primaryPool"), + "SecondaryPool": secondary_pool, + # ensure the outputdirectory with correct slashes + "OutputDirectory0": output_dir.replace("\\", "/") + }, + "PluginInfo": { + "Version": self.plugin_pype_version, + "Arguments": " ".join(args), + "SingleFrameOnly": "True", + }, + # Mandatory for Deadline, may be empty + "AuxFiles": [], + } + + if job.get("_id"): + payload["JobInfo"]["JobDependency0"] = job["_id"] + + for index, (key_, value_) in enumerate(environment.items()): + payload["JobInfo"].update( + { + "EnvironmentKeyValue%d" + % index: "{key}={value}".format( + key=key_, value=value_ + ) + } + ) + # remove secondary pool + payload["JobInfo"].pop("SecondaryPool", None) + + self.log.debug("Submitting Deadline publish job ...") + + url = "{}/api/jobs".format(self.deadline_url) + response = requests.post(url, json=payload, timeout=10) + if not response.ok: + raise Exception(response.text) + + deadline_publish_job_id = response.json()["_id"] + + return deadline_publish_job_id + + def process(self, instance): + # type: (pyblish.api.Instance) -> None + """Process plugin. + + Detect type of render farm submission and create and post dependent + job in case of Deadline. It creates json file with metadata needed for + publishing in directory of render. + + Args: + instance (pyblish.api.Instance): Instance data. + + """ + if not instance.data.get("farm"): + self.log.debug("Skipping local instance.") + return + + anatomy = instance.context.data["anatomy"] + + instance_skeleton_data = create_skeleton_instance_cache(instance) + """ + if content of `expectedFiles` list are dictionaries, we will handle + it as list of AOVs, creating instance for every one of them. + + Example: + -------- + + expectedFiles = [ + { + "beauty": [ + "foo_v01.0001.exr", + "foo_v01.0002.exr" + ], + + "Z": [ + "boo_v01.0001.exr", + "boo_v01.0002.exr" + ] + } + ] + + This will create instances for `beauty` and `Z` subset + adding those files to their respective representations. + + If we have only list of files, we collect all file sequences. + More then one doesn't probably make sense, but we'll handle it + like creating one instance with multiple representations. + + Example: + -------- + + expectedFiles = [ + "foo_v01.0001.exr", + "foo_v01.0002.exr", + "xxx_v01.0001.exr", + "xxx_v01.0002.exr" + ] + + This will result in one instance with two representations: + `foo` and `xxx` + """ + + if isinstance(instance.data.get("expectedFiles")[0], dict): + instances = create_instances_for_cache( + instance, instance_skeleton_data) + else: + representations = prepare_cache_representations( + instance_skeleton_data, + instance.data.get("expectedFiles"), + anatomy + ) + + if "representations" not in instance_skeleton_data.keys(): + instance_skeleton_data["representations"] = [] + + # add representation + instance_skeleton_data["representations"] += representations + instances = [instance_skeleton_data] + + # attach instances to subset + if instance.data.get("attachTo"): + instances = attach_instances_to_subset( + instance.data.get("attachTo"), instances + ) + + r''' SUBMiT PUBLiSH JOB 2 D34DLiN3 + ____ + ' ' .---. .---. .--. .---. .--..--..--..--. .---. + | | --= \ | . \/ _|/ \| . \ || || \ |/ _| + | JOB | --= / | | || __| .. | | | |;_ || \ || __| + | | |____./ \.__|._||_.|___./|_____|||__|\__|\.___| + ._____. + + ''' + + render_job = None + submission_type = "" + if instance.data.get("toBeRenderedOn") == "deadline": + render_job = instance.data.pop("deadlineSubmissionJob", None) + submission_type = "deadline" + + if not render_job: + import getpass + + render_job = {} + self.log.debug("Faking job data ...") + render_job["Props"] = {} + # Render job doesn't exist because we do not have prior submission. + # We still use data from it so lets fake it. + # + # Batch name reflect original scene name + + if instance.data.get("assemblySubmissionJobs"): + render_job["Props"]["Batch"] = instance.data.get( + "jobBatchName") + else: + batch = os.path.splitext(os.path.basename( + instance.context.data.get("currentFile")))[0] + render_job["Props"]["Batch"] = batch + # User is deadline user + render_job["Props"]["User"] = instance.context.data.get( + "deadlineUser", getpass.getuser()) + + deadline_publish_job_id = None + if submission_type == "deadline": + # get default deadline webservice url from deadline module + self.deadline_url = instance.context.data["defaultDeadline"] + # if custom one is set in instance, use that + if instance.data.get("deadlineUrl"): + self.deadline_url = instance.data.get("deadlineUrl") + assert self.deadline_url, "Requires Deadline Webservice URL" + + deadline_publish_job_id = \ + self._submit_deadline_post_job(instance, render_job) + + # Inject deadline url to instances. + for inst in instances: + inst["deadlineUrl"] = self.deadline_url + + # publish job file + publish_job = { + "asset": instance_skeleton_data["asset"], + "frameStart": instance_skeleton_data["frameStart"], + "frameEnd": instance_skeleton_data["frameEnd"], + "fps": instance_skeleton_data["fps"], + "source": instance_skeleton_data["source"], + "user": instance.context.data["user"], + "version": instance.context.data["version"], # workfile version + "intent": instance.context.data.get("intent"), + "comment": instance.context.data.get("comment"), + "job": render_job or None, + "session": legacy_io.Session.copy(), + "instances": instances + } + + if deadline_publish_job_id: + publish_job["deadline_publish_job_id"] = deadline_publish_job_id + + metadata_path, rootless_metadata_path = \ + create_metadata_path(instance, anatomy) + + with open(metadata_path, "w") as f: + json.dump(publish_job, f, indent=4, sort_keys=True) + + def _get_publish_folder(self, anatomy, template_data, + asset, subset, context, + family, version=None): + """ + Extracted logic to pre-calculate real publish folder, which is + calculated in IntegrateNew inside of Deadline process. + This should match logic in: + 'collect_anatomy_instance_data' - to + get correct anatomy, family, version for subset and + 'collect_resources_path' + get publish_path + + Args: + anatomy (openpype.pipeline.anatomy.Anatomy): + template_data (dict): pre-calculated collected data for process + asset (string): asset name + subset (string): subset name (actually group name of subset) + family (string): for current deadline process it's always 'render' + TODO - for generic use family needs to be dynamically + calculated like IntegrateNew does + version (int): override version from instance if exists + + Returns: + (string): publish folder where rendered and published files will + be stored + based on 'publish' template + """ + + project_name = context.data["projectName"] + if not version: + version = get_last_version_by_subset_name( + project_name, + subset, + asset_name=asset + ) + if version: + version = int(version["name"]) + 1 + else: + version = get_versioning_start( + project_name, + template_data["app"], + task_name=template_data["task"]["name"], + task_type=template_data["task"]["type"], + family="render", + subset=subset, + project_settings=context.data["project_settings"] + ) + + host_name = context.data["hostName"] + task_info = template_data.get("task") or {} + + template_name = publish.get_publish_template_name( + project_name, + host_name, + family, + task_info.get("name"), + task_info.get("type"), + ) + + template_data["subset"] = subset + template_data["family"] = family + template_data["version"] = version + + render_templates = anatomy.templates_obj[template_name] + if "folder" in render_templates: + publish_folder = render_templates["folder"].format_strict( + template_data + ) + else: + # solve deprecated situation when `folder` key is not underneath + # `publish` anatomy + self.log.warning(( + "Deprecation warning: Anatomy does not have set `folder`" + " key underneath `publish` (in global of for project `{}`)." + ).format(project_name)) + + file_path = render_templates["path"].format_strict(template_data) + publish_folder = os.path.dirname(file_path) + + return publish_folder + + @classmethod + def get_attribute_defs(cls): + return [ + EnumDef("publishJobState", + label="Publish Job State", + items=["Active", "Suspended"], + default="Active") + ] diff --git a/openpype/modules/deadline/plugins/publish/validate_deadline_pools.py b/openpype/modules/deadline/plugins/publish/validate_deadline_pools.py index 949caff7d8..90b8241803 100644 --- a/openpype/modules/deadline/plugins/publish/validate_deadline_pools.py +++ b/openpype/modules/deadline/plugins/publish/validate_deadline_pools.py @@ -22,7 +22,8 @@ class ValidateDeadlinePools(OptionalPyblishPluginMixin, "render.frames_farm", "renderFarm", "renderlayer", - "maxrender"] + "maxrender", + "publish.hou"] optional = True # cache diff --git a/openpype/modules/deadline/repository/custom/plugins/GlobalJobPreLoad.py b/openpype/modules/deadline/repository/custom/plugins/GlobalJobPreLoad.py index 642608f991..96f131b922 100644 --- a/openpype/modules/deadline/repository/custom/plugins/GlobalJobPreLoad.py +++ b/openpype/modules/deadline/repository/custom/plugins/GlobalJobPreLoad.py @@ -429,7 +429,7 @@ def inject_ayon_environment(deadlinePlugin): "separated list \"{}\"." "The path to the render executable can be configured" " from the Plugin Configuration in the Deadline Monitor." - ).format(";".join(exe_list))) + ).format(exe_list)) print("--- Ayon executable: {}".format(exe)) diff --git a/openpype/modules/ftrack/plugins/publish/integrate_ftrack_instances.py b/openpype/modules/ftrack/plugins/publish/integrate_ftrack_instances.py index 75f43cb22f..a3e6bc25c5 100644 --- a/openpype/modules/ftrack/plugins/publish/integrate_ftrack_instances.py +++ b/openpype/modules/ftrack/plugins/publish/integrate_ftrack_instances.py @@ -61,6 +61,7 @@ class IntegrateFtrackInstance(pyblish.api.InstancePlugin): additional_metadata_keys = [] def process(self, instance): + # QUESTION: should this be operating even for `farm` target? self.log.debug("instance {}".format(instance)) instance_repres = instance.data.get("representations") @@ -126,87 +127,119 @@ class IntegrateFtrackInstance(pyblish.api.InstancePlugin): other_representations = [] has_movie_review = False for repre in instance_repres: - self.log.debug("Representation {}".format(repre)) repre_tags = repre.get("tags") or [] + # exclude representations with are going to be published on farm + if "publish_on_farm" in repre_tags: + continue + + self.log.debug("Representation {}".format(repre)) + + # include only thumbnail representations if repre.get("thumbnail") or "thumbnail" in repre_tags: thumbnail_representations.append(repre) + # include only review representations elif "ftrackreview" in repre_tags: review_representations.append(repre) if self._is_repre_video(repre): has_movie_review = True else: + # include all other representations other_representations.append(repre) # Prepare ftrack locations unmanaged_location_name = "ftrack.unmanaged" ftrack_server_location_name = "ftrack.server" + # check if any outputName keys are in review_representations + # also check if any outputName keys are in thumbnail_representations + synced_multiple_output_names = [] + for review_repre in review_representations: + review_output_name = review_repre.get("outputName") + if not review_output_name: + continue + for thumb_repre in thumbnail_representations: + thumb_output_name = thumb_repre.get("outputName") + if not thumb_output_name: + continue + if ( + thumb_output_name == review_output_name + # output name can be added also as tags during intermediate + # files creation + or thumb_output_name in review_repre.get("tags", []) + ): + synced_multiple_output_names.append( + thumb_repre["outputName"]) + self.log.debug("Multiple output names: {}".format( + synced_multiple_output_names + )) + multiple_synced_thumbnails = len(synced_multiple_output_names) > 1 + # Components data component_list = [] - # Components that will be duplicated to unmanaged location - src_components_to_add = [] + thumbnail_data_items = [] # Create thumbnail components - # TODO what if there is multiple thumbnails? - first_thumbnail_component = None - first_thumbnail_component_repre = None - - if not review_representations or has_movie_review: - for repre in thumbnail_representations: - repre_path = get_publish_repre_path(instance, repre, False) - if not repre_path: - self.log.warning( - "Published path is not set and source was removed." - ) - continue - - # Create copy of base comp item and append it - thumbnail_item = copy.deepcopy(base_component_item) - thumbnail_item["component_path"] = repre_path - thumbnail_item["component_data"] = { - "name": "thumbnail" - } - thumbnail_item["thumbnail"] = True - - # Create copy of item before setting location - if "delete" not in repre.get("tags", []): - src_components_to_add.append(copy.deepcopy(thumbnail_item)) - # Create copy of first thumbnail - if first_thumbnail_component is None: - first_thumbnail_component_repre = repre - first_thumbnail_component = thumbnail_item - # Set location - thumbnail_item["component_location_name"] = ( - ftrack_server_location_name - ) - - # Add item to component list - component_list.append(thumbnail_item) - - if first_thumbnail_component is not None: - metadata = self._prepare_image_component_metadata( - first_thumbnail_component_repre, - first_thumbnail_component["component_path"] + for repre in thumbnail_representations: + # get repre path from representation + # and return published_path if available + # the path is validated and if it does not exists it returns None + repre_path = get_publish_repre_path( + instance, + repre, + only_published=False ) + if not repre_path: + self.log.warning( + "Published path is not set or source was removed." + ) + continue - if metadata: - component_data = first_thumbnail_component["component_data"] - component_data["metadata"] = metadata + # Create copy of base comp item and append it + thumbnail_item = copy.deepcopy(base_component_item) + thumbnail_item.update({ + "component_path": repre_path, + "component_data": { + "name": ( + "thumbnail" if review_representations + else "ftrackreview-image" + ), + "metadata": self._prepare_image_component_metadata( + repre, + repre_path + ) + }, + "thumbnail": True, + "component_location_name": ftrack_server_location_name + }) - if review_representations: - component_data["name"] = "thumbnail" - else: - component_data["name"] = "ftrackreview-image" + # add thumbnail data to items for future synchronization + current_item_data = { + "sync_key": repre.get("outputName"), + "representation": repre, + "item": thumbnail_item + } + # Create copy of item before setting location + if "delete" not in repre.get("tags", []): + src_comp = self._create_src_component( + instance, + repre, + copy.deepcopy(thumbnail_item), + unmanaged_location_name + ) + component_list.append(src_comp) + + current_item_data["src_component"] = src_comp + + # Add item to component list + thumbnail_data_items.append(current_item_data) # Create review components # Change asset name of each new component for review - is_first_review_repre = True - not_first_components = [] - extended_asset_name = "" multiple_reviewable = len(review_representations) > 1 - for repre in review_representations: + extended_asset_name = None + for index, repre in enumerate(review_representations): if not self._is_repre_video(repre) and has_movie_review: self.log.debug("Movie repre has priority " "from {}".format(repre)) @@ -222,45 +255,50 @@ class IntegrateFtrackInstance(pyblish.api.InstancePlugin): # Create copy of base comp item and append it review_item = copy.deepcopy(base_component_item) - # get asset name and define extended name variant - asset_name = review_item["asset_data"]["name"] - extended_asset_name = "_".join( - (asset_name, repre["name"]) + # get first or synchronize thumbnail item + sync_thumbnail_item = None + sync_thumbnail_item_src = None + sync_thumbnail_data = self._get_matching_thumbnail_item( + repre, + thumbnail_data_items, + multiple_synced_thumbnails ) + if sync_thumbnail_data: + sync_thumbnail_item = sync_thumbnail_data.get("item") + sync_thumbnail_item_src = sync_thumbnail_data.get( + "src_component") - # reset extended if no need for extended asset name - if ( - self.keep_first_subset_name_for_review - and is_first_review_repre - ): - extended_asset_name = "" - else: - # only rename if multiple reviewable - if multiple_reviewable: - review_item["asset_data"]["name"] = extended_asset_name - else: - extended_asset_name = "" + """ + Renaming asset name only to those components which are explicitly + allowed in settings. Usually clients wanted to keep first component + as untouched product name with version and any other assetVersion + to be named with extended form. The renaming will only happen if + there is more than one reviewable component and extended name is + not empty. + """ + extended_asset_name = self._make_extended_component_name( + base_component_item, repre, index) - # rename all already created components - # only if first repre and extended name available - if is_first_review_repre and extended_asset_name: - # and rename all already created components - for _ci in component_list: - _ci["asset_data"]["name"] = extended_asset_name + if multiple_reviewable and extended_asset_name: + review_item["asset_data"]["name"] = extended_asset_name + # rename also thumbnail + if sync_thumbnail_item: + sync_thumbnail_item["asset_data"]["name"] = ( + extended_asset_name + ) + # rename also src_thumbnail + if sync_thumbnail_item_src: + sync_thumbnail_item_src["asset_data"]["name"] = ( + extended_asset_name + ) - # and rename all already created src components - for _sci in src_components_to_add: - _sci["asset_data"]["name"] = extended_asset_name - - # rename also first thumbnail component if any - if first_thumbnail_component is not None: - first_thumbnail_component[ - "asset_data"]["name"] = extended_asset_name - - # Change location - review_item["component_path"] = repre_path - # Change component data + # adding thumbnail component to component list + if sync_thumbnail_item: + component_list.append(copy.deepcopy(sync_thumbnail_item)) + if sync_thumbnail_item_src: + component_list.append(copy.deepcopy(sync_thumbnail_item_src)) + # add metadata to review component if self._is_repre_video(repre): component_name = "ftrackreview-mp4" metadata = self._prepare_video_component_metadata( @@ -273,28 +311,29 @@ class IntegrateFtrackInstance(pyblish.api.InstancePlugin): ) review_item["thumbnail"] = True - review_item["component_data"] = { - # Default component name is "main". - "name": component_name, - "metadata": metadata - } - - if is_first_review_repre: - is_first_review_repre = False - else: - # later detection for thumbnail duplication - not_first_components.append(review_item) + review_item.update({ + "component_path": repre_path, + "component_data": { + "name": component_name, + "metadata": metadata + }, + "component_location_name": ftrack_server_location_name + }) # Create copy of item before setting location if "delete" not in repre.get("tags", []): - src_components_to_add.append(copy.deepcopy(review_item)) + src_comp = self._create_src_component( + instance, + repre, + copy.deepcopy(review_item), + unmanaged_location_name + ) + component_list.append(src_comp) - # Set location - review_item["component_location_name"] = ( - ftrack_server_location_name - ) # Add item to component list component_list.append(review_item) + + if self.upload_reviewable_with_origin_name: origin_name_component = copy.deepcopy(review_item) filename = os.path.basename(repre_path) @@ -303,34 +342,6 @@ class IntegrateFtrackInstance(pyblish.api.InstancePlugin): ) component_list.append(origin_name_component) - # Duplicate thumbnail component for all not first reviews - if first_thumbnail_component is not None: - for component_item in not_first_components: - asset_name = component_item["asset_data"]["name"] - new_thumbnail_component = copy.deepcopy( - first_thumbnail_component - ) - new_thumbnail_component["asset_data"]["name"] = asset_name - new_thumbnail_component["component_location_name"] = ( - ftrack_server_location_name - ) - component_list.append(new_thumbnail_component) - - # Add source components for review and thubmnail components - for copy_src_item in src_components_to_add: - # Make sure thumbnail is disabled - copy_src_item["thumbnail"] = False - # Set location - copy_src_item["component_location_name"] = unmanaged_location_name - # Modify name of component to have suffix "_src" - component_data = copy_src_item["component_data"] - component_name = component_data["name"] - component_data["name"] = component_name + "_src" - component_data["metadata"] = self._prepare_component_metadata( - instance, repre, copy_src_item["component_path"], False - ) - component_list.append(copy_src_item) - # Add others representations as component for repre in other_representations: published_path = get_publish_repre_path(instance, repre, True) @@ -346,15 +357,17 @@ class IntegrateFtrackInstance(pyblish.api.InstancePlugin): ): other_item["asset_data"]["name"] = extended_asset_name - component_data = { - "name": repre["name"], - "metadata": self._prepare_component_metadata( - instance, repre, published_path, False - ) - } - other_item["component_data"] = component_data - other_item["component_location_name"] = unmanaged_location_name - other_item["component_path"] = published_path + other_item.update({ + "component_path": published_path, + "component_data": { + "name": repre["name"], + "metadata": self._prepare_component_metadata( + instance, repre, published_path, False + ) + }, + "component_location_name": unmanaged_location_name, + }) + component_list.append(other_item) def json_obj_parser(obj): @@ -370,6 +383,124 @@ class IntegrateFtrackInstance(pyblish.api.InstancePlugin): )) instance.data["ftrackComponentsList"] = component_list + def _get_matching_thumbnail_item( + self, + review_representation, + thumbnail_data_items, + are_multiple_synced_thumbnails + ): + """Return matching thumbnail item from list of thumbnail items. + + If a thumbnail item already exists, this should return it. + The benefit is that if an `outputName` key is found in + representation and is also used as a `sync_key` in a thumbnail + data item, it can sync with that item. + + Args: + review_representation (dict): Review representation + thumbnail_data_items (list): List of thumbnail data items + are_multiple_synced_thumbnails (bool): If there are multiple synced + thumbnails + + Returns: + dict: Thumbnail data item or empty dict + """ + output_name = review_representation.get("outputName") + tags = review_representation.get("tags", []) + matching_thumbnail_item = {} + for thumb_item in thumbnail_data_items: + if ( + are_multiple_synced_thumbnails + and ( + thumb_item["sync_key"] == output_name + # intermediate files can have preset name in tags + # this is usually aligned with `outputName` distributed + # during thumbnail creation in `need_thumbnail` tagging + # workflow + or thumb_item["sync_key"] in tags + ) + ): + # return only synchronized thumbnail if multiple + matching_thumbnail_item = thumb_item + break + elif not are_multiple_synced_thumbnails: + # return any first found thumbnail since we need thumbnail + # but dont care which one + matching_thumbnail_item = thumb_item + break + + if not matching_thumbnail_item: + # WARNING: this can only happen if multiple thumbnails + # workflow is broken, since it found multiple matching outputName + # in representation but they do not align with any thumbnail item + self.log.warning( + "No matching thumbnail item found for output name " + "'{}'".format(output_name) + ) + if not thumbnail_data_items: + self.log.warning( + "No thumbnail data items found" + ) + return {} + # as fallback return first thumbnail item + return thumbnail_data_items[0] + + return matching_thumbnail_item + + def _make_extended_component_name( + self, component_item, repre, iteration_index): + """ Returns the extended component name + + Name is based on the asset name and representation name. + + Args: + component_item (dict): The component item dictionary. + repre (dict): The representation dictionary. + iteration_index (int): The index of the iteration. + + Returns: + str: The extended component name. + + """ + # reset extended if no need for extended asset name + if self.keep_first_subset_name_for_review and iteration_index == 0: + return + + # get asset name and define extended name variant + asset_name = component_item["asset_data"]["name"] + return "_".join( + (asset_name, repre["name"]) + ) + + def _create_src_component( + self, instance, repre, component_item, location): + """Create src component for thumbnail. + + This will replicate the input component and change its name to + have suffix "_src". + + Args: + instance (pyblish.api.Instance): Instance + repre (dict): Representation + component_item (dict): Component item + location (str): Location name + + Returns: + dict: Component item + """ + # Make sure thumbnail is disabled + component_item["thumbnail"] = False + # Set location + component_item["component_location_name"] = location + # Modify name of component to have suffix "_src" + component_data = component_item["component_data"] + component_name = component_data["name"] + component_data["name"] = component_name + "_src" + component_data["metadata"] = self._prepare_component_metadata( + instance, repre, component_item["component_path"], False + ) + return component_item + def _collect_additional_metadata(self, streams): pass @@ -472,9 +603,6 @@ class IntegrateFtrackInstance(pyblish.api.InstancePlugin): stream_width = tmp_width stream_height = tmp_height - self.log.debug("FPS from stream is {} and duration is {}".format( - input_framerate, stream_duration - )) frame_out = float(stream_duration) * stream_fps break diff --git a/openpype/modules/python_console_interpreter/window/widgets.py b/openpype/modules/python_console_interpreter/window/widgets.py index b670352f44..28950f8369 100644 --- a/openpype/modules/python_console_interpreter/window/widgets.py +++ b/openpype/modules/python_console_interpreter/window/widgets.py @@ -8,10 +8,12 @@ import appdirs from qtpy import QtCore, QtWidgets, QtGui from openpype import resources +from openpype import AYON_SERVER_ENABLED from openpype.style import load_stylesheet from openpype.lib import JSONSettingRegistry + openpype_art = """ . . .. . .. _oOOP3OPP3Op_. . @@ -27,6 +29,18 @@ openpype_art = """ ~P3.OPPPO3OP~ . .. . . ' '. . .. . . . .. . +""" + +ayon_art = r""" + + ▄██▄ + ▄███▄ ▀██▄ ▀██▀ ▄██▀ ▄██▀▀▀██▄ ▀███▄ █▄ + ▄▄ ▀██▄ ▀██▄ ▄██▀ ██▀ ▀██▄ ▄ ▀██▄ ███ + ▄██▀ ██▄ ▀ ▄▄ ▀ ██ ▄██ ███ ▀██▄ ███ + ▄██▀ ▀██▄ ██ ▀██▄ ▄██▀ ███ ▀██ ▀█▀ + ▄██▀ ▀██▄ ▀█ ▀██▄▄▄▄██▀ █▀ ▀██▄ + + · · - =[ by YNPUT ]:[ http://ayon.ynput.io ]= - · · """ @@ -41,8 +55,12 @@ class PythonInterpreterRegistry(JSONSettingRegistry): """ def __init__(self): - self.vendor = "pypeclub" - self.product = "openpype" + if AYON_SERVER_ENABLED: + self.vendor = "ynput" + self.product = "ayon" + else: + self.vendor = "pypeclub" + self.product = "openpype" name = "python_interpreter_tool" path = appdirs.user_data_dir(self.product, self.vendor) super(PythonInterpreterRegistry, self).__init__(name, path) @@ -339,7 +357,9 @@ class PythonInterpreterWidget(QtWidgets.QWidget): def __init__(self, parent=None): super(PythonInterpreterWidget, self).__init__(parent) - self.setWindowTitle("OpenPype Console") + self.setWindowTitle("{} Console".format( + "AYON" if AYON_SERVER_ENABLED else "OpenPype" + )) self.setWindowIcon(QtGui.QIcon(resources.get_openpype_icon_filepath())) self.ansi_escape = re.compile( @@ -387,7 +407,10 @@ class PythonInterpreterWidget(QtWidgets.QWidget): self._tab_widget = tab_widget self._line_check_timer = line_check_timer - self._append_lines([openpype_art]) + if AYON_SERVER_ENABLED: + self._append_lines([ayon_art]) + else: + self._append_lines([openpype_art]) self._first_show = True self._splitter_size_ratio = None diff --git a/openpype/modules/royalrender/lib.py b/openpype/modules/royalrender/lib.py index 4708d25eed..9c4221d9cd 100644 --- a/openpype/modules/royalrender/lib.py +++ b/openpype/modules/royalrender/lib.py @@ -1,23 +1,28 @@ # -*- coding: utf-8 -*- """Submitting render job to RoyalRender.""" import os -import re +import json import platform +import re +import tempfile +import uuid from datetime import datetime import pyblish.api -from openpype.tests.lib import is_in_tests -from openpype.pipeline.publish.lib import get_published_workfile_instance -from openpype.pipeline.publish import KnownPublishError + +from openpype.lib import BoolDef, NumberDef, is_running_from_build +from openpype.lib.execute import run_openpype_process from openpype.modules.royalrender.api import Api as rrApi from openpype.modules.royalrender.rr_job import ( - RRJob, CustomAttribute, get_rr_platform) -from openpype.lib import ( - is_running_from_build, - BoolDef, - NumberDef, + CustomAttribute, + RRJob, + RREnvList, + get_rr_platform, ) from openpype.pipeline import OpenPypePyblishPluginMixin +from openpype.pipeline.publish import KnownPublishError +from openpype.pipeline.publish.lib import get_published_workfile_instance +from openpype.tests.lib import is_in_tests class BaseCreateRoyalRenderJob(pyblish.api.InstancePlugin, @@ -302,3 +307,68 @@ class BaseCreateRoyalRenderJob(pyblish.api.InstancePlugin, path = path.replace(first_frame, "#" * padding) return path + + def inject_environment(self, instance, job): + # type: (pyblish.api.Instance, RRJob) -> RRJob + """Inject environment variables for RR submission. + + This function mimics the behaviour of the Deadline + integration. It is just temporary solution until proper + runtime environment injection is implemented in RR. + + Args: + instance (pyblish.api.Instance): Publishing instance + job (RRJob): RRJob instance to be injected. + + Returns: + RRJob: Injected RRJob instance. + + Throws: + RuntimeError: If any of the required env vars is missing. + + """ + + temp_file_name = "{}_{}.json".format( + datetime.utcnow().strftime('%Y%m%d%H%M%S%f'), + str(uuid.uuid1()) + ) + + export_url = os.path.join(tempfile.gettempdir(), temp_file_name) + print(">>> Temporary path: {}".format(export_url)) + + args = [ + "--headless", + "extractenvironments", + export_url + ] + + anatomy_data = instance.context.data["anatomyData"] + + add_kwargs = { + "project": anatomy_data["project"]["name"], + "asset": instance.context.data["asset"], + "task": anatomy_data["task"]["name"], + "app": instance.context.data.get("appName"), + "envgroup": "farm" + } + + if os.getenv('IS_TEST'): + args.append("--automatic-tests") + + if not all(add_kwargs.values()): + raise RuntimeError(( + "Missing required env vars: AVALON_PROJECT, AVALON_ASSET," + " AVALON_TASK, AVALON_APP_NAME" + )) + + for key, value in add_kwargs.items(): + args.extend([f"--{key}", value]) + self.log.debug("Executing: {}".format(" ".join(args))) + run_openpype_process(*args, logger=self.log) + + self.log.debug("Loading file ...") + with open(export_url) as fp: + contents = json.load(fp) + + job.rrEnvList = RREnvList(contents).serialize() + return job diff --git a/openpype/modules/royalrender/plugins/publish/create_maya_royalrender_job.py b/openpype/modules/royalrender/plugins/publish/create_maya_royalrender_job.py index 22d910b7cd..775a2964fd 100644 --- a/openpype/modules/royalrender/plugins/publish/create_maya_royalrender_job.py +++ b/openpype/modules/royalrender/plugins/publish/create_maya_royalrender_job.py @@ -2,7 +2,7 @@ """Submitting render job to RoyalRender.""" import os -from maya.OpenMaya import MGlobal +from maya.OpenMaya import MGlobal # noqa: F401 from openpype.modules.royalrender import lib from openpype.pipeline.farm.tools import iter_expected_files @@ -38,5 +38,6 @@ class CreateMayaRoyalRenderJob(lib.BaseCreateRoyalRenderJob): job = self.get_job(instance, self.scene_path, first_file_path, layer_name) job = self.update_job_with_host_specific(instance, job) + job = self.inject_environment(instance, job) instance.data["rrJobs"].append(job) diff --git a/openpype/modules/royalrender/plugins/publish/create_nuke_royalrender_job.py b/openpype/modules/royalrender/plugins/publish/create_nuke_royalrender_job.py index 71daa6edf8..4f589e56f8 100644 --- a/openpype/modules/royalrender/plugins/publish/create_nuke_royalrender_job.py +++ b/openpype/modules/royalrender/plugins/publish/create_nuke_royalrender_job.py @@ -25,6 +25,7 @@ class CreateNukeRoyalRenderJob(lib.BaseCreateRoyalRenderJob): jobs = self.create_jobs(instance) for job in jobs: job = self.update_job_with_host_specific(instance, job) + job = self.inject_environment(instance, job) instance.data["rrJobs"].append(job) diff --git a/openpype/modules/royalrender/plugins/publish/create_publish_royalrender_job.py b/openpype/modules/royalrender/plugins/publish/create_publish_royalrender_job.py index 3eb49a39ee..d4af1c2aee 100644 --- a/openpype/modules/royalrender/plugins/publish/create_publish_royalrender_job.py +++ b/openpype/modules/royalrender/plugins/publish/create_publish_royalrender_job.py @@ -189,7 +189,7 @@ class CreatePublishRoyalRenderJob(pyblish.api.InstancePlugin, environment = RREnvList({ "AVALON_PROJECT": anatomy_data["project"]["name"], - "AVALON_ASSET": anatomy_data["asset"], + "AVALON_ASSET": instance.context.data["asset"], "AVALON_TASK": anatomy_data["task"]["name"], "OPENPYPE_USERNAME": anatomy_data["user"] }) @@ -205,6 +205,9 @@ class CreatePublishRoyalRenderJob(pyblish.api.InstancePlugin, jobs_pre_ids = [] for job in instance.data["rrJobs"]: # type: RRJob if job.rrEnvList: + if len(job.rrEnvList) > 2000: + self.log.warning(("Job environment is too long " + f"{len(job.rrEnvList)} > 2000")) job_environ.update( dict(RREnvList.parse(job.rrEnvList)) ) diff --git a/openpype/modules/royalrender/rr_job.py b/openpype/modules/royalrender/rr_job.py index b85ac592f8..62a82d45e8 100644 --- a/openpype/modules/royalrender/rr_job.py +++ b/openpype/modules/royalrender/rr_job.py @@ -32,7 +32,7 @@ class RREnvList(dict): """Parse rrEnvList string and return it as RREnvList object.""" out = RREnvList() for var in data.split("~~~"): - k, v = var.split("=") + k, v = var.split("=", maxsplit=1) out[k] = v return out @@ -172,7 +172,7 @@ class RRJob(object): # Environment # only used in RR 8.3 and newer - rrEnvList = attr.ib(default=None) # type: str + rrEnvList = attr.ib(default=None, type=str) # type: str class SubmitterParameter: diff --git a/openpype/modules/timers_manager/timers_manager.py b/openpype/modules/timers_manager/timers_manager.py index 43286f7da4..674d834a1d 100644 --- a/openpype/modules/timers_manager/timers_manager.py +++ b/openpype/modules/timers_manager/timers_manager.py @@ -247,7 +247,7 @@ class TimersManager( return { "project_name": project_name, "asset_id": str(asset_doc["_id"]), - "asset_name": asset_doc["name"], + "asset_name": asset_name, "task_name": task_name, "task_type": task_type, "hierarchy": hierarchy_items diff --git a/openpype/pipeline/actions.py b/openpype/pipeline/actions.py index feb1bd05d2..68533f7485 100644 --- a/openpype/pipeline/actions.py +++ b/openpype/pipeline/actions.py @@ -7,6 +7,8 @@ from openpype.pipeline.plugin_discover import ( deregister_plugin_path ) +from .load.utils import get_representation_path_from_context + class LauncherAction(object): """A custom action available""" @@ -100,6 +102,10 @@ class InventoryAction(object): """ return True + @classmethod + def filepath_from_context(cls, context): + return get_representation_path_from_context(context) + # Launcher action def discover_launcher_actions(): diff --git a/openpype/pipeline/context_tools.py b/openpype/pipeline/context_tools.py index 034bbc0070..a607c90912 100644 --- a/openpype/pipeline/context_tools.py +++ b/openpype/pipeline/context_tools.py @@ -18,6 +18,7 @@ from openpype.client import ( get_asset_by_id, get_asset_by_name, version_is_latest, + get_asset_name_identifier, get_ayon_server_api_connection, ) from openpype.lib.events import emit_event @@ -44,7 +45,7 @@ from . import ( _is_installed = False _process_id = None -_registered_root = {"_": ""} +_registered_root = {"_": {}} _registered_host = {"_": None} # Keep modules manager (and it's modules) in memory # - that gives option to register modules' callbacks @@ -85,15 +86,22 @@ def register_root(path): def registered_root(): - """Return currently registered root""" - root = _registered_root["_"] - if root: - return root + """Return registered roots from current project anatomy. - root = legacy_io.Session.get("AVALON_PROJECTS") - if root: - return os.path.normpath(root) - return "" + Consider this does return roots only for current project and current + platforms, only if host was installer using 'install_host'. + + Deprecated: + Please use project 'Anatomy' to get roots. This function is still used + at current core functions of load logic, but that will change + in future and this function will be removed eventually. Using this + function at new places can cause problems in the future. + + Returns: + dict[str, str]: Root paths. + """ + + return _registered_root["_"] def install_host(host): @@ -592,14 +600,12 @@ def compute_session_changes( Dict[str, str]: Changes in the Session dictionary. """ - changes = {} - # Get asset document and asset if not asset_doc: task_name = None asset_name = None else: - asset_name = asset_doc["name"] + asset_name = get_asset_name_identifier(asset_doc) # Detect any changes compared session mapping = { diff --git a/openpype/pipeline/create/context.py b/openpype/pipeline/create/context.py index 25f03ddd3b..683699a0d1 100644 --- a/openpype/pipeline/create/context.py +++ b/openpype/pipeline/create/context.py @@ -11,7 +11,12 @@ from contextlib import contextmanager import pyblish.logic import pyblish.api -from openpype.client import get_assets, get_asset_by_name +from openpype import AYON_SERVER_ENABLED +from openpype.client import ( + get_assets, + get_asset_by_name, + get_asset_name_identifier, +) from openpype.settings import ( get_system_settings, get_project_settings @@ -922,9 +927,19 @@ class CreatedInstance: self._orig_data = copy.deepcopy(data) # Pop family and subset to prevent unexpected changes + # TODO change to 'productType' and 'productName' in AYON data.pop("family", None) data.pop("subset", None) + if AYON_SERVER_ENABLED: + asset_name = data.pop("asset", None) + if "folderPath" not in data: + data["folderPath"] = asset_name + + elif "folderPath" in data: + asset_name = data.pop("folderPath").split("/")[-1] + if "asset" not in data: + data["asset"] = asset_name # QUESTION Does it make sense to have data stored as ordered dict? self._data = collections.OrderedDict() @@ -1268,6 +1283,8 @@ class CreatedInstance: def has_set_asset(self): """Asset name is set in data.""" + if AYON_SERVER_ENABLED: + return "folderPath" in self._data return "asset" in self._data @property @@ -2003,8 +2020,14 @@ class CreateContext: project_name, self.host_name ) + asset_name = get_asset_name_identifier(asset_doc) + if AYON_SERVER_ENABLED: + asset_name_key = "folderPath" + else: + asset_name_key = "asset" + instance_data = { - "asset": asset_doc["name"], + asset_name_key: asset_name, "task": task_name, "family": creator.family, "variant": variant @@ -2229,34 +2252,51 @@ class CreateContext: task_names_by_asset_name = {} for instance in instances: task_name = instance.get("task") - asset_name = instance.get("asset") + if AYON_SERVER_ENABLED: + asset_name = instance.get("folderPath") + else: + asset_name = instance.get("asset") if asset_name: task_names_by_asset_name[asset_name] = set() if task_name: task_names_by_asset_name[asset_name].add(task_name) - asset_names = [ + asset_names = { asset_name for asset_name in task_names_by_asset_name.keys() if asset_name is not None - ] + } + fields = {"name", "data.tasks"} + if AYON_SERVER_ENABLED: + fields |= {"data.parents"} asset_docs = list(get_assets( self.project_name, asset_names=asset_names, - fields=["name", "data.tasks"] + fields=fields )) task_names_by_asset_name = {} + asset_docs_by_name = collections.defaultdict(list) for asset_doc in asset_docs: - asset_name = asset_doc["name"] + asset_name = get_asset_name_identifier(asset_doc) tasks = asset_doc.get("data", {}).get("tasks") or {} task_names_by_asset_name[asset_name] = set(tasks.keys()) + asset_docs_by_name[asset_doc["name"]].append(asset_doc) for instance in instances: if not instance.has_valid_asset or not instance.has_valid_task: continue - asset_name = instance["asset"] + if AYON_SERVER_ENABLED: + asset_name = instance["folderPath"] + if asset_name and "/" not in asset_name: + asset_docs = asset_docs_by_name.get(asset_name) + if len(asset_docs) == 1: + asset_name = get_asset_name_identifier(asset_docs[0]) + instance["folderPath"] = asset_name + else: + asset_name = instance["asset"] + if asset_name not in task_names_by_asset_name: instance.set_asset_invalid(True) continue diff --git a/openpype/pipeline/create/utils.py b/openpype/pipeline/create/utils.py index 2ef1f02bd6..ce4af8f474 100644 --- a/openpype/pipeline/create/utils.py +++ b/openpype/pipeline/create/utils.py @@ -1,6 +1,11 @@ import collections -from openpype.client import get_assets, get_subsets, get_last_versions +from openpype.client import ( + get_assets, + get_subsets, + get_last_versions, + get_asset_name_identifier, +) def get_last_versions_for_instances( @@ -52,10 +57,10 @@ def get_last_versions_for_instances( asset_docs = get_assets( project_name, asset_names=subset_names_by_asset_name.keys(), - fields=["name", "_id"] + fields=["name", "_id", "data.parents"] ) asset_names_by_id = { - asset_doc["_id"]: asset_doc["name"] + asset_doc["_id"]: get_asset_name_identifier(asset_doc) for asset_doc in asset_docs } if not asset_names_by_id: diff --git a/openpype/pipeline/farm/pyblish_functions.py b/openpype/pipeline/farm/pyblish_functions.py index 7ef3439dbd..54ff2627e1 100644 --- a/openpype/pipeline/farm/pyblish_functions.py +++ b/openpype/pipeline/farm/pyblish_functions.py @@ -145,6 +145,9 @@ def get_transferable_representations(instance): trans_rep = representation.copy() + # remove publish_on_farm from representations tags + trans_rep["tags"].remove("publish_on_farm") + staging_dir = trans_rep.get("stagingDir") if staging_dir: @@ -745,6 +748,238 @@ def get_resources(project_name, version, extension=None): return resources +def create_skeleton_instance_cache(instance): + # type: (pyblish.api.Instance, list, dict) -> dict + """Create skeleton instance from original instance data. + + This will create dictionary containing skeleton + - common - data used for publishing rendered instances. + This skeleton instance is then extended with additional data + and serialized to be processed by farm job. + + Args: + instance (pyblish.api.Instance): Original instance to + be used as a source of data. + + Returns: + dict: Dictionary with skeleton instance data. + + """ + # list of family names to transfer to new family if present + + context = instance.context + data = instance.data.copy() + anatomy = instance.context.data["anatomy"] # type: Anatomy + + # get time related data from instance (or context) + time_data = get_time_data_from_instance_or_context(instance) + + if data.get("extendFrames", False): + time_data.start, time_data.end = extend_frames( + data["asset"], + data["subset"], + time_data.start, + time_data.end, + ) + + source = data.get("source") or context.data.get("currentFile") + success, rootless_path = ( + anatomy.find_root_template_from_path(source) + ) + if success: + source = rootless_path + else: + # `rootless_path` is not set to `source` if none of roots match + log = Logger.get_logger("farm_publishing") + log.warning(("Could not find root path for remapping \"{}\". " + "This may cause issues.").format(source)) + + family = instance.data["family"] + # Make sure "render" is in the families to go through + # validating expected and rendered files + # during publishing job. + families = ["render", family] + + instance_skeleton_data = { + "family": family, + "subset": data["subset"], + "families": families, + "asset": data["asset"], + "frameStart": time_data.start, + "frameEnd": time_data.end, + "handleStart": time_data.handle_start, + "handleEnd": time_data.handle_end, + "frameStartHandle": time_data.start - time_data.handle_start, + "frameEndHandle": time_data.end + time_data.handle_end, + "comment": data.get("comment"), + "fps": time_data.fps, + "source": source, + "extendFrames": data.get("extendFrames"), + "overrideExistingFrame": data.get("overrideExistingFrame"), + "jobBatchName": data.get("jobBatchName", ""), + # map inputVersions `ObjectId` -> `str` so json supports it + "inputVersions": list(map(str, data.get("inputVersions", []))), + } + + # skip locking version if we are creating v01 + instance_version = data.get("version") # take this if exists + if instance_version != 1: + instance_skeleton_data["version"] = instance_version + + representations = get_transferable_representations(instance) + instance_skeleton_data["representations"] = representations + + persistent = instance.data.get("stagingDir_persistent") is True + instance_skeleton_data["stagingDir_persistent"] = persistent + + return instance_skeleton_data + + +def prepare_cache_representations(skeleton_data, exp_files, anatomy): + """Create representations for file sequences. + + This will return representations of expected files if they are not + in hierarchy of aovs. There should be only one sequence of files for + most cases, but if not - we create representation from each of them. + + Arguments: + skeleton_data (dict): instance data for which we are + setting representations + exp_files (list): list of expected files + anatomy (Anatomy) + Returns: + list of representations + + """ + representations = [] + collections, remainders = clique.assemble(exp_files) + + log = Logger.get_logger("farm_publishing") + + # create representation for every collected sequence + for collection in collections: + ext = collection.tail.lstrip(".") + + staging = os.path.dirname(list(collection)[0]) + success, rootless_staging_dir = ( + anatomy.find_root_template_from_path(staging) + ) + if success: + staging = rootless_staging_dir + else: + log.warning(( + "Could not find root path for remapping \"{}\"." + " This may cause issues on farm." + ).format(staging)) + + frame_start = int(skeleton_data.get("frameStartHandle")) + rep = { + "name": ext, + "ext": ext, + "files": [os.path.basename(f) for f in list(collection)], + "frameStart": frame_start, + "frameEnd": int(skeleton_data.get("frameEndHandle")), + # If expectedFile are absolute, we need only filenames + "stagingDir": staging, + "fps": skeleton_data.get("fps") + } + + representations.append(rep) + + return representations + + +def create_instances_for_cache(instance, skeleton): + """Create instance for cache. + + This will create new instance for every AOV it can detect in expected + files list. + + Args: + instance (pyblish.api.Instance): Original instance. + skeleton (dict): Skeleton data for instance (those needed) later + by collector. + + + Returns: + list of instances + + Throws: + ValueError: + + """ + anatomy = instance.context.data["anatomy"] + subset = skeleton["subset"] + family = skeleton["family"] + exp_files = instance.data["expectedFiles"] + log = Logger.get_logger("farm_publishing") + + instances = [] + # go through AOVs in expected files + for _, files in exp_files[0].items(): + cols, rem = clique.assemble(files) + # we shouldn't have any reminders. And if we do, it should + # be just one item for single frame renders. + if not cols and rem: + if len(rem) != 1: + raise ValueError("Found multiple non related files " + "to render, don't know what to do " + "with them.") + col = rem[0] + ext = os.path.splitext(col)[1].lstrip(".") + else: + # but we really expect only one collection. + # Nothing else make sense. + if len(cols) != 1: + raise ValueError("Only one image sequence type is expected.") # noqa: E501 + ext = cols[0].tail.lstrip(".") + col = list(cols[0]) + + if isinstance(col, (list, tuple)): + staging = os.path.dirname(col[0]) + else: + staging = os.path.dirname(col) + + try: + staging = remap_source(staging, anatomy) + except ValueError as e: + log.warning(e) + + new_instance = deepcopy(skeleton) + + new_instance["subset"] = subset + log.info("Creating data for: {}".format(subset)) + new_instance["family"] = family + new_instance["families"] = skeleton["families"] + # create representation + if isinstance(col, (list, tuple)): + files = [os.path.basename(f) for f in col] + else: + files = os.path.basename(col) + + rep = { + "name": ext, + "ext": ext, + "files": files, + "frameStart": int(skeleton["frameStartHandle"]), + "frameEnd": int(skeleton["frameEndHandle"]), + # If expectedFile are absolute, we need only filenames + "stagingDir": staging, + "fps": new_instance.get("fps"), + "tags": [], + } + + new_instance["representations"] = [rep] + + # if extending frames from existing version, copy files from there + # into our destination directory + if new_instance.get("extendFrames", False): + copy_extend_frames(new_instance, rep) + instances.append(new_instance) + log.debug("instances:{}".format(instances)) + return instances + + def copy_extend_frames(instance, representation): """Copy existing frames from latest version. diff --git a/openpype/pipeline/legacy_io.py b/openpype/pipeline/legacy_io.py index 60fa035c22..864102dff9 100644 --- a/openpype/pipeline/legacy_io.py +++ b/openpype/pipeline/legacy_io.py @@ -30,7 +30,7 @@ def install(): session = session_data_from_environment(context_keys=True) - session["schema"] = "openpype:session-3.0" + session["schema"] = "openpype:session-4.0" try: schema.validate(session) except schema.ValidationError as e: diff --git a/openpype/pipeline/mongodb.py b/openpype/pipeline/mongodb.py index 41a44c7373..c948983c3d 100644 --- a/openpype/pipeline/mongodb.py +++ b/openpype/pipeline/mongodb.py @@ -62,8 +62,6 @@ def auto_reconnect(func): SESSION_CONTEXT_KEYS = ( - # Root directory of projects on disk - "AVALON_PROJECTS", # Name of current Project "AVALON_PROJECT", # Name of current Asset diff --git a/openpype/pipeline/schema/session-4.0.json b/openpype/pipeline/schema/session-4.0.json new file mode 100644 index 0000000000..0dab48aa46 --- /dev/null +++ b/openpype/pipeline/schema/session-4.0.json @@ -0,0 +1,61 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + + "title": "openpype:session-4.0", + "description": "The Avalon environment", + + "type": "object", + + "additionalProperties": true, + + "required": [ + "AVALON_PROJECT" + ], + + "properties": { + "AVALON_PROJECT": { + "description": "Name of project", + "type": "string", + "pattern": "^\\w*$", + "example": "Hulk" + }, + "AVALON_ASSET": { + "description": "Name of asset", + "type": "string", + "pattern": "^[\\/\\w]*$", + "example": "Bruce" + }, + "AVALON_TASK": { + "description": "Name of task", + "type": "string", + "pattern": "^\\w*$", + "example": "modeling" + }, + "AVALON_APP": { + "description": "Name of host", + "type": "string", + "pattern": "^\\w*$", + "example": "maya" + }, + "AVALON_DB": { + "description": "Name of database", + "type": "string", + "pattern": "^\\w*$", + "example": "avalon", + "default": "avalon" + }, + "AVALON_LABEL": { + "description": "Nice name of Avalon, used in e.g. graphical user interfaces", + "type": "string", + "example": "MyLabel", + "default": "Avalon" + }, + "AVALON_TIMEOUT": { + "description": "Wherever there is a need for a timeout, this is the default value.", + "type": "string", + "pattern": "^[0-9]*$", + "default": "1000", + "example": "1000" + } + } +} diff --git a/openpype/pipeline/workfile/workfile_template_builder.py b/openpype/pipeline/workfile/workfile_template_builder.py index 99bdb12543..9dc833061a 100644 --- a/openpype/pipeline/workfile/workfile_template_builder.py +++ b/openpype/pipeline/workfile/workfile_template_builder.py @@ -19,6 +19,7 @@ from abc import ABCMeta, abstractmethod import six +from openpype import AYON_SERVER_ENABLED from openpype.client import ( get_asset_by_name, get_linked_assets, @@ -1272,31 +1273,54 @@ class PlaceholderLoadMixin(object): # Sort for readability families = list(sorted(families)) - return [ + if AYON_SERVER_ENABLED: + builder_type_enum_items = [ + {"label": "Current folder", "value": "context_folder"}, + # TODO implement linked folders + # {"label": "Linked folders", "value": "linked_folders"}, + {"label": "All folders", "value": "all_folders"}, + ] + build_type_label = "Folder Builder Type" + build_type_help = ( + "Folder Builder Type\n" + "\nBuilder type describe what template loader will look" + " for." + "\nCurrent Folder: Template loader will look for products" + " of current context folder (Folder /assets/bob will" + " find asset)" + "\nAll folders: All folders matching the regex will be" + " used." + ) + else: + builder_type_enum_items = [ + {"label": "Current asset", "value": "context_asset"}, + {"label": "Linked assets", "value": "linked_asset"}, + {"label": "All assets", "value": "all_assets"}, + ] + build_type_label = "Asset Builder Type" + build_type_help = ( + "Asset Builder Type\n" + "\nBuilder type describe what template loader will look" + " for." + "\ncontext_asset : Template loader will look for subsets" + " of current context asset (Asset bob will find asset)" + "\nlinked_asset : Template loader will look for assets" + " linked to current context asset." + "\nLinked asset are looked in database under" + " field \"inputLinks\"" + ) + + attr_defs = [ attribute_definitions.UISeparatorDef(), attribute_definitions.UILabelDef("Main attributes"), attribute_definitions.UISeparatorDef(), attribute_definitions.EnumDef( "builder_type", - label="Asset Builder Type", + label=build_type_label, default=options.get("builder_type"), - items=[ - {"label": "Current asset", "value": "context_asset"}, - {"label": "Linked assets", "value": "linked_asset"}, - {"label": "All assets", "value": "all_assets"}, - ], - tooltip=( - "Asset Builder Type\n" - "\nBuilder type describe what template loader will look" - " for." - "\ncontext_asset : Template loader will look for subsets" - " of current context asset (Asset bob will find asset)" - "\nlinked_asset : Template loader will look for assets" - " linked to current context asset." - "\nLinked asset are looked in database under" - " field \"inputLinks\"" - ) + items=builder_type_enum_items, + tooltip=build_type_help ), attribute_definitions.EnumDef( "family", @@ -1352,34 +1376,63 @@ class PlaceholderLoadMixin(object): attribute_definitions.UISeparatorDef(), attribute_definitions.UILabelDef("Optional attributes"), attribute_definitions.UISeparatorDef(), - attribute_definitions.TextDef( - "asset", - label="Asset filter", - default=options.get("asset"), - placeholder="regex filtering by asset name", - tooltip=( - "Filtering assets by matching field regex to asset's name" - ) - ), - attribute_definitions.TextDef( - "subset", - label="Subset filter", - default=options.get("subset"), - placeholder="regex filtering by subset name", - tooltip=( - "Filtering assets by matching field regex to subset's name" - ) - ), - attribute_definitions.TextDef( - "hierarchy", - label="Hierarchy filter", - default=options.get("hierarchy"), - placeholder="regex filtering by asset's hierarchy", - tooltip=( - "Filtering assets by matching field asset's hierarchy" - ) - ) ] + if AYON_SERVER_ENABLED: + attr_defs.extend([ + attribute_definitions.TextDef( + "folder_path", + label="Folder filter", + default=options.get("folder_path"), + placeholder="regex filtering by folder path", + tooltip=( + "Filtering assets by matching" + " field regex to folder path" + ) + ), + attribute_definitions.TextDef( + "product_name", + label="Product filter", + default=options.get("product_name"), + placeholder="regex filtering by product name", + tooltip=( + "Filtering assets by matching" + " field regex to product name" + ) + ), + ]) + else: + attr_defs.extend([ + attribute_definitions.TextDef( + "asset", + label="Asset filter", + default=options.get("asset"), + placeholder="regex filtering by asset name", + tooltip=( + "Filtering assets by matching" + " field regex to asset's name" + ) + ), + attribute_definitions.TextDef( + "subset", + label="Subset filter", + default=options.get("subset"), + placeholder="regex filtering by subset name", + tooltip=( + "Filtering assets by matching" + " field regex to subset's name" + ) + ), + attribute_definitions.TextDef( + "hierarchy", + label="Hierarchy filter", + default=options.get("hierarchy"), + placeholder="regex filtering by asset's hierarchy", + tooltip=( + "Filtering assets by matching field asset's hierarchy" + ) + ) + ]) + return attr_defs def parse_loader_args(self, loader_args): """Helper function to parse string of loader arugments. @@ -1409,6 +1462,117 @@ class PlaceholderLoadMixin(object): return {} + def _query_by_folder_regex(self, project_name, folder_regex): + """Query folders by folder path regex. + + WARNING: + This method will be removed once the same functionality is + available in ayon-python-api. + + Args: + project_name (str): Project name. + folder_regex (str): Regex for folder path. + + Returns: + list[str]: List of folder paths. + """ + + from ayon_api.graphql_queries import folders_graphql_query + from openpype.client import get_ayon_server_api_connection + + query = folders_graphql_query({"id"}) + + folders_field = None + for child in query._children: + if child.path != "project": + continue + + for project_child in child._children: + if project_child.path == "project/folders": + folders_field = project_child + break + if folders_field: + break + + if "folderPathRegex" not in query._variables: + folder_path_regex_var = query.add_variable( + "folderPathRegex", "String!" + ) + folders_field.set_filter("pathEx", folder_path_regex_var) + + query.set_variable_value("projectName", project_name) + if folder_regex: + query.set_variable_value("folderPathRegex", folder_regex) + + api = get_ayon_server_api_connection() + for parsed_data in query.continuous_query(api): + for folder in parsed_data["project"]["folders"]: + yield folder["id"] + + def _get_representations_ayon(self, placeholder): + # An OpenPype placeholder loaded in AYON + if "asset" in placeholder.data: + return [] + + representation_name = placeholder.data["representation"] + if not representation_name: + return [] + + project_name = self.builder.project_name + current_asset_doc = self.builder.current_asset_doc + + folder_path_regex = placeholder.data["folder_path"] + product_name_regex_value = placeholder.data["product_name"] + product_name_regex = None + if product_name_regex_value: + product_name_regex = re.compile(product_name_regex_value) + product_type = placeholder.data["family"] + + builder_type = placeholder.data["builder_type"] + folder_ids = [] + if builder_type == "context_folder": + folder_ids = [current_asset_doc["_id"]] + + elif builder_type == "all_folders": + folder_ids = list(self._query_by_folder_regex( + project_name, folder_path_regex + )) + + if not folder_ids: + return [] + + from ayon_api import get_products, get_last_versions + + products = list(get_products( + project_name, + folder_ids=folder_ids, + product_types=[product_type], + fields={"id", "name"} + )) + filtered_product_ids = set() + for product in products: + if ( + product_name_regex is None + or product_name_regex.match(product["name"]) + ): + filtered_product_ids.add(product["id"]) + + if not filtered_product_ids: + return [] + + version_ids = set( + version["id"] + for version in get_last_versions( + project_name, filtered_product_ids, fields={"id"} + ).values() + ) + return list(get_representations( + project_name, + representation_names=[representation_name], + version_ids=version_ids + )) + + def _get_representations(self, placeholder): """Prepared query of representations based on load options. @@ -1428,6 +1592,13 @@ class PlaceholderLoadMixin(object): from placeholder data. """ + if AYON_SERVER_ENABLED: + return self._get_representations_ayon(placeholder) + + # An AYON placeholder loaded in OpenPype + if "folder_path" in placeholder.data: + return [] + project_name = self.builder.project_name current_asset_doc = self.builder.current_asset_doc linked_asset_docs = self.builder.linked_asset_docs diff --git a/openpype/plugins/publish/collect_anatomy_instance_data.py b/openpype/plugins/publish/collect_anatomy_instance_data.py index b4f4d6a16a..1b4b44e40e 100644 --- a/openpype/plugins/publish/collect_anatomy_instance_data.py +++ b/openpype/plugins/publish/collect_anatomy_instance_data.py @@ -30,7 +30,8 @@ import pyblish.api from openpype.client import ( get_assets, get_subsets, - get_last_versions + get_last_versions, + get_asset_name_identifier, ) from openpype.pipeline.version_start import get_versioning_start @@ -60,6 +61,9 @@ class CollectAnatomyInstanceData(pyblish.api.ContextPlugin): self.log.debug("Querying asset documents for instances.") context_asset_doc = context.data.get("assetEntity") + context_asset_name = None + if context_asset_doc: + context_asset_name = get_asset_name_identifier(context_asset_doc) instances_with_missing_asset_doc = collections.defaultdict(list) for instance in context: @@ -68,15 +72,15 @@ class CollectAnatomyInstanceData(pyblish.api.ContextPlugin): # There is possibility that assetEntity on instance is already set # which can happen in standalone publisher - if ( - instance_asset_doc - and instance_asset_doc["name"] == _asset_name - ): - continue + if instance_asset_doc: + instance_asset_name = get_asset_name_identifier( + instance_asset_doc) + if instance_asset_name == _asset_name: + continue # Check if asset name is the same as what is in context # - they may be different, e.g. in NukeStudio - if context_asset_doc and context_asset_doc["name"] == _asset_name: + if context_asset_name and context_asset_name == _asset_name: instance.data["assetEntity"] = context_asset_doc else: @@ -93,7 +97,7 @@ class CollectAnatomyInstanceData(pyblish.api.ContextPlugin): asset_docs = get_assets(project_name, asset_names=asset_names) asset_docs_by_name = { - asset_doc["name"]: asset_doc + get_asset_name_identifier(asset_doc): asset_doc for asset_doc in asset_docs } @@ -183,35 +187,29 @@ class CollectAnatomyInstanceData(pyblish.api.ContextPlugin): self.log.debug("Storing anatomy data to instance data.") project_doc = context.data["projectEntity"] - context_asset_doc = context.data.get("assetEntity") - project_task_types = project_doc["config"]["tasks"] for instance in context: + asset_doc = instance.data.get("assetEntity") anatomy_updates = { - "asset": instance.data["asset"], - "folder": { - "name": instance.data["asset"], - }, "family": instance.data["family"], "subset": instance.data["subset"], } - - # Hierarchy - asset_doc = instance.data.get("assetEntity") - if ( - asset_doc - and ( - not context_asset_doc - or asset_doc["_id"] != context_asset_doc["_id"] - ) - ): + if asset_doc: parents = asset_doc["data"].get("parents") or list() parent_name = project_doc["name"] if parents: parent_name = parents[-1] - anatomy_updates["hierarchy"] = "/".join(parents) - anatomy_updates["parent"] = parent_name + + hierarchy = "/".join(parents) + anatomy_updates.update({ + "asset": asset_doc["name"], + "hierarchy": hierarchy, + "parent": parent_name, + "folder": { + "name": asset_doc["name"], + }, + }) # Task task_type = None diff --git a/openpype/plugins/publish/collect_audio.py b/openpype/plugins/publish/collect_audio.py index 6aaadfc568..734a625852 100644 --- a/openpype/plugins/publish/collect_audio.py +++ b/openpype/plugins/publish/collect_audio.py @@ -6,6 +6,7 @@ from openpype.client import ( get_subsets, get_last_versions, get_representations, + get_asset_name_identifier, ) from openpype.pipeline.load import get_representation_path_with_anatomy @@ -121,12 +122,13 @@ class CollectAudio(pyblish.api.ContextPlugin): asset_docs = get_assets( project_name, asset_names=asset_names, - fields=["_id", "name"] + fields=["_id", "name", "data.parents"] ) - asset_id_by_name = {} - for asset_doc in asset_docs: - asset_id_by_name[asset_doc["name"]] = asset_doc["_id"] + asset_id_by_name = { + get_asset_name_identifier(asset_doc): asset_doc["_id"] + for asset_doc in asset_docs + } asset_ids = set(asset_id_by_name.values()) # Query subsets with name define by 'audio_subset_name' attr diff --git a/openpype/plugins/publish/collect_from_create_context.py b/openpype/plugins/publish/collect_from_create_context.py index 8806a13ca0..84f6141069 100644 --- a/openpype/plugins/publish/collect_from_create_context.py +++ b/openpype/plugins/publish/collect_from_create_context.py @@ -4,6 +4,7 @@ import os import pyblish.api +from openpype import AYON_SERVER_ENABLED from openpype.host import IPublishHost from openpype.pipeline import legacy_io, registered_host from openpype.pipeline.create import CreateContext @@ -38,6 +39,8 @@ class CollectFromCreateContext(pyblish.api.ContextPlugin): for created_instance in create_context.instances: instance_data = created_instance.data_to_store() + if AYON_SERVER_ENABLED: + instance_data["asset"] = instance_data.pop("folderPath") if instance_data["active"]: thumbnail_path = thumbnail_paths_by_instance_id.get( created_instance.id diff --git a/openpype/plugins/publish/collect_resources_path.py b/openpype/plugins/publish/collect_resources_path.py index 14c13310df..0f29fec054 100644 --- a/openpype/plugins/publish/collect_resources_path.py +++ b/openpype/plugins/publish/collect_resources_path.py @@ -68,11 +68,6 @@ class CollectResourcesPath(pyblish.api.InstancePlugin): ] def process(self, instance): - # editorial would fail since they might not be in database yet - is_editorial = instance.data.get("isEditorial") - if is_editorial: - self.log.debug("Instance is Editorial. Skipping.") - return anatomy = instance.context.data["anatomy"] diff --git a/openpype/plugins/publish/extract_burnin.py b/openpype/plugins/publish/extract_burnin.py index 9a978ed286..56d45e477b 100644 --- a/openpype/plugins/publish/extract_burnin.py +++ b/openpype/plugins/publish/extract_burnin.py @@ -89,8 +89,8 @@ class ExtractBurnin(publish.Extractor): self.main_process(instance) - # Remove any representations tagged for deletion. - # QUESTION Is possible to have representation with "delete" tag? + # Remove only representation tagged with both + # tags `delete` and `burnin` for repre in tuple(instance.data["representations"]): if all(x in repre.get("tags", []) for x in ['delete', 'burnin']): self.log.debug("Removing representation: {}".format(repre)) diff --git a/openpype/plugins/publish/extract_hierarchy_to_ayon.py b/openpype/plugins/publish/extract_hierarchy_to_ayon.py index 0d9131718b..ef69369d67 100644 --- a/openpype/plugins/publish/extract_hierarchy_to_ayon.py +++ b/openpype/plugins/publish/extract_hierarchy_to_ayon.py @@ -8,7 +8,7 @@ from ayon_api import slugify_string from ayon_api.entity_hub import EntityHub from openpype import AYON_SERVER_ENABLED -from openpype.client import get_assets +from openpype.client import get_assets, get_asset_name_identifier from openpype.pipeline.template_data import ( get_asset_template_data, get_task_template_data, @@ -58,7 +58,7 @@ class ExtractHierarchyToAYON(pyblish.api.ContextPlugin): project_name, asset_names=instances_by_asset_name.keys() ) asset_docs_by_name = { - asset_doc["name"]: asset_doc + get_asset_name_identifier(asset_doc): asset_doc for asset_doc in asset_docs } for asset_name, instances in instances_by_asset_name.items(): @@ -191,15 +191,15 @@ class ExtractHierarchyToAYON(pyblish.api.ContextPlugin): """ # filter only the active publishing instances - active_folder_names = set() + active_folder_paths = set() for instance in context: if instance.data.get("publish") is not False: - active_folder_names.add(instance.data.get("asset")) + active_folder_paths.add(instance.data.get("asset")) - active_folder_names.discard(None) + active_folder_paths.discard(None) - self.log.debug("Active folder names: {}".format(active_folder_names)) - if not active_folder_names: + self.log.debug("Active folder paths: {}".format(active_folder_paths)) + if not active_folder_paths: return None project_item = None @@ -230,12 +230,13 @@ class ExtractHierarchyToAYON(pyblish.api.ContextPlugin): if not children_context: continue - for asset_name, asset_info in children_context.items(): + for asset, asset_info in children_context.items(): if ( - asset_name not in active_folder_names + asset not in active_folder_paths and not asset_info.get("childs") ): continue + asset_name = asset.split("/")[-1] item_id = uuid.uuid4().hex new_item = copy.deepcopy(asset_info) new_item["name"] = asset_name @@ -252,7 +253,7 @@ class ExtractHierarchyToAYON(pyblish.api.ContextPlugin): items_by_id[item_id] = new_item parent_id_by_item_id[item_id] = parent_id - if asset_name in active_folder_names: + if asset in active_folder_paths: valid_ids.add(item_id) hierarchy_queue.append((item_id, new_children_context)) diff --git a/openpype/plugins/publish/extract_otio_audio_tracks.py b/openpype/plugins/publish/extract_otio_audio_tracks.py index 4b73321f02..d5ab1d6032 100644 --- a/openpype/plugins/publish/extract_otio_audio_tracks.py +++ b/openpype/plugins/publish/extract_otio_audio_tracks.py @@ -319,6 +319,7 @@ class ExtractOtioAudioTracks(pyblish.api.ContextPlugin): Returns: str: temp fpath """ + name = name.replace("/", "_") return os.path.normpath( tempfile.mktemp( prefix="pyblish_tmp_{}_".format(name), diff --git a/openpype/plugins/publish/extract_review.py b/openpype/plugins/publish/extract_review.py index cd0f78530a..8448c45e70 100644 --- a/openpype/plugins/publish/extract_review.py +++ b/openpype/plugins/publish/extract_review.py @@ -89,8 +89,18 @@ class ExtractReview(pyblish.api.InstancePlugin): # Make sure cleanup happens and pop representations with "delete" tag. for repre in tuple(instance.data["representations"]): tags = repre.get("tags") or [] - if "delete" in tags and "thumbnail" not in tags: - instance.data["representations"].remove(repre) + # Representation is not marked to be deleted + if "delete" not in tags: + continue + + # The representation can be used as thumbnail source + if "thumbnail" in tags or "need_thumbnail" in tags: + continue + + self.log.debug( + "Removing representation: {}".format(repre) + ) + instance.data["representations"].remove(repre) def _get_outputs_for_instance(self, instance): host_name = instance.context.data["hostName"] @@ -321,19 +331,26 @@ class ExtractReview(pyblish.api.InstancePlugin): # Create copy of representation new_repre = copy.deepcopy(repre) + new_tags = new_repre.get("tags") or [] # Make sure new representation has origin staging dir # - this is because source representation may change # it's staging dir because of ffmpeg conversion new_repre["stagingDir"] = src_repre_staging_dir # Remove "delete" tag from new repre if there is - if "delete" in new_repre["tags"]: - new_repre["tags"].remove("delete") + if "delete" in new_tags: + new_tags.remove("delete") + + if "need_thumbnail" in new_tags: + new_tags.remove("need_thumbnail") # Add additional tags from output definition to representation for tag in output_def["tags"]: - if tag not in new_repre["tags"]: - new_repre["tags"].append(tag) + if tag not in new_tags: + new_tags.append(tag) + + # Return tags to new representation + new_repre["tags"] = new_tags # Add burnin link from output definition to representation for burnin in output_def["burnins"]: diff --git a/openpype/plugins/publish/extract_review_slate.py b/openpype/plugins/publish/extract_review_slate.py index d89fbb90c4..4e3406d3f9 100644 --- a/openpype/plugins/publish/extract_review_slate.py +++ b/openpype/plugins/publish/extract_review_slate.py @@ -376,9 +376,13 @@ class ExtractReviewSlate(publish.Extractor): # Remove any representations tagged for deletion. for repre in inst_data.get("representations", []): - if "delete" in repre.get("tags", []): - self.log.debug("Removing representation: {}".format(repre)) - inst_data["representations"].remove(repre) + tags = repre.get("tags", []) + if "delete" not in tags: + continue + if "need_thumbnail" in tags: + continue + self.log.debug("Removing representation: {}".format(repre)) + inst_data["representations"].remove(repre) self.log.debug(inst_data["representations"]) diff --git a/openpype/plugins/publish/extract_thumbnail.py b/openpype/plugins/publish/extract_thumbnail.py index 0ddbb3f40b..2b4ea0529a 100644 --- a/openpype/plugins/publish/extract_thumbnail.py +++ b/openpype/plugins/publish/extract_thumbnail.py @@ -1,3 +1,4 @@ +import copy import os import subprocess import tempfile @@ -5,12 +6,17 @@ import tempfile import pyblish.api from openpype.lib import ( get_ffmpeg_tool_args, - get_oiio_tool_args, - is_oiio_supported, + get_ffprobe_data, + + is_oiio_supported, + get_rescaled_command_arguments, - run_subprocess, path_to_subprocess_arg, + run_subprocess, ) +from openpype.lib.transcoding import convert_colorspace + +from openpype.lib.transcoding import VIDEO_EXTENSIONS class ExtractThumbnail(pyblish.api.InstancePlugin): @@ -22,13 +28,49 @@ class ExtractThumbnail(pyblish.api.InstancePlugin): "imagesequence", "render", "render2d", "prerender", "source", "clip", "take", "online", "image" ] - hosts = ["shell", "fusion", "resolve", "traypublisher", "substancepainter"] + hosts = [ + "shell", + "fusion", + "resolve", + "traypublisher", + "substancepainter", + "nuke", + ] enabled = False - # presetable attribute + integrate_thumbnail = False + target_size = { + "type": "resize", + "width": 1920, + "height": 1080 + } + background_color = None + duration_split = 0.5 + # attribute presets from settings + oiiotool_defaults = None ffmpeg_args = None def process(self, instance): + # run main process + self._main_process(instance) + + # Make sure cleanup happens to representations which are having both + # tags `delete` and `need_thumbnail` + for repre in tuple(instance.data.get("representations", [])): + tags = repre.get("tags") or [] + # skip representations which are going to be published on farm + if "publish_on_farm" in tags: + continue + if ( + "delete" in tags + and "need_thumbnail" in tags + ): + self.log.debug( + "Removing representation: {}".format(repre) + ) + instance.data["representations"].remove(repre) + + def _main_process(self, instance): subset_name = instance.data["subset"] instance_repres = instance.data.get("representations") if not instance_repres: @@ -61,7 +103,13 @@ class ExtractThumbnail(pyblish.api.InstancePlugin): self.log.debug("Skipping crypto passes.") return - filtered_repres = self._get_filtered_repres(instance) + # first check for any explicitly marked representations for thumbnail + explicit_repres = self._get_explicit_repres_for_thumbnail(instance) + if explicit_repres: + filtered_repres = explicit_repres + else: + filtered_repres = self._get_filtered_repres(instance) + if not filtered_repres: self.log.info( "Instance doesn't have representations that can be used " @@ -82,29 +130,62 @@ class ExtractThumbnail(pyblish.api.InstancePlugin): oiio_supported = is_oiio_supported() for repre in filtered_repres: repre_files = repre["files"] + src_staging = os.path.normpath(repre["stagingDir"]) if not isinstance(repre_files, (list, tuple)): - input_file = repre_files + # convert any video file to frame so oiio doesn't need to + # read video file (it is slow) and also we are having control + # over which frame is used for thumbnail + # this will also work with ffmpeg fallback conversion in case + # oiio is not supported + repre_extension = os.path.splitext(repre_files)[1] + if repre_extension in VIDEO_EXTENSIONS: + video_file_path = os.path.join( + src_staging, repre_files + ) + file_path = self._create_frame_from_video( + video_file_path, + dst_staging + ) + if file_path: + src_staging, input_file = os.path.split(file_path) + else: + # if it is not video file then just use first file + input_file = repre_files else: - file_index = int(float(len(repre_files)) * 0.5) + repre_files_thumb = copy.deepcopy(repre_files) + # exclude first frame if slate in representation tags + if "slate-frame" in repre.get("tags", []): + repre_files_thumb = repre_files_thumb[1:] + file_index = int( + float(len(repre_files_thumb)) * self.duration_split) input_file = repre_files[file_index] - src_staging = os.path.normpath(repre["stagingDir"]) full_input_path = os.path.join(src_staging, input_file) self.log.debug("input {}".format(full_input_path)) + filename = os.path.splitext(input_file)[0] jpeg_file = filename + "_thumb.jpg" full_output_path = os.path.join(dst_staging, jpeg_file) + colorspace_data = repre.get("colorspaceData") - if oiio_supported: - self.log.debug("Trying to convert with OIIO") + # only use OIIO if it is supported and representation has + # colorspace data + if oiio_supported and colorspace_data: + self.log.debug( + "Trying to convert with OIIO " + "with colorspace data: {}".format(colorspace_data) + ) # If the input can read by OIIO then use OIIO method for # conversion otherwise use ffmpeg - thumbnail_created = self.create_thumbnail_oiio( - full_input_path, full_output_path + thumbnail_created = self._create_thumbnail_oiio( + full_input_path, + full_output_path, + colorspace_data ) # Try to use FFMPEG if OIIO is not supported or for cases when - # oiiotool isn't available + # oiiotool isn't available or representation is not having + # colorspace data if not thumbnail_created: if oiio_supported: self.log.debug( @@ -112,7 +193,7 @@ class ExtractThumbnail(pyblish.api.InstancePlugin): " can't be read by OIIO." ) - thumbnail_created = self.create_thumbnail_ffmpeg( + thumbnail_created = self._create_thumbnail_ffmpeg( full_input_path, full_output_path ) @@ -120,25 +201,58 @@ class ExtractThumbnail(pyblish.api.InstancePlugin): if not thumbnail_created: continue + if len(explicit_repres) > 1: + repre_name = "thumbnail_{}".format(repre["outputName"]) + else: + repre_name = "thumbnail" + + # add thumbnail path to instance data for integrator + instance_thumb_path = instance.data.get("thumbnailPath") + if ( + not instance_thumb_path + or not os.path.isfile(instance_thumb_path) + ): + self.log.debug( + "Adding thumbnail path to instance data: {}".format( + full_output_path + ) + ) + instance.data["thumbnailPath"] = full_output_path + + new_repre_tags = ["thumbnail"] + # for workflows which needs to have thumbnails published as + # separate representations `delete` tag should not be added + if not self.integrate_thumbnail: + new_repre_tags.append("delete") + new_repre = { - "name": "thumbnail", + "name": repre_name, "ext": "jpg", "files": jpeg_file, "stagingDir": dst_staging, "thumbnail": True, - "tags": ["thumbnail"] + "tags": new_repre_tags } # adding representation - self.log.debug( - "Adding thumbnail representation: {}".format(new_repre) - ) instance.data["representations"].append(new_repre) - # There is no need to create more then one thumbnail - break + + if explicit_repres: + # this key will then align assetVersion ftrack thumbnail sync + new_repre["outputName"] = ( + repre.get("outputName") or repre["name"]) + self.log.debug( + "Adding explicit thumbnail representation: {}".format( + new_repre)) + else: + self.log.debug( + "Adding thumbnail representation: {}".format(new_repre) + ) + # There is no need to create more then one thumbnail + break if not thumbnail_created: - self.log.warning("Thumbanil has not been created.") + self.log.warning("Thumbnail has not been created.") def _is_review_instance(self, instance): # TODO: We should probably handle "not creating" of thumbnail @@ -154,12 +268,42 @@ class ExtractThumbnail(pyblish.api.InstancePlugin): return True return False + def _get_explicit_repres_for_thumbnail(self, instance): + src_repres = instance.data.get("representations") or [] + # This is mainly for Nuke where we have multiple representations for + # one instance and representations are tagged for thumbnail. + # First check if any of the representations have + # `need_thumbnail` in tags and add them to filtered_repres + need_thumb_repres = [ + repre for repre in src_repres + if "need_thumbnail" in repre.get("tags", []) + if "publish_on_farm" not in repre.get("tags", []) + ] + if not need_thumb_repres: + return [] + + self.log.info( + "Instance has representation with tag `need_thumbnail`. " + "Using only this representations for thumbnail creation. " + ) + self.log.debug( + "Representations: {}".format(need_thumb_repres) + ) + return need_thumb_repres + def _get_filtered_repres(self, instance): filtered_repres = [] src_repres = instance.data.get("representations") or [] + for repre in src_repres: self.log.debug(repre) tags = repre.get("tags") or [] + + if "publish_on_farm" in tags: + # only process representations with are going + # to be published locally + continue + valid = "review" in tags or "thumb-nuke" in tags if not valid: continue @@ -173,17 +317,68 @@ class ExtractThumbnail(pyblish.api.InstancePlugin): filtered_repres.append(repre) return filtered_repres - def create_thumbnail_oiio(self, src_path, dst_path): - self.log.debug("Extracting thumbnail with OIIO: {}".format(dst_path)) - oiio_cmd = get_oiio_tool_args( - "oiiotool", - "-a", src_path, - "-o", dst_path - ) - self.log.debug("running: {}".format(" ".join(oiio_cmd))) + def _create_thumbnail_oiio( + self, + src_path, + dst_path, + colorspace_data, + ): + """Create thumbnail using OIIO tool oiiotool + + Args: + src_path (str): path to source file + dst_path (str): path to destination file + colorspace_data (dict): colorspace data from representation + keys: + colorspace (str) + config (dict) + display (Optional[str]) + view (Optional[str]) + + Returns: + str: path to created thumbnail + """ + self.log.info("Extracting thumbnail {}".format(dst_path)) + resolution_arg = self._get_resolution_arg("oiiotool", src_path) + + repre_display = colorspace_data.get("display") + repre_view = colorspace_data.get("view") + oiio_default_type = None + oiio_default_display = None + oiio_default_view = None + oiio_default_colorspace = None + # first look into representation colorspaceData, perhaps it has + # display and view + if all([repre_display, repre_view]): + self.log.info( + "Using Display & View from " + "representation: '{} ({})'".format( + repre_view, + repre_display + ) + ) + # if representation doesn't have display and view then use + # oiiotool_defaults + elif self.oiiotool_defaults: + oiio_default_type = self.oiiotool_defaults["type"] + if "colorspace" in oiio_default_type: + oiio_default_colorspace = self.oiiotool_defaults["colorspace"] + else: + oiio_default_display = self.oiiotool_defaults["display"] + oiio_default_view = self.oiiotool_defaults["view"] + try: - run_subprocess(oiio_cmd, logger=self.log) - return True + convert_colorspace( + src_path, + dst_path, + colorspace_data["config"]["path"], + colorspace_data["colorspace"], + display=repre_display or oiio_default_display, + view=repre_view or oiio_default_view, + target_colorspace=oiio_default_colorspace, + additional_command_args=resolution_arg, + logger=self.log, + ) except Exception: self.log.warning( "Failed to create thumbnail using oiiotool", @@ -191,9 +386,11 @@ class ExtractThumbnail(pyblish.api.InstancePlugin): ) return False - def create_thumbnail_ffmpeg(self, src_path, dst_path): - self.log.debug("Extracting thumbnail with FFMPEG: {}".format(dst_path)) + return True + def _create_thumbnail_ffmpeg(self, src_path, dst_path): + self.log.debug("Extracting thumbnail with FFMPEG: {}".format(dst_path)) + resolution_arg = self._get_resolution_arg("ffmpeg", src_path) ffmpeg_path_args = get_ffmpeg_tool_args("ffmpeg") ffmpeg_args = self.ffmpeg_args or {} @@ -215,6 +412,10 @@ class ExtractThumbnail(pyblish.api.InstancePlugin): jpeg_items.extend(ffmpeg_args.get("output") or []) # we just want one frame from movie files jpeg_items.extend(["-vframes", "1"]) + + if resolution_arg: + jpeg_items.extend(resolution_arg) + # output file jpeg_items.append(path_to_subprocess_arg(dst_path)) subprocess_command = " ".join(jpeg_items) @@ -229,3 +430,69 @@ class ExtractThumbnail(pyblish.api.InstancePlugin): exc_info=True ) return False + + def _create_frame_from_video(self, video_file_path, output_dir): + """Convert video file to one frame image via ffmpeg""" + # create output file path + base_name = os.path.basename(video_file_path) + filename = os.path.splitext(base_name)[0] + output_thumb_file_path = os.path.join( + output_dir, "{}.png".format(filename)) + + # Set video input attributes + max_int = str(2147483647) + video_data = get_ffprobe_data(video_file_path, logger=self.log) + duration = float(video_data["format"]["duration"]) + + cmd_args = [ + "-y", + "-ss", str(duration * self.duration_split), + "-i", video_file_path, + "-analyzeduration", max_int, + "-probesize", max_int, + "-vframes", "1" + ] + + # add output file path + cmd_args.append(output_thumb_file_path) + + # create ffmpeg command + cmd = get_ffmpeg_tool_args( + "ffmpeg", + *cmd_args + ) + try: + # run subprocess + self.log.debug("Executing: {}".format(" ".join(cmd))) + run_subprocess(cmd, logger=self.log) + self.log.debug( + "Thumbnail created: {}".format(output_thumb_file_path)) + return output_thumb_file_path + except RuntimeError as error: + self.log.warning( + "Failed intermediate thumb source using ffmpeg: {}".format( + error) + ) + return None + + def _get_resolution_arg( + self, + application, + input_path, + ): + # get settings + if self.target_size.get("type") == "source": + return [] + + target_width = self.target_size["width"] + target_height = self.target_size["height"] + + # form arg string per application + return get_rescaled_command_arguments( + application, + input_path, + target_width, + target_height, + bg_color=self.background_color, + log=self.log + ) diff --git a/openpype/plugins/publish/integrate.py b/openpype/plugins/publish/integrate.py index 5bb51a3049..581c0c012f 100644 --- a/openpype/plugins/publish/integrate.py +++ b/openpype/plugins/publish/integrate.py @@ -137,7 +137,6 @@ class IntegrateAsset(pyblish.api.InstancePlugin): "mvUsd", "mvUsdComposition", "mvUsdOverride", - "simpleUnrealTexture", "online", "uasset", "blendScene", diff --git a/openpype/plugins/publish/integrate_thumbnail_ayon.py b/openpype/plugins/publish/integrate_thumbnail_ayon.py index f9b48eebec..1947c9dd4c 100644 --- a/openpype/plugins/publish/integrate_thumbnail_ayon.py +++ b/openpype/plugins/publish/integrate_thumbnail_ayon.py @@ -72,7 +72,7 @@ class IntegrateThumbnailsAYON(pyblish.api.ContextPlugin): ) def _prepare_instances(self, context): - context_thumbnail_path = context.get("thumbnailPath") + context_thumbnail_path = context.data.get("thumbnailPath") valid_context_thumbnail = bool( context_thumbnail_path and os.path.exists(context_thumbnail_path) @@ -92,8 +92,13 @@ class IntegrateThumbnailsAYON(pyblish.api.ContextPlugin): continue # Find thumbnail path on instance - thumbnail_path = self._get_instance_thumbnail_path( - published_repres) + thumbnail_source = instance.data.get("thumbnailSource") + thumbnail_path = instance.data.get("thumbnailPath") + thumbnail_path = ( + thumbnail_source + or thumbnail_path + or self._get_instance_thumbnail_path(published_repres) + ) if thumbnail_path: self.log.debug(( "Found thumbnail path for instance \"{}\"." @@ -131,7 +136,7 @@ class IntegrateThumbnailsAYON(pyblish.api.ContextPlugin): thumb_repre_doc = None for repre_info in published_representations.values(): repre_doc = repre_info["representation"] - if repre_doc["name"].lower() == "thumbnail": + if "thumbnail" in repre_doc["name"].lower(): thumb_repre_doc = repre_doc break @@ -157,8 +162,8 @@ class IntegrateThumbnailsAYON(pyblish.api.ContextPlugin): ): from openpype.client.server.operations import create_thumbnail - op_session = OperationsSession() - + # Make sure each entity id has defined only one thumbnail id + thumbnail_info_by_entity_id = {} for instance_item in filtered_instance_items: instance, thumbnail_path, version_id = instance_item instance_label = self._get_instance_label(instance) @@ -172,12 +177,10 @@ class IntegrateThumbnailsAYON(pyblish.api.ContextPlugin): thumbnail_id = create_thumbnail(project_name, thumbnail_path) # Set thumbnail id for version - op_session.update_entity( - project_name, - version_doc["type"], - version_doc["_id"], - {"data.thumbnail_id": thumbnail_id} - ) + thumbnail_info_by_entity_id[version_id] = { + "thumbnail_id": thumbnail_id, + "entity_type": version_doc["type"], + } if version_doc["type"] == "hero_version": version_name = "Hero" else: @@ -187,16 +190,23 @@ class IntegrateThumbnailsAYON(pyblish.api.ContextPlugin): )) asset_entity = instance.data["assetEntity"] - op_session.update_entity( - project_name, - asset_entity["type"], - asset_entity["_id"], - {"data.thumbnail_id": thumbnail_id} - ) + thumbnail_info_by_entity_id[asset_entity["_id"]] = { + "thumbnail_id": thumbnail_id, + "entity_type": "asset", + } self.log.debug("Setting thumbnail for asset \"{}\" <{}>".format( asset_entity["name"], version_id )) + op_session = OperationsSession() + for entity_id, thumbnail_info in thumbnail_info_by_entity_id.items(): + thumbnail_id = thumbnail_info["thumbnail_id"] + op_session.update_entity( + project_name, + thumbnail_info["entity_type"], + entity_id, + {"data.thumbnail_id": thumbnail_id} + ) op_session.commit() def _get_instance_label(self, instance): diff --git a/openpype/plugins/publish/validate_editorial_asset_name.py b/openpype/plugins/publish/validate_editorial_asset_name.py index fca0d8e7f5..b5afc49f2e 100644 --- a/openpype/plugins/publish/validate_editorial_asset_name.py +++ b/openpype/plugins/publish/validate_editorial_asset_name.py @@ -2,7 +2,7 @@ from pprint import pformat import pyblish.api -from openpype.client import get_assets +from openpype.client import get_assets, get_asset_name_identifier class ValidateEditorialAssetName(pyblish.api.ContextPlugin): @@ -34,8 +34,11 @@ class ValidateEditorialAssetName(pyblish.api.ContextPlugin): self.log.debug("__ db_assets: {}".format(db_assets)) asset_db_docs = { - str(e["name"]): [str(p) for p in e["data"]["parents"]] - for e in db_assets} + get_asset_name_identifier(asset_doc): list( + asset_doc["data"]["parents"] + ) + for asset_doc in db_assets + } self.log.debug("__ project_entities: {}".format( pformat(asset_db_docs))) diff --git a/openpype/pype_commands.py b/openpype/pype_commands.py index b5828d3dfe..f744337c67 100644 --- a/openpype/pype_commands.py +++ b/openpype/pype_commands.py @@ -185,7 +185,7 @@ class PypeCommands: task, app, env_group=env_group, - launch_type=LaunchTypes.farm_render, + launch_type=LaunchTypes.farm_render ) else: env = os.environ.copy() @@ -214,7 +214,7 @@ class PypeCommands: def run_tests(self, folder, mark, pyargs, test_data_folder, persist, app_variant, timeout, setup_only, - mongo_url, app_group): + mongo_url, app_group, dump_databases): """ Runs tests from 'folder' @@ -275,6 +275,13 @@ class PypeCommands: if mongo_url: args.extend(["--mongo_url", mongo_url]) + if dump_databases: + msg = "dump_databases format is not recognized: {}".format( + dump_databases + ) + assert dump_databases in ["bson", "json"], msg + args.extend(["--dump_databases", dump_databases]) + print("run_tests args: {}".format(args)) import pytest pytest.main(args) diff --git a/openpype/resources/__init__.py b/openpype/resources/__init__.py index b33d1bf023..c429fb8c3e 100644 --- a/openpype/resources/__init__.py +++ b/openpype/resources/__init__.py @@ -1,6 +1,6 @@ import os from openpype import AYON_SERVER_ENABLED -from openpype.lib.openpype_version import is_running_staging +from openpype.lib.openpype_version import is_staging_enabled RESOURCES_DIR = os.path.dirname(os.path.abspath(__file__)) @@ -59,7 +59,7 @@ def get_openpype_icon_filepath(staging=None): return get_resource("icons", "AYON_icon_dev.png") if staging is None: - staging = is_running_staging() + staging = is_staging_enabled() if staging: return get_openpype_staging_icon_filepath() @@ -68,7 +68,7 @@ def get_openpype_icon_filepath(staging=None): def get_openpype_splash_filepath(staging=None): if staging is None: - staging = is_running_staging() + staging = is_staging_enabled() if AYON_SERVER_ENABLED: if os.getenv("AYON_USE_DEV") == "1": diff --git a/openpype/resources/app_icons/wrap.png b/openpype/resources/app_icons/wrap.png new file mode 100644 index 0000000000..34ae1d68ed Binary files /dev/null and b/openpype/resources/app_icons/wrap.png differ diff --git a/openpype/settings/ayon_settings.py b/openpype/settings/ayon_settings.py index 5171517232..222ce68c0f 100644 --- a/openpype/settings/ayon_settings.py +++ b/openpype/settings/ayon_settings.py @@ -572,6 +572,27 @@ def _convert_maya_project_settings(ayon_settings, output): for item in viewport_options["pluginObjects"] } + ayon_playblast_settings = ayon_publish["ExtractPlayblast"]["profiles"] + if ayon_playblast_settings: + for setting in ayon_playblast_settings: + capture_preset = setting["capture_preset"] + display_options = capture_preset["DisplayOptions"] + for key in ("background", "backgroundBottom", "backgroundTop"): + display_options[key] = _convert_color(display_options[key]) + + for src_key, dst_key in ( + ("DisplayOptions", "Display Options"), + ("ViewportOptions", "Viewport Options"), + ("CameraOptions", "Camera Options"), + ): + capture_preset[dst_key] = capture_preset.pop(src_key) + + viewport_options = capture_preset["Viewport Options"] + viewport_options["pluginObjects"] = { + item["name"]: item["value"] + for item in viewport_options["pluginObjects"] + } + # Extract Camera Alembic bake attributes try: bake_attributes = json.loads( @@ -821,28 +842,6 @@ def _convert_nuke_project_settings(ayon_settings, output): collect_instance_data.pop( "sync_workfile_version_on_product_types")) - # TODO 'ExtractThumbnail' does not have ideal schema in v3 - ayon_extract_thumbnail = ayon_publish["ExtractThumbnail"] - new_thumbnail_nodes = {} - for item in ayon_extract_thumbnail["nodes"]: - name = item["nodeclass"] - value = [] - for knob in _convert_nuke_knobs(item["knobs"]): - knob_name = knob["name"] - # This may crash - if knob["type"] == "expression": - knob_value = knob["expression"] - else: - knob_value = knob["value"] - value.append([knob_name, knob_value]) - new_thumbnail_nodes[name] = value - - ayon_extract_thumbnail["nodes"] = new_thumbnail_nodes - - if "reposition_nodes" in ayon_extract_thumbnail: - for item in ayon_extract_thumbnail["reposition_nodes"]: - item["knobs"] = _convert_nuke_knobs(item["knobs"]) - # --- ImageIO --- # NOTE 'monitorOutLut' is maybe not yet in v3 (ut should be) _convert_host_imageio(ayon_nuke) @@ -1241,6 +1240,26 @@ def _convert_global_project_settings(ayon_settings, output, default_settings): profile["outputs"] = new_outputs + # ExtractThumbnail plugin + ayon_extract_thumbnail = ayon_publish["ExtractThumbnail"] + # fix display and view at oiio defaults + ayon_default_oiio = copy.deepcopy( + ayon_extract_thumbnail["oiiotool_defaults"]) + display_and_view = ayon_default_oiio.pop("display_and_view") + ayon_default_oiio["display"] = display_and_view["display"] + ayon_default_oiio["view"] = display_and_view["view"] + ayon_extract_thumbnail["oiiotool_defaults"] = ayon_default_oiio + # fix target size + ayon_default_resize = copy.deepcopy(ayon_extract_thumbnail["target_size"]) + resize = ayon_default_resize.pop("resize") + ayon_default_resize["width"] = resize["width"] + ayon_default_resize["height"] = resize["height"] + ayon_extract_thumbnail["target_size"] = ayon_default_resize + # fix background color + ayon_extract_thumbnail["background_color"] = _convert_color( + ayon_extract_thumbnail["background_color"] + ) + # ExtractOIIOTranscode plugin extract_oiio_transcode = ayon_publish["ExtractOIIOTranscode"] extract_oiio_transcode_profiles = extract_oiio_transcode["profiles"] @@ -1591,3 +1610,18 @@ def get_ayon_system_settings(default_values): return convert_system_settings( ayon_settings, default_values, addon_versions ) + + +def get_ayon_settings(project_name=None): + """AYON studio settings. + + Raw AYON settings values. + + Args: + project_name (Optional[str]): Project name. + + Returns: + dict[str, Any]: AYON settings. + """ + + return _AyonSettingsCache.get_value_by_project(project_name) diff --git a/openpype/settings/defaults/project_anatomy/templates.json b/openpype/settings/defaults/project_anatomy/templates.json index 5766a09100..6c3e038d27 100644 --- a/openpype/settings/defaults/project_anatomy/templates.json +++ b/openpype/settings/defaults/project_anatomy/templates.json @@ -38,16 +38,6 @@ "file": "{subset}_{@version}<_{output}><.{@frame}>.{ext}", "path": "{@folder}/{@file}" }, - "simpleUnrealTextureHero": { - "folder": "{root[work]}/{project[name]}/{hierarchy}/{asset}/publish/{family}/hero", - "file": "{originalBasename}.{ext}", - "path": "{@folder}/{@file}" - }, - "simpleUnrealTexture": { - "folder": "{root[work]}/{project[name]}/{hierarchy}/{asset}/publish/{family}/{@version}", - "file": "{originalBasename}_{@version}.{ext}", - "path": "{@folder}/{@file}" - }, "online": { "folder": "{root[work]}/{project[name]}/{hierarchy}/{asset}/publish/{family}/{subset}/{@version}", "file": "{originalBasename}<.{@frame}><_{udim}>.{ext}", @@ -68,8 +58,6 @@ }, "__dynamic_keys_labels__": { "maya2unreal": "Maya to Unreal", - "simpleUnrealTextureHero": "Simple Unreal Texture - Hero", - "simpleUnrealTexture": "Simple Unreal Texture", "online": "online", "tycache": "tycache", "source": "source", diff --git a/openpype/settings/defaults/project_settings/deadline.json b/openpype/settings/defaults/project_settings/deadline.json index 2c5e0dc65d..a19464a5c1 100644 --- a/openpype/settings/defaults/project_settings/deadline.json +++ b/openpype/settings/defaults/project_settings/deadline.json @@ -107,7 +107,16 @@ "use_published": true, "priority": 50, "chunk_size": 10, - "group": "none" + "group": "none", + "job_delay": "00:00:00:00" + }, + "ProcessSubmittedCacheJobOnFarm": { + "enabled": true, + "deadline_department": "", + "deadline_pool": "", + "deadline_group": "", + "deadline_chunk_size": 1, + "deadline_priority": 50 }, "ProcessSubmittedJobOnFarm": { "enabled": true, diff --git a/openpype/settings/defaults/project_settings/global.json b/openpype/settings/defaults/project_settings/global.json index 9ccf5cae05..bb7e3266bd 100644 --- a/openpype/settings/defaults/project_settings/global.json +++ b/openpype/settings/defaults/project_settings/global.json @@ -70,6 +70,25 @@ }, "ExtractThumbnail": { "enabled": true, + "integrate_thumbnail": false, + "background_color": [ + 0, + 0, + 0, + 255 + ], + "duration_split": 0.5, + "target_size": { + "type": "resize", + "width": 1920, + "height": 1080 + }, + "oiiotool_defaults": { + "type": "colorspace", + "colorspace": "color_picking", + "view": "sRGB", + "display": "default" + }, "ffmpeg_args": { "input": [ "-apply_trc gamma22" @@ -316,22 +335,9 @@ "animation", "setdress", "layout", - "mayaScene", - "simpleUnrealTexture" + "mayaScene" ], - "template_name_profiles": [ - { - "families": [ - "simpleUnrealTexture" - ], - "hosts": [ - "standalonepublisher" - ], - "task_types": [], - "task_names": [], - "template_name": "simpleUnrealTextureHero" - } - ] + "template_name_profiles": [] }, "CleanUp": { "paterns": [], @@ -513,17 +519,6 @@ "task_names": [], "template_name": "render" }, - { - "families": [ - "simpleUnrealTexture" - ], - "hosts": [ - "standalonepublisher" - ], - "task_types": [], - "task_names": [], - "template_name": "simpleUnrealTexture" - }, { "families": [ "staticMesh", @@ -559,19 +554,7 @@ "template_name": "tycache" } ], - "hero_template_name_profiles": [ - { - "families": [ - "simpleUnrealTexture" - ], - "hosts": [ - "standalonepublisher" - ], - "task_types": [], - "task_names": [], - "template_name": "simpleUnrealTextureHero" - } - ], + "hero_template_name_profiles": [], "custom_staging_dir_profiles": [] } }, diff --git a/openpype/settings/defaults/project_settings/houdini.json b/openpype/settings/defaults/project_settings/houdini.json index 0dd8443e44..0001b23967 100644 --- a/openpype/settings/defaults/project_settings/houdini.json +++ b/openpype/settings/defaults/project_settings/houdini.json @@ -137,6 +137,11 @@ } }, "publish": { + "CollectChunkSize": { + "enabled": true, + "optional": true, + "chunk_size": 999999 + }, "CollectAssetHandles": { "use_asset_handles": true }, diff --git a/openpype/settings/defaults/project_settings/max.json b/openpype/settings/defaults/project_settings/max.json index 97fcf69e31..19c9d10496 100644 --- a/openpype/settings/defaults/project_settings/max.json +++ b/openpype/settings/defaults/project_settings/max.json @@ -56,6 +56,31 @@ "enabled": false, "optional": true, "family_plugins_mapping": [] + }, + "ExtractModelObj": { + "enabled": true, + "optional": true, + "active": false + }, + "ExtractModelFbx": { + "enabled": true, + "optional": true, + "active": false + }, + "ExtractModelUSD": { + "enabled": true, + "optional": true, + "active": false + }, + "ExtractModel": { + "enabled": true, + "optional": true, + "active": true + }, + "ExtractMaxSceneRaw": { + "enabled": true, + "optional": true, + "active": true } } } diff --git a/openpype/settings/defaults/project_settings/nuke.json b/openpype/settings/defaults/project_settings/nuke.json index 20df0ad5c2..17932c793d 100644 --- a/openpype/settings/defaults/project_settings/nuke.json +++ b/openpype/settings/defaults/project_settings/nuke.json @@ -379,68 +379,6 @@ "optional": true, "active": true }, - "ExtractThumbnail": { - "enabled": true, - "use_rendered": true, - "bake_viewer_process": true, - "bake_viewer_input_process": true, - "nodes": { - "Reformat": [ - [ - "type", - "to format" - ], - [ - "format", - "HD_1080" - ], - [ - "filter", - "Lanczos6" - ], - [ - "black_outside", - true - ], - [ - "pbb", - false - ] - ] - }, - "reposition_nodes": [ - { - "node_class": "Reformat", - "knobs": [ - { - "type": "text", - "name": "type", - "value": "to format" - }, - { - "type": "text", - "name": "format", - "value": "HD_1080" - }, - { - "type": "text", - "name": "filter", - "value": "Lanczos6" - }, - { - "type": "bool", - "name": "black_outside", - "value": true - }, - { - "type": "bool", - "name": "pbb", - "value": false - } - ] - } - ] - }, "ExtractReviewData": { "enabled": false }, diff --git a/openpype/settings/defaults/project_settings/standalonepublisher.json b/openpype/settings/defaults/project_settings/standalonepublisher.json index d923b4db43..44982133eb 100644 --- a/openpype/settings/defaults/project_settings/standalonepublisher.json +++ b/openpype/settings/defaults/project_settings/standalonepublisher.json @@ -133,14 +133,6 @@ ], "help": "Texture files with UDIM together with worfile" }, - "create_simple_unreal_texture": { - "name": "simple_unreal_texture", - "label": "Simple Unreal Texture", - "family": "simpleUnrealTexture", - "icon": "Image", - "defaults": [], - "help": "Texture files with Unreal naming convention" - }, "create_vdb": { "name": "vdb", "label": "VDB Volumetric Data", diff --git a/openpype/settings/defaults/project_settings/traypublisher.json b/openpype/settings/defaults/project_settings/traypublisher.json index e13de11414..7d2f358cb2 100644 --- a/openpype/settings/defaults/project_settings/traypublisher.json +++ b/openpype/settings/defaults/project_settings/traypublisher.json @@ -244,19 +244,6 @@ ".hda" ] }, - { - "family": "simpleUnrealTexture", - "identifier": "", - "label": "Simple UE texture", - "icon": "fa.image", - "default_variants": [], - "description": "Simple Unreal Engine texture", - "detailed_description": "Texture files with Unreal Engine naming conventions", - "allow_sequences": false, - "allow_multiple_items": true, - "allow_version_control": false, - "extensions": [] - }, { "family": "audio", "identifier": "", diff --git a/openpype/settings/defaults/system_settings/modules.json b/openpype/settings/defaults/system_settings/modules.json index f524f01d45..bb943524f1 100644 --- a/openpype/settings/defaults/system_settings/modules.json +++ b/openpype/settings/defaults/system_settings/modules.json @@ -210,5 +210,8 @@ "darwin": "", "linux": "" } + }, + "asset_reporter": { + "enabled": false } } diff --git a/openpype/settings/entities/schemas/projects_schema/schema_project_deadline.json b/openpype/settings/entities/schemas/projects_schema/schema_project_deadline.json index 64db852c89..1aea778e32 100644 --- a/openpype/settings/entities/schemas/projects_schema/schema_project_deadline.json +++ b/openpype/settings/entities/schemas/projects_schema/schema_project_deadline.json @@ -581,6 +581,51 @@ "type": "text", "key": "group", "label": "Group Name" + }, + { + "type": "text", + "key": "job_delay", + "label": "Delay job (timecode dd:hh:mm:ss)" + } + ] + }, + { + "type": "dict", + "collapsible": true, + "key": "ProcessSubmittedCacheJobOnFarm", + "label": "ProcessSubmittedCacheJobOnFarm", + "checkbox_key": "enabled", + "is_group": true, + "children": [ + { + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, + { + "type": "text", + "key": "deadline_department", + "label": "Deadline department" + }, + { + "type": "text", + "key": "deadline_pool", + "label": "Deadline Pool" + }, + { + "type": "text", + "key": "deadline_group", + "label": "Deadline Group" + }, + { + "type": "number", + "key": "deadline_chunk_size", + "label": "Deadline Chunk Size" + }, + { + "type": "number", + "key": "deadline_priority", + "label": "Deadline Priotity" } ] }, diff --git a/openpype/settings/entities/schemas/projects_schema/schemas/schema_global_publish.json b/openpype/settings/entities/schemas/projects_schema/schemas/schema_global_publish.json index c7e91fd22d..ac2d9e190d 100644 --- a/openpype/settings/entities/schemas/projects_schema/schemas/schema_global_publish.json +++ b/openpype/settings/entities/schemas/projects_schema/schemas/schema_global_publish.json @@ -202,6 +202,104 @@ "key": "enabled", "label": "Enabled" }, + { + "type": "boolean", + "key": "integrate_thumbnail", + "label": "Integrate thumbnail as representation" + }, + { + "type": "dict-conditional", + "use_label_wrap": false, + "collapsible": false, + "key": "target_size", + "label": "Target size", + "enum_key": "type", + "enum_label": "Type", + "enum_children": [ + { + "key": "source", + "label": "Image source", + "children": [ + { + "type": "label", + "label": "Image size will be inherited from source image." + } + ] + }, + { + "key": "resize", + "label": "Resize", + "children": [ + { + "type": "label", + "label": "Image will be resized to specified size." + }, + { + "type": "number", + "key": "width", + "label": "Width", + "decimal": 0, + "minimum": 0, + "maximum": 99999 + }, + { + "type": "number", + "key": "height", + "label": "Height", + "decimal": 0, + "minimum": 0, + "maximum": 99999 + } + ] + } + ] + }, + { + "type": "color", + "label": "Background color", + "key": "background_color" + }, + { + "key": "duration_split", + "label": "Duration split ratio", + "type": "number", + "decimal": 1, + "default": 0.5, + "minimum": 0, + "maximum": 1 + }, + { + "type": "dict", + "collapsible": true, + "key": "oiiotool_defaults", + "label": "OIIOtool defaults", + "children": [ + { + "type": "enum", + "key": "type", + "label": "Target type", + "enum_items": [ + { "colorspace": "Colorspace" }, + { "display_and_view": "Display & View" } + ] + }, + { + "type": "text", + "key": "colorspace", + "label": "Colorspace" + }, + { + "type": "text", + "key": "view", + "label": "View" + }, + { + "type": "text", + "key": "display", + "label": "Display" + } + ] + }, { "type": "dict", "key": "ffmpeg_args", diff --git a/openpype/settings/entities/schemas/projects_schema/schemas/schema_houdini_publish.json b/openpype/settings/entities/schemas/projects_schema/schemas/schema_houdini_publish.json index 324cfd8d58..935c2a4c35 100644 --- a/openpype/settings/entities/schemas/projects_schema/schemas/schema_houdini_publish.json +++ b/openpype/settings/entities/schemas/projects_schema/schemas/schema_houdini_publish.json @@ -55,6 +55,31 @@ } ] }, + { + "type": "dict", + "collapsible": true, + "checkbox_key": "enabled", + "key": "CollectChunkSize", + "label": "Collect Chunk Size", + "is_group": true, + "children": [ + { + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, + { + "type": "boolean", + "key": "optional", + "label": "Optional" + }, + { + "type": "number", + "key": "chunk_size", + "label": "Frames Per Task" + } + ] + }, { "type": "dict", "collapsible": true, diff --git a/openpype/settings/entities/schemas/projects_schema/schemas/schema_max_publish.json b/openpype/settings/entities/schemas/projects_schema/schemas/schema_max_publish.json index c6d37ae993..b4d85bda98 100644 --- a/openpype/settings/entities/schemas/projects_schema/schemas/schema_max_publish.json +++ b/openpype/settings/entities/schemas/projects_schema/schemas/schema_max_publish.json @@ -90,6 +90,131 @@ } } ] + }, + { + "type": "dict", + "collapsible": true, + "checkbox_key": "enabled", + "key": "ExtractModelObj", + "label": "Extract Obj", + "is_group": true, + "children": [ + { + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, + { + "type": "boolean", + "key": "optional", + "label": "Optional" + }, + { + "type": "boolean", + "key": "active", + "label": "Active" + } + ] + }, + { + "type": "dict", + "collapsible": true, + "checkbox_key": "enabled", + "key": "ExtractModelFbx", + "label": "Extract FBX", + "is_group": true, + "children": [ + { + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, + { + "type": "boolean", + "key": "optional", + "label": "Optional" + }, + { + "type": "boolean", + "key": "active", + "label": "Active" + } + ] + }, + { + "type": "dict", + "collapsible": true, + "checkbox_key": "enabled", + "key": "ExtractModelUSD", + "label": "Extract Geometry (USD)", + "is_group": true, + "children": [ + { + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, + { + "type": "boolean", + "key": "optional", + "label": "Optional" + }, + { + "type": "boolean", + "key": "active", + "label": "Active" + } + ] + }, + { + "type": "dict", + "collapsible": true, + "checkbox_key": "enabled", + "key": "ExtractModel", + "label": "Extract Geometry (Alembic)", + "is_group": true, + "children": [ + { + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, + { + "type": "boolean", + "key": "optional", + "label": "Optional" + }, + { + "type": "boolean", + "key": "active", + "label": "Active" + } + ] + }, + { + "type": "dict", + "collapsible": true, + "checkbox_key": "enabled", + "key": "ExtractMaxSceneRaw", + "label": "Extract Max Scene (Raw)", + "is_group": true, + "children": [ + { + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, + { + "type": "boolean", + "key": "optional", + "label": "Optional" + }, + { + "type": "boolean", + "key": "active", + "label": "Active" + } + ] } ] } diff --git a/openpype/settings/entities/schemas/projects_schema/schemas/schema_nuke_publish.json b/openpype/settings/entities/schemas/projects_schema/schemas/schema_nuke_publish.json index e0cd086119..09b67e7d1a 100644 --- a/openpype/settings/entities/schemas/projects_schema/schemas/schema_nuke_publish.json +++ b/openpype/settings/entities/schemas/projects_schema/schemas/schema_nuke_publish.json @@ -125,81 +125,6 @@ "type": "label", "label": "Extractors" }, - { - "type": "dict", - "collapsible": true, - "checkbox_key": "enabled", - "key": "ExtractThumbnail", - "label": "ExtractThumbnail", - "is_group": true, - "children": [ - { - "type": "boolean", - "key": "enabled", - "label": "Enabled" - }, - { - "type": "boolean", - "key": "use_rendered", - "label": "Use rendered images" - }, - { - "type": "boolean", - "key": "bake_viewer_process", - "label": "Bake viewer process" - }, - { - "type": "boolean", - "key": "bake_viewer_input_process", - "label": "Bake viewer input process" - }, - { - "type": "collapsible-wrap", - "label": "Nodes", - "collapsible": true, - "children": [ - { - "type": "label", - "label": "Nodes attribute will be deprecated in future releases. Use reposition_nodes instead." - }, - { - "type": "raw-json", - "key": "nodes", - "label": "Nodes [depricated]" - }, - { - "type": "label", - "label": "Reposition knobs supported only. You can add multiple reformat nodes
and set their knobs. Order of reformat nodes is important. First reformat node
will be applied first and last reformat node will be applied last." - }, - { - "key": "reposition_nodes", - "type": "list", - "label": "Reposition nodes", - "object_type": { - "type": "dict", - "children": [ - { - "key": "node_class", - "label": "Node class", - "type": "text" - }, - { - "type": "schema_template", - "name": "template_nuke_knob_inputs", - "template_data": [ - { - "label": "Node knobs", - "key": "knobs" - } - ] - } - ] - } - } - ] - } - ] - }, { "type": "dict", "collapsible": true, diff --git a/openpype/settings/entities/schemas/system_schema/schema_modules.json b/openpype/settings/entities/schemas/system_schema/schema_modules.json index 952b38040c..5b189eae88 100644 --- a/openpype/settings/entities/schemas/system_schema/schema_modules.json +++ b/openpype/settings/entities/schemas/system_schema/schema_modules.json @@ -355,6 +355,20 @@ { "type": "dynamic_schema", "name": "system_settings/modules" + }, + { + "type": "dict", + "key": "asset_reporter", + "label": "Asset Usage Reporter", + "collapsible": true, + "checkbox_key": "enabled", + "children": [ + { + "type": "boolean", + "key": "enabled", + "label": "Enabled" + } + ] } ] } diff --git a/openpype/settings/lib.py b/openpype/settings/lib.py index ce62dde43f..d62e50d3c7 100644 --- a/openpype/settings/lib.py +++ b/openpype/settings/lib.py @@ -172,7 +172,7 @@ def save_studio_settings(data): clear_metadata_from_settings(new_data) changes = calculate_changes(old_data, new_data) - modules_manager = ModulesManager(_system_settings=new_data) + modules_manager = ModulesManager(new_data) warnings = [] for module in modules_manager.get_enabled_modules(): diff --git a/openpype/tools/attribute_defs/widgets.py b/openpype/tools/attribute_defs/widgets.py index 8957f2b19d..7dea01e0a8 100644 --- a/openpype/tools/attribute_defs/widgets.py +++ b/openpype/tools/attribute_defs/widgets.py @@ -608,7 +608,7 @@ class UnknownAttrWidget(_BaseAttrDefWidget): class HiddenAttrWidget(_BaseAttrDefWidget): def _ui_init(self): self.setVisible(False) - self._value = None + self._value = self.attr_def.default self._multivalue = False def setVisible(self, visible): diff --git a/openpype/tools/ayon_launcher/models/actions.py b/openpype/tools/ayon_launcher/models/actions.py index 93ec115734..d7c4219dc2 100644 --- a/openpype/tools/ayon_launcher/models/actions.py +++ b/openpype/tools/ayon_launcher/models/actions.py @@ -402,12 +402,12 @@ class ActionsModel: ) def _prepare_session(self, project_name, folder_id, task_id): - folder_name = None + folder_path = None if folder_id: folder = self._controller.get_folder_entity( project_name, folder_id) if folder: - folder_name = folder["name"] + folder_path = folder["path"] task_name = None if task_id: @@ -417,7 +417,7 @@ class ActionsModel: return { "AVALON_PROJECT": project_name, - "AVALON_ASSET": folder_name, + "AVALON_ASSET": folder_path, "AVALON_TASK": task_name, } diff --git a/openpype/tools/ayon_loader/abstract.py b/openpype/tools/ayon_loader/abstract.py index 45042395d9..bf3e81d485 100644 --- a/openpype/tools/ayon_loader/abstract.py +++ b/openpype/tools/ayon_loader/abstract.py @@ -137,7 +137,7 @@ class VersionItem: handles, step, comment, - source + source, ): self.version_id = version_id self.product_id = product_id @@ -215,7 +215,7 @@ class RepreItem: representation_name, representation_icon, product_name, - folder_label, + folder_label ): self.representation_id = representation_id self.representation_name = representation_name @@ -590,6 +590,22 @@ class FrontendLoaderController(_BaseLoaderController): pass + @abstractmethod + def get_versions_representation_count( + self, project_name, version_ids, sender=None + ): + """ + Args: + project_name (str): Project name. + version_ids (Iterable[str]): Version ids. + sender (Optional[str]): Sender who requested the items. + + Returns: + dict[str, int]: Representation count by version id. + """ + + pass + @abstractmethod def get_thumbnail_path(self, project_name, thumbnail_id): """Get thumbnail path for thumbnail id. @@ -849,3 +865,80 @@ class FrontendLoaderController(_BaseLoaderController): """ pass + + # Site sync functions + @abstractmethod + def is_site_sync_enabled(self, project_name=None): + """Is site sync enabled. + + Site sync addon can be enabled but can be disabled per project. + + When asked for enabled state without project name, it should return + True if site sync addon is available and enabled. + + Args: + project_name (Optional[str]): Project name. + + Returns: + bool: True if site sync is enabled. + """ + + pass + + @abstractmethod + def get_active_site_icon_def(self, project_name): + """Active site icon definition. + + Args: + project_name (Union[str, None]): Project name. + + Returns: + Union[dict[str, Any], None]: Icon definition or None if site sync + is not enabled for the project. + """ + + pass + + @abstractmethod + def get_remote_site_icon_def(self, project_name): + """Remote site icon definition. + + Args: + project_name (Union[str, None]): Project name. + + Returns: + Union[dict[str, Any], None]: Icon definition or None if site sync + is not enabled for the project. + """ + + pass + + @abstractmethod + def get_version_sync_availability(self, project_name, version_ids): + """Version sync availability. + + Args: + project_name (str): Project name. + version_ids (Iterable[str]): Version ids. + + Returns: + dict[str, tuple[int, int]]: Sync availability by version id. + """ + + pass + + @abstractmethod + def get_representations_sync_status( + self, project_name, representation_ids + ): + """Representations sync status. + + Args: + project_name (str): Project name. + representation_ids (Iterable[str]): Representation ids. + + Returns: + dict[str, tuple[int, int]]: Sync status by representation id. + """ + + pass diff --git a/openpype/tools/ayon_loader/control.py b/openpype/tools/ayon_loader/control.py index c38973d0b3..060cef6661 100644 --- a/openpype/tools/ayon_loader/control.py +++ b/openpype/tools/ayon_loader/control.py @@ -15,7 +15,12 @@ from openpype.tools.ayon_utils.models import ( ) from .abstract import BackendLoaderController, FrontendLoaderController -from .models import SelectionModel, ProductsModel, LoaderActionsModel +from .models import ( + SelectionModel, + ProductsModel, + LoaderActionsModel, + SiteSyncModel +) class ExpectedSelection: @@ -108,6 +113,7 @@ class LoaderController(BackendLoaderController, FrontendLoaderController): self._products_model = ProductsModel(self) self._loader_actions_model = LoaderActionsModel(self) self._thumbnails_model = ThumbnailsModel() + self._site_sync_model = SiteSyncModel(self) @property def log(self): @@ -143,6 +149,7 @@ class LoaderController(BackendLoaderController, FrontendLoaderController): self._loader_actions_model.reset() self._projects_model.reset() self._thumbnails_model.reset() + self._site_sync_model.reset() self._projects_model.refresh() @@ -195,13 +202,22 @@ class LoaderController(BackendLoaderController, FrontendLoaderController): project_name, version_ids, sender ) + def get_versions_representation_count( + self, project_name, version_ids, sender=None + ): + return self._products_model.get_versions_repre_count( + project_name, version_ids, sender + ) + def get_folder_thumbnail_ids(self, project_name, folder_ids): return self._thumbnails_model.get_folder_thumbnail_ids( - project_name, folder_ids) + project_name, folder_ids + ) def get_version_thumbnail_ids(self, project_name, version_ids): return self._thumbnails_model.get_version_thumbnail_ids( - project_name, version_ids) + project_name, version_ids + ) def get_thumbnail_path(self, project_name, thumbnail_id): return self._thumbnails_model.get_thumbnail_path( @@ -219,8 +235,16 @@ class LoaderController(BackendLoaderController, FrontendLoaderController): def get_representations_action_items( self, project_name, representation_ids): - return self._loader_actions_model.get_representations_action_items( + action_items = ( + self._loader_actions_model.get_representations_action_items( + project_name, representation_ids) + ) + + action_items.extend(self._site_sync_model.get_site_sync_action_items( project_name, representation_ids) + ) + + return action_items def trigger_action_item( self, @@ -230,6 +254,14 @@ class LoaderController(BackendLoaderController, FrontendLoaderController): version_ids, representation_ids ): + if self._site_sync_model.is_site_sync_action(identifier): + self._site_sync_model.trigger_action_item( + identifier, + project_name, + representation_ids + ) + return + self._loader_actions_model.trigger_action_item( identifier, options, @@ -290,7 +322,7 @@ class LoaderController(BackendLoaderController, FrontendLoaderController): project_name = context.get("project_name") asset_name = context.get("asset_name") if project_name and asset_name: - folder = ayon_api.get_folder_by_name( + folder = ayon_api.get_folder_by_path( project_name, asset_name, fields=["id"] ) if folder: @@ -336,6 +368,27 @@ class LoaderController(BackendLoaderController, FrontendLoaderController): self._loaded_products_cache.update_data(product_ids) return self._loaded_products_cache.get_data() + def is_site_sync_enabled(self, project_name=None): + return self._site_sync_model.is_site_sync_enabled(project_name) + + def get_active_site_icon_def(self, project_name): + return self._site_sync_model.get_active_site_icon_def(project_name) + + def get_remote_site_icon_def(self, project_name): + return self._site_sync_model.get_remote_site_icon_def(project_name) + + def get_version_sync_availability(self, project_name, version_ids): + return self._site_sync_model.get_version_sync_availability( + project_name, version_ids + ) + + def get_representations_sync_status( + self, project_name, representation_ids + ): + return self._site_sync_model.get_representations_sync_status( + project_name, representation_ids + ) + def is_loaded_products_supported(self): return self._host is not None diff --git a/openpype/tools/ayon_loader/models/__init__.py b/openpype/tools/ayon_loader/models/__init__.py index 6adfe71d86..8e640659a0 100644 --- a/openpype/tools/ayon_loader/models/__init__.py +++ b/openpype/tools/ayon_loader/models/__init__.py @@ -1,10 +1,12 @@ from .selection import SelectionModel from .products import ProductsModel from .actions import LoaderActionsModel +from .site_sync import SiteSyncModel __all__ = ( "SelectionModel", "ProductsModel", "LoaderActionsModel", + "SiteSyncModel", ) diff --git a/openpype/tools/ayon_loader/models/products.py b/openpype/tools/ayon_loader/models/products.py index 816dabaf90..135f28df97 100644 --- a/openpype/tools/ayon_loader/models/products.py +++ b/openpype/tools/ayon_loader/models/products.py @@ -44,7 +44,7 @@ def version_item_from_entity(version): # NOTE There is also 'updatedAt', should be used that instead? # TODO skip conversion - converting to '%Y%m%dT%H%M%SZ' is because # 'PrettyTimeDelegate' expects it - created_at = arrow.get(version["createdAt"]) + created_at = arrow.get(version["createdAt"]).to("local") published_time = created_at.strftime("%Y%m%dT%H%M%SZ") author = version["author"] version_num = version["version"] @@ -317,6 +317,42 @@ class ProductsModel: return output + def get_versions_repre_count(self, project_name, version_ids, sender): + """Get representation count for passed version ids. + + Args: + project_name (str): Project name. + version_ids (Iterable[str]): Version ids. + sender (Union[str, None]): Who triggered the method. + + Returns: + dict[str, int]: Number of representations by version id. + """ + + output = {} + if not any((project_name, version_ids)): + return output + + invalid_version_ids = set() + project_cache = self._repre_items_cache[project_name] + for version_id in version_ids: + version_cache = project_cache[version_id] + if version_cache.is_valid: + output[version_id] = len(version_cache.get_data()) + else: + invalid_version_ids.add(version_id) + + if invalid_version_ids: + self.refresh_representation_items( + project_name, invalid_version_ids, sender + ) + + for version_id in invalid_version_ids: + version_cache = project_cache[version_id] + output[version_id] = len(version_cache.get_data()) + + return output + def change_products_group(self, project_name, product_ids, group_name): """Change group name for passed product ids. diff --git a/openpype/tools/ayon_loader/models/site_sync.py b/openpype/tools/ayon_loader/models/site_sync.py new file mode 100644 index 0000000000..90852b6954 --- /dev/null +++ b/openpype/tools/ayon_loader/models/site_sync.py @@ -0,0 +1,509 @@ +import collections + +from openpype.lib import Logger +from openpype.client.entities import get_representations +from openpype.client import get_linked_representation_id +from openpype.modules import ModulesManager +from openpype.tools.ayon_utils.models import NestedCacheItem +from openpype.tools.ayon_loader.abstract import ActionItem + +DOWNLOAD_IDENTIFIER = "sitesync.download" +UPLOAD_IDENTIFIER = "sitesync.upload" +REMOVE_IDENTIFIER = "sitesync.remove" + +log = Logger.get_logger(__name__) + + +def _default_version_availability(): + return 0, 0 + + +def _default_repre_status(): + return 0.0, 0.0 + + +class SiteSyncModel: + """Model handling site sync logic. + + Model cares about handling of site sync functionality. All public + functions should be possible to call even if site sync is not available. + """ + + lifetime = 60 # In seconds (minute by default) + status_lifetime = 20 + + def __init__(self, controller): + self._controller = controller + + self._site_icons = None + self._site_sync_enabled_cache = NestedCacheItem( + levels=1, lifetime=self.lifetime + ) + self._active_site_cache = NestedCacheItem( + levels=1, lifetime=self.lifetime + ) + self._remote_site_cache = NestedCacheItem( + levels=1, lifetime=self.lifetime + ) + self._version_availability_cache = NestedCacheItem( + levels=2, + default_factory=_default_version_availability, + lifetime=self.status_lifetime + ) + self._repre_status_cache = NestedCacheItem( + levels=2, + default_factory=_default_repre_status, + lifetime=self.status_lifetime + ) + + manager = ModulesManager() + self._site_sync_addon = manager.get("sync_server") + + def reset(self): + self._site_icons = None + self._site_sync_enabled_cache.reset() + self._active_site_cache.reset() + self._remote_site_cache.reset() + self._version_availability_cache.reset() + self._repre_status_cache.reset() + + def is_site_sync_enabled(self, project_name=None): + """Site sync is enabled for a project. + + Returns false if site sync addon is not available or enabled + or project has disabled it. + + Args: + project_name (Union[str, None]): Project name. If project name + is 'None', True is returned if site sync addon + is available and enabled. + + Returns: + bool: Site sync is enabled. + """ + + if not self._is_site_sync_addon_enabled(): + return False + cache = self._site_sync_enabled_cache[project_name] + if not cache.is_valid: + enabled = True + if project_name: + enabled = self._site_sync_addon.is_project_enabled( + project_name, single=True + ) + cache.update_data(enabled) + return cache.get_data() + + def get_active_site(self, project_name): + """Active site name for a project. + + Args: + project_name (str): Project name. + + Returns: + Union[str, None]: Remote site name. + """ + + cache = self._active_site_cache[project_name] + if not cache.is_valid: + site_name = None + if project_name and self._is_site_sync_addon_enabled(): + site_name = self._site_sync_addon.get_active_site(project_name) + cache.update_data(site_name) + return cache.get_data() + + def get_remote_site(self, project_name): + """Remote site name for a project. + + Args: + project_name (str): Project name. + + Returns: + Union[str, None]: Remote site name. + """ + + cache = self._remote_site_cache[project_name] + if not cache.is_valid: + site_name = None + if project_name and self._is_site_sync_addon_enabled(): + site_name = self._site_sync_addon.get_remote_site(project_name) + cache.update_data(site_name) + return cache.get_data() + + def get_active_site_icon_def(self, project_name): + """Active site icon definition. + + Args: + project_name (Union[str, None]): Name of project. + + Returns: + Union[dict[str, Any], None]: Site icon definition. + """ + + if not project_name: + return None + + active_site = self.get_active_site(project_name) + provider = self._get_provider_for_site(project_name, active_site) + return self._get_provider_icon(provider) + + def get_remote_site_icon_def(self, project_name): + """Remote site icon definition. + + Args: + project_name (Union[str, None]): Name of project. + + Returns: + Union[dict[str, Any], None]: Site icon definition. + """ + + if not project_name or not self.is_site_sync_enabled(project_name): + return None + remote_site = self.get_remote_site(project_name) + provider = self._get_provider_for_site(project_name, remote_site) + return self._get_provider_icon(provider) + + def get_version_sync_availability(self, project_name, version_ids): + """Returns how many representations are available on sites. + + Returned value `{version_id: (4, 6)}` denotes that locally are + available 4 and remotely 6 representation. + NOTE: Available means they were synced to site. + + Returns: + dict[str, tuple[int, int]] + """ + + if not self.is_site_sync_enabled(project_name): + return { + version_id: _default_version_availability() + for version_id in version_ids + } + + output = {} + project_cache = self._version_availability_cache[project_name] + invalid_ids = set() + for version_id in version_ids: + repre_cache = project_cache[version_id] + if repre_cache.is_valid: + output[version_id] = repre_cache.get_data() + else: + invalid_ids.add(version_id) + + if invalid_ids: + self._refresh_version_availability( + project_name, invalid_ids + ) + for version_id in invalid_ids: + version_cache = project_cache[version_id] + output[version_id] = version_cache.get_data() + return output + + def get_representations_sync_status( + self, project_name, representation_ids + ): + """ + + Args: + project_name (str): Project name. + representation_ids (Iterable[str]): Representation ids. + + Returns: + dict[str, tuple[float, float]] + """ + + if not self.is_site_sync_enabled(project_name): + return { + repre_id: _default_repre_status() + for repre_id in representation_ids + } + + output = {} + project_cache = self._repre_status_cache[project_name] + invalid_ids = set() + for repre_id in representation_ids: + repre_cache = project_cache[repre_id] + if repre_cache.is_valid: + output[repre_id] = repre_cache.get_data() + else: + invalid_ids.add(repre_id) + + if invalid_ids: + self._refresh_representations_sync_status( + project_name, invalid_ids + ) + for repre_id in invalid_ids: + repre_cache = project_cache[repre_id] + output[repre_id] = repre_cache.get_data() + return output + + def get_site_sync_action_items(self, project_name, representation_ids): + """ + + Args: + project_name (str): Project name. + representation_ids (Iterable[str]): Representation ids. + + Returns: + list[ActionItem]: Actions that can be shown in loader. + """ + + if not self.is_site_sync_enabled(project_name): + return [] + + repres_status = self.get_representations_sync_status( + project_name, representation_ids + ) + + repre_ids_per_identifier = collections.defaultdict(set) + for repre_id in representation_ids: + repre_status = repres_status[repre_id] + local_status, remote_status = repre_status + + if local_status: + repre_ids_per_identifier[UPLOAD_IDENTIFIER].add(repre_id) + repre_ids_per_identifier[REMOVE_IDENTIFIER].add(repre_id) + + if remote_status: + repre_ids_per_identifier[DOWNLOAD_IDENTIFIER].add(repre_id) + + action_items = [] + for identifier, repre_ids in repre_ids_per_identifier.items(): + if identifier == DOWNLOAD_IDENTIFIER: + action_items.append(self._create_download_action_item( + project_name, repre_ids + )) + elif identifier == UPLOAD_IDENTIFIER: + action_items.append(self._create_upload_action_item( + project_name, repre_ids + )) + elif identifier == REMOVE_IDENTIFIER: + action_items.append(self._create_delete_action_item( + project_name, repre_ids + )) + + return action_items + + def is_site_sync_action(self, identifier): + """Should be `identifier` handled by SiteSync. + + Args: + identifier (str): Action identifier. + + Returns: + bool: Should action be handled by SiteSync. + """ + + return identifier in { + UPLOAD_IDENTIFIER, + DOWNLOAD_IDENTIFIER, + REMOVE_IDENTIFIER, + } + + def trigger_action_item( + self, + identifier, + project_name, + representation_ids + ): + """Resets status for site_name or remove local files. + + Args: + identifier (str): Action identifier. + project_name (str): Project name. + representation_ids (Iterable[str]): Representation ids. + """ + + active_site = self.get_active_site(project_name) + remote_site = self.get_remote_site(project_name) + + repre_docs = list(get_representations( + project_name, representation_ids=representation_ids + )) + families_per_repre_id = { + item["_id"]: item["context"]["family"] + for item in repre_docs + } + + for repre_id in representation_ids: + family = families_per_repre_id[repre_id] + if identifier == DOWNLOAD_IDENTIFIER: + self._add_site( + project_name, repre_id, active_site, family + ) + + elif identifier == UPLOAD_IDENTIFIER: + self._add_site( + project_name, repre_id, remote_site, family + ) + + elif identifier == REMOVE_IDENTIFIER: + self._site_sync_addon.remove_site( + project_name, + repre_id, + active_site, + remove_local_files=True + ) + + def _is_site_sync_addon_enabled(self): + """ + Returns: + bool: Site sync addon is enabled. + """ + + if self._site_sync_addon is None: + return False + return self._site_sync_addon.enabled + + def _get_provider_for_site(self, project_name, site_name): + """Provider for a site. + + Args: + project_name (str): Project name. + site_name (str): Site name. + + Returns: + Union[str, None]: Provider name. + """ + + if not self._is_site_sync_addon_enabled(): + return None + return self._site_sync_addon.get_provider_for_site( + project_name, site_name + ) + + def _get_provider_icon(self, provider): + """site provider icons. + + Returns: + Union[dict[str, Any], None]: Icon of site provider. + """ + + if not provider: + return None + + if self._site_icons is None: + self._site_icons = self._site_sync_addon.get_site_icons() + return self._site_icons.get(provider) + + def _refresh_version_availability(self, project_name, version_ids): + if not project_name or not version_ids: + return + project_cache = self._version_availability_cache[project_name] + + avail_by_id = self._site_sync_addon.get_version_availability( + project_name, + version_ids, + self.get_active_site(project_name), + self.get_remote_site(project_name), + ) + for version_id in version_ids: + status = avail_by_id.get(version_id) + if status is None: + status = _default_version_availability() + project_cache[version_id].update_data(status) + + def _refresh_representations_sync_status( + self, project_name, representation_ids + ): + if not project_name or not representation_ids: + return + project_cache = self._repre_status_cache[project_name] + status_by_repre_id = ( + self._site_sync_addon.get_representations_sync_state( + project_name, + representation_ids, + self.get_active_site(project_name), + self.get_remote_site(project_name), + ) + ) + for repre_id in representation_ids: + status = status_by_repre_id.get(repre_id) + if status is None: + status = _default_repre_status() + project_cache[repre_id].update_data(status) + + def _create_download_action_item(self, project_name, representation_ids): + return self._create_action_item( + project_name, + representation_ids, + DOWNLOAD_IDENTIFIER, + "Download", + "Mark representation for download locally", + "fa.download" + ) + + def _create_upload_action_item(self, project_name, representation_ids): + return self._create_action_item( + project_name, + representation_ids, + UPLOAD_IDENTIFIER, + "Upload", + "Mark representation for upload remotely", + "fa.upload" + ) + + def _create_delete_action_item(self, project_name, representation_ids): + return self._create_action_item( + project_name, + representation_ids, + REMOVE_IDENTIFIER, + "Remove from local", + "Remove local synchronization", + "fa.trash" + ) + + def _create_action_item( + self, + project_name, + representation_ids, + identifier, + label, + tooltip, + icon_name + ): + return ActionItem( + identifier, + label, + icon={ + "type": "awesome-font", + "name": icon_name, + "color": "#999999" + }, + tooltip=tooltip, + options={}, + order=1, + project_name=project_name, + folder_ids=[], + product_ids=[], + version_ids=[], + representation_ids=representation_ids, + ) + + def _add_site(self, project_name, repre_id, site_name, family): + self._site_sync_addon.add_site( + project_name, repre_id, site_name, force=True + ) + + # TODO this should happen in site sync addon + if family != "workfile": + return + + links = get_linked_representation_id( + project_name, + repre_id=repre_id, + link_type="reference" + ) + for link_repre_id in links: + try: + print("Adding {} to linked representation: {}".format( + site_name, link_repre_id)) + self._site_sync_addon.add_site( + project_name, + link_repre_id, + site_name, + force=False + ) + except Exception: + # do not add/reset working site for references + log.debug("Site present", exc_info=True) diff --git a/openpype/tools/ayon_loader/ui/products_delegates.py b/openpype/tools/ayon_loader/ui/products_delegates.py index 6729468bfa..979fa57fd2 100644 --- a/openpype/tools/ayon_loader/ui/products_delegates.py +++ b/openpype/tools/ayon_loader/ui/products_delegates.py @@ -8,6 +8,11 @@ from .products_model import ( VERSION_NAME_EDIT_ROLE, VERSION_ID_ROLE, PRODUCT_IN_SCENE_ROLE, + ACTIVE_SITE_ICON_ROLE, + REMOTE_SITE_ICON_ROLE, + REPRESENTATIONS_COUNT_ROLE, + SYNC_ACTIVE_SITE_AVAILABILITY, + SYNC_REMOTE_SITE_AVAILABILITY, ) @@ -189,3 +194,78 @@ class LoadedInSceneDelegate(QtWidgets.QStyledItemDelegate): value = index.data(PRODUCT_IN_SCENE_ROLE) color = self._colors.get(value, self._default_color) option.palette.setBrush(QtGui.QPalette.Text, color) + + +class SiteSyncDelegate(QtWidgets.QStyledItemDelegate): + """Paints icons and downloaded representation ration for both sites.""" + + def paint(self, painter, option, index): + super(SiteSyncDelegate, self).paint(painter, option, index) + option = QtWidgets.QStyleOptionViewItem(option) + option.showDecorationSelected = True + + active_icon = index.data(ACTIVE_SITE_ICON_ROLE) + remote_icon = index.data(REMOTE_SITE_ICON_ROLE) + + availability_active = "{}/{}".format( + index.data(SYNC_ACTIVE_SITE_AVAILABILITY), + index.data(REPRESENTATIONS_COUNT_ROLE) + ) + availability_remote = "{}/{}".format( + index.data(SYNC_REMOTE_SITE_AVAILABILITY), + index.data(REPRESENTATIONS_COUNT_ROLE) + ) + + if availability_active is None or availability_remote is None: + return + + items_to_draw = [ + (value, icon) + for value, icon in ( + (availability_active, active_icon), + (availability_remote, remote_icon), + ) + if icon + ] + if not items_to_draw: + return + + icon_size = QtCore.QSize(24, 24) + padding = 10 + pos_x = option.rect.x() + + item_width = int(option.rect.width() / len(items_to_draw)) + if item_width < 1: + item_width = 0 + + for value, icon in items_to_draw: + item_rect = QtCore.QRect( + pos_x, + option.rect.y(), + item_width, + option.rect.height() + ) + # Prepare pos_x for next item + pos_x = item_rect.x() + item_rect.width() + + pixmap = icon.pixmap(icon.actualSize(icon_size)) + point = QtCore.QPoint( + item_rect.x() + padding, + item_rect.y() + ((item_rect.height() - pixmap.height()) * 0.5) + ) + painter.drawPixmap(point, pixmap) + + icon_offset = icon_size.width() + (padding * 2) + text_rect = QtCore.QRect(item_rect) + text_rect.setLeft(text_rect.left() + icon_offset) + if text_rect.width() < 1: + continue + + painter.drawText( + text_rect, + option.displayAlignment, + value + ) + + def displayText(self, value, locale): + pass diff --git a/openpype/tools/ayon_loader/ui/products_model.py b/openpype/tools/ayon_loader/ui/products_model.py index 741f15766b..84f5bc9a5f 100644 --- a/openpype/tools/ayon_loader/ui/products_model.py +++ b/openpype/tools/ayon_loader/ui/products_model.py @@ -29,6 +29,11 @@ VERSION_HANDLES_ROLE = QtCore.Qt.UserRole + 18 VERSION_STEP_ROLE = QtCore.Qt.UserRole + 19 VERSION_AVAILABLE_ROLE = QtCore.Qt.UserRole + 20 VERSION_THUMBNAIL_ID_ROLE = QtCore.Qt.UserRole + 21 +ACTIVE_SITE_ICON_ROLE = QtCore.Qt.UserRole + 22 +REMOTE_SITE_ICON_ROLE = QtCore.Qt.UserRole + 23 +REPRESENTATIONS_COUNT_ROLE = QtCore.Qt.UserRole + 24 +SYNC_ACTIVE_SITE_AVAILABILITY = QtCore.Qt.UserRole + 25 +SYNC_REMOTE_SITE_AVAILABILITY = QtCore.Qt.UserRole + 26 class ProductsModel(QtGui.QStandardItemModel): @@ -68,6 +73,7 @@ class ProductsModel(QtGui.QStandardItemModel): published_time_col = column_labels.index("Time") folders_label_col = column_labels.index("Folder") in_scene_col = column_labels.index("In scene") + site_sync_avail_col = column_labels.index("Availability") def __init__(self, controller): super(ProductsModel, self).__init__() @@ -303,7 +309,26 @@ class ProductsModel(QtGui.QStandardItemModel): model_item.setData( version_item.thumbnail_id, VERSION_THUMBNAIL_ID_ROLE) - def _get_product_model_item(self, product_item): + # TODO call site sync methods for all versions at once + project_name = self._last_project_name + version_id = version_item.version_id + repre_count = self._controller.get_versions_representation_count( + project_name, [version_id] + )[version_id] + active, remote = self._controller.get_version_sync_availability( + project_name, [version_id] + )[version_id] + + model_item.setData(repre_count, REPRESENTATIONS_COUNT_ROLE) + model_item.setData(active, SYNC_ACTIVE_SITE_AVAILABILITY) + model_item.setData(remote, SYNC_REMOTE_SITE_AVAILABILITY) + + def _get_product_model_item( + self, + product_item, + active_site_icon, + remote_site_icon + ): model_item = self._items_by_id.get(product_item.product_id) versions = list(product_item.version_items.values()) versions.sort() @@ -329,6 +354,9 @@ class ProductsModel(QtGui.QStandardItemModel): in_scene = 1 if product_item.product_in_scene else 0 model_item.setData(in_scene, PRODUCT_IN_SCENE_ROLE) + model_item.setData(active_site_icon, ACTIVE_SITE_ICON_ROLE) + model_item.setData(remote_site_icon, REMOTE_SITE_ICON_ROLE) + self._set_version_data_to_product_item(model_item, last_version) return model_item @@ -341,6 +369,15 @@ class ProductsModel(QtGui.QStandardItemModel): self._last_project_name = project_name self._last_folder_ids = folder_ids + active_site_icon_def = self._controller.get_active_site_icon_def( + project_name + ) + remote_site_icon_def = self._controller.get_remote_site_icon_def( + project_name + ) + active_site_icon = get_qt_icon(active_site_icon_def) + remote_site_icon = get_qt_icon(remote_site_icon_def) + product_items = self._controller.get_product_items( project_name, folder_ids, @@ -402,7 +439,11 @@ class ProductsModel(QtGui.QStandardItemModel): new_root_items.append(parent_item) for product_item in top_items: - item = self._get_product_model_item(product_item) + item = self._get_product_model_item( + product_item, + active_site_icon, + remote_site_icon, + ) new_items.append(item) for path_info in merged_product_items.values(): @@ -418,7 +459,11 @@ class ProductsModel(QtGui.QStandardItemModel): merged_product_types = set() new_merged_items = [] for product_item in product_items: - item = self._get_product_model_item(product_item) + item = self._get_product_model_item( + product_item, + active_site_icon, + remote_site_icon, + ) new_merged_items.append(item) merged_product_types.add(product_item.product_type) diff --git a/openpype/tools/ayon_loader/ui/products_widget.py b/openpype/tools/ayon_loader/ui/products_widget.py index 2d4959dc19..99faefe693 100644 --- a/openpype/tools/ayon_loader/ui/products_widget.py +++ b/openpype/tools/ayon_loader/ui/products_widget.py @@ -19,7 +19,11 @@ from .products_model import ( VERSION_ID_ROLE, VERSION_THUMBNAIL_ID_ROLE, ) -from .products_delegates import VersionDelegate, LoadedInSceneDelegate +from .products_delegates import ( + VersionDelegate, + LoadedInSceneDelegate, + SiteSyncDelegate +) from .actions_utils import show_actions_menu @@ -92,7 +96,7 @@ class ProductsWidget(QtWidgets.QWidget): 55, # Handles 10, # Step 25, # Loaded in scene - 65, # Site info (maybe?) + 65, # Site sync info ) def __init__(self, controller, parent): @@ -135,6 +139,10 @@ class ProductsWidget(QtWidgets.QWidget): products_view.setItemDelegateForColumn( products_model.in_scene_col, in_scene_delegate) + site_sync_delegate = SiteSyncDelegate() + products_view.setItemDelegateForColumn( + products_model.site_sync_avail_col, site_sync_delegate) + main_layout = QtWidgets.QHBoxLayout(self) main_layout.setContentsMargins(0, 0, 0, 0) main_layout.addWidget(products_view, 1) @@ -167,6 +175,8 @@ class ProductsWidget(QtWidgets.QWidget): self._version_delegate = version_delegate self._time_delegate = time_delegate + self._in_scene_delegate = in_scene_delegate + self._site_sync_delegate = site_sync_delegate self._selected_project_name = None self._selected_folder_ids = set() @@ -182,6 +192,9 @@ class ProductsWidget(QtWidgets.QWidget): products_model.in_scene_col, not controller.is_loaded_products_supported() ) + self._set_site_sync_visibility( + self._controller.is_site_sync_enabled() + ) def set_name_filter(self, name): """Set filter of product name. @@ -216,6 +229,12 @@ class ProductsWidget(QtWidgets.QWidget): def refresh(self): self._refresh_model() + def _set_site_sync_visibility(self, site_sync_enabled): + self._products_view.setColumnHidden( + self._products_model.site_sync_avail_col, + not site_sync_enabled + ) + def _fill_version_editor(self): model = self._products_proxy_model index_queue = collections.deque() @@ -375,7 +394,12 @@ class ProductsWidget(QtWidgets.QWidget): self._on_selection_change() def _on_folders_selection_change(self, event): - self._selected_project_name = event["project_name"] + project_name = event["project_name"] + site_sync_enabled = self._controller.is_site_sync_enabled( + project_name + ) + self._set_site_sync_visibility(site_sync_enabled) + self._selected_project_name = project_name self._selected_folder_ids = event["folder_ids"] self._refresh_model() self._update_folders_label_visible() diff --git a/openpype/tools/ayon_loader/ui/repres_widget.py b/openpype/tools/ayon_loader/ui/repres_widget.py index 7de582e629..efc1bb89a4 100644 --- a/openpype/tools/ayon_loader/ui/repres_widget.py +++ b/openpype/tools/ayon_loader/ui/repres_widget.py @@ -14,6 +14,10 @@ REPRESENTATION_ID_ROLE = QtCore.Qt.UserRole + 2 PRODUCT_NAME_ROLE = QtCore.Qt.UserRole + 3 FOLDER_LABEL_ROLE = QtCore.Qt.UserRole + 4 GROUP_TYPE_ROLE = QtCore.Qt.UserRole + 5 +ACTIVE_SITE_ICON_ROLE = QtCore.Qt.UserRole + 6 +REMOTE_SITE_ICON_ROLE = QtCore.Qt.UserRole + 7 +SYNC_ACTIVE_SITE_PROGRESS = QtCore.Qt.UserRole + 8 +SYNC_REMOTE_SITE_PROGRESS = QtCore.Qt.UserRole + 9 class RepresentationsModel(QtGui.QStandardItemModel): @@ -22,12 +26,14 @@ class RepresentationsModel(QtGui.QStandardItemModel): ("Name", 120), ("Product name", 125), ("Folder", 125), - # ("Active site", 85), - # ("Remote site", 85) + ("Active site", 85), + ("Remote site", 85) ] column_labels = [label for label, _ in colums_info] column_widths = [width for _, width in colums_info] folder_column = column_labels.index("Product name") + active_site_column = column_labels.index("Active site") + remote_site_column = column_labels.index("Remote site") def __init__(self, controller): super(RepresentationsModel, self).__init__() @@ -59,7 +65,7 @@ class RepresentationsModel(QtGui.QStandardItemModel): repre_items = self._controller.get_representation_items( self._selected_project_name, self._selected_version_ids ) - self._fill_items(repre_items) + self._fill_items(repre_items, self._selected_project_name) self.refreshed.emit() def data(self, index, role=None): @@ -69,13 +75,23 @@ class RepresentationsModel(QtGui.QStandardItemModel): col = index.column() if col != 0: if role == QtCore.Qt.DecorationRole: - return None + if col == 3: + role = ACTIVE_SITE_ICON_ROLE + elif col == 4: + role = REMOTE_SITE_ICON_ROLE + else: + return None if role == QtCore.Qt.DisplayRole: if col == 1: role = PRODUCT_NAME_ROLE elif col == 2: role = FOLDER_LABEL_ROLE + elif col == 3: + role = SYNC_ACTIVE_SITE_PROGRESS + elif col == 4: + role = SYNC_REMOTE_SITE_PROGRESS + index = self.index(index.row(), 0, index.parent()) return super(RepresentationsModel, self).data(index, role) @@ -89,7 +105,13 @@ class RepresentationsModel(QtGui.QStandardItemModel): root_item = self.invisibleRootItem() root_item.removeRows(0, root_item.rowCount()) - def _get_repre_item(self, repre_item): + def _get_repre_item( + self, + repre_item, + active_site_icon, + remote_site_icon, + repres_sync_status + ): repre_id = repre_item.representation_id repre_name = repre_item.representation_name repre_icon = repre_item.representation_icon @@ -102,6 +124,12 @@ class RepresentationsModel(QtGui.QStandardItemModel): item.setColumnCount(self.columnCount()) item.setEditable(False) + sync_status = repres_sync_status[repre_id] + active_progress, remote_progress = sync_status + + active_site_progress = "{}%".format(int(active_progress * 100)) + remote_site_progress = "{}%".format(int(remote_progress * 100)) + icon = get_qt_icon(repre_icon) item.setData(repre_name, QtCore.Qt.DisplayRole) item.setData(icon, QtCore.Qt.DecorationRole) @@ -109,6 +137,10 @@ class RepresentationsModel(QtGui.QStandardItemModel): item.setData(repre_id, REPRESENTATION_ID_ROLE) item.setData(repre_item.product_name, PRODUCT_NAME_ROLE) item.setData(repre_item.folder_label, FOLDER_LABEL_ROLE) + item.setData(active_site_icon, ACTIVE_SITE_ICON_ROLE) + item.setData(remote_site_icon, REMOTE_SITE_ICON_ROLE) + item.setData(active_site_progress, SYNC_ACTIVE_SITE_PROGRESS) + item.setData(remote_site_progress, SYNC_REMOTE_SITE_PROGRESS) return is_new_item, item def _get_group_icon(self): @@ -134,14 +166,29 @@ class RepresentationsModel(QtGui.QStandardItemModel): self._groups_items_by_name[repre_name] = item return True, item - def _fill_items(self, repre_items): + def _fill_items(self, repre_items, project_name): + active_site_icon_def = self._controller.get_active_site_icon_def( + project_name + ) + remote_site_icon_def = self._controller.get_remote_site_icon_def( + project_name + ) + active_site_icon = get_qt_icon(active_site_icon_def) + remote_site_icon = get_qt_icon(remote_site_icon_def) + items_to_remove = set(self._items_by_id.keys()) repre_items_by_name = collections.defaultdict(list) + repre_ids = set() for repre_item in repre_items: + repre_ids.add(repre_item.representation_id) items_to_remove.discard(repre_item.representation_id) repre_name = repre_item.representation_name repre_items_by_name[repre_name].append(repre_item) + repres_sync_status = self._controller.get_representations_sync_status( + project_name, repre_ids + ) + root_item = self.invisibleRootItem() for repre_id in items_to_remove: item = self._items_by_id.pop(repre_id) @@ -164,7 +211,12 @@ class RepresentationsModel(QtGui.QStandardItemModel): new_group_items = [] for repre_item in repre_name_items: - is_new_item, item = self._get_repre_item(repre_item) + is_new_item, item = self._get_repre_item( + repre_item, + active_site_icon, + remote_site_icon, + repres_sync_status + ) item_parent = item.parent() if item_parent is None: item_parent = root_item @@ -255,6 +307,9 @@ class RepresentationsWidget(QtWidgets.QWidget): self._repre_model = repre_model self._repre_proxy_model = repre_proxy_model + self._set_site_sync_visibility( + self._controller.is_site_sync_enabled() + ) self._set_multiple_folders_selected(False) def refresh(self): @@ -265,6 +320,20 @@ class RepresentationsWidget(QtWidgets.QWidget): def _on_project_change(self, event): self._selected_project_name = event["project_name"] + site_sync_enabled = self._controller.is_site_sync_enabled( + self._selected_project_name + ) + self._set_site_sync_visibility(site_sync_enabled) + + def _set_site_sync_visibility(self, site_sync_enabled): + self._repre_view.setColumnHidden( + self._repre_model.active_site_column, + not site_sync_enabled + ) + self._repre_view.setColumnHidden( + self._repre_model.remote_site_column, + not site_sync_enabled + ) def _set_multiple_folders_selected(self, selected_multiple_folders): if selected_multiple_folders == self._selected_multiple_folders: diff --git a/openpype/tools/ayon_sceneinventory/control.py b/openpype/tools/ayon_sceneinventory/control.py index e98b0e307b..6111d7e43b 100644 --- a/openpype/tools/ayon_sceneinventory/control.py +++ b/openpype/tools/ayon_sceneinventory/control.py @@ -70,19 +70,12 @@ class SceneInventoryController: context = self.get_current_context() project_name = context["project_name"] - folder_path = context.get("folder_path") folder_name = context.get("asset_name") folder_id = None - if folder_path: - folder = ayon_api.get_folder_by_path(project_name, folder_path) + if folder_name: + folder = ayon_api.get_folder_by_path(project_name, folder_name) if folder: folder_id = folder["id"] - elif folder_name: - for folder in ayon_api.get_folders( - project_name, folder_names=[folder_name] - ): - folder_id = folder["id"] - break self._current_folder_id = folder_id self._current_folder_set = True diff --git a/openpype/tools/ayon_utils/widgets/utils.py b/openpype/tools/ayon_utils/widgets/utils.py index 2817b5efc0..5165b3a262 100644 --- a/openpype/tools/ayon_utils/widgets/utils.py +++ b/openpype/tools/ayon_utils/widgets/utils.py @@ -15,6 +15,7 @@ class RefreshThread(QtCore.QThread): self._callback = partial(func, *args, **kwargs) self._exception = None self._result = None + self.finished.connect(self._on_finish_callback) @property def id(self): @@ -29,11 +30,19 @@ class RefreshThread(QtCore.QThread): self._result = self._callback() except Exception as exc: self._exception = exc - self.refresh_finished.emit(self.id) def get_result(self): return self._result + def _on_finish_callback(self): + """Trigger custom signal with thread id. + + Listening for 'finished' signal we make sure that execution of thread + finished and QThread object can be safely deleted. + """ + + self.refresh_finished.emit(self.id) + class _IconsCache: """Cache for icons.""" diff --git a/openpype/tools/ayon_workfiles/control.py b/openpype/tools/ayon_workfiles/control.py index fbe6df3155..9d19571267 100644 --- a/openpype/tools/ayon_workfiles/control.py +++ b/openpype/tools/ayon_workfiles/control.py @@ -473,7 +473,7 @@ class BaseWorkfileController( current_file = self.get_current_workfile() folder_id = None if folder_name: - folder = ayon_api.get_folder_by_name(project_name, folder_name) + folder = ayon_api.get_folder_by_path(project_name, folder_name) if folder: folder_id = folder["id"] diff --git a/openpype/tools/ayon_workfiles/models/workfiles.py b/openpype/tools/ayon_workfiles/models/workfiles.py index 907b9b5383..d74a8e164d 100644 --- a/openpype/tools/ayon_workfiles/models/workfiles.py +++ b/openpype/tools/ayon_workfiles/models/workfiles.py @@ -606,7 +606,7 @@ class PublishWorkfilesModel: print("Failed to format workfile path: {}".format(exc)) dirpath, filename = os.path.split(workfile_path) - created_at = arrow.get(repre_entity["createdAt"]) + created_at = arrow.get(repre_entity["createdAt"].to("local")) return FileItem( dirpath, filename, diff --git a/openpype/tools/creator/window.py b/openpype/tools/creator/window.py index 47f27a262a..117519e1d7 100644 --- a/openpype/tools/creator/window.py +++ b/openpype/tools/creator/window.py @@ -214,7 +214,7 @@ class CreatorWindow(QtWidgets.QDialog): asset_name = self._asset_name_input.text() # Early exit if no asset name - if not asset_name.strip(): + if not asset_name: self._build_menu() self.echo("Asset name is required ..") self._set_valid_state(False) diff --git a/openpype/tools/experimental_tools/dialog.py b/openpype/tools/experimental_tools/dialog.py index 00b6ae07a4..3a25d72ff4 100644 --- a/openpype/tools/experimental_tools/dialog.py +++ b/openpype/tools/experimental_tools/dialog.py @@ -1,5 +1,6 @@ from qtpy import QtWidgets, QtCore, QtGui +from openpype import AYON_SERVER_ENABLED from openpype.style import ( load_stylesheet, app_icon_path @@ -26,7 +27,8 @@ class ExperimentalToolsDialog(QtWidgets.QDialog): def __init__(self, parent=None): super(ExperimentalToolsDialog, self).__init__(parent) - self.setWindowTitle("OpenPype Experimental tools") + app_label = "AYON" if AYON_SERVER_ENABLED else "OpenPype" + self.setWindowTitle("{} Experimental tools".format(app_label)) icon = QtGui.QIcon(app_icon_path()) self.setWindowIcon(icon) self.setStyleSheet(load_stylesheet()) @@ -68,8 +70,8 @@ class ExperimentalToolsDialog(QtWidgets.QDialog): tool_btns_label = QtWidgets.QLabel( ( "You can enable these features in" - "
OpenPype tray -> Settings -> Experimental tools" - ), + "
{} tray -> Settings -> Experimental tools" + ).format(app_label), tool_btns_widget ) tool_btns_label.setAlignment(QtCore.Qt.AlignCenter) @@ -113,6 +115,7 @@ class ExperimentalToolsDialog(QtWidgets.QDialog): self._window_is_active = False def refresh(self): + app_label = "AYON" if AYON_SERVER_ENABLED else "OpenPype" self._experimental_tools.refresh_availability() buttons_to_remove = set(self._buttons_by_tool_identifier.keys()) @@ -139,8 +142,8 @@ class ExperimentalToolsDialog(QtWidgets.QDialog): elif is_new or button.isEnabled(): button.setToolTip(( "You can enable this tool in local settings." - "\n\nOpenPype Tray > Settings > Experimental Tools" - )) + "\n\n{} Tray > Settings > Experimental Tools" + ).format(app_label)) if tool.enabled != button.isEnabled(): button.setEnabled(tool.enabled) diff --git a/openpype/tools/publisher/control.py b/openpype/tools/publisher/control.py index 3192fe949f..b02d83e4f6 100644 --- a/openpype/tools/publisher/control.py +++ b/openpype/tools/publisher/control.py @@ -12,10 +12,12 @@ from abc import ABCMeta, abstractmethod import six import pyblish.api +from openpype import AYON_SERVER_ENABLED from openpype.client import ( get_assets, get_asset_by_id, get_subsets, + get_asset_name_identifier, ) from openpype.lib.events import EventSystem from openpype.lib.attribute_definitions import ( @@ -73,6 +75,8 @@ class AssetDocsCache: "data.visualParent": True, "data.tasks": True } + if AYON_SERVER_ENABLED: + projection["data.parents"] = True def __init__(self, controller): self._controller = controller @@ -105,7 +109,7 @@ class AssetDocsCache: elif "tasks" not in asset_doc["data"]: asset_doc["data"]["tasks"] = {} - asset_name = asset_doc["name"] + asset_name = get_asset_name_identifier(asset_doc) asset_tasks = asset_doc["data"]["tasks"] task_names_by_asset_name[asset_name] = list(asset_tasks.keys()) asset_docs_by_name[asset_name] = asset_doc @@ -2513,7 +2517,7 @@ class PublisherController(BasePublisherController): else: msg = ( "Something went wrong. Send report" - " to your supervisor or OpenPype." + " to your supervisor or Ynput team." ) self.publish_error_msg = msg self.publish_has_crashed = True diff --git a/openpype/tools/publisher/widgets/assets_widget.py b/openpype/tools/publisher/widgets/assets_widget.py index c536f93c9b..32be514dd7 100644 --- a/openpype/tools/publisher/widgets/assets_widget.py +++ b/openpype/tools/publisher/widgets/assets_widget.py @@ -11,7 +11,8 @@ from openpype.tools.utils import ( from openpype.tools.utils.assets_widget import ( SingleSelectAssetsWidget, ASSET_ID_ROLE, - ASSET_NAME_ROLE + ASSET_NAME_ROLE, + ASSET_PATH_ROLE, ) @@ -31,6 +32,15 @@ class CreateWidgetAssetsWidget(SingleSelectAssetsWidget): self._last_filter_height = None + def get_selected_asset_name(self): + if AYON_SERVER_ENABLED: + selection_model = self._view.selectionModel() + indexes = selection_model.selectedRows() + for index in indexes: + return index.data(ASSET_PATH_ROLE) + return None + return super(CreateWidgetAssetsWidget, self).get_selected_asset_name() + def _check_header_height(self): """Catch header height changes. @@ -100,21 +110,24 @@ class AssetsHierarchyModel(QtGui.QStandardItemModel): self._controller = controller self._items_by_name = {} + self._items_by_path = {} self._items_by_asset_id = {} def reset(self): self.clear() self._items_by_name = {} + self._items_by_path = {} self._items_by_asset_id = {} assets_by_parent_id = self._controller.get_asset_hierarchy() items_by_name = {} + items_by_path = {} items_by_asset_id = {} _queue = collections.deque() - _queue.append((self.invisibleRootItem(), None)) + _queue.append((self.invisibleRootItem(), None, None)) while _queue: - parent_item, parent_id = _queue.popleft() + parent_item, parent_id, parent_path = _queue.popleft() children = assets_by_parent_id.get(parent_id) if not children: continue @@ -127,6 +140,11 @@ class AssetsHierarchyModel(QtGui.QStandardItemModel): for name in sorted(children_by_name.keys()): child = children_by_name[name] child_id = child["_id"] + if parent_path: + child_path = "{}/{}".format(parent_path, name) + else: + child_path = "/{}".format(name) + has_children = bool(assets_by_parent_id.get(child_id)) icon = get_asset_icon(child, has_children) @@ -138,15 +156,18 @@ class AssetsHierarchyModel(QtGui.QStandardItemModel): item.setData(icon, QtCore.Qt.DecorationRole) item.setData(child_id, ASSET_ID_ROLE) item.setData(name, ASSET_NAME_ROLE) + item.setData(child_path, ASSET_PATH_ROLE) items_by_name[name] = item + items_by_path[child_path] = item items_by_asset_id[child_id] = item items.append(item) - _queue.append((item, child_id)) + _queue.append((item, child_id, child_path)) parent_item.appendRows(items) self._items_by_name = items_by_name + self._items_by_path = items_by_path self._items_by_asset_id = items_by_asset_id def get_index_by_asset_id(self, asset_id): @@ -156,12 +177,20 @@ class AssetsHierarchyModel(QtGui.QStandardItemModel): return QtCore.QModelIndex() def get_index_by_asset_name(self, asset_name): - item = self._items_by_name.get(asset_name) + item = None + if AYON_SERVER_ENABLED: + item = self._items_by_path.get(asset_name) + + if item is None: + item = self._items_by_name.get(asset_name) + if item is None: return QtCore.QModelIndex() return item.index() def name_is_valid(self, item_name): + if AYON_SERVER_ENABLED and item_name in self._items_by_path: + return True return item_name in self._items_by_name @@ -296,7 +325,10 @@ class AssetsDialog(QtWidgets.QDialog): index = self._asset_view.currentIndex() asset_name = None if index.isValid(): - asset_name = index.data(ASSET_NAME_ROLE) + if AYON_SERVER_ENABLED: + asset_name = index.data(ASSET_PATH_ROLE) + else: + asset_name = index.data(ASSET_NAME_ROLE) self._selected_asset = asset_name self.done(1) diff --git a/openpype/tools/publisher/widgets/create_widget.py b/openpype/tools/publisher/widgets/create_widget.py index 64fed1d70c..73dcae51a5 100644 --- a/openpype/tools/publisher/widgets/create_widget.py +++ b/openpype/tools/publisher/widgets/create_widget.py @@ -816,8 +816,13 @@ class CreateWidget(QtWidgets.QWidget): # Where to define these data? # - what data show be stored? + if AYON_SERVER_ENABLED: + asset_key = "folderPath" + else: + asset_key = "asset" + instance_data = { - "asset": asset_name, + asset_key: asset_name, "task": task_name, "variant": variant, "family": family diff --git a/openpype/tools/publisher/widgets/widgets.py b/openpype/tools/publisher/widgets/widgets.py index 1860287fcf..ecccc4e0c8 100644 --- a/openpype/tools/publisher/widgets/widgets.py +++ b/openpype/tools/publisher/widgets/widgets.py @@ -540,6 +540,7 @@ class AssetsField(BaseClickableFrame): Does not change selected items (assets). """ self._name_input.setText(text) + self._name_input.end(False) def set_selected_items(self, asset_names=None): """Set asset names for selection of instances. @@ -1187,7 +1188,10 @@ class GlobalAttrsWidget(QtWidgets.QWidget): asset_names = [] for instance in self._current_instances: new_variant_value = instance.get("variant") - new_asset_name = instance.get("asset") + if AYON_SERVER_ENABLED: + new_asset_name = instance.get("folderPath") + else: + new_asset_name = instance.get("asset") new_task_name = instance.get("task") if variant_value is not None: new_variant_value = variant_value @@ -1219,7 +1223,11 @@ class GlobalAttrsWidget(QtWidgets.QWidget): instance["variant"] = variant_value if asset_name is not None: - instance["asset"] = asset_name + if AYON_SERVER_ENABLED: + instance["folderPath"] = asset_name + else: + instance["asset"] = asset_name + instance.set_asset_invalid(False) if task_name is not None: @@ -1317,7 +1325,10 @@ class GlobalAttrsWidget(QtWidgets.QWidget): variants.add(instance.get("variant") or self.unknown_value) families.add(instance.get("family") or self.unknown_value) - asset_name = instance.get("asset") or self.unknown_value + if AYON_SERVER_ENABLED: + asset_name = instance.get("folderPath") or self.unknown_value + else: + asset_name = instance.get("asset") or self.unknown_value task_name = instance.get("task") or "" asset_names.add(asset_name) asset_task_combinations.append((asset_name, task_name)) diff --git a/openpype/tools/publisher/window.py b/openpype/tools/publisher/window.py index 2416763c27..b3138c3f45 100644 --- a/openpype/tools/publisher/window.py +++ b/openpype/tools/publisher/window.py @@ -9,6 +9,7 @@ from openpype import ( resources, style ) +from openpype import AYON_SERVER_ENABLED from openpype.tools.utils import ( ErrorMessageBox, PlaceholderLineEdit, @@ -53,7 +54,9 @@ class PublisherWindow(QtWidgets.QDialog): self.setObjectName("PublishWindow") - self.setWindowTitle("OpenPype publisher") + self.setWindowTitle("{} publisher".format( + "AYON" if AYON_SERVER_ENABLED else "OpenPype" + )) icon = QtGui.QIcon(resources.get_openpype_icon_filepath()) self.setWindowIcon(icon) diff --git a/openpype/tools/tray/pype_info_widget.py b/openpype/tools/tray/pype_info_widget.py index dc222b79b5..acd937e711 100644 --- a/openpype/tools/tray/pype_info_widget.py +++ b/openpype/tools/tray/pype_info_widget.py @@ -6,6 +6,7 @@ import ayon_api from qtpy import QtCore, QtGui, QtWidgets from openpype import style +import openpype.version from openpype import resources from openpype import AYON_SERVER_ENABLED from openpype.settings.lib import get_local_settings @@ -219,7 +220,9 @@ class PypeInfoWidget(QtWidgets.QWidget): icon = QtGui.QIcon(resources.get_openpype_icon_filepath()) self.setWindowIcon(icon) - self.setWindowTitle("OpenPype info") + self.setWindowTitle( + "{} info".format("AYON" if AYON_SERVER_ENABLED else "OpenPype") + ) scroll_area = QtWidgets.QScrollArea(self) info_widget = PypeInfoSubWidget(scroll_area) @@ -441,16 +444,19 @@ class PypeInfoSubWidget(QtWidgets.QWidget): info_values = { "executable": executable_args[-1], "server_url": os.environ["AYON_SERVER_URL"], + "bundle_name": os.environ["AYON_BUNDLE_NAME"], "username": username } key_label_mapping = { "executable": "AYON Executable:", "server_url": "AYON Server:", + "bundle_name": "AYON Bundle:", "username": "AYON Username:" } # Prepare keys order keys_order = [ "server_url", + "bundle_name", "username", "executable", ] @@ -513,4 +519,16 @@ class PypeInfoSubWidget(QtWidgets.QWidget): info_layout.addWidget( value_label, row, 1, 1, 1 ) + if AYON_SERVER_ENABLED: + row = info_layout.rowCount() + info_layout.addWidget( + QtWidgets.QLabel("OpenPype Addon:"), row, 0, 1, 1 + ) + value_label = QtWidgets.QLabel(openpype.version.__version__) + value_label.setTextInteractionFlags( + QtCore.Qt.TextSelectableByMouse + ) + info_layout.addWidget( + value_label, row, 1, 1, 1 + ) return info_widget diff --git a/openpype/tools/tray/pype_tray.py b/openpype/tools/tray/pype_tray.py index a5876ca721..769ed4272b 100644 --- a/openpype/tools/tray/pype_tray.py +++ b/openpype/tools/tray/pype_tray.py @@ -599,7 +599,10 @@ class TrayManager: subversion = os.environ.get("OPENPYPE_SUBVERSION") client_name = os.environ.get("OPENPYPE_CLIENT") - version_string = openpype.version.__version__ + if AYON_SERVER_ENABLED: + version_string = os.getenv("AYON_VERSION", "AYON Info") + else: + version_string = openpype.version.__version__ if subversion: version_string += " ({})".format(subversion) @@ -632,6 +635,14 @@ class TrayManager: self.exit() elif result.restart or result.token_changed: + # Remove environment variables from current connection + # - keep develop, staging, headless values + for key in { + "AYON_SERVER_URL", + "AYON_API_KEY", + "AYON_BUNDLE_NAME", + }: + os.environ.pop(key, None) self.restart() def _on_restart_action(self): diff --git a/openpype/tools/utils/assets_widget.py b/openpype/tools/utils/assets_widget.py index a45d762c73..b83f4dfcaf 100644 --- a/openpype/tools/utils/assets_widget.py +++ b/openpype/tools/utils/assets_widget.py @@ -36,6 +36,7 @@ ASSET_ID_ROLE = QtCore.Qt.UserRole + 1 ASSET_NAME_ROLE = QtCore.Qt.UserRole + 2 ASSET_LABEL_ROLE = QtCore.Qt.UserRole + 3 ASSET_UNDERLINE_COLORS_ROLE = QtCore.Qt.UserRole + 4 +ASSET_PATH_ROLE = QtCore.Qt.UserRole + 5 class AssetsView(TreeViewSpinner, DeselectableTreeView): diff --git a/openpype/vendor/python/common/ayon_api/_api.py b/openpype/vendor/python/common/ayon_api/_api.py index 9f89d3d59e..9d4fc697ae 100644 --- a/openpype/vendor/python/common/ayon_api/_api.py +++ b/openpype/vendor/python/common/ayon_api/_api.py @@ -374,7 +374,7 @@ def get_default_settings_variant(): """ con = get_server_api_connection() - return con.get_client_version() + return con.get_default_settings_variant() def set_default_settings_variant(variant): diff --git a/openpype/vendor/python/common/ayon_api/constants.py b/openpype/vendor/python/common/ayon_api/constants.py index eaeb77b607..c31940d93a 100644 --- a/openpype/vendor/python/common/ayon_api/constants.py +++ b/openpype/vendor/python/common/ayon_api/constants.py @@ -3,6 +3,10 @@ SERVER_URL_ENV_KEY = "AYON_SERVER_URL" SERVER_API_ENV_KEY = "AYON_API_KEY" SERVER_TIMEOUT_ENV_KEY = "AYON_SERVER_TIMEOUT" SERVER_RETRIES_ENV_KEY = "AYON_SERVER_RETRIES" +# Default variant used for settings +DEFAULT_VARIANT_ENV_KEY = "AYON_DEFAULT_SETTINGS_VARIANT" +# Default site id used for connection +SITE_ID_ENV_KEY = "AYON_SITE_ID" # Backwards compatibility SERVER_TOKEN_ENV_KEY = SERVER_API_ENV_KEY @@ -40,6 +44,7 @@ DEFAULT_PROJECT_FIELDS = { "code", "config", "createdAt", + "data", } # --- Folders --- @@ -52,6 +57,7 @@ DEFAULT_FOLDER_FIELDS = { "parentId", "active", "thumbnailId", + "data", } # --- Tasks --- @@ -63,6 +69,7 @@ DEFAULT_TASK_FIELDS = { "folderId", "active", "assignees", + "data", } # --- Products --- @@ -72,6 +79,7 @@ DEFAULT_PRODUCT_FIELDS = { "folderId", "active", "productType", + "data", } # --- Versions --- @@ -86,6 +94,7 @@ DEFAULT_VERSION_FIELDS = { "thumbnailId", "createdAt", "updatedAt", + "data", } # --- Representations --- @@ -96,6 +105,7 @@ DEFAULT_REPRESENTATION_FIELDS = { "createdAt", "active", "versionId", + "data", } REPRESENTATION_FILES_FIELDS = { @@ -119,6 +129,7 @@ DEFAULT_WORKFILE_INFO_FIELDS = { "thumbnailId", "updatedAt", "updatedBy", + "data", } DEFAULT_EVENT_FIELDS = { diff --git a/openpype/vendor/python/common/ayon_api/entity_hub.py b/openpype/vendor/python/common/ayon_api/entity_hub.py index b9b017bac5..61d740fe57 100644 --- a/openpype/vendor/python/common/ayon_api/entity_hub.py +++ b/openpype/vendor/python/common/ayon_api/entity_hub.py @@ -36,11 +36,20 @@ class EntityHub(object): """ def __init__( - self, project_name, connection=None, allow_data_changes=False + self, project_name, connection=None, allow_data_changes=None ): if not connection: connection = get_server_api_connection() + major, minor, patch, _, _ = connection.server_version_tuple + path_start_with_slash = True + if (major, minor) < (0, 6): + path_start_with_slash = False + + if allow_data_changes is None: + allow_data_changes = connection.graphql_allows_data_in_query + self._connection = connection + self._path_start_with_slash = path_start_with_slash self._project_name = project_name self._entities_by_id = {} @@ -65,6 +74,18 @@ class EntityHub(object): return self._allow_data_changes + @property + def path_start_with_slash(self): + """Folder path should start with slash. + + This changed in 0.6.x server version. + + Returns: + bool: Path starts with slash. + """ + + return self._path_start_with_slash + @property def project_name(self): """Project name which is maintained by hub. @@ -2419,10 +2440,13 @@ class FolderEntity(BaseEntity): if self._path is None: parent = self.parent - path = self.name if parent.entity_type == "folder": parent_path = parent.path - path = "/".join([parent_path, path]) + path = "/".join([parent_path, self.name]) + elif self._entity_hub.path_start_with_slash: + path = "/{}".format(self.name) + else: + path = self.name self._path = path return self._path @@ -2525,7 +2549,10 @@ class FolderEntity(BaseEntity): if self.thumbnail_id is not UNKNOWN_VALUE: output["thumbnailId"] = self.thumbnail_id - if self._entity_hub.allow_data_changes: + if ( + self._entity_hub.allow_data_changes + and self._data is not UNKNOWN_VALUE + ): output["data"] = self._data return output diff --git a/openpype/vendor/python/common/ayon_api/graphql.py b/openpype/vendor/python/common/ayon_api/graphql.py index 854f207a00..2594b45966 100644 --- a/openpype/vendor/python/common/ayon_api/graphql.py +++ b/openpype/vendor/python/common/ayon_api/graphql.py @@ -202,6 +202,15 @@ class GraphQlQuery: self._variables[key]["value"] = value + def get_variable_keys(self): + """Get all variable keys. + + Returns: + set[str]: Variable keys. + """ + + return set(self._variables.keys()) + def get_variables_values(self): """Calculate variable values used that should be used in query. diff --git a/openpype/vendor/python/common/ayon_api/graphql_queries.py b/openpype/vendor/python/common/ayon_api/graphql_queries.py index cedb3ed2ac..f121a5649f 100644 --- a/openpype/vendor/python/common/ayon_api/graphql_queries.py +++ b/openpype/vendor/python/common/ayon_api/graphql_queries.py @@ -175,10 +175,15 @@ def folders_graphql_query(fields): folder_ids_var = query.add_variable("folderIds", "[String!]") parent_folder_ids_var = query.add_variable("parentFolderIds", "[String!]") folder_paths_var = query.add_variable("folderPaths", "[String!]") + folder_path_regex_var = query.add_variable("folderPathRegex", "String!") folder_names_var = query.add_variable("folderNames", "[String!]") folder_types_var = query.add_variable("folderTypes", "[String!]") - statuses_var = query.add_variable("folderStatuses", "[String!]") has_products_var = query.add_variable("folderHasProducts", "Boolean!") + has_tasks_var = query.add_variable("folderHasTasks", "Boolean!") + has_links_var = query.add_variable("folderHasLinks", "HasLinksFilter") + has_children_var = query.add_variable("folderHasChildren", "Boolean!") + statuses_var = query.add_variable("folderStatuses", "[String!]") + tags_var = query.add_variable("folderTags", "[String!]") project_field = query.add_field("project") project_field.set_filter("name", project_name_var) @@ -188,9 +193,14 @@ def folders_graphql_query(fields): folders_field.set_filter("parentIds", parent_folder_ids_var) folders_field.set_filter("names", folder_names_var) folders_field.set_filter("paths", folder_paths_var) + folders_field.set_filter("pathEx", folder_path_regex_var) folders_field.set_filter("folderTypes", folder_types_var) folders_field.set_filter("statuses", statuses_var) + folders_field.set_filter("tags", tags_var) folders_field.set_filter("hasProducts", has_products_var) + folders_field.set_filter("hasTasks", has_tasks_var) + folders_field.set_filter("hasLinks", has_links_var) + folders_field.set_filter("hasChildren", has_children_var) nested_fields = fields_to_dict(fields) add_links_fields(folders_field, nested_fields) @@ -218,6 +228,10 @@ def tasks_graphql_query(fields): task_names_var = query.add_variable("taskNames", "[String!]") task_types_var = query.add_variable("taskTypes", "[String!]") folder_ids_var = query.add_variable("folderIds", "[String!]") + assignees_any_var = query.add_variable("taskAssigneesAny", "[String!]") + assignees_all_var = query.add_variable("taskAssigneesAll", "[String!]") + statuses_var = query.add_variable("taskStatuses", "[String!]") + tags_var = query.add_variable("taskTags", "[String!]") project_field = query.add_field("project") project_field.set_filter("name", project_name_var) @@ -228,6 +242,10 @@ def tasks_graphql_query(fields): tasks_field.set_filter("names", task_names_var) tasks_field.set_filter("taskTypes", task_types_var) tasks_field.set_filter("folderIds", folder_ids_var) + tasks_field.set_filter("assigneesAny", assignees_any_var) + tasks_field.set_filter("assignees", assignees_all_var) + tasks_field.set_filter("statuses", statuses_var) + tasks_field.set_filter("tags", tags_var) nested_fields = fields_to_dict(fields) add_links_fields(tasks_field, nested_fields) @@ -256,7 +274,10 @@ def products_graphql_query(fields): product_names_var = query.add_variable("productNames", "[String!]") folder_ids_var = query.add_variable("folderIds", "[String!]") product_types_var = query.add_variable("productTypes", "[String!]") - statuses_var = query.add_variable("statuses", "[String!]") + product_name_regex_var = query.add_variable("productNameRegex", "String!") + product_path_regex_var = query.add_variable("productPathRegex", "String!") + statuses_var = query.add_variable("productStatuses.", "[String!]") + tags_var = query.add_variable("productTags.", "[String!]") project_field = query.add_field("project") project_field.set_filter("name", project_name_var) @@ -267,6 +288,9 @@ def products_graphql_query(fields): products_field.set_filter("folderIds", folder_ids_var) products_field.set_filter("productTypes", product_types_var) products_field.set_filter("statuses", statuses_var) + products_field.set_filter("tags", tags_var) + products_field.set_filter("nameEx", product_name_regex_var) + products_field.set_filter("pathEx", product_path_regex_var) nested_fields = fields_to_dict(set(fields)) add_links_fields(products_field, nested_fields) @@ -299,24 +323,28 @@ def versions_graphql_query(fields): hero_or_latest_only_var = query.add_variable( "heroOrLatestOnly", "Boolean" ) + statuses_var = query.add_variable("versionStatuses", "[String!]") + tags_var = query.add_variable("versionTags", "[String!]") project_field = query.add_field("project") project_field.set_filter("name", project_name_var) - products_field = project_field.add_field_with_edges("versions") - products_field.set_filter("ids", version_ids_var) - products_field.set_filter("productIds", product_ids_var) - products_field.set_filter("versions", versions_var) - products_field.set_filter("heroOnly", hero_only_var) - products_field.set_filter("latestOnly", latest_only_var) - products_field.set_filter("heroOrLatestOnly", hero_or_latest_only_var) + versions_field = project_field.add_field_with_edges("versions") + versions_field.set_filter("ids", version_ids_var) + versions_field.set_filter("productIds", product_ids_var) + versions_field.set_filter("versions", versions_var) + versions_field.set_filter("heroOnly", hero_only_var) + versions_field.set_filter("latestOnly", latest_only_var) + versions_field.set_filter("heroOrLatestOnly", hero_or_latest_only_var) + versions_field.set_filter("statuses", statuses_var) + versions_field.set_filter("tags", tags_var) nested_fields = fields_to_dict(set(fields)) - add_links_fields(products_field, nested_fields) + add_links_fields(versions_field, nested_fields) query_queue = collections.deque() for key, value in nested_fields.items(): - query_queue.append((key, value, products_field)) + query_queue.append((key, value, versions_field)) while query_queue: item = query_queue.popleft() @@ -337,6 +365,13 @@ def representations_graphql_query(fields): repre_ids_var = query.add_variable("representationIds", "[String!]") repre_names_var = query.add_variable("representationNames", "[String!]") version_ids_var = query.add_variable("versionIds", "[String!]") + has_links_var = query.add_variable("representationHasLinks", "HasLinksFilter") + statuses_var = query.add_variable( + "representationStatuses", "[String!]" + ) + tags_var = query.add_variable( + "representationTags", "[String!]" + ) project_field = query.add_field("project") project_field.set_filter("name", project_name_var) @@ -345,6 +380,9 @@ def representations_graphql_query(fields): repres_field.set_filter("ids", repre_ids_var) repres_field.set_filter("versionIds", version_ids_var) repres_field.set_filter("names", repre_names_var) + repres_field.set_filter("hasLinks", has_links_var) + repres_field.set_filter("statuses", statuses_var) + repres_field.set_filter("tags", tags_var) nested_fields = fields_to_dict(set(fields)) add_links_fields(repres_field, nested_fields) @@ -412,6 +450,10 @@ def workfiles_info_graphql_query(fields): workfiles_info_ids = query.add_variable("workfileIds", "[String!]") task_ids_var = query.add_variable("taskIds", "[String!]") paths_var = query.add_variable("paths", "[String!]") + path_regex_var = query.add_variable("workfilePathRegex", "String!") + has_links_var = query.add_variable("workfilehasLinks", "HasLinksFilter") + statuses_var = query.add_variable("workfileStatuses", "[String!]") + tags_var = query.add_variable("workfileTags", "[String!]") project_field = query.add_field("project") project_field.set_filter("name", project_name_var) @@ -420,6 +462,10 @@ def workfiles_info_graphql_query(fields): workfiles_field.set_filter("ids", workfiles_info_ids) workfiles_field.set_filter("taskIds", task_ids_var) workfiles_field.set_filter("paths", paths_var) + workfiles_field.set_filter("pathEx", path_regex_var) + workfiles_field.set_filter("hasLinks", has_links_var) + workfiles_field.set_filter("statuses", statuses_var) + workfiles_field.set_filter("tags", tags_var) nested_fields = fields_to_dict(set(fields)) add_links_fields(workfiles_field, nested_fields) @@ -447,6 +493,9 @@ def events_graphql_query(fields): states_var = query.add_variable("eventStates", "[String!]") users_var = query.add_variable("eventUsers", "[String!]") include_logs_var = query.add_variable("includeLogsFilter", "Boolean!") + has_children_var = query.add_variable("hasChildrenFilter", "Boolean!") + newer_than_var = query.add_variable("newerThanFilter", "String!") + older_than_var = query.add_variable("olderThanFilter", "String!") events_field = query.add_field_with_edges("events") events_field.set_filter("topics", topics_var) @@ -454,6 +503,9 @@ def events_graphql_query(fields): events_field.set_filter("states", states_var) events_field.set_filter("users", users_var) events_field.set_filter("includeLogs", include_logs_var) + events_field.set_filter("hasChildren", has_children_var) + events_field.set_filter("newerThan", newer_than_var) + events_field.set_filter("olderThan", older_than_var) nested_fields = fields_to_dict(set(fields)) diff --git a/openpype/vendor/python/common/ayon_api/server_api.py b/openpype/vendor/python/common/ayon_api/server_api.py index 3bac59c192..e4e7146279 100644 --- a/openpype/vendor/python/common/ayon_api/server_api.py +++ b/openpype/vendor/python/common/ayon_api/server_api.py @@ -9,6 +9,9 @@ import platform import copy import uuid from contextlib import contextmanager + +import six + try: from http import HTTPStatus except ImportError: @@ -27,7 +30,6 @@ except ImportError: from json import JSONDecodeError as RequestsJSONDecodeError from .constants import ( - SERVER_TIMEOUT_ENV_KEY, SERVER_RETRIES_ENV_KEY, DEFAULT_PRODUCT_TYPE_FIELDS, DEFAULT_PROJECT_FIELDS, @@ -76,8 +78,11 @@ from .utils import ( create_dependency_package_basename, ThumbnailContent, get_default_timeout, + get_default_settings_variant, + get_default_site_id, ) +_PLACEHOLDER = object() PatternType = type(re.compile("")) JSONDecodeError = getattr(json, "JSONDecodeError", ValueError) # This should be collected from server schema @@ -176,6 +181,11 @@ class RestApiResponse(object): return self.status def raise_for_status(self, message=None): + if self._response is None: + if self._data and self._data.get("detail"): + raise ServerError(self._data["detail"]) + raise ValueError("Response is not available.") + try: self._response.raise_for_status() except requests.exceptions.HTTPError as exc: @@ -353,12 +363,16 @@ class ServerAPI(object): max_retries (Optional[int]): Number of retries for requests. """ _default_max_retries = 3 + # 1 MB chunk by default + # TODO find out if these are reasonable default value + default_download_chunk_size = 1024 * 1024 + default_upload_chunk_size = 1024 * 1024 def __init__( self, base_url, token=None, - site_id=None, + site_id=_PLACEHOLDER, client_version=None, default_settings_variant=None, sender=None, @@ -377,11 +391,14 @@ class ServerAPI(object): self._graphql_url = "{}/graphql".format(base_url) self._log = None self._access_token = token + # Allow to have 'site_id' to 'None' + if site_id is _PLACEHOLDER: + site_id = get_default_site_id() self._site_id = site_id self._client_version = client_version self._default_settings_variant = ( default_settings_variant - or "production" + or get_default_settings_variant() ) self._sender = sender @@ -411,6 +428,8 @@ class ServerAPI(object): self._server_version = None self._server_version_tuple = None + self._graphql_allows_data_in_query = None + self._session = None self._base_functions_mapping = { @@ -936,6 +955,26 @@ class ServerAPI(object): server_version = property(get_server_version) server_version_tuple = property(get_server_version_tuple) + @property + def graphql_allows_data_in_query(self): + """GraphlQl query can support 'data' field. + + This applies only to project hierarchy entities 'project', 'folder', + 'task', 'product', 'version' and 'representation'. Others like 'user' + still require to use rest api to access 'data'. + + Returns: + bool: True if server supports 'data' field in GraphQl query. + """ + + if self._graphql_allows_data_in_query is None: + major, minor, patch, _, _ = self.server_version_tuple + graphql_allows_data_in_query = True + if (major, minor, patch) < (0, 5, 5): + graphql_allows_data_in_query = False + self._graphql_allows_data_in_query = graphql_allows_data_in_query + return self._graphql_allows_data_in_query + def _get_user_info(self): if self._access_token is None: return None @@ -1279,6 +1318,9 @@ class ServerAPI(object): states=None, users=None, include_logs=None, + has_children=None, + newer_than=None, + older_than=None, fields=None ): """Get events from server with filtering options. @@ -1294,6 +1336,12 @@ class ServerAPI(object): users (Optional[Iterable[str]]): Filtering by users who created/triggered an event. include_logs (Optional[bool]): Query also log events. + has_children (Optional[bool]): Event is with/without children + events. If 'None' then all events are returned, default. + newer_than (Optional[str]): Return only events newer than given + iso datetime string. + older_than (Optional[str]): Return only events older than given + iso datetime string. fields (Optional[Iterable[str]]): Fields that should be received for each event. @@ -1330,6 +1378,15 @@ class ServerAPI(object): include_logs = False filters["includeLogsFilter"] = include_logs + if has_children is not None: + filters["hasChildrenFilter"] = has_children + + if newer_than is not None: + filters["newerThanFilter"] = newer_than + + if older_than is not None: + filters["olderThanFilter"] = older_than + if not fields: fields = self.get_default_fields_for_type("event") @@ -1512,8 +1569,9 @@ class ServerAPI(object): "sourceTopic": source_topic, "targetTopic": target_topic, "sender": sender, - "maxRetries": max_retries, } + if max_retries is not None: + kwargs["maxRetries"] = max_retries if sequential is not None: kwargs["sequential"] = sequential if description is not None: @@ -1560,6 +1618,10 @@ class ServerAPI(object): download happens in thread and other thread want to catch changes over time. + Todos: + Use retries and timeout. + Return RestApiResponse. + Args: endpoint (str): Endpoint or URL to file that should be downloaded. filepath (str): Path where file will be downloaded. @@ -1570,8 +1632,7 @@ class ServerAPI(object): """ if not chunk_size: - # 1 MB chunk by default - chunk_size = 1024 * 1024 + chunk_size = self.default_download_chunk_size if endpoint.startswith(self._base_url): url = endpoint @@ -1598,33 +1659,93 @@ class ServerAPI(object): progress.set_transfer_done() return progress - def _upload_file(self, url, filepath, progress, request_type=None): + @staticmethod + def _upload_chunks_iter(file_stream, progress, chunk_size): + """Generator that yields chunks of file. + + Args: + file_stream (io.BinaryIO): Byte stream. + progress (TransferProgress): Object to track upload progress. + chunk_size (int): Size of chunks that are uploaded at once. + + Yields: + bytes: Chunk of file. + """ + + # Get size of file + file_stream.seek(0, io.SEEK_END) + size = file_stream.tell() + file_stream.seek(0) + # Set content size to progress object + progress.set_content_size(size) + + while True: + chunk = file_stream.read(chunk_size) + if not chunk: + break + progress.add_transferred_chunk(len(chunk)) + yield chunk + + def _upload_file( + self, + url, + filepath, + progress, + request_type=None, + chunk_size=None, + **kwargs + ): + """ + + Args: + url (str): Url where file will be uploaded. + filepath (str): Source filepath. + progress (TransferProgress): Object that gives ability to track + progress. + request_type (Optional[RequestType]): Type of request that will + be used. Default is PUT. + chunk_size (Optional[int]): Size of chunks that are uploaded + at once. + **kwargs (Any): Additional arguments that will be passed + to request function. + + Returns: + RestApiResponse: Server response. + """ + if request_type is None: request_type = RequestTypes.put - kwargs = {} + if self._session is None: - kwargs["headers"] = self.get_headers() + headers = kwargs.setdefault("headers", {}) + for key, value in self.get_headers().items(): + if key not in headers: + headers[key] = value post_func = self._base_functions_mapping[request_type] else: post_func = self._session_functions_mapping[request_type] + if not chunk_size: + chunk_size = self.default_upload_chunk_size + with open(filepath, "rb") as stream: - stream.seek(0, io.SEEK_END) - size = stream.tell() - stream.seek(0) - progress.set_content_size(size) - response = post_func(url, data=stream, **kwargs) + response = post_func( + url, + data=self._upload_chunks_iter(stream, progress, chunk_size), + **kwargs + ) + response.raise_for_status() - progress.set_transferred_size(size) return response def upload_file( - self, endpoint, filepath, progress=None, request_type=None + self, endpoint, filepath, progress=None, request_type=None, **kwargs ): """Upload file to server. Todos: - Uploading with more detailed progress. + Use retries and timeout. + Return RestApiResponse. Args: endpoint (str): Endpoint or url where file will be uploaded. @@ -1633,6 +1754,8 @@ class ServerAPI(object): to track upload progress. request_type (Optional[RequestType]): Type of request that will be used to upload file. + **kwargs (Any): Additional arguments that will be passed + to request function. Returns: requests.Response: Response object. @@ -1654,7 +1777,9 @@ class ServerAPI(object): progress.set_started() try: - return self._upload_file(url, filepath, progress, request_type) + return self._upload_file( + url, filepath, progress, request_type, **kwargs + ) except Exception as exc: progress.set_failed(str(exc)) @@ -1877,31 +2002,45 @@ class ServerAPI(object): return set(DEFAULT_EVENT_FIELDS) if entity_type == "project": - entity_type_defaults = DEFAULT_PROJECT_FIELDS + entity_type_defaults = set(DEFAULT_PROJECT_FIELDS) + if not self.graphql_allows_data_in_query: + entity_type_defaults.discard("data") elif entity_type == "folder": - entity_type_defaults = DEFAULT_FOLDER_FIELDS + entity_type_defaults = set(DEFAULT_FOLDER_FIELDS) + if not self.graphql_allows_data_in_query: + entity_type_defaults.discard("data") elif entity_type == "task": - entity_type_defaults = DEFAULT_TASK_FIELDS + entity_type_defaults = set(DEFAULT_TASK_FIELDS) + if not self.graphql_allows_data_in_query: + entity_type_defaults.discard("data") elif entity_type == "product": - entity_type_defaults = DEFAULT_PRODUCT_FIELDS + entity_type_defaults = set(DEFAULT_PRODUCT_FIELDS) + if not self.graphql_allows_data_in_query: + entity_type_defaults.discard("data") elif entity_type == "version": - entity_type_defaults = DEFAULT_VERSION_FIELDS + entity_type_defaults = set(DEFAULT_VERSION_FIELDS) + if not self.graphql_allows_data_in_query: + entity_type_defaults.discard("data") elif entity_type == "representation": entity_type_defaults = ( DEFAULT_REPRESENTATION_FIELDS | REPRESENTATION_FILES_FIELDS ) + if not self.graphql_allows_data_in_query: + entity_type_defaults.discard("data") elif entity_type == "productType": - entity_type_defaults = DEFAULT_PRODUCT_TYPE_FIELDS + entity_type_defaults = set(DEFAULT_PRODUCT_TYPE_FIELDS) elif entity_type == "workfile": - entity_type_defaults = DEFAULT_WORKFILE_INFO_FIELDS + entity_type_defaults = set(DEFAULT_WORKFILE_INFO_FIELDS) + if not self.graphql_allows_data_in_query: + entity_type_defaults.discard("data") elif entity_type == "user": entity_type_defaults = set(DEFAULT_USER_FIELDS) @@ -3549,8 +3688,14 @@ class ServerAPI(object): folder_names=None, folder_types=None, parent_ids=None, + folder_path_regex=None, + has_products=None, + has_tasks=None, + has_children=None, statuses=None, + tags=None, active=True, + has_links=None, fields=None, own_attributes=False ): @@ -3574,10 +3719,22 @@ class ServerAPI(object): for filtering. parent_ids (Optional[Iterable[str]]): Ids of folder parents. Use 'None' if folder is direct child of project. + folder_path_regex (Optional[str]): Folder path regex used + for filtering. + has_products (Optional[bool]): Filter folders with/without + products. Ignored when None, default behavior. + has_tasks (Optional[bool]): Filter folders with/without + tasks. Ignored when None, default behavior. + has_children (Optional[bool]): Filter folders with/without + children. Ignored when None, default behavior. statuses (Optional[Iterable[str]]): Folder statuses used for filtering. + tags (Optional[Iterable[str]]): Folder tags used + for filtering. active (Optional[bool]): Filter active/inactive folders. Both are returned if is set to None. + has_links (Optional[Literal[IN, OUT, ANY]]): Filter + representations with IN/OUT/ANY links. fields (Optional[Iterable[str]]): Fields to be queried for folder. All possible folder fields are returned if 'None' is passed. @@ -3624,6 +3781,12 @@ class ServerAPI(object): return filters["folderStatuses"] = list(statuses) + if tags is not None: + tags = set(tags) + if not tags: + return + filters["folderTags"] = list(tags) + if parent_ids is not None: parent_ids = set(parent_ids) if not parent_ids: @@ -3644,6 +3807,21 @@ class ServerAPI(object): filters["parentFolderIds"] = list(parent_ids) + if folder_path_regex is not None: + filters["folderPathRegex"] = folder_path_regex + + if has_products is not None: + filters["folderHasProducts"] = has_products + + if has_tasks is not None: + filters["folderHasTasks"] = has_tasks + + if has_links is not None: + filters["folderHasLinks"] = has_links.upper() + + if has_children is not None: + filters["folderHasChildren"] = has_children + if not fields: fields = self.get_default_fields_for_type("folder") else: @@ -3653,7 +3831,7 @@ class ServerAPI(object): fields |= self.get_attributes_fields_for_type("folder") use_rest = False - if "data" in fields: + if "data" in fields and not self.graphql_allows_data_in_query: use_rest = True fields = {"id"} @@ -3674,6 +3852,8 @@ class ServerAPI(object): if use_rest: folder = self.get_rest_folder(project_name, folder["id"]) + else: + self._convert_entity_data(folder) if own_attributes: fill_own_attribs(folder) @@ -3826,6 +4006,10 @@ class ServerAPI(object): task_names=None, task_types=None, folder_ids=None, + assignees=None, + assignees_all=None, + statuses=None, + tags=None, active=True, fields=None, own_attributes=False @@ -3839,6 +4023,16 @@ class ServerAPI(object): task_types (Iterable[str]): Task types used for filtering. folder_ids (Iterable[str]): Ids of task parents. Use 'None' if folder is direct child of project. + assignees (Optional[Iterable[str]]): Task assignees used for + filtering. All tasks with any of passed assignees are + returned. + assignees_all (Optional[Iterable[str]]): Task assignees used + for filtering. Task must have all of passed assignees to be + returned. + statuses (Optional[Iterable[str]]): Task statuses used for + filtering. + tags (Optional[Iterable[str]]): Task tags used for + filtering. active (Optional[bool]): Filter active/inactive tasks. Both are returned if is set to None. fields (Optional[Iterable[str]]): Fields to be queried for @@ -3882,6 +4076,30 @@ class ServerAPI(object): return filters["folderIds"] = list(folder_ids) + if assignees is not None: + assignees = set(assignees) + if not assignees: + return + filters["taskAssigneesAny"] = list(assignees) + + if assignees_all is not None: + assignees_all = set(assignees_all) + if not assignees_all: + return + filters["taskAssigneesAll"] = list(assignees_all) + + if statuses is not None: + statuses = set(statuses) + if not statuses: + return + filters["taskStatuses"] = list(statuses) + + if tags is not None: + tags = set(tags) + if not tags: + return + filters["taskTags"] = list(tags) + if not fields: fields = self.get_default_fields_for_type("task") else: @@ -3891,7 +4109,7 @@ class ServerAPI(object): fields |= self.get_attributes_fields_for_type("task") use_rest = False - if "data" in fields: + if "data" in fields and not self.graphql_allows_data_in_query: use_rest = True fields = {"id"} @@ -3912,6 +4130,8 @@ class ServerAPI(object): if use_rest: task = self.get_rest_task(project_name, task["id"]) + else: + self._convert_entity_data(task) if own_attributes: fill_own_attribs(task) @@ -3992,6 +4212,8 @@ class ServerAPI(object): if use_rest: product = self.get_rest_product(project_name, product["id"]) + else: + self._convert_entity_data(product) if own_attributes: fill_own_attribs(product) @@ -4005,8 +4227,11 @@ class ServerAPI(object): product_names=None, folder_ids=None, product_types=None, - statuses=None, + product_name_regex=None, + product_path_regex=None, names_by_folder_ids=None, + statuses=None, + tags=None, active=True, fields=None, own_attributes=False @@ -4026,10 +4251,15 @@ class ServerAPI(object): Use 'None' if folder is direct child of project. product_types (Optional[Iterable[str]]): Product types used for filtering. - statuses (Optional[Iterable[str]]): Product statuses used for - filtering. + product_name_regex (Optional[str]): Filter products by name regex. + product_path_regex (Optional[str]): Filter products by path regex. + Path starts with folder path and ends with product name. names_by_folder_ids (Optional[dict[str, Iterable[str]]]): Product name filtering by folder id. + statuses (Optional[Iterable[str]]): Product statuses used + for filtering. + tags (Optional[Iterable[str]]): Product tags used + for filtering. active (Optional[bool]): Filter active/inactive products. Both are returned if is set to None. fields (Optional[Iterable[str]]): Fields to be queried for @@ -4045,11 +4275,7 @@ class ServerAPI(object): if not project_name: return - if product_ids is not None: - product_ids = set(product_ids) - if not product_ids: - return - + # Prepare these filters before 'name_by_filter_ids' filter filter_product_names = None if product_names is not None: filter_product_names = set(product_names) @@ -4062,18 +4288,6 @@ class ServerAPI(object): if not filter_folder_ids: return - filter_product_types = None - if product_types is not None: - filter_product_types = set(product_types) - if not filter_product_types: - return - - filter_statuses = None - if statuses is not None: - filter_statuses = set(statuses) - if not filter_statuses: - return - # This will disable 'folder_ids' and 'product_names' filters # - maybe could be enhanced in future? if names_by_folder_ids is not None: @@ -4098,7 +4312,7 @@ class ServerAPI(object): fields = self.get_default_fields_for_type("product") use_rest = False - if "data" in fields: + if "data" in fields and not self.graphql_allows_data_in_query: use_rest = True fields = {"id"} @@ -4117,21 +4331,43 @@ class ServerAPI(object): filters = { "projectName": project_name } + if filter_folder_ids: filters["folderIds"] = list(filter_folder_ids) - if filter_product_types: - filters["productTypes"] = list(filter_product_types) - - if filter_statuses: - filters["statuses"] = list(filter_statuses) - - if product_ids: - filters["productIds"] = list(product_ids) - if filter_product_names: filters["productNames"] = list(filter_product_names) + if product_ids is not None: + product_ids = set(product_ids) + if not product_ids: + return + filters["productIds"] = list(product_ids) + + if product_types is not None: + product_types = set(product_types) + if not product_types: + return + filters["productTypes"] = list(product_types) + + if statuses is not None: + statuses = set(statuses) + if not statuses: + return + filters["productStatuses"] = list(statuses) + + if tags is not None: + tags = set(tags) + if not tags: + return + filters["productTags"] = list(tags) + + if product_name_regex: + filters["productNameRegex"] = product_name_regex + + if product_path_regex: + filters["productPathRegex"] = product_path_regex + query = products_graphql_query(fields) for attr, filter_value in filters.items(): query.set_variable_value(attr, filter_value) @@ -4323,6 +4559,8 @@ class ServerAPI(object): hero=True, standard=True, latest=None, + statuses=None, + tags=None, active=True, fields=None, own_attributes=False @@ -4342,6 +4580,10 @@ class ServerAPI(object): latest (Optional[bool]): Return only latest version of standard versions. This can be combined only with 'standard' attribute set to True. + statuses (Optional[Iterable[str]]): Representation statuses used + for filtering. + tags (Optional[Iterable[str]]): Representation tags used + for filtering. active (Optional[bool]): Receive active/inactive entities. Both are returned when 'None' is passed. fields (Optional[Iterable[str]]): Fields to be queried @@ -4366,7 +4608,7 @@ class ServerAPI(object): fields |= {"id", "version"} use_rest = False - if "data" in fields: + if "data" in fields and not self.graphql_allows_data_in_query: use_rest = True fields = {"id"} @@ -4398,6 +4640,18 @@ class ServerAPI(object): return filters["versions"] = list(versions) + if statuses is not None: + statuses = set(statuses) + if not statuses: + return + filters["versionStatuses"] = list(statuses) + + if tags is not None: + tags = set(tags) + if not tags: + return + filters["versionTags"] = list(tags) + if not hero and not standard: return @@ -4446,6 +4700,8 @@ class ServerAPI(object): version = self.get_rest_version( project_name, version["id"] ) + else: + self._convert_entity_data(version) if own_attributes: fill_own_attribs(version) @@ -4652,6 +4908,10 @@ class ServerAPI(object): dict[str, dict[str, Any]]: Last versions by product id. """ + if fields: + fields = set(fields) + fields.add("productId") + versions = self.get_versions( project_name, product_ids=product_ids, @@ -4661,7 +4921,7 @@ class ServerAPI(object): own_attributes=own_attributes ) return { - version["parent"]: version + version["productId"]: version for version in versions } @@ -4775,6 +5035,23 @@ class ServerAPI(object): ) return latest_version["id"] == version_id + def _representation_conversion(self, representation): + if "context" in representation: + orig_context = representation["context"] + context = {} + if orig_context and orig_context != "null": + context = json.loads(orig_context) + representation["context"] = context + + repre_files = representation.get("files") + if not repre_files: + return + + for repre_file in repre_files: + repre_file_size = repre_file.get("size") + if repre_file_size is not None: + repre_file["size"] = int(repre_file["size"]) + def get_representations( self, project_name, @@ -4782,7 +5059,10 @@ class ServerAPI(object): representation_names=None, version_ids=None, names_by_version_ids=None, + statuses=None, + tags=None, active=True, + has_links=None, fields=None, own_attributes=False ): @@ -4804,8 +5084,14 @@ class ServerAPI(object): names_by_version_ids (Optional[bool]): Find representations by names and version ids. This filter discard all other filters. + statuses (Optional[Iterable[str]]): Representation statuses used + for filtering. + tags (Optional[Iterable[str]]): Representation tags used + for filtering. active (Optional[bool]): Receive active/inactive entities. Both are returned when 'None' is passed. + has_links (Optional[Literal[IN, OUT, ANY]]): Filter + representations with IN/OUT/ANY links. fields (Optional[Iterable[str]]): Fields to be queried for representation. All possible fields are returned if 'None' is passed. @@ -4822,10 +5108,12 @@ class ServerAPI(object): fields = set(fields) if "attrib" in fields: fields.remove("attrib") - fields |= self.get_attributes_fields_for_type("representation") + fields |= self.get_attributes_fields_for_type( + "representation" + ) use_rest = False - if "data" in fields: + if "data" in fields and not self.graphql_allows_data_in_query: use_rest = True fields = {"id"} @@ -4874,6 +5162,21 @@ class ServerAPI(object): if representaion_names_filter: filters["representationNames"] = list(representaion_names_filter) + if statuses is not None: + statuses = set(statuses) + if not statuses: + return + filters["representationStatuses"] = list(statuses) + + if tags is not None: + tags = set(tags) + if not tags: + return + filters["representationTags"] = list(tags) + + if has_links is not None: + filters["representationHasLinks"] = has_links.upper() + query = representations_graphql_query(fields) for attr, filter_value in filters.items(): @@ -4888,13 +5191,10 @@ class ServerAPI(object): repre = self.get_rest_representation( project_name, repre["id"] ) + else: + self._convert_entity_data(repre) - if "context" in repre: - orig_context = repre["context"] - context = {} - if orig_context and orig_context != "null": - context = json.loads(orig_context) - repre["context"] = context + self._representation_conversion(repre) if own_attributes: fill_own_attribs(repre) @@ -5007,6 +5307,9 @@ class ServerAPI(object): version = repre.pop("version") product = version.pop("product") folder = product.pop("folder") + self._convert_entity_data(version) + self._convert_entity_data(product) + self._convert_entity_data(folder) output[repre_id] = RepresentationParents( version, product, folder, project ) @@ -5128,6 +5431,10 @@ class ServerAPI(object): workfile_ids=None, task_ids=None, paths=None, + path_regex=None, + statuses=None, + tags=None, + has_links=None, fields=None, own_attributes=False ): @@ -5138,6 +5445,13 @@ class ServerAPI(object): workfile_ids (Optional[Iterable[str]]): Workfile ids. task_ids (Optional[Iterable[str]]): Task ids. paths (Optional[Iterable[str]]): Rootless workfiles paths. + path_regex (Optional[str]): Regex filter for workfile path. + statuses (Optional[Iterable[str]]): Workfile info statuses used + for filtering. + tags (Optional[Iterable[str]]): Workfile info tags used + for filtering. + has_links (Optional[Literal[IN, OUT, ANY]]): Filter + representations with IN/OUT/ANY links. fields (Optional[Iterable[str]]): Fields to be queried for representation. All possible fields are returned if 'None' is passed. @@ -5161,12 +5475,30 @@ class ServerAPI(object): return filters["paths"] = list(paths) + if path_regex is not None: + filters["workfilePathRegex"] = path_regex + if workfile_ids is not None: workfile_ids = set(workfile_ids) if not workfile_ids: return filters["workfileIds"] = list(workfile_ids) + if statuses is not None: + statuses = set(statuses) + if not statuses: + return + filters["workfileStatuses"] = list(statuses) + + if tags is not None: + tags = set(tags) + if not tags: + return + filters["workfileTags"] = list(tags) + + if has_links is not None: + filters["workfilehasLinks"] = has_links.upper() + if not fields: fields = self.get_default_fields_for_type("workfile") @@ -5459,16 +5791,14 @@ class ServerAPI(object): return thumbnail_id mime_type = self._get_thumbnail_mime_type(src_filepath) - with open(src_filepath, "rb") as stream: - content = stream.read() - - response = self.raw_post( + response = self.upload_file( "projects/{}/thumbnails".format(project_name), + src_filepath, + request_type=RequestTypes.post, headers={"Content-Type": mime_type}, - data=content ) response.raise_for_status() - return response.data["id"] + return response.json()["id"] def update_thumbnail(self, project_name, thumbnail_id, src_filepath): """Change thumbnail content by id. @@ -5489,13 +5819,11 @@ class ServerAPI(object): raise ValueError("Entered filepath does not exist.") mime_type = self._get_thumbnail_mime_type(src_filepath) - with open(src_filepath, "rb") as stream: - content = stream.read() - - response = self.raw_put( + response = self.upload_file( "projects/{}/thumbnails/{}".format(project_name, thumbnail_id), + src_filepath, + request_type=RequestTypes.put, headers={"Content-Type": mime_type}, - data=content ) response.raise_for_status() @@ -6317,3 +6645,13 @@ class ServerAPI(object): op_result["detail"], )) return op_results + + def _convert_entity_data(self, entity): + if not entity: + return + entity_data = entity.get("data") + if ( + entity_data is not None + and isinstance(entity_data, six.string_types) + ): + entity["data"] = json.loads(entity_data) diff --git a/openpype/vendor/python/common/ayon_api/utils.py b/openpype/vendor/python/common/ayon_api/utils.py index 502d24f713..e9d7f53771 100644 --- a/openpype/vendor/python/common/ayon_api/utils.py +++ b/openpype/vendor/python/common/ayon_api/utils.py @@ -16,7 +16,11 @@ except ImportError: import requests import unidecode -from .constants import SERVER_TIMEOUT_ENV_KEY +from .constants import ( + SERVER_TIMEOUT_ENV_KEY, + DEFAULT_VARIANT_ENV_KEY, + SITE_ID_ENV_KEY, +) from .exceptions import UrlError REMOVED_VALUE = object() @@ -46,6 +50,26 @@ def get_default_timeout(): return 10.0 +def get_default_settings_variant(): + """Default settings variant. + + Returns: + str: Settings variant from environment variable or 'production'. + """ + + return os.environ.get(DEFAULT_VARIANT_ENV_KEY) or "production" + + +def get_default_site_id(): + """Site id used for server connection. + + Returns: + Union[str, None]: Site id from environment variable or None. + """ + + return os.environ.get(SITE_ID_ENV_KEY) + + class ThumbnailContent: """Wrapper for thumbnail content. diff --git a/openpype/vendor/python/common/ayon_api/version.py b/openpype/vendor/python/common/ayon_api/version.py index ac4f32997f..bc1107da1e 100644 --- a/openpype/vendor/python/common/ayon_api/version.py +++ b/openpype/vendor/python/common/ayon_api/version.py @@ -1,2 +1,2 @@ """Package declaring Python API for Ayon server.""" -__version__ = "0.5.1" +__version__ = "1.0.0-rc.1" diff --git a/openpype/version.py b/openpype/version.py index 9d8724f926..cdaafa0559 100644 --- a/openpype/version.py +++ b/openpype/version.py @@ -1,3 +1,3 @@ # -*- coding: utf-8 -*- """Package declaring Pype version.""" -__version__ = "3.17.7-nightly.1" +__version__ = "3.17.7-nightly.7" diff --git a/server_addon/applications/server/applications.json b/server_addon/applications/server/applications.json index f846b04215..35f1b4cfbb 100644 --- a/server_addon/applications/server/applications.json +++ b/server_addon/applications/server/applications.json @@ -14,7 +14,7 @@ "windows": [ "C:\\Program Files\\Autodesk\\Maya2024\\bin\\maya.exe" ], - "darwin": [], + "darwin": ["/Applications/Autodesk/maya2024/Maya.app"], "linux": [ "/usr/autodesk/maya2024/bin/maya" ] @@ -34,7 +34,7 @@ "windows": [ "C:\\Program Files\\Autodesk\\Maya2023\\bin\\maya.exe" ], - "darwin": [], + "darwin": ["/Applications/Autodesk/maya2023/Maya.app"], "linux": [ "/usr/autodesk/maya2023/bin/maya" ] @@ -54,7 +54,7 @@ "windows": [ "C:\\Program Files\\Autodesk\\Maya2022\\bin\\maya.exe" ], - "darwin": [], + "darwin": ["/Applications/Autodesk/maya2022/Maya.app"], "linux": [ "/usr/autodesk/maya2022/bin/maya" ] @@ -125,6 +125,23 @@ "host_name": "max", "environment": "{\n \"ADSK_3DSMAX_STARTUPSCRIPTS_ADDON_DIR\": \"{OPENPYPE_ROOT}/openpype/hosts/max/startup\"\n}", "variants": [ + { + "name": "2024", + "use_python_2": false, + "executables": { + "windows": [ + "C:\\Program Files\\Autodesk\\3ds Max 2024\\3dsmax.exe" + ], + "darwin": [], + "linux": [] + }, + "arguments": { + "windows": [], + "darwin": [], + "linux": [] + }, + "environment": "{\n \"3DSMAX_VERSION\": \"2024\"\n}" + }, { "name": "2023", "use_python_2": false, @@ -200,18 +217,40 @@ "host_name": "nuke", "environment": "{\n \"NUKE_PATH\": [\n \"{NUKE_PATH}\",\n \"{OPENPYPE_STUDIO_PLUGINS}/nuke\"\n ]\n}", "variants": [ + { + "name": "15-0", + "label": "15.0", + "executables": { + "windows": [ + "C:\\Program Files\\Nuke15.0v2\\Nuke15.0.exe" + ], + "darwin": [ + "/Applications/Nuke15.0v2/Nuke15.0v2.app" + ], + "linux": [ + "/usr/local/Nuke5.0v2/Nuke15.0" + ] + }, + "arguments": { + "windows": [], + "darwin": [], + "linux": [] + }, + "environment": "{}", + "use_python_2": false + }, { "name": "14-0", "label": "14.0", "executables": { "windows": [ - "C:\\Program Files\\Nuke14.0v4\\Nuke14.0.exe" + "C:\\Program Files\\Nuke14.0v5\\Nuke14.0.exe" ], "darwin": [ - "/Applications/Nuke14.0v4/Nuke14.0v4.app" + "/Applications/Nuke14.0v5/Nuke14.0v5.app" ], "linux": [ - "/usr/local/Nuke14.0v4/Nuke14.0" + "/usr/local/Nuke14.0v5/Nuke14.0" ] }, "arguments": { @@ -243,28 +282,6 @@ }, "environment": "{}", "use_python_2": false - }, - { - "name": "13-0", - "label": "13.0", - "use_python_2": false, - "executables": { - "windows": [ - "C:\\Program Files\\Nuke13.0v1\\Nuke13.0.exe" - ], - "darwin": [ - "/Applications/Nuke13.0v1/Nuke13.0v1.app" - ], - "linux": [ - "/usr/local/Nuke13.0v1/Nuke13.0" - ] - }, - "arguments": { - "windows": [], - "darwin": [], - "linux": [] - }, - "environment": "{}" } ] }, @@ -275,28 +292,46 @@ "host_name": "nuke", "environment": "{\n \"NUKE_PATH\": [\n \"{NUKE_PATH}\",\n \"{OPENPYPE_STUDIO_PLUGINS}/nuke\"\n ]\n}", "variants": [ + { + "name": "15-0", + "label": "15.0", + "executables": { + "windows": [ + "C:\\Program Files\\Nuke15.0v2\\Nuke15.0.exe" + ], + "darwin": [ + "/Applications/Nuke15.0v2/NukeAssist15.0v2.app" + ], + "linux": [ + "/usr/local/Nuke5.0v2/Nuke15.0" + ] + }, + "arguments": { + "windows": [], + "darwin": [], + "linux": [] + }, + "environment": "{}", + "use_python_2": false + }, { "name": "14-0", "label": "14.0", "executables": { "windows": [ - "C:\\Program Files\\Nuke14.0v4\\Nuke14.0.exe" + "C:\\Program Files\\Nuke14.0v5\\Nuke14.0.exe" ], "darwin": [ - "/Applications/Nuke14.0v4/NukeAssist14.0v4.app" + "/Applications/Nuke14.0v5/NukeAssist14.0v5.app" ], "linux": [ - "/usr/local/Nuke14.0v4/Nuke14.0" + "/usr/local/Nuke14.0v5/Nuke14.0" ] }, "arguments": { - "windows": [ - "--nukeassist" - ], + "windows": [], "darwin": [], - "linux": [ - "--nukeassist" - ] + "linux": [] }, "environment": "{}", "use_python_2": false @@ -316,42 +351,12 @@ ] }, "arguments": { - "windows": [ - "--nukeassist" - ], + "windows": [], "darwin": [], - "linux": [ - "--nukeassist" - ] + "linux": [] }, "environment": "{}", "use_python_2": false - }, - { - "name": "13-0", - "label": "13.0", - "use_python_2": false, - "executables": { - "windows": [ - "C:\\Program Files\\Nuke13.0v1\\Nuke13.0.exe" - ], - "darwin": [ - "/Applications/Nuke13.0v1/NukeAssist13.0v1.app" - ], - "linux": [ - "/usr/local/Nuke13.0v1/Nuke13.0" - ] - }, - "arguments": { - "windows": [ - "--nukeassist" - ], - "darwin": [], - "linux": [ - "--nukeassist" - ] - }, - "environment": "{}" } ] }, @@ -362,28 +367,46 @@ "host_name": "nuke", "environment": "{\n \"NUKE_PATH\": [\n \"{NUKE_PATH}\",\n \"{OPENPYPE_STUDIO_PLUGINS}/nuke\"\n ]\n}", "variants": [ + { + "name": "15-0", + "label": "15.0", + "executables": { + "windows": [ + "C:\\Program Files\\Nuke15.0v2\\Nuke15.0.exe" + ], + "darwin": [ + "/Applications/Nuke15.0v2/NukeX15.0v2.app" + ], + "linux": [ + "/usr/local/Nuke5.0v2/Nuke15.0" + ] + }, + "arguments": { + "windows": [], + "darwin": [], + "linux": [] + }, + "environment": "{}", + "use_python_2": false + }, { "name": "14-0", "label": "14.0", "executables": { "windows": [ - "C:\\Program Files\\Nuke14.0v4\\Nuke14.0.exe" + "C:\\Program Files\\Nuke14.0v5\\Nuke14.0.exe" ], "darwin": [ - "/Applications/Nuke14.0v4/NukeX14.0v4.app" + "/Applications/Nuke14.0v5/NukeX14.0v5.app" ], "linux": [ - "/usr/local/Nuke14.0v4/Nuke14.0" + "/usr/local/Nuke14.0v5/Nuke14.0" ] }, "arguments": { - "windows": [ - "--nukex" - ], + "windows": [], "darwin": [], - "linux": [ - "--nukex" - ] + "linux": [] }, "environment": "{}", "use_python_2": false @@ -403,42 +426,12 @@ ] }, "arguments": { - "windows": [ - "--nukex" - ], + "windows": [], "darwin": [], - "linux": [ - "--nukex" - ] + "linux": [] }, "environment": "{}", "use_python_2": false - }, - { - "name": "13-0", - "label": "13.0", - "use_python_2": false, - "executables": { - "windows": [ - "C:\\Program Files\\Nuke13.0v1\\Nuke13.0.exe" - ], - "darwin": [ - "/Applications/Nuke13.0v1/NukeX13.0v1.app" - ], - "linux": [ - "/usr/local/Nuke13.0v1/Nuke13.0" - ] - }, - "arguments": { - "windows": [ - "--nukex" - ], - "darwin": [], - "linux": [ - "--nukex" - ] - }, - "environment": "{}" } ] }, @@ -449,28 +442,46 @@ "host_name": "hiero", "environment": "{\n \"WORKFILES_STARTUP\": \"0\",\n \"TAG_ASSETBUILD_STARTUP\": \"0\"\n}", "variants": [ + { + "name": "15-0", + "label": "15.0", + "executables": { + "windows": [ + "C:\\Program Files\\Nuke15.0v2\\Nuke15.0.exe" + ], + "darwin": [ + "/Applications/Nuke15.0v2/NukeStudio15.0v2.app" + ], + "linux": [ + "/usr/local/Nuke5.0v2/Nuke15.0" + ] + }, + "arguments": { + "windows": [], + "darwin": [], + "linux": [] + }, + "environment": "{}", + "use_python_2": false + }, { "name": "14-0", "label": "14.0", "executables": { "windows": [ - "C:\\Program Files\\Nuke14.0v4\\Nuke14.0.exe" + "C:\\Program Files\\Nuke14.0v5\\Nuke14.0.exe" ], "darwin": [ - "/Applications/Nuke14.0v4/NukeStudio14.0v4.app" + "/Applications/Nuke14.0v5/NukeStudio14.0v5.app" ], "linux": [ - "/usr/local/Nuke14.0v4/Nuke14.0" + "/usr/local/Nuke14.0v5/Nuke14.0" ] }, "arguments": { - "windows": [ - "--studio" - ], + "windows": [], "darwin": [], - "linux": [ - "--studio" - ] + "linux": [] }, "environment": "{}", "use_python_2": false @@ -490,42 +501,12 @@ ] }, "arguments": { - "windows": [ - "--studio" - ], + "windows": [], "darwin": [], - "linux": [ - "--studio" - ] + "linux": [] }, "environment": "{}", "use_python_2": false - }, - { - "name": "13-0", - "label": "13.0", - "use_python_2": false, - "executables": { - "windows": [ - "C:\\Program Files\\Nuke13.0v1\\Nuke13.0.exe" - ], - "darwin": [ - "/Applications/Nuke13.0v1/NukeStudio13.0v1.app" - ], - "linux": [ - "/usr/local/Nuke13.0v1/Nuke13.0" - ] - }, - "arguments": { - "windows": [ - "--studio" - ], - "darwin": [], - "linux": [ - "--studio" - ] - }, - "environment": "{}" } ] }, @@ -536,28 +517,46 @@ "host_name": "hiero", "environment": "{\n \"WORKFILES_STARTUP\": \"0\",\n \"TAG_ASSETBUILD_STARTUP\": \"0\"\n}", "variants": [ + { + "name": "15-0", + "label": "15.0", + "executables": { + "windows": [ + "C:\\Program Files\\Nuke15.0v2\\Nuke15.0.exe" + ], + "darwin": [ + "/Applications/Nuke15.0v2/Hiero15.0v2.app" + ], + "linux": [ + "/usr/local/Nuke5.0v2/Nuke15.0" + ] + }, + "arguments": { + "windows": [], + "darwin": [], + "linux": [] + }, + "environment": "{}", + "use_python_2": false + }, { "name": "14-0", "label": "14.0", "executables": { "windows": [ - "C:\\Program Files\\Nuke14.0v4\\Nuke14.0.exe" + "C:\\Program Files\\Nuke14.0v5\\Nuke14.0.exe" ], "darwin": [ - "/Applications/Nuke14.0v4/Hiero14.0v4.app" + "/Applications/Nuke14.0v5/Hiero14.0v5.app" ], "linux": [ - "/usr/local/Nuke14.0v4/Nuke14.0" + "/usr/local/Nuke14.0v5/Nuke14.0" ] }, "arguments": { - "windows": [ - "--hiero" - ], + "windows": [], "darwin": [], - "linux": [ - "--hiero" - ] + "linux": [] }, "environment": "{}", "use_python_2": false @@ -577,42 +576,12 @@ ] }, "arguments": { - "windows": [ - "--hiero" - ], + "windows": [], "darwin": [], - "linux": [ - "--hiero" - ] + "linux": [] }, "environment": "{}", "use_python_2": false - }, - { - "name": "13-0", - "label": "13.0", - "use_python_2": false, - "executables": { - "windows": [ - "C:\\Program Files\\Nuke13.0v1\\Nuke13.0.exe" - ], - "darwin": [ - "/Applications/Nuke13.0v1/Hiero13.0v1.app" - ], - "linux": [ - "/usr/local/Nuke13.0v1/Nuke13.0" - ] - }, - "arguments": { - "windows": [ - "--hiero" - ], - "darwin": [], - "linux": [ - "--hiero" - ] - }, - "environment": "{}" } ] }, @@ -623,6 +592,23 @@ "host_name": "fusion", "environment": "{\n \"FUSION_PYTHON3_HOME\": {\n \"windows\": \"{LOCALAPPDATA}/Programs/Python/Python36\",\n \"darwin\": \"~/Library/Python/3.6/bin\",\n \"linux\": \"/opt/Python/3.6/bin\"\n }\n}", "variants": [ + { + "name": "18", + "label": "18", + "executables": { + "windows": [ + "C:\\Program Files\\Blackmagic Design\\Fusion 18\\Fusion.exe" + ], + "darwin": [], + "linux": [] + }, + "arguments": { + "windows": [], + "darwin": [], + "linux": [] + }, + "environment": "{}" + }, { "name": "17", "label": "17", @@ -656,23 +642,6 @@ "linux": [] }, "environment": "{}" - }, - { - "name": "9", - "label": "9", - "executables": { - "windows": [ - "C:\\Program Files\\Blackmagic Design\\Fusion 9\\Fusion.exe" - ], - "darwin": [], - "linux": [] - }, - "arguments": { - "windows": [], - "darwin": [], - "linux": [] - }, - "environment": "{}" } ] }, @@ -710,11 +679,11 @@ "environment": "{}", "variants": [ { - "name": "18-5", - "label": "18.5", + "name": "19-5", + "label": "19.5", "executables": { "windows": [ - "C:\\Program Files\\Side Effects Software\\Houdini 18.5.499\\bin\\houdini.exe" + "C:\\Program Files\\Side Effects Software\\Houdini 19.5.805\\bin\\houdini.exe" ], "darwin": [], "linux": [] @@ -728,10 +697,12 @@ "use_python_2": true }, { - "name": "18", - "label": "18", + "name": "19-0", + "label": "19.0", "executables": { - "windows": [], + "windows": [ + "C:\\Program Files\\Side Effects Software\\Houdini 19.0.720\\bin\\houdini.exe" + ], "darwin": [], "linux": [] }, @@ -744,10 +715,12 @@ "use_python_2": true }, { - "name": "17", - "label": "17", + "name": "18-5", + "label": "18.5", "executables": { - "windows": [], + "windows": [ + "C:\\Program Files\\Side Effects Software\\Houdini 18.5.759\\bin\\houdini.exe" + ], "darwin": [], "linux": [] }, @@ -769,11 +742,11 @@ "environment": "{}", "variants": [ { - "name": "2-83", - "label": "2.83", + "name": "3-6-5", + "label": "3.6.5 LTS", "executables": { "windows": [ - "C:\\Program Files\\Blender Foundation\\Blender 2.83\\blender.exe" + "C:\\Program Files\\Blender Foundation\\Blender 3.6\\blender.exe" ], "darwin": [], "linux": [] @@ -846,6 +819,25 @@ "host_name": "harmony", "environment": "{\n \"AVALON_HARMONY_WORKFILES_ON_LAUNCH\": \"1\"\n}", "variants": [ + { + "name": "22", + "label": "22", + "executables": { + "windows": [ + "c:\\Program Files (x86)\\Toon Boom Animation\\Toon Boom Harmony 22 Premium\\win64\\bin\\HarmonyPremium.exe" + ], + "darwin": [ + "/Applications/Toon Boom Harmony 22 Premium/Harmony Premium.app/Contents/MacOS/Harmony Premium" + ], + "linux": [] + }, + "arguments": { + "windows": [], + "darwin": [], + "linux": [] + }, + "environment": "{}" + }, { "name": "21", "label": "21", @@ -955,40 +947,6 @@ "host_name": "photoshop", "environment": "{\n \"AVALON_PHOTOSHOP_WORKFILES_ON_LAUNCH\": \"1\",\n \"WORKFILES_SAVE_AS\": \"Yes\"\n}", "variants": [ - { - "name": "2020", - "label": "2020", - "executables": { - "windows": [ - "C:\\Program Files\\Adobe\\Adobe Photoshop 2020\\Photoshop.exe" - ], - "darwin": [], - "linux": [] - }, - "arguments": { - "windows": [], - "darwin": [], - "linux": [] - }, - "environment": "{}" - }, - { - "name": "2021", - "label": "2021", - "executables": { - "windows": [ - "C:\\Program Files\\Adobe\\Adobe Photoshop 2021\\Photoshop.exe" - ], - "darwin": [], - "linux": [] - }, - "arguments": { - "windows": [], - "darwin": [], - "linux": [] - }, - "environment": "{}" - }, { "name": "2022", "label": "2022", @@ -1005,6 +963,40 @@ "linux": [] }, "environment": "{}" + }, + { + "name": "2023", + "label": "2023", + "executables": { + "windows": [ + "C:\\Program Files\\Adobe\\Adobe Photoshop 2023\\Photoshop.exe" + ], + "darwin": [], + "linux": [] + }, + "arguments": { + "windows": [], + "darwin": [], + "linux": [] + }, + "environment": "{}" + }, + { + "name": "2024", + "label": "2024", + "executables": { + "windows": [ + "C:\\Program Files\\Adobe\\Adobe Photoshop 2024\\Photoshop.exe" + ], + "darwin": [], + "linux": [] + }, + "arguments": { + "windows": [], + "darwin": [], + "linux": [] + }, + "environment": "{}" } ] }, @@ -1015,23 +1007,6 @@ "host_name": "aftereffects", "environment": "{\n \"AVALON_AFTEREFFECTS_WORKFILES_ON_LAUNCH\": \"1\",\n \"WORKFILES_SAVE_AS\": \"Yes\"\n}", "variants": [ - { - "name": "2020", - "label": "2020", - "executables": { - "windows": [ - "C:\\Program Files\\Adobe\\Adobe After Effects 2020\\Support Files\\AfterFX.exe" - ], - "darwin": [], - "linux": [] - }, - "arguments": { - "windows": [], - "darwin": [], - "linux": [] - }, - "environment": "{}" - }, { "name": "2021", "label": "2021", @@ -1065,6 +1040,40 @@ "linux": [] }, "environment": "{\n \"MULTIPROCESS\": \"No\"\n}" + }, + { + "name": "2023", + "label": "2023", + "executables": { + "windows": [ + "C:\\Program Files\\Adobe\\Adobe After Effects 2023\\Support Files\\AfterFX.exe" + ], + "darwin": [], + "linux": [] + }, + "arguments": { + "windows": [], + "darwin": [], + "linux": [] + }, + "environment": "{\n \"MULTIPROCESS\": \"No\"\n}" + }, + { + "name": "2024", + "label": "2024", + "executables": { + "windows": [ + "C:\\Program Files\\Adobe\\Adobe After Effects 2024\\Support Files\\AfterFX.exe" + ], + "darwin": [], + "linux": [] + }, + "arguments": { + "windows": [], + "darwin": [], + "linux": [] + }, + "environment": "{\n \"MULTIPROCESS\": \"No\"\n}" } ] }, @@ -1100,8 +1109,8 @@ "environment": "{}", "variants": [ { - "name": "8-2-0", - "label": "8.2", + "name": "stable", + "label": "Stable", "executables": { "windows": [ "C:\\Program Files\\Adobe\\Adobe Substance 3D Painter\\Adobe Substance 3D Painter.exe" @@ -1119,16 +1128,48 @@ ] }, "unreal": { - "enabled": true, + "enabled": false, "label": "Unreal Editor", "icon": "{}/app_icons/ue4.png", "host_name": "unreal", "environment": "{}", "variants": [ { - "name": "4-26", - "label": "4.26", - "executables": {}, + "name": "5-0", + "label": "5.0", + "executables": { + "windows": [ + "C:\\Program Files\\Epic Games\\UE_5.0\\Engine\\Binaries\\Win64\\UnrealEditor.exe" + ], + "darwin": [], + "linux": [] + }, + "arguments": {}, + "environment": "{}" + }, + { + "name": "5-1", + "label": "5.1", + "executables": { + "windows": [ + "C:\\Program Files\\Epic Games\\UE_5.1\\Engine\\Binaries\\Win64\\UnrealEditor.exe" + ], + "darwin": [], + "linux": [] + }, + "arguments": {}, + "environment": "{}" + }, + { + "name": "5-2", + "label": "5.2", + "executables": { + "windows": [ + "C:\\Program Files\\Epic Games\\UE_5.2\\Engine\\Binaries\\Win64\\UnrealEditor.exe" + ], + "darwin": [], + "linux": [] + }, "arguments": {}, "environment": "{}" } @@ -1158,6 +1199,32 @@ } ] }, + "wrap": { + "enabled": true, + "label": "Wrap", + "icon": "{}/app_icons/wrap.png", + "host_name": "wrap", + "environment": "{\n \n}", + "variants": [ + { + "name": "2023", + "use_python_2": false, + "executables": { + "windows": [ + "c:\\Program Files\\Faceform\\Wrap 2023.10.2\\Wrap.exe" + ], + "darwin": [], + "linux": [] + }, + "arguments": { + "windows": [], + "darwin": [], + "linux": [] + }, + "environment": "{\n \n}" + } + ] + }, "additional_apps": [] } } diff --git a/server_addon/applications/server/settings.py b/server_addon/applications/server/settings.py index 981d56c30f..70c8b57c6a 100644 --- a/server_addon/applications/server/settings.py +++ b/server_addon/applications/server/settings.py @@ -168,6 +168,8 @@ class ApplicationsSettings(BaseSettingsModel): default_factory=AppGroupWithPython, title="Substance Painter") unreal: AppGroup = Field( default_factory=AppGroupWithPython, title="Unreal Editor") + wrap: AppGroup = Field( + default_factory=AppGroupWithPython, title="Wrap") additional_apps: list[AdditionalAppGroup] = Field( default_factory=list, title="Additional Applications") @@ -197,5 +199,5 @@ class ApplicationsAddonSettings(BaseSettingsModel): DEFAULT_VALUES = { - "only_available": False + "only_available": True } diff --git a/server_addon/blender/server/settings/main.py b/server_addon/blender/server/settings/main.py index 5eff276ef5..3d53162e45 100644 --- a/server_addon/blender/server/settings/main.py +++ b/server_addon/blender/server/settings/main.py @@ -57,7 +57,7 @@ DEFAULT_VALUES = { "unit_scale_settings": { "enabled": True, "apply_on_opening": False, - "base_file_unit_scale": 0.01 + "base_file_unit_scale": 1.00 }, "set_frames_startup": True, "set_resolution_startup": True, diff --git a/server_addon/blender/server/settings/publish_plugins.py b/server_addon/blender/server/settings/publish_plugins.py index 1c4ad0c6fd..9a1e0c681e 100644 --- a/server_addon/blender/server/settings/publish_plugins.py +++ b/server_addon/blender/server/settings/publish_plugins.py @@ -128,7 +128,7 @@ class PublishPuginsModel(BaseSettingsModel): ) ExtractLayout: ValidatePluginModel = Field( default_factory=ValidatePluginModel, - title="Extract Layout" + title="Extract Layout (JSON)" ) ExtractThumbnail: ExtractPlayblastModel = Field( default_factory=ExtractPlayblastModel, @@ -142,7 +142,7 @@ class PublishPuginsModel(BaseSettingsModel): DEFAULT_BLENDER_PUBLISH_SETTINGS = { "ValidateCameraZeroKeyframe": { - "enabled": True, + "enabled": False, "optional": True, "active": True }, @@ -173,13 +173,13 @@ DEFAULT_BLENDER_PUBLISH_SETTINGS = { "active": True }, "ValidateTransformZero": { - "enabled": True, - "optional": False, + "enabled": False, + "optional": True, "active": True }, "ValidateNoColonsInName": { - "enabled": True, - "optional": False, + "enabled": False, + "optional": True, "active": True }, "ValidateInstanceEmpty": { @@ -201,9 +201,9 @@ DEFAULT_BLENDER_PUBLISH_SETTINGS = { ] }, "ExtractFBX": { - "enabled": True, + "enabled": False, "optional": True, - "active": False + "active": True }, "ExtractModelABC": { "enabled": True, @@ -216,9 +216,9 @@ DEFAULT_BLENDER_PUBLISH_SETTINGS = { "active": True }, "ExtractAnimationFBX": { - "enabled": True, + "enabled": False, "optional": True, - "active": False + "active": True }, "ExtractCamera": { "enabled": True, diff --git a/server_addon/core/server/settings/main.py b/server_addon/core/server/settings/main.py index 433d0ef2f0..f9e572cbf9 100644 --- a/server_addon/core/server/settings/main.py +++ b/server_addon/core/server/settings/main.py @@ -198,7 +198,7 @@ DEFAULT_VALUES = { }, "studio_name": "", "studio_code": "", - "environments": "{}", + "environments": "{\n\"STUDIO_SW\": {\n \"darwin\": \"/mnt/REPO_SW\",\n \"linux\": \"/mnt/REPO_SW\",\n \"windows\": \"P:/REPO_SW\"\n }\n}", "tools": DEFAULT_TOOLS_VALUES, "version_start_category": { "profiles": [] diff --git a/server_addon/core/server/settings/publish_plugins.py b/server_addon/core/server/settings/publish_plugins.py index 93d8db964d..ef52416369 100644 --- a/server_addon/core/server/settings/publish_plugins.py +++ b/server_addon/core/server/settings/publish_plugins.py @@ -84,7 +84,6 @@ class ValidateIntentModel(BaseSettingsModel): class ExtractThumbnailFFmpegModel(BaseSettingsModel): - _layout = "expanded" input: list[str] = Field( default_factory=list, title="FFmpeg input arguments" @@ -95,9 +94,109 @@ class ExtractThumbnailFFmpegModel(BaseSettingsModel): ) +class ResizeItemModel(BaseSettingsModel): + _layout = "expanded" + width: int = Field( + 1920, + ge=0, + le=100000, + title="Width", + description="Width and Height must be both set to higher value than 0" + " else source resolution is used." + ) + height: int = Field( + 1080, + title="Height", + ge=0, + le=100000, + ) + + +_resize_types_enum = [ + {"value": "source", "label": "Image source"}, + {"value": "resize", "label": "Resize"}, +] + + +class ResizeModel(BaseSettingsModel): + _layout = "expanded" + + type: str = Field( + title="Type", + description="Type of resizing", + enum_resolver=lambda: _resize_types_enum, + conditionalEnum=True, + default="source" + ) + + resize: ResizeItemModel = Field( + default_factory=ResizeItemModel, + title="Resize" + ) + + +_thumbnail_oiio_transcoding_type = [ + {"value": "colorspace", "label": "Use Colorspace"}, + {"value": "display_and_view", "label": "Use Display&View"} +] + + +class DisplayAndViewModel(BaseSettingsModel): + _layout = "expanded" + display: str = Field( + "default", + title="Display" + ) + view: str = Field( + "sRGB", + title="View" + ) + + +class ExtractThumbnailOIIODefaultsModel(BaseSettingsModel): + type: str = Field( + title="Type", + description="Transcoding type", + enum_resolver=lambda: _thumbnail_oiio_transcoding_type, + conditionalEnum=True, + default="colorspace" + ) + + colorspace: str = Field( + "", + title="Colorspace" + ) + display_and_view: DisplayAndViewModel = Field( + default_factory=DisplayAndViewModel, + title="Display&View" + ) + + class ExtractThumbnailModel(BaseSettingsModel): _isGroup = True enabled: bool = Field(True) + integrate_thumbnail: bool = Field( + True, + title="Integrate Thumbnail Representation" + ) + target_size: ResizeModel = Field( + default_factory=ResizeModel, + title="Target size" + ) + background_color: ColorRGBA_uint8 = Field( + (0, 0, 0, 0.0), + title="Background color" + ) + duration_split: float = Field( + 0.5, + title="Duration split", + ge=0.0, + le=1.0 + ) + oiiotool_defaults: ExtractThumbnailOIIODefaultsModel = Field( + default_factory=ExtractThumbnailOIIODefaultsModel, + title="OIIOtool defaults" + ) ffmpeg_args: ExtractThumbnailFFmpegModel = Field( default_factory=ExtractThumbnailFFmpegModel ) @@ -741,6 +840,15 @@ DEFAULT_PUBLISH_VALUES = { }, "ExtractThumbnail": { "enabled": True, + "integrate_thumbnail": True, + "target_size": { + "type": "source" + }, + "duration_split": 0.5, + "oiiotool_defaults": { + "type": "colorspace", + "colorspace": "color_picking" + }, "ffmpeg_args": { "input": [ "-apply_trc gamma22" diff --git a/server_addon/core/server/version.py b/server_addon/core/server/version.py index ae7362549b..bbab0242f6 100644 --- a/server_addon/core/server/version.py +++ b/server_addon/core/server/version.py @@ -1 +1 @@ -__version__ = "0.1.3" +__version__ = "0.1.4" diff --git a/server_addon/create_ayon_addons.py b/server_addon/create_ayon_addons.py index fe8d278321..fc7a673dcc 100644 --- a/server_addon/create_ayon_addons.py +++ b/server_addon/create_ayon_addons.py @@ -33,6 +33,20 @@ IGNORE_FILE_PATTERNS: List[Pattern] = [ } ] +IGNORED_HOSTS = [ + "flame", + "harmony", +] + +IGNORED_MODULES = [ + "ftrack", + "shotgrid", + "sync_server", + "example_addons", + "slack", + "kitsu", +] + class ZipFileLongPaths(zipfile.ZipFile): """Allows longer paths in zip files. @@ -202,16 +216,6 @@ def create_openpype_package( str(pyproject_path), (private_dir / pyproject_path.name) ) - - ignored_hosts = [] - ignored_modules = [ - "ftrack", - "shotgrid", - "sync_server", - "example_addons", - "slack", - "kitsu", - ] # Subdirs that won't be added to output zip file ignored_subpaths = [ ["addons"], @@ -219,11 +223,11 @@ def create_openpype_package( ] ignored_subpaths.extend( ["hosts", host_name] - for host_name in ignored_hosts + for host_name in IGNORED_HOSTS ) ignored_subpaths.extend( ["modules", module_name] - for module_name in ignored_modules + for module_name in IGNORED_MODULES ) # Zip client @@ -297,6 +301,7 @@ def main( # Make sure output dir is created output_dir.mkdir(parents=True, exist_ok=True) + ignored_addons = set(IGNORED_HOSTS) | set(IGNORED_MODULES) for addon_dir in current_dir.iterdir(): if not addon_dir.is_dir(): continue @@ -304,6 +309,9 @@ def main( if addons and addon_dir.name not in addons: continue + if addon_dir.name in ignored_addons: + continue + server_dir = addon_dir / "server" if not server_dir.exists(): continue diff --git a/server_addon/deadline/server/settings/main.py b/server_addon/deadline/server/settings/main.py index f158b7464d..f766ef9db8 100644 --- a/server_addon/deadline/server/settings/main.py +++ b/server_addon/deadline/server/settings/main.py @@ -14,15 +14,35 @@ class ServerListSubmodel(BaseSettingsModel): value: str = Field(title="Value") +async def defined_deadline_ws_name_enum_resolver( + addon: "BaseServerAddon", + settings_variant: str = "production", + project_name: str | None = None, +) -> list[str]: + """Provides list of names of configured Deadline webservice urls.""" + if addon is None: + return [] + + settings = await addon.get_studio_settings(variant=settings_variant) + + ws_urls = [] + for deadline_url_item in settings.deadline_urls: + ws_urls.append(deadline_url_item.name) + + return ws_urls + + class DeadlineSettings(BaseSettingsModel): deadline_urls: list[ServerListSubmodel] = Field( default_factory=list, title="System Deadline Webservice URLs", scope=["studio"], ) - deadline_servers: list[str] = Field( - title="Project deadline servers", + deadline_server: str = Field( + title="Project deadline server", section="---", + scope=["project"], + enum_resolver=defined_deadline_ws_name_enum_resolver ) publish: PublishPluginsModel = Field( default_factory=PublishPluginsModel, @@ -42,7 +62,6 @@ DEFAULT_VALUES = { "value": "http://127.0.0.1:8082" } ], - # TODO: this needs to be dynamic from "deadline_urls" - "deadline_servers": [], + "deadline_server": "default", "publish": DEFAULT_DEADLINE_PLUGINS_SETTINGS } diff --git a/server_addon/deadline/server/settings/publish_plugins.py b/server_addon/deadline/server/settings/publish_plugins.py index 54b7ff57c1..a989f3ad9d 100644 --- a/server_addon/deadline/server/settings/publish_plugins.py +++ b/server_addon/deadline/server/settings/publish_plugins.py @@ -3,12 +3,6 @@ from pydantic import Field, validator from ayon_server.settings import BaseSettingsModel, ensure_unique_names -class CollectDefaultDeadlineServerModel(BaseSettingsModel): - """Settings for event handlers running in ftrack service.""" - - pass_mongo_url: bool = Field(title="Pass Mongo url to job") - - class CollectDeadlinePoolsModel(BaseSettingsModel): """Settings Deadline default pools.""" @@ -237,6 +231,7 @@ class BlenderSubmitDeadlineModel(BaseSettingsModel): priority: int = Field(title="Priority") chunk_size: int = Field(title="Frame per Task") group: str = Field("", title="Group Name") + job_delay: str = Field("", title="Delay job (timecode dd:hh:mm:ss)") class AOVFilterSubmodel(BaseSettingsModel): @@ -248,6 +243,17 @@ class AOVFilterSubmodel(BaseSettingsModel): ) +class ProcessCacheJobFarmModel(BaseSettingsModel): + """Process submitted job on farm.""" + + enabled: bool = Field(title="Enabled") + deadline_department: str = Field(title="Department") + deadline_pool: str = Field(title="Pool") + deadline_group: str = Field(title="Group") + deadline_chunk_size: int = Field(title="Chunk Size") + deadline_priority: int = Field(title="Priority") + + class ProcessSubmittedJobOnFarmModel(BaseSettingsModel): """Process submitted job on farm.""" @@ -274,12 +280,6 @@ class ProcessSubmittedJobOnFarmModel(BaseSettingsModel): class PublishPluginsModel(BaseSettingsModel): - CollectDefaultDeadlineServer: CollectDefaultDeadlineServerModel = Field( - default_factory=CollectDefaultDeadlineServerModel, - title="Default Deadline Webservice") - CollectDefaultDeadlineServer: CollectDefaultDeadlineServerModel = Field( - default_factory=CollectDefaultDeadlineServerModel, - title="Default Deadline Webservice") CollectDeadlinePools: CollectDeadlinePoolsModel = Field( default_factory=CollectDeadlinePoolsModel, title="Default Pools") @@ -311,15 +311,15 @@ class PublishPluginsModel(BaseSettingsModel): BlenderSubmitDeadline: BlenderSubmitDeadlineModel = Field( default_factory=BlenderSubmitDeadlineModel, title="Blender Submit Deadline") + ProcessSubmittedCacheJobOnFarm: ProcessCacheJobFarmModel = Field( + default_factory=ProcessCacheJobFarmModel, + title="Process submitted cache Job on farm.") ProcessSubmittedJobOnFarm: ProcessSubmittedJobOnFarmModel = Field( default_factory=ProcessSubmittedJobOnFarmModel, title="Process submitted job on farm.") DEFAULT_DEADLINE_PLUGINS_SETTINGS = { - "CollectDefaultDeadlineServer": { - "pass_mongo_url": True - }, "CollectDeadlinePools": { "primary_pool": "", "secondary_pool": "" @@ -424,7 +424,16 @@ DEFAULT_DEADLINE_PLUGINS_SETTINGS = { "use_published": True, "priority": 50, "chunk_size": 10, - "group": "none" + "group": "none", + "job_delay": "00:00:00:00" + }, + "ProcessSubmittedCacheJobOnFarm": { + "enabled": True, + "deadline_department": "", + "deadline_pool": "", + "deadline_group": "", + "deadline_chunk_size": 1, + "deadline_priority": 50 }, "ProcessSubmittedJobOnFarm": { "enabled": True, diff --git a/server_addon/deadline/server/version.py b/server_addon/deadline/server/version.py index ae7362549b..1276d0254f 100644 --- a/server_addon/deadline/server/version.py +++ b/server_addon/deadline/server/version.py @@ -1 +1 @@ -__version__ = "0.1.3" +__version__ = "0.1.5" diff --git a/server_addon/hiero/server/settings/scriptsmenu.py b/server_addon/hiero/server/settings/scriptsmenu.py index 51cb088298..ea898dd7ff 100644 --- a/server_addon/hiero/server/settings/scriptsmenu.py +++ b/server_addon/hiero/server/settings/scriptsmenu.py @@ -28,14 +28,14 @@ class ScriptsmenuSettings(BaseSettingsModel): DEFAULT_SCRIPTSMENU_SETTINGS = { - "name": "OpenPype Tools", + "name": "Custom Tools", "definition": [ { "type": "action", "sourcetype": "python", - "title": "OpenPype Docs", - "command": "import webbrowser;webbrowser.open(url='https://openpype.io/docs/artist_hosts_hiero')", - "tooltip": "Open the OpenPype Hiero user doc page" + "title": "Ayon Hiero Docs", + "command": "import webbrowser;webbrowser.open(url='https://ayon.ynput.io/docs/addon_hiero_artist')", # noqa + "tooltip": "Open the Ayon Hiero user doc page" } ] } diff --git a/server_addon/hiero/server/version.py b/server_addon/hiero/server/version.py index 3dc1f76bc6..485f44ac21 100644 --- a/server_addon/hiero/server/version.py +++ b/server_addon/hiero/server/version.py @@ -1 +1 @@ -__version__ = "0.1.0" +__version__ = "0.1.1" diff --git a/server_addon/max/server/settings/publishers.py b/server_addon/max/server/settings/publishers.py index b48f14a064..d40d85a99b 100644 --- a/server_addon/max/server/settings/publishers.py +++ b/server_addon/max/server/settings/publishers.py @@ -68,6 +68,28 @@ class PublishersModel(BaseSettingsModel): default_factory=ValidateLoadedPluginModel, title="Validate Loaded Plugin" ) + ExtractModelObj: BasicValidateModel = Field( + default_factory=BasicValidateModel, + title="Extract OBJ", + section="Extractors" + ) + ExtractModelFbx: BasicValidateModel = Field( + default_factory=BasicValidateModel, + title="Extract FBX" + ) + ExtractModelUSD: BasicValidateModel = Field( + default_factory=BasicValidateModel, + title="Extract Geometry (USD)" + ) + ExtractModel: BasicValidateModel = Field( + default_factory=BasicValidateModel, + title="Extract Geometry (Alembic)" + ) + ExtractMaxSceneRaw: BasicValidateModel = Field( + default_factory=BasicValidateModel, + title="Extract Max Scene (Raw)" + ) + DEFAULT_PUBLISH_SETTINGS = { "ValidateFrameRange": { @@ -83,5 +105,30 @@ DEFAULT_PUBLISH_SETTINGS = { "enabled": False, "optional": True, "family_plugins_mapping": [] + }, + "ExtractModelObj": { + "enabled": True, + "optional": True, + "active": False + }, + "ExtractModelFbx": { + "enabled": True, + "optional": True, + "active": False + }, + "ExtractModelUSD": { + "enabled": True, + "optional": True, + "active": False + }, + "ExtractModel": { + "enabled": True, + "optional": True, + "active": True + }, + "ExtractMaxSceneRaw": { + "enabled": True, + "optional": True, + "active": True } } diff --git a/server_addon/max/server/version.py b/server_addon/max/server/version.py index b3f4756216..ae7362549b 100644 --- a/server_addon/max/server/version.py +++ b/server_addon/max/server/version.py @@ -1 +1 @@ -__version__ = "0.1.2" +__version__ = "0.1.3" diff --git a/server_addon/maya/server/settings/main.py b/server_addon/maya/server/settings/main.py index c8021614be..62fd12ec8a 100644 --- a/server_addon/maya/server/settings/main.py +++ b/server_addon/maya/server/settings/main.py @@ -97,11 +97,12 @@ DEFAULT_MEL_WORKSPACE_SETTINGS = "\n".join(( 'workspace -fr "renderData" "renderData";', 'workspace -fr "sourceImages" "sourceimages";', 'workspace -fr "fileCache" "cache/nCache";', + 'workspace -fr "autoSave" "autosave"', '', )) DEFAULT_MAYA_SETTING = { - "open_workfile_post_initialization": False, + "open_workfile_post_initialization": True, "explicit_plugins_loading": DEFAULT_EXPLITCIT_PLUGINS_LOADING_SETTINGS, "imageio": DEFAULT_IMAGEIO_SETTINGS, "mel_workspace": DEFAULT_MEL_WORKSPACE_SETTINGS, diff --git a/server_addon/maya/server/settings/publishers.py b/server_addon/maya/server/settings/publishers.py index dd8d4a0a37..e823efe681 100644 --- a/server_addon/maya/server/settings/publishers.py +++ b/server_addon/maya/server/settings/publishers.py @@ -785,7 +785,7 @@ DEFAULT_PUBLISH_SETTINGS = { "sync_workfile_version": False }, "CollectFbxAnimation": { - "enabled": True + "enabled": False }, "CollectFbxCamera": { "enabled": False @@ -862,7 +862,7 @@ DEFAULT_PUBLISH_SETTINGS = { ] }, "ValidatePluginPathAttributes": { - "enabled": True, + "enabled": False, "optional": False, "active": True, "attribute": [ @@ -917,12 +917,12 @@ DEFAULT_PUBLISH_SETTINGS = { "active": True }, "ValidateGLSLMaterial": { - "enabled": True, + "enabled": False, "optional": False, "active": True }, "ValidateGLSLPlugin": { - "enabled": True, + "enabled": False, "optional": False, "active": True }, @@ -1154,7 +1154,7 @@ DEFAULT_PUBLISH_SETTINGS = { "active": True }, "ExtractProxyAlembic": { - "enabled": True, + "enabled": False, "families": [ "proxyAbc" ] @@ -1311,7 +1311,7 @@ DEFAULT_PUBLISH_SETTINGS = { "bake_attributes": "[]" }, "ExtractGLB": { - "enabled": True, + "enabled": False, "active": True, "ogsfx_path": "/maya2glTF/PBR/shaders/glTF_PBR.ogsfx" }, diff --git a/server_addon/maya/server/settings/scriptsmenu.py b/server_addon/maya/server/settings/scriptsmenu.py index 82c1c2e53c..4ac2263f7a 100644 --- a/server_addon/maya/server/settings/scriptsmenu.py +++ b/server_addon/maya/server/settings/scriptsmenu.py @@ -26,7 +26,7 @@ class ScriptsmenuModel(BaseSettingsModel): DEFAULT_SCRIPTSMENU_SETTINGS = { - "name": "OpenPype Tools", + "name": "Custom Tools", "definition": [ { "type": "action", diff --git a/server_addon/maya/server/settings/workfile_build_settings.py b/server_addon/maya/server/settings/workfile_build_settings.py index dc56d1a320..2c7fea85c4 100644 --- a/server_addon/maya/server/settings/workfile_build_settings.py +++ b/server_addon/maya/server/settings/workfile_build_settings.py @@ -104,7 +104,7 @@ DEFAULT_WORKFILE_SETTING = { { "product_name_filters": [], "product_types": [ - "sedress" + "setdress" ], "repre_names": [ "ma" diff --git a/server_addon/maya/server/version.py b/server_addon/maya/server/version.py index 805897cda3..b87834cc35 100644 --- a/server_addon/maya/server/version.py +++ b/server_addon/maya/server/version.py @@ -1,3 +1,3 @@ # -*- coding: utf-8 -*- """Package declaring addon version.""" -__version__ = "0.1.6" +__version__ = "0.1.7" diff --git a/server_addon/nuke/server/settings/publish_plugins.py b/server_addon/nuke/server/settings/publish_plugins.py index 81663fa5aa..84457d2484 100644 --- a/server_addon/nuke/server/settings/publish_plugins.py +++ b/server_addon/nuke/server/settings/publish_plugins.py @@ -51,17 +51,6 @@ class NodeModel(BaseSettingsModel): return value -class ThumbnailRepositionNodeModel(BaseSettingsModel): - node_class: str = Field(title="Node class") - knobs: list[KnobModel] = Field(title="Knobs", default_factory=list) - - @validator("knobs") - def ensure_unique_names(cls, value): - """Ensure name fields within the lists have unique names.""" - ensure_unique_names(value) - return value - - class CollectInstanceDataModel(BaseSettingsModel): sync_workfile_version_on_product_types: list[str] = Field( default_factory=list, @@ -89,22 +78,6 @@ class ValidateKnobsModel(BaseSettingsModel): return validate_json_dict(value) -class ExtractThumbnailModel(BaseSettingsModel): - enabled: bool = Field(title="Enabled") - use_rendered: bool = Field(title="Use rendered images") - bake_viewer_process: bool = Field(title="Bake view process") - bake_viewer_input_process: bool = Field(title="Bake viewer input process") - - nodes: list[NodeModel] = Field( - default_factory=list, - title="Nodes (deprecated)" - ) - reposition_nodes: list[ThumbnailRepositionNodeModel] = Field( - title="Reposition nodes", - default_factory=list - ) - - class ExtractReviewDataModel(BaseSettingsModel): enabled: bool = Field(title="Enabled") @@ -153,16 +126,29 @@ class IntermediateOutputModel(BaseSettingsModel): name: str = Field(title="Output name") filter: BakingStreamFilterModel = Field( title="Filter", default_factory=BakingStreamFilterModel) - read_raw: bool = Field(title="Read raw switch") - viewer_process_override: str = Field(title="Viewer process override") - bake_viewer_process: bool = Field(title="Bake viewer process") + read_raw: bool = Field( + False, + title="Read raw switch" + ) + viewer_process_override: str = Field( + "", + title="Viewer process override" + ) + bake_viewer_process: bool = Field( + True, + title="Bake viewer process" + ) bake_viewer_input_process: bool = Field( + True, title="Bake viewer input process node (LUT)" ) reformat_nodes_config: ReformatNodesConfigModel = Field( default_factory=ReformatNodesConfigModel, title="Reformat Nodes") - extension: str = Field(title="File extension") + extension: str = Field( + "mov", + title="File extension" + ) add_custom_tags: list[str] = Field( title="Custom tags", default_factory=list) @@ -267,11 +253,6 @@ class PublishPuginsModel(BaseSettingsModel): title="Validate workfile attributes", default_factory=OptionalPluginModel ) - ExtractThumbnail: ExtractThumbnailModel = Field( - title="Extract Thumbnail", - default_factory=ExtractThumbnailModel, - section="Extractors" - ) ExtractReviewData: ExtractReviewDataModel = Field( title="Extract Review Data", default_factory=ExtractReviewDataModel @@ -350,78 +331,6 @@ DEFAULT_PUBLISH_PLUGIN_SETTINGS = { "optional": True, "active": True }, - "ExtractThumbnail": { - "enabled": True, - "use_rendered": True, - "bake_viewer_process": True, - "bake_viewer_input_process": True, - "nodes": [ - { - "name": "Reformat01", - "nodeclass": "Reformat", - "dependency": "", - "knobs": [ - { - "type": "text", - "name": "type", - "text": "to format" - }, - { - "type": "text", - "name": "format", - "text": "HD_1080" - }, - { - "type": "text", - "name": "filter", - "text": "Lanczos6" - }, - { - "type": "boolean", - "name": "black_outside", - "boolean": True - }, - { - "type": "boolean", - "name": "pbb", - "boolean": False - } - ] - } - ], - "reposition_nodes": [ - { - "node_class": "Reformat", - "knobs": [ - { - "type": "text", - "name": "type", - "text": "to format" - }, - { - "type": "text", - "name": "format", - "text": "HD_1080" - }, - { - "type": "text", - "name": "filter", - "text": "Lanczos6" - }, - { - "type": "boolean", - "name": "black_outside", - "boolean": True - }, - { - "type": "boolean", - "name": "pbb", - "boolean": False - } - ] - } - ] - }, "ExtractReviewData": { "enabled": False }, diff --git a/server_addon/nuke/server/settings/scriptsmenu.py b/server_addon/nuke/server/settings/scriptsmenu.py index 0b2d660da5..3dd6765920 100644 --- a/server_addon/nuke/server/settings/scriptsmenu.py +++ b/server_addon/nuke/server/settings/scriptsmenu.py @@ -26,27 +26,27 @@ class ScriptsmenuSettings(BaseSettingsModel): DEFAULT_SCRIPTSMENU_SETTINGS = { - "name": "OpenPype Tools", + "name": "Custom Tools", "definition": [ { "type": "action", "sourcetype": "python", - "title": "OpenPype Docs", - "command": "import webbrowser;webbrowser.open(url='https://openpype.io/docs/artist_hosts_nuke_tut')", - "tooltip": "Open the OpenPype Nuke user doc page" + "title": "Ayon Nuke Docs", + "command": "import webbrowser;webbrowser.open(url='https://ayon.ynput.io/docs/addon_nuke_artist')", # noqa + "tooltip": "Open the Ayon Nuke user doc page" }, { "type": "action", "sourcetype": "python", "title": "Set Frame Start (Read Node)", - "command": "from openpype.hosts.nuke.startup.frame_setting_for_read_nodes import main;main();", + "command": "from openpype.hosts.nuke.startup.frame_setting_for_read_nodes import main;main();", # noqa "tooltip": "Set frame start for read node(s)" }, { "type": "action", "sourcetype": "python", "title": "Set non publish output for Write Node", - "command": "from openpype.hosts.nuke.startup.custom_write_node import main;main();", + "command": "from openpype.hosts.nuke.startup.custom_write_node import main;main();", # noqa "tooltip": "Open the OpenPype Nuke user doc page" } ] diff --git a/server_addon/nuke/server/version.py b/server_addon/nuke/server/version.py index 1276d0254f..f1380eede2 100644 --- a/server_addon/nuke/server/version.py +++ b/server_addon/nuke/server/version.py @@ -1 +1 @@ -__version__ = "0.1.5" +__version__ = "0.1.7" diff --git a/server_addon/photoshop/server/settings/publish_plugins.py b/server_addon/photoshop/server/settings/publish_plugins.py index 6bc72b4072..2863979ca9 100644 --- a/server_addon/photoshop/server/settings/publish_plugins.py +++ b/server_addon/photoshop/server/settings/publish_plugins.py @@ -150,7 +150,7 @@ class PhotoshopPublishPlugins(BaseSettingsModel): ) CollectVersion: CollectVersionPlugin = Field( - title="Create Image", + title="Collect Version", default_factory=CollectVersionPlugin, ) diff --git a/server_addon/photoshop/server/settings/workfile_builder.py b/server_addon/photoshop/server/settings/workfile_builder.py index ec2ee136ad..68db05270d 100644 --- a/server_addon/photoshop/server/settings/workfile_builder.py +++ b/server_addon/photoshop/server/settings/workfile_builder.py @@ -1,31 +1,18 @@ from pydantic import Field -from pathlib import Path -from ayon_server.settings import BaseSettingsModel - - -class PathsTemplate(BaseSettingsModel): - windows: Path = Field( - '', - title="Windows" - ) - darwin: Path = Field( - '', - title="MacOS" - ) - linux: Path = Field( - '', - title="Linux" - ) +from ayon_server.settings import BaseSettingsModel, MultiplatformPathModel class CustomBuilderTemplate(BaseSettingsModel): + _layout = "expanded" task_types: list[str] = Field( default_factory=list, title="Task types", ) - template_path: PathsTemplate = Field( - default_factory=PathsTemplate + + path: MultiplatformPathModel = Field( + default_factory=MultiplatformPathModel, + title="Template path" ) @@ -37,5 +24,6 @@ class WorkfileBuilderPlugin(BaseSettingsModel): ) custom_templates: list[CustomBuilderTemplate] = Field( - default_factory=CustomBuilderTemplate + default_factory=CustomBuilderTemplate, + title="Template profiles" ) diff --git a/server_addon/unreal/server/settings.py b/server_addon/unreal/server/settings.py index 479e041e25..110ccc563a 100644 --- a/server_addon/unreal/server/settings.py +++ b/server_addon/unreal/server/settings.py @@ -53,11 +53,11 @@ class UnrealSettings(BaseSettingsModel): DEFAULT_VALUES = { - "level_sequences_for_layouts": False, + "level_sequences_for_layouts": True, "delete_unmatched_assets": False, "render_config_path": "", "preroll_frames": 0, - "render_format": "png", + "render_format": "exr", "project_setup": { "dev_mode": False } diff --git a/tests/conftest.py b/tests/conftest.py index a862030fff..cb4806998a 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -39,6 +39,11 @@ def pytest_addoption(parser): help="Provide url of the Mongo database." ) + parser.addoption( + "--dump_databases", action="store", default=None, + help="Dump databases to data folder." + ) + @pytest.fixture(scope="module") def test_data_folder(request): @@ -75,6 +80,11 @@ def mongo_url(request): return request.config.getoption("--mongo_url") +@pytest.fixture(scope="module") +def dump_databases(request): + return request.config.getoption("--dump_databases") + + @pytest.hookimpl(tryfirst=True, hookwrapper=True) def pytest_runtest_makereport(item, call): # execute all other hooks to obtain the report object @@ -85,3 +95,11 @@ def pytest_runtest_makereport(item, call): # be "setup", "call", "teardown" setattr(item, "rep_" + rep.when, rep) + + # In the event of module scoped fixtures, also mark failure in module. + module = item + while module is not None and not isinstance(module, pytest.Module): + module = module.parent + if module is not None: + if rep.when == 'call' and (rep.failed or rep.skipped): + module.module_test_failure = True diff --git a/tests/integration/README.md b/tests/integration/README.md index 7b9b7cd706..1e45b55ed5 100644 --- a/tests/integration/README.md +++ b/tests/integration/README.md @@ -29,7 +29,7 @@ Command line arguments - "--timeout" - "Provide specific timeout value for test case", - "--setup_only" - "Only create dbs, do not run tests", - "--mongo_url" - "MongoDB for testing.", - + - "--dump_databases" - ("json"|"bson") export database in expected format after successful test (to output folder in temp location - which is made persistent by this, must be cleared manually) Run Tray for test ----------------- In case of failed test you might want to run it manually and visually debug what happened. diff --git a/tests/integration/hosts/aftereffects/test_deadline_publish_in_aftereffects.py b/tests/integration/hosts/aftereffects/test_deadline_publish_in_aftereffects.py index 30761693a8..1aa612207d 100644 --- a/tests/integration/hosts/aftereffects/test_deadline_publish_in_aftereffects.py +++ b/tests/integration/hosts/aftereffects/test_deadline_publish_in_aftereffects.py @@ -60,7 +60,7 @@ class TestDeadlinePublishInAfterEffects(AEDeadlinePublishTestClass): name="renderTest_taskMain")) failures.append( - DBAssert.count_of_types(dbcon, "representation", 4)) + DBAssert.count_of_types(dbcon, "representation", 3)) additional_args = {"context.subset": "workfileTest_task", "context.ext": "aep"} @@ -77,7 +77,7 @@ class TestDeadlinePublishInAfterEffects(AEDeadlinePublishTestClass): additional_args = {"context.subset": "renderTest_taskMain", "name": "thumbnail"} failures.append( - DBAssert.count_of_types(dbcon, "representation", 1, + DBAssert.count_of_types(dbcon, "representation", 0, additional_args=additional_args)) additional_args = {"context.subset": "renderTest_taskMain", diff --git a/tests/integration/hosts/aftereffects/test_deadline_publish_in_aftereffects_multicomposition.py b/tests/integration/hosts/aftereffects/test_deadline_publish_in_aftereffects_multicomposition.py index 0e9cd3b00d..4254b951b5 100644 --- a/tests/integration/hosts/aftereffects/test_deadline_publish_in_aftereffects_multicomposition.py +++ b/tests/integration/hosts/aftereffects/test_deadline_publish_in_aftereffects_multicomposition.py @@ -71,7 +71,7 @@ class TestDeadlinePublishInAfterEffectsMultiComposition(AEDeadlinePublishTestCla name="renderTest_taskMain2")) failures.append( - DBAssert.count_of_types(dbcon, "representation", 5)) + DBAssert.count_of_types(dbcon, "representation", 4)) additional_args = {"context.subset": "workfileTest_task", "context.ext": "aep"} @@ -89,7 +89,7 @@ class TestDeadlinePublishInAfterEffectsMultiComposition(AEDeadlinePublishTestCla additional_args = {"context.subset": "renderTest_taskMain", "name": "thumbnail"} failures.append( - DBAssert.count_of_types(dbcon, "representation", 1, + DBAssert.count_of_types(dbcon, "representation", 0, additional_args=additional_args)) additional_args = {"context.subset": "renderTest_taskMain", diff --git a/tests/integration/hosts/aftereffects/test_publish_in_aftereffects.py b/tests/integration/hosts/aftereffects/test_publish_in_aftereffects.py index 2e4f343a5a..f13043d8bb 100644 --- a/tests/integration/hosts/aftereffects/test_publish_in_aftereffects.py +++ b/tests/integration/hosts/aftereffects/test_publish_in_aftereffects.py @@ -58,7 +58,7 @@ class TestPublishInAfterEffects(AELocalPublishTestClass): name="renderTest_taskMain")) failures.append( - DBAssert.count_of_types(dbcon, "representation", 4)) + DBAssert.count_of_types(dbcon, "representation", 3)) additional_args = {"context.subset": "workfileTest_task", "context.ext": "aep"} @@ -75,7 +75,7 @@ class TestPublishInAfterEffects(AELocalPublishTestClass): additional_args = {"context.subset": "renderTest_taskMain", "name": "thumbnail"} failures.append( - DBAssert.count_of_types(dbcon, "representation", 1, + DBAssert.count_of_types(dbcon, "representation", 0, additional_args=additional_args)) additional_args = {"context.subset": "renderTest_taskMain", diff --git a/tests/integration/hosts/aftereffects/test_publish_in_aftereffects_legacy.py b/tests/integration/hosts/aftereffects/test_publish_in_aftereffects_legacy.py index a62036e4a7..b99db24e75 100644 --- a/tests/integration/hosts/aftereffects/test_publish_in_aftereffects_legacy.py +++ b/tests/integration/hosts/aftereffects/test_publish_in_aftereffects_legacy.py @@ -60,7 +60,7 @@ class TestPublishInAfterEffects(AELocalPublishTestClass): name="renderTest_taskMain")) failures.append( - DBAssert.count_of_types(dbcon, "representation", 4)) + DBAssert.count_of_types(dbcon, "representation", 2)) additional_args = {"context.subset": "workfileTest_task", "context.ext": "aep"} @@ -77,7 +77,7 @@ class TestPublishInAfterEffects(AELocalPublishTestClass): additional_args = {"context.subset": "renderTest_taskMain", "name": "thumbnail"} failures.append( - DBAssert.count_of_types(dbcon, "representation", 1, + DBAssert.count_of_types(dbcon, "representation", 0, additional_args=additional_args)) additional_args = {"context.subset": "renderTest_taskMain", @@ -89,7 +89,7 @@ class TestPublishInAfterEffects(AELocalPublishTestClass): additional_args = {"context.subset": "renderTest_taskMain", "name": "thumbnail"} failures.append( - DBAssert.count_of_types(dbcon, "representation", 1, + DBAssert.count_of_types(dbcon, "representation", 0, additional_args=additional_args)) additional_args = {"context.subset": "renderTest_taskMain", diff --git a/tests/integration/hosts/aftereffects/test_publish_in_aftereffects_multiframe.py b/tests/integration/hosts/aftereffects/test_publish_in_aftereffects_multiframe.py index dcf34844d1..bd9d3e9b50 100644 --- a/tests/integration/hosts/aftereffects/test_publish_in_aftereffects_multiframe.py +++ b/tests/integration/hosts/aftereffects/test_publish_in_aftereffects_multiframe.py @@ -45,7 +45,7 @@ class TestPublishInAfterEffects(AELocalPublishTestClass): name="renderTest_taskMain")) failures.append( - DBAssert.count_of_types(dbcon, "representation", 4)) + DBAssert.count_of_types(dbcon, "representation", 3)) additional_args = {"context.subset": "workfileTest_task", "context.ext": "aep"} @@ -62,7 +62,7 @@ class TestPublishInAfterEffects(AELocalPublishTestClass): additional_args = {"context.subset": "renderTest_taskMain", "name": "thumbnail"} failures.append( - DBAssert.count_of_types(dbcon, "representation", 1, + DBAssert.count_of_types(dbcon, "representation", 0, additional_args=additional_args)) additional_args = {"context.subset": "renderTest_taskMain", diff --git a/tests/integration/hosts/maya/test_deadline_publish_in_maya.py b/tests/integration/hosts/maya/test_deadline_publish_in_maya.py index c2ef342600..79d6c22a26 100644 --- a/tests/integration/hosts/maya/test_deadline_publish_in_maya.py +++ b/tests/integration/hosts/maya/test_deadline_publish_in_maya.py @@ -21,7 +21,7 @@ class TestDeadlinePublishInMaya(MayaDeadlinePublishTestClass): {OPENPYPE_ROOT}/.venv/Scripts/python.exe {OPENPYPE_ROOT}/start.py runtests ../tests/integration/hosts/maya # noqa: E501 """ - PERSIST = True + PERSIST = False TEST_FILES = [ ("test_deadline_publish_in_maya", "", "") @@ -54,7 +54,7 @@ class TestDeadlinePublishInMaya(MayaDeadlinePublishTestClass): DBAssert.count_of_types(dbcon, "subset", 1, name="workfileTest_task")) - failures.append(DBAssert.count_of_types(dbcon, "representation", 8)) + failures.append(DBAssert.count_of_types(dbcon, "representation", 7)) # hero included additional_args = {"context.subset": "modelMain", @@ -85,7 +85,7 @@ class TestDeadlinePublishInMaya(MayaDeadlinePublishTestClass): additional_args = {"context.subset": "renderTest_taskMain_beauty", "context.ext": "jpg"} failures.append( - DBAssert.count_of_types(dbcon, "representation", 1, + DBAssert.count_of_types(dbcon, "representation", 0, additional_args=additional_args)) additional_args = {"context.subset": "renderTest_taskMain_beauty", diff --git a/tests/integration/hosts/maya/test_deadline_publish_in_maya/expected/test_project/test_asset/publish/render/renderTest_taskMain_beauty/v001/test_project_test_asset_renderTest_taskMain_beauty_v001.jpg b/tests/integration/hosts/maya/test_deadline_publish_in_maya/expected/test_project/test_asset/publish/render/renderTest_taskMain_beauty/v001/test_project_test_asset_renderTest_taskMain_beauty_v001.jpg deleted file mode 100644 index 79ff799e8b..0000000000 Binary files a/tests/integration/hosts/maya/test_deadline_publish_in_maya/expected/test_project/test_asset/publish/render/renderTest_taskMain_beauty/v001/test_project_test_asset_renderTest_taskMain_beauty_v001.jpg and /dev/null differ diff --git a/tests/integration/hosts/maya/test_deadline_publish_in_maya/input/workfile/test_project_test_asset_test_task_v001.ma b/tests/integration/hosts/maya/test_deadline_publish_in_maya/input/workfile/test_project_test_asset_test_task_v001.ma index c476a78086..2e882a5baa 100644 --- a/tests/integration/hosts/maya/test_deadline_publish_in_maya/input/workfile/test_project_test_asset_test_task_v001.ma +++ b/tests/integration/hosts/maya/test_deadline_publish_in_maya/input/workfile/test_project_test_asset_test_task_v001.ma @@ -236,6 +236,7 @@ createNode polyDisc -n "polyDisc1"; rename -uid "9ED8A7BD-4FFD-6107-4322-35ACD1D3AC42"; createNode aiOptions -s -n "defaultArnoldRenderOptions"; rename -uid "31A81965-48A6-B90D-503D-2FA162B7C982"; + setAttr ".skip_license_check" yes; createNode aiAOVFilter -s -n "defaultArnoldFilter"; rename -uid "77A2BCB1-4613-905E-080E-B997FD5E1C6F"; setAttr ".ai_translator" -type "string" "gaussian"; diff --git a/tests/integration/hosts/maya/test_publish_in_maya/expected/test_project/test_asset/publish/workfile/workfileTest_task/v001/test_project_test_asset_workfileTest_task_v001.ma b/tests/integration/hosts/maya/test_publish_in_maya/expected/test_project/test_asset/publish/workfile/workfileTest_task/v001/test_project_test_asset_workfileTest_task_v001.ma index e438d80d5f..2cc87c2f48 100644 --- a/tests/integration/hosts/maya/test_publish_in_maya/expected/test_project/test_asset/publish/workfile/workfileTest_task/v001/test_project_test_asset_workfileTest_task_v001.ma +++ b/tests/integration/hosts/maya/test_publish_in_maya/expected/test_project/test_asset/publish/workfile/workfileTest_task/v001/test_project_test_asset_workfileTest_task_v001.ma @@ -1,22 +1,22 @@ -//Maya ASCII 2022 scene -//Name: test_project_test_asset_test_task_v001.ma -//Last modified: Thu, Sep 14, 2023 06:31:00 PM +//Maya ASCII 2023 scene +//Name: test_project_test_asset_test_task_v002.ma +//Last modified: Thu, Dec 07, 2023 03:53:06 PM //Codeset: 1252 -requires maya "2022"; -requires -nodeType "polyDisc" "modelingToolkit" "0.0.0.0"; -requires "stereoCamera" "10.0"; -requires -nodeType "aiOptions" -nodeType "aiAOVDriver" -nodeType "aiAOVFilter" "mtoa" "5.2.2.1"; +requires maya "2023"; requires -nodeType "simpleSelector" -nodeType "renderSetupLayer" -nodeType "renderSetup" -nodeType "collection" "renderSetup.py" "1.0"; requires "stereoCamera" "10.0"; +requires -nodeType "aiOptions" -nodeType "aiAOVDriver" -nodeType "aiAOVFilter" "mtoa" "5.2.1.1"; +requires -nodeType "polyDisc" "modelingToolkit" "0.0.0.0"; +requires "stereoCamera" "10.0"; currentUnit -l centimeter -a degree -t pal; fileInfo "application" "maya"; -fileInfo "product" "Maya 2022"; -fileInfo "version" "2022"; -fileInfo "cutIdentifier" "202205171752-c25c06f306"; -fileInfo "osv" "Windows 10 Pro v2009 (Build: 19044)"; +fileInfo "product" "Maya 2023"; +fileInfo "version" "2023"; +fileInfo "cutIdentifier" "202211021031-847a9f9623"; +fileInfo "osv" "Windows 10 Pro v2009 (Build: 19045)"; fileInfo "license" "education"; -fileInfo "UUID" "019C7F50-40EF-1435-E27F-729F64685E67"; +fileInfo "UUID" "7A992745-4AD5-777F-5575-B4BFAC62B1D0"; fileInfo "OpenPypeContext" "eyJwdWJsaXNoX2F0dHJpYnV0ZXMiOiB7IlZhbGlkYXRlQ29udGFpbmVycyI6IHsiYWN0aXZlIjogdHJ1ZX19fQ=="; createNode transform -s -n "persp"; rename -uid "D52C935B-47C9-D868-A875-D799DD17B3A1"; @@ -142,19 +142,20 @@ createNode camera -n "perspShape1" -p "persp1"; setAttr ".hc" -type "string" "viewSet -p %camera"; setAttr ".dr" yes; createNode lightLinker -s -n "lightLinker1"; - rename -uid "6B9ADCD4-41B9-5BCC-826D-4A874A278510"; + rename -uid "09465BD3-42E5-18E4-7906-20A99BB2A6C0"; setAttr -s 2 ".lnk"; setAttr -s 2 ".slnk"; createNode shapeEditorManager -n "shapeEditorManager"; - rename -uid "5B4518C5-46C9-6921-690E-EFAF77B21A36"; + rename -uid "9F2E8009-4D69-046B-FCC4-28A8CE8F86DB"; createNode poseInterpolatorManager -n "poseInterpolatorManager"; - rename -uid "8518F293-4F06-BFF2-647A-72A099FBF025"; + rename -uid "6757AD81-40B0-A747-69C3-D9A56259571E"; createNode displayLayerManager -n "layerManager"; - rename -uid "04D880D5-4D86-0C58-CA3D-208ABE3E1E16"; + rename -uid "6F055ED5-4D91-8F85-7951-B4A13543A561"; createNode displayLayer -n "defaultLayer"; rename -uid "4A776D1B-401F-7069-1C74-A7AAE84CEE03"; + setAttr ".ufem" -type "stringArray" 0 ; createNode renderLayerManager -n "renderLayerManager"; - rename -uid "B719B8BE-46BF-12E6-BEBA-B0AD4DBDBA87"; + rename -uid "55626D2B-4FD5-61A1-7AB2-47B13F19D8AA"; setAttr -s 2 ".rlmi[1]" 1; setAttr -s 2 ".rlmi"; createNode renderLayer -n "defaultRenderLayer"; @@ -167,6 +168,7 @@ createNode polySphere -n "polySphere1"; createNode objectSet -n "modelMain"; rename -uid "A76AD4F8-4CF5-AA0D-4E98-BABEE6454CC3"; addAttr -ci true -sn "cbId" -ln "cbId" -dt "string"; + addAttr -ci true -sn "instance_id" -ln "instance_id" -dt "string"; addAttr -ci true -sn "id" -ln "id" -dt "string"; addAttr -ci true -sn "family" -ln "family" -dt "string"; addAttr -ci true -sn "subset" -ln "subset" -dt "string"; @@ -175,18 +177,19 @@ createNode objectSet -n "modelMain"; addAttr -ci true -sn "variant" -ln "variant" -dt "string"; addAttr -ci true -sn "asset" -ln "asset" -dt "string"; addAttr -ci true -sn "task" -ln "task" -dt "string"; - addAttr -ci true -sn "instance_id" -ln "instance_id" -dt "string"; addAttr -ci true -sn "writeColorSets" -ln "writeColorSets" -min 0 -max 1 -at "bool"; addAttr -ci true -sn "writeFaceSets" -ln "writeFaceSets" -min 0 -max 1 -at "bool"; - addAttr -ci true -sn "includeParentHierarchy" -ln "includeParentHierarchy" -min + addAttr -ci true -sn "includeParentHierarchy" -ln "includeParentHierarchy" -min 0 -max 1 -at "bool"; addAttr -ci true -sn "attr" -ln "attr" -dt "string"; addAttr -ci true -sn "attrPrefix" -ln "attrPrefix" -dt "string"; addAttr -ci true -sn "publish_attributes" -ln "publish_attributes" -dt "string"; - addAttr -ci true -sn "__creator_attributes_keys" -ln "__creator_attributes_keys" + addAttr -ci true -sn "creator_attributes" -ln "creator_attributes" -dt "string"; + addAttr -ci true -sn "__creator_attributes_keys" -ln "__creator_attributes_keys" -dt "string"; setAttr ".ihi" 0; setAttr ".cbId" -type "string" "60df31e2be2b48bd3695c056:7364ea6776c9"; + setAttr ".instance_id" -type "string" "6889d3db-b813-43db-96de-9ba555dc4472"; setAttr ".id" -type "string" "pyblish.avalon.instance"; setAttr ".family" -type "string" "model"; setAttr ".subset" -type "string" "modelMain"; @@ -195,59 +198,68 @@ createNode objectSet -n "modelMain"; setAttr ".variant" -type "string" "Main"; setAttr ".asset" -type "string" "test_asset"; setAttr ".task" -type "string" "test_task"; - setAttr ".instance_id" -type "string" "6889d3db-b813-43db-96de-9ba555dc4472"; setAttr -cb on ".writeColorSets"; setAttr -cb on ".writeFaceSets"; setAttr -cb on ".includeParentHierarchy"; setAttr ".attr" -type "string" ""; setAttr ".attrPrefix" -type "string" ""; - setAttr ".publish_attributes" -type "string" "{\"ValidateNodeIDsRelated\": {\"active\": true}, \"ValidateTransformNamingSuffix\": {\"active\": true}, \"ValidateColorSets\": {\"active\": true}, \"ValidateMeshArnoldAttributes\": {\"active\": true}, \"ValidateMeshHasUVs\": {\"active\": true}, \"ValidateMeshNonZeroEdgeLength\": {\"active\": true}, \"ExtractModel\": {\"active\": true}}"; + setAttr ".publish_attributes" -type "string" "{\"ValidateNodeIDsRelated\": {\"active\": true}, \"ValidateInstanceInContext\": {\"active\": true}, \"ValidateTransformNamingSuffix\": {\"active\": true}, \"ValidateColorSets\": {\"active\": true}, \"ValidateMeshHasUVs\": {\"active\": true}, \"ValidateMeshNonZeroEdgeLength\": {\"active\": true}, \"ExtractModel\": {\"active\": true}, \"ValidateMeshArnoldAttributes\": {\"active\": true}}"; + setAttr ".creator_attributes" -type "string" "{}"; setAttr ".__creator_attributes_keys" -type "string" "writeColorSets,writeFaceSets,includeParentHierarchy,attr,attrPrefix"; createNode script -n "uiConfigurationScriptNode"; rename -uid "4B7AFB53-452E-E870-63E1-CCA1DD6EAF13"; setAttr ".b" -type "string" ( "// Maya Mel UI Configuration File.\n//\n// This script is machine generated. Edit at your own risk.\n//\n//\n\nglobal string $gMainPane;\nif (`paneLayout -exists $gMainPane`) {\n\n\tglobal int $gUseScenePanelConfig;\n\tint $useSceneConfig = $gUseScenePanelConfig;\n\tint $nodeEditorPanelVisible = stringArrayContains(\"nodeEditorPanel1\", `getPanel -vis`);\n\tint $nodeEditorWorkspaceControlOpen = (`workspaceControl -exists nodeEditorPanel1Window` && `workspaceControl -q -visible nodeEditorPanel1Window`);\n\tint $menusOkayInPanels = `optionVar -q allowMenusInPanels`;\n\tint $nVisPanes = `paneLayout -q -nvp $gMainPane`;\n\tint $nPanes = 0;\n\tstring $editorName;\n\tstring $panelName;\n\tstring $itemFilterName;\n\tstring $panelConfig;\n\n\t//\n\t// get current state of the UI\n\t//\n\tsceneUIReplacement -update $gMainPane;\n\n\t$panelName = `sceneUIReplacement -getNextPanel \"modelPanel\" (localizedPanelLabel(\"Top View\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tmodelPanel -edit -l (localizedPanelLabel(\"Top View\")) -mbv $menusOkayInPanels $panelName;\n" - + "\t\t$editorName = $panelName;\n modelEditor -e \n -camera \"|top\" \n -useInteractiveMode 0\n -displayLights \"default\" \n -displayAppearance \"smoothShaded\" \n -activeOnly 0\n -ignorePanZoom 0\n -wireframeOnShaded 0\n -headsUpDisplay 1\n -holdOuts 1\n -selectionHiliteDisplay 1\n -useDefaultMaterial 0\n -bufferMode \"double\" \n -twoSidedLighting 0\n -backfaceCulling 0\n -xray 0\n -jointXray 0\n -activeComponentsXray 0\n -displayTextures 0\n -smoothWireframe 0\n -lineWidth 1\n -textureAnisotropic 0\n -textureHilight 1\n -textureSampling 2\n -textureDisplay \"modulate\" \n -textureMaxSize 16384\n -fogging 0\n -fogSource \"fragment\" \n -fogMode \"linear\" \n -fogStart 0\n -fogEnd 100\n -fogDensity 0.1\n -fogColor 0.5 0.5 0.5 1 \n" + + "\t\t$editorName = $panelName;\n modelEditor -e \n -camera \"|top\" \n -useInteractiveMode 0\n -displayLights \"default\" \n -displayAppearance \"smoothShaded\" \n -activeOnly 0\n -ignorePanZoom 0\n -wireframeOnShaded 0\n -headsUpDisplay 1\n -holdOuts 1\n -selectionHiliteDisplay 1\n -useDefaultMaterial 0\n -bufferMode \"double\" \n -twoSidedLighting 0\n -backfaceCulling 0\n -xray 0\n -jointXray 0\n -activeComponentsXray 0\n -displayTextures 0\n -smoothWireframe 0\n -lineWidth 1\n -textureAnisotropic 0\n -textureHilight 1\n -textureSampling 2\n -textureDisplay \"modulate\" \n -textureMaxSize 32768\n -fogging 0\n -fogSource \"fragment\" \n -fogMode \"linear\" \n -fogStart 0\n -fogEnd 100\n -fogDensity 0.1\n -fogColor 0.5 0.5 0.5 1 \n" + " -depthOfFieldPreview 1\n -maxConstantTransparency 1\n -rendererName \"vp2Renderer\" \n -objectFilterShowInHUD 1\n -isFiltered 0\n -colorResolution 256 256 \n -bumpResolution 512 512 \n -textureCompression 0\n -transparencyAlgorithm \"frontAndBackCull\" \n -transpInShadows 0\n -cullingOverride \"none\" \n -lowQualityLighting 0\n -maximumNumHardwareLights 1\n -occlusionCulling 0\n -shadingModel 0\n -useBaseRenderer 0\n -useReducedRenderer 0\n -smallObjectCulling 0\n -smallObjectThreshold -1 \n -interactiveDisableShadows 0\n -interactiveBackFaceCull 0\n -sortTransparent 1\n -controllers 1\n -nurbsCurves 1\n -nurbsSurfaces 1\n -polymeshes 1\n -subdivSurfaces 1\n -planes 1\n -lights 1\n -cameras 1\n -controlVertices 1\n" - + " -hulls 1\n -grid 1\n -imagePlane 1\n -joints 1\n -ikHandles 1\n -deformers 1\n -dynamics 1\n -particleInstancers 1\n -fluids 1\n -hairSystems 1\n -follicles 1\n -nCloths 1\n -nParticles 1\n -nRigids 1\n -dynamicConstraints 1\n -locators 1\n -manipulators 1\n -pluginShapes 1\n -dimensions 1\n -handles 1\n -pivots 1\n -textures 1\n -strokes 1\n -motionTrails 1\n -clipGhosts 1\n -greasePencils 1\n -shadows 0\n -captureSequenceNumber -1\n -width 1\n -height 1\n -sceneRenderFilter 0\n $editorName;\n modelEditor -e -viewSelected 0 $editorName;\n modelEditor -e \n -pluginObjects \"gpuCacheDisplayFilter\" 1 \n $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n" - + "\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextPanel \"modelPanel\" (localizedPanelLabel(\"Side View\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tmodelPanel -edit -l (localizedPanelLabel(\"Side View\")) -mbv $menusOkayInPanels $panelName;\n\t\t$editorName = $panelName;\n modelEditor -e \n -camera \"|side\" \n -useInteractiveMode 0\n -displayLights \"default\" \n -displayAppearance \"smoothShaded\" \n -activeOnly 0\n -ignorePanZoom 0\n -wireframeOnShaded 0\n -headsUpDisplay 1\n -holdOuts 1\n -selectionHiliteDisplay 1\n -useDefaultMaterial 0\n -bufferMode \"double\" \n -twoSidedLighting 0\n -backfaceCulling 0\n -xray 0\n -jointXray 0\n -activeComponentsXray 0\n -displayTextures 0\n -smoothWireframe 0\n -lineWidth 1\n -textureAnisotropic 0\n -textureHilight 1\n -textureSampling 2\n" - + " -textureDisplay \"modulate\" \n -textureMaxSize 16384\n -fogging 0\n -fogSource \"fragment\" \n -fogMode \"linear\" \n -fogStart 0\n -fogEnd 100\n -fogDensity 0.1\n -fogColor 0.5 0.5 0.5 1 \n -depthOfFieldPreview 1\n -maxConstantTransparency 1\n -rendererName \"vp2Renderer\" \n -objectFilterShowInHUD 1\n -isFiltered 0\n -colorResolution 256 256 \n -bumpResolution 512 512 \n -textureCompression 0\n -transparencyAlgorithm \"frontAndBackCull\" \n -transpInShadows 0\n -cullingOverride \"none\" \n -lowQualityLighting 0\n -maximumNumHardwareLights 1\n -occlusionCulling 0\n -shadingModel 0\n -useBaseRenderer 0\n -useReducedRenderer 0\n -smallObjectCulling 0\n -smallObjectThreshold -1 \n -interactiveDisableShadows 0\n -interactiveBackFaceCull 0\n" - + " -sortTransparent 1\n -controllers 1\n -nurbsCurves 1\n -nurbsSurfaces 1\n -polymeshes 1\n -subdivSurfaces 1\n -planes 1\n -lights 1\n -cameras 1\n -controlVertices 1\n -hulls 1\n -grid 1\n -imagePlane 1\n -joints 1\n -ikHandles 1\n -deformers 1\n -dynamics 1\n -particleInstancers 1\n -fluids 1\n -hairSystems 1\n -follicles 1\n -nCloths 1\n -nParticles 1\n -nRigids 1\n -dynamicConstraints 1\n -locators 1\n -manipulators 1\n -pluginShapes 1\n -dimensions 1\n -handles 1\n -pivots 1\n -textures 1\n -strokes 1\n -motionTrails 1\n -clipGhosts 1\n -greasePencils 1\n -shadows 0\n -captureSequenceNumber -1\n -width 1\n -height 1\n" - + " -sceneRenderFilter 0\n $editorName;\n modelEditor -e -viewSelected 0 $editorName;\n modelEditor -e \n -pluginObjects \"gpuCacheDisplayFilter\" 1 \n $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextPanel \"modelPanel\" (localizedPanelLabel(\"Front View\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tmodelPanel -edit -l (localizedPanelLabel(\"Front View\")) -mbv $menusOkayInPanels $panelName;\n\t\t$editorName = $panelName;\n modelEditor -e \n -camera \"|front\" \n -useInteractiveMode 0\n -displayLights \"default\" \n -displayAppearance \"smoothShaded\" \n -activeOnly 0\n -ignorePanZoom 0\n -wireframeOnShaded 0\n -headsUpDisplay 1\n -holdOuts 1\n -selectionHiliteDisplay 1\n -useDefaultMaterial 0\n -bufferMode \"double\" \n -twoSidedLighting 0\n -backfaceCulling 0\n" - + " -xray 0\n -jointXray 0\n -activeComponentsXray 0\n -displayTextures 0\n -smoothWireframe 0\n -lineWidth 1\n -textureAnisotropic 0\n -textureHilight 1\n -textureSampling 2\n -textureDisplay \"modulate\" \n -textureMaxSize 16384\n -fogging 0\n -fogSource \"fragment\" \n -fogMode \"linear\" \n -fogStart 0\n -fogEnd 100\n -fogDensity 0.1\n -fogColor 0.5 0.5 0.5 1 \n -depthOfFieldPreview 1\n -maxConstantTransparency 1\n -rendererName \"vp2Renderer\" \n -objectFilterShowInHUD 1\n -isFiltered 0\n -colorResolution 256 256 \n -bumpResolution 512 512 \n -textureCompression 0\n -transparencyAlgorithm \"frontAndBackCull\" \n -transpInShadows 0\n -cullingOverride \"none\" \n -lowQualityLighting 0\n -maximumNumHardwareLights 1\n -occlusionCulling 0\n" - + " -shadingModel 0\n -useBaseRenderer 0\n -useReducedRenderer 0\n -smallObjectCulling 0\n -smallObjectThreshold -1 \n -interactiveDisableShadows 0\n -interactiveBackFaceCull 0\n -sortTransparent 1\n -controllers 1\n -nurbsCurves 1\n -nurbsSurfaces 1\n -polymeshes 1\n -subdivSurfaces 1\n -planes 1\n -lights 1\n -cameras 1\n -controlVertices 1\n -hulls 1\n -grid 1\n -imagePlane 1\n -joints 1\n -ikHandles 1\n -deformers 1\n -dynamics 1\n -particleInstancers 1\n -fluids 1\n -hairSystems 1\n -follicles 1\n -nCloths 1\n -nParticles 1\n -nRigids 1\n -dynamicConstraints 1\n -locators 1\n -manipulators 1\n -pluginShapes 1\n -dimensions 1\n -handles 1\n -pivots 1\n" - + " -textures 1\n -strokes 1\n -motionTrails 1\n -clipGhosts 1\n -greasePencils 1\n -shadows 0\n -captureSequenceNumber -1\n -width 1\n -height 1\n -sceneRenderFilter 0\n $editorName;\n modelEditor -e -viewSelected 0 $editorName;\n modelEditor -e \n -pluginObjects \"gpuCacheDisplayFilter\" 1 \n $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextPanel \"modelPanel\" (localizedPanelLabel(\"Persp View\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tmodelPanel -edit -l (localizedPanelLabel(\"Persp View\")) -mbv $menusOkayInPanels $panelName;\n\t\t$editorName = $panelName;\n modelEditor -e \n -camera \"|persp\" \n -useInteractiveMode 0\n -displayLights \"default\" \n -displayAppearance \"smoothShaded\" \n -activeOnly 0\n -ignorePanZoom 0\n" - + " -wireframeOnShaded 0\n -headsUpDisplay 1\n -holdOuts 1\n -selectionHiliteDisplay 1\n -useDefaultMaterial 0\n -bufferMode \"double\" \n -twoSidedLighting 0\n -backfaceCulling 0\n -xray 0\n -jointXray 0\n -activeComponentsXray 0\n -displayTextures 0\n -smoothWireframe 0\n -lineWidth 1\n -textureAnisotropic 0\n -textureHilight 1\n -textureSampling 2\n -textureDisplay \"modulate\" \n -textureMaxSize 16384\n -fogging 0\n -fogSource \"fragment\" \n -fogMode \"linear\" \n -fogStart 0\n -fogEnd 100\n -fogDensity 0.1\n -fogColor 0.5 0.5 0.5 1 \n -depthOfFieldPreview 1\n -maxConstantTransparency 1\n -rendererName \"vp2Renderer\" \n -objectFilterShowInHUD 1\n -isFiltered 0\n -colorResolution 256 256 \n -bumpResolution 512 512 \n" - + " -textureCompression 0\n -transparencyAlgorithm \"frontAndBackCull\" \n -transpInShadows 0\n -cullingOverride \"none\" \n -lowQualityLighting 0\n -maximumNumHardwareLights 1\n -occlusionCulling 0\n -shadingModel 0\n -useBaseRenderer 0\n -useReducedRenderer 0\n -smallObjectCulling 0\n -smallObjectThreshold -1 \n -interactiveDisableShadows 0\n -interactiveBackFaceCull 0\n -sortTransparent 1\n -controllers 1\n -nurbsCurves 1\n -nurbsSurfaces 1\n -polymeshes 1\n -subdivSurfaces 1\n -planes 1\n -lights 1\n -cameras 1\n -controlVertices 1\n -hulls 1\n -grid 1\n -imagePlane 1\n -joints 1\n -ikHandles 1\n -deformers 1\n -dynamics 1\n -particleInstancers 1\n -fluids 1\n -hairSystems 1\n -follicles 1\n" - + " -nCloths 1\n -nParticles 1\n -nRigids 1\n -dynamicConstraints 1\n -locators 1\n -manipulators 1\n -pluginShapes 1\n -dimensions 1\n -handles 1\n -pivots 1\n -textures 1\n -strokes 1\n -motionTrails 1\n -clipGhosts 1\n -greasePencils 1\n -shadows 0\n -captureSequenceNumber -1\n -width 1312\n -height 732\n -sceneRenderFilter 0\n $editorName;\n modelEditor -e -viewSelected 0 $editorName;\n modelEditor -e \n -pluginObjects \"gpuCacheDisplayFilter\" 1 \n $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextPanel \"outlinerPanel\" (localizedPanelLabel(\"ToggledOutliner\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\toutlinerPanel -edit -l (localizedPanelLabel(\"ToggledOutliner\")) -mbv $menusOkayInPanels $panelName;\n" - + "\t\t$editorName = $panelName;\n outlinerEditor -e \n -docTag \"isolOutln_fromSeln\" \n -showShapes 0\n -showAssignedMaterials 0\n -showTimeEditor 1\n -showReferenceNodes 1\n -showReferenceMembers 1\n -showAttributes 0\n -showConnected 0\n -showAnimCurvesOnly 0\n -showMuteInfo 0\n -organizeByLayer 1\n -organizeByClip 1\n -showAnimLayerWeight 1\n -autoExpandLayers 1\n -autoExpand 0\n -showDagOnly 1\n -showAssets 1\n -showContainedOnly 1\n -showPublishedAsConnected 0\n -showParentContainers 0\n -showContainerContents 1\n -ignoreDagHierarchy 0\n -expandConnections 0\n -showUpstreamCurves 1\n -showUnitlessCurves 1\n -showCompounds 1\n -showLeafs 1\n -showNumericAttrsOnly 0\n -highlightActive 1\n -autoSelectNewObjects 0\n" - + " -doNotSelectNewObjects 0\n -dropIsParent 1\n -transmitFilters 0\n -setFilter \"defaultSetFilter\" \n -showSetMembers 1\n -allowMultiSelection 1\n -alwaysToggleSelect 0\n -directSelect 0\n -isSet 0\n -isSetMember 0\n -displayMode \"DAG\" \n -expandObjects 0\n -setsIgnoreFilters 1\n -containersIgnoreFilters 0\n -editAttrName 0\n -showAttrValues 0\n -highlightSecondary 0\n -showUVAttrsOnly 0\n -showTextureNodesOnly 0\n -attrAlphaOrder \"default\" \n -animLayerFilterOptions \"allAffecting\" \n -sortOrder \"none\" \n -longNames 0\n -niceNames 1\n -selectCommand \"print(\\\"\\\")\" \n -showNamespace 1\n -showPinIcons 0\n -mapMotionTrails 0\n -ignoreHiddenAttribute 1\n -ignoreOutlinerColor 0\n -renderFilterVisible 0\n -renderFilterIndex 0\n" - + " -selectionOrder \"chronological\" \n -expandAttribute 0\n $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextPanel \"outlinerPanel\" (localizedPanelLabel(\"Outliner\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\toutlinerPanel -edit -l (localizedPanelLabel(\"Outliner\")) -mbv $menusOkayInPanels $panelName;\n\t\t$editorName = $panelName;\n outlinerEditor -e \n -showShapes 0\n -showAssignedMaterials 0\n -showTimeEditor 1\n -showReferenceNodes 0\n -showReferenceMembers 0\n -showAttributes 0\n -showConnected 0\n -showAnimCurvesOnly 0\n -showMuteInfo 0\n -organizeByLayer 1\n -organizeByClip 1\n -showAnimLayerWeight 1\n -autoExpandLayers 1\n -autoExpand 0\n -showDagOnly 1\n -showAssets 1\n -showContainedOnly 1\n -showPublishedAsConnected 0\n" - + " -showParentContainers 0\n -showContainerContents 1\n -ignoreDagHierarchy 0\n -expandConnections 0\n -showUpstreamCurves 1\n -showUnitlessCurves 1\n -showCompounds 1\n -showLeafs 1\n -showNumericAttrsOnly 0\n -highlightActive 1\n -autoSelectNewObjects 0\n -doNotSelectNewObjects 0\n -dropIsParent 1\n -transmitFilters 0\n -setFilter \"defaultSetFilter\" \n -showSetMembers 1\n -allowMultiSelection 1\n -alwaysToggleSelect 0\n -directSelect 0\n -displayMode \"DAG\" \n -expandObjects 0\n -setsIgnoreFilters 1\n -containersIgnoreFilters 0\n -editAttrName 0\n -showAttrValues 0\n -highlightSecondary 0\n -showUVAttrsOnly 0\n -showTextureNodesOnly 0\n -attrAlphaOrder \"default\" \n -animLayerFilterOptions \"allAffecting\" \n -sortOrder \"none\" \n" - + " -longNames 0\n -niceNames 1\n -showNamespace 1\n -showPinIcons 0\n -mapMotionTrails 0\n -ignoreHiddenAttribute 0\n -ignoreOutlinerColor 0\n -renderFilterVisible 0\n $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"graphEditor\" (localizedPanelLabel(\"Graph Editor\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Graph Editor\")) -mbv $menusOkayInPanels $panelName;\n\n\t\t\t$editorName = ($panelName+\"OutlineEd\");\n outlinerEditor -e \n -showShapes 1\n -showAssignedMaterials 0\n -showTimeEditor 1\n -showReferenceNodes 0\n -showReferenceMembers 0\n -showAttributes 1\n -showConnected 1\n -showAnimCurvesOnly 1\n -showMuteInfo 0\n -organizeByLayer 1\n" - + " -organizeByClip 1\n -showAnimLayerWeight 1\n -autoExpandLayers 1\n -autoExpand 1\n -showDagOnly 0\n -showAssets 1\n -showContainedOnly 0\n -showPublishedAsConnected 0\n -showParentContainers 0\n -showContainerContents 0\n -ignoreDagHierarchy 0\n -expandConnections 1\n -showUpstreamCurves 1\n -showUnitlessCurves 1\n -showCompounds 0\n -showLeafs 1\n -showNumericAttrsOnly 1\n -highlightActive 0\n -autoSelectNewObjects 1\n -doNotSelectNewObjects 0\n -dropIsParent 1\n -transmitFilters 1\n -setFilter \"0\" \n -showSetMembers 0\n -allowMultiSelection 1\n -alwaysToggleSelect 0\n -directSelect 0\n -displayMode \"DAG\" \n -expandObjects 0\n" - + " -setsIgnoreFilters 1\n -containersIgnoreFilters 0\n -editAttrName 0\n -showAttrValues 0\n -highlightSecondary 0\n -showUVAttrsOnly 0\n -showTextureNodesOnly 0\n -attrAlphaOrder \"default\" \n -animLayerFilterOptions \"allAffecting\" \n -sortOrder \"none\" \n -longNames 0\n -niceNames 1\n -showNamespace 1\n -showPinIcons 1\n -mapMotionTrails 1\n -ignoreHiddenAttribute 0\n -ignoreOutlinerColor 0\n -renderFilterVisible 0\n $editorName;\n\n\t\t\t$editorName = ($panelName+\"GraphEd\");\n animCurveEditor -e \n -displayValues 0\n -snapTime \"integer\" \n -snapValue \"none\" \n -showPlayRangeShades \"on\" \n -lockPlayRangeShades \"off\" \n -smoothness \"fine\" \n -resultSamples 1.041667\n" - + " -resultScreenSamples 0\n -resultUpdate \"delayed\" \n -showUpstreamCurves 1\n -keyMinScale 1\n -stackedCurvesMin -1\n -stackedCurvesMax 1\n -stackedCurvesSpace 0.2\n -preSelectionHighlight 0\n -constrainDrag 0\n -valueLinesToggle 1\n -highlightAffectedCurves 0\n $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"dopeSheetPanel\" (localizedPanelLabel(\"Dope Sheet\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Dope Sheet\")) -mbv $menusOkayInPanels $panelName;\n\n\t\t\t$editorName = ($panelName+\"OutlineEd\");\n outlinerEditor -e \n -showShapes 1\n -showAssignedMaterials 0\n -showTimeEditor 1\n -showReferenceNodes 0\n -showReferenceMembers 0\n" - + " -showAttributes 1\n -showConnected 1\n -showAnimCurvesOnly 1\n -showMuteInfo 0\n -organizeByLayer 1\n -organizeByClip 1\n -showAnimLayerWeight 1\n -autoExpandLayers 1\n -autoExpand 0\n -showDagOnly 0\n -showAssets 1\n -showContainedOnly 0\n -showPublishedAsConnected 0\n -showParentContainers 0\n -showContainerContents 0\n -ignoreDagHierarchy 0\n -expandConnections 1\n -showUpstreamCurves 1\n -showUnitlessCurves 0\n -showCompounds 1\n -showLeafs 1\n -showNumericAttrsOnly 1\n -highlightActive 0\n -autoSelectNewObjects 0\n -doNotSelectNewObjects 1\n -dropIsParent 1\n -transmitFilters 0\n -setFilter \"0\" \n -showSetMembers 0\n" - + " -allowMultiSelection 1\n -alwaysToggleSelect 0\n -directSelect 0\n -displayMode \"DAG\" \n -expandObjects 0\n -setsIgnoreFilters 1\n -containersIgnoreFilters 0\n -editAttrName 0\n -showAttrValues 0\n -highlightSecondary 0\n -showUVAttrsOnly 0\n -showTextureNodesOnly 0\n -attrAlphaOrder \"default\" \n -animLayerFilterOptions \"allAffecting\" \n -sortOrder \"none\" \n -longNames 0\n -niceNames 1\n -showNamespace 1\n -showPinIcons 0\n -mapMotionTrails 1\n -ignoreHiddenAttribute 0\n -ignoreOutlinerColor 0\n -renderFilterVisible 0\n $editorName;\n\n\t\t\t$editorName = ($panelName+\"DopeSheetEd\");\n dopeSheetEditor -e \n -displayValues 0\n -snapTime \"integer\" \n" - + " -snapValue \"none\" \n -outliner \"dopeSheetPanel1OutlineEd\" \n -showSummary 1\n -showScene 0\n -hierarchyBelow 0\n -showTicks 1\n -selectionWindow 0 0 0 0 \n $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"timeEditorPanel\" (localizedPanelLabel(\"Time Editor\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Time Editor\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"clipEditorPanel\" (localizedPanelLabel(\"Trax Editor\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Trax Editor\")) -mbv $menusOkayInPanels $panelName;\n\n\t\t\t$editorName = clipEditorNameFromPanel($panelName);\n" - + " clipEditor -e \n -displayValues 0\n -snapTime \"none\" \n -snapValue \"none\" \n -initialized 0\n -manageSequencer 0 \n $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"sequenceEditorPanel\" (localizedPanelLabel(\"Camera Sequencer\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Camera Sequencer\")) -mbv $menusOkayInPanels $panelName;\n\n\t\t\t$editorName = sequenceEditorNameFromPanel($panelName);\n clipEditor -e \n -displayValues 0\n -snapTime \"none\" \n -snapValue \"none\" \n -initialized 0\n -manageSequencer 1 \n $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"hyperGraphPanel\" (localizedPanelLabel(\"Hypergraph Hierarchy\")) `;\n" - + "\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Hypergraph Hierarchy\")) -mbv $menusOkayInPanels $panelName;\n\n\t\t\t$editorName = ($panelName+\"HyperGraphEd\");\n hyperGraph -e \n -graphLayoutStyle \"hierarchicalLayout\" \n -orientation \"horiz\" \n -mergeConnections 0\n -zoom 1\n -animateTransition 0\n -showRelationships 1\n -showShapes 0\n -showDeformers 0\n -showExpressions 0\n -showConstraints 0\n -showConnectionFromSelected 0\n -showConnectionToSelected 0\n -showConstraintLabels 0\n -showUnderworld 0\n -showInvisible 0\n -transitionFrames 1\n -opaqueContainers 0\n -freeform 0\n -imagePosition 0 0 \n -imageScale 1\n -imageEnabled 0\n -graphType \"DAG\" \n" - + " -heatMapDisplay 0\n -updateSelection 1\n -updateNodeAdded 1\n -useDrawOverrideColor 0\n -limitGraphTraversal -1\n -range 0 0 \n -iconSize \"smallIcons\" \n -showCachedConnections 0\n $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"hyperShadePanel\" (localizedPanelLabel(\"Hypershade\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Hypershade\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"visorPanel\" (localizedPanelLabel(\"Visor\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Visor\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n" - + "\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"nodeEditorPanel\" (localizedPanelLabel(\"Node Editor\")) `;\n\tif ($nodeEditorPanelVisible || $nodeEditorWorkspaceControlOpen) {\n\t\tif (\"\" == $panelName) {\n\t\t\tif ($useSceneConfig) {\n\t\t\t\t$panelName = `scriptedPanel -unParent -type \"nodeEditorPanel\" -l (localizedPanelLabel(\"Node Editor\")) -mbv $menusOkayInPanels `;\n\n\t\t\t$editorName = ($panelName+\"NodeEditorEd\");\n nodeEditor -e \n -allAttributes 0\n -allNodes 0\n -autoSizeNodes 1\n -consistentNameSize 1\n -createNodeCommand \"nodeEdCreateNodeCommand\" \n -connectNodeOnCreation 0\n -connectOnDrop 0\n -copyConnectionsOnPaste 0\n -connectionStyle \"bezier\" \n -defaultPinnedState 0\n -additiveGraphingMode 0\n -settingsChangedCallback \"nodeEdSyncControls\" \n -traversalDepthLimit -1\n -keyPressCommand \"nodeEdKeyPressCommand\" \n" - + " -nodeTitleMode \"name\" \n -gridSnap 0\n -gridVisibility 1\n -crosshairOnEdgeDragging 0\n -popupMenuScript \"nodeEdBuildPanelMenus\" \n -showNamespace 1\n -showShapes 1\n -showSGShapes 0\n -showTransforms 1\n -useAssets 1\n -syncedSelection 1\n -extendToShapes 1\n -editorMode \"default\" \n -hasWatchpoint 0\n $editorName;\n\t\t\t}\n\t\t} else {\n\t\t\t$label = `panel -q -label $panelName`;\n\t\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Node Editor\")) -mbv $menusOkayInPanels $panelName;\n\n\t\t\t$editorName = ($panelName+\"NodeEditorEd\");\n nodeEditor -e \n -allAttributes 0\n -allNodes 0\n -autoSizeNodes 1\n -consistentNameSize 1\n -createNodeCommand \"nodeEdCreateNodeCommand\" \n -connectNodeOnCreation 0\n -connectOnDrop 0\n" - + " -copyConnectionsOnPaste 0\n -connectionStyle \"bezier\" \n -defaultPinnedState 0\n -additiveGraphingMode 0\n -settingsChangedCallback \"nodeEdSyncControls\" \n -traversalDepthLimit -1\n -keyPressCommand \"nodeEdKeyPressCommand\" \n -nodeTitleMode \"name\" \n -gridSnap 0\n -gridVisibility 1\n -crosshairOnEdgeDragging 0\n -popupMenuScript \"nodeEdBuildPanelMenus\" \n -showNamespace 1\n -showShapes 1\n -showSGShapes 0\n -showTransforms 1\n -useAssets 1\n -syncedSelection 1\n -extendToShapes 1\n -editorMode \"default\" \n -hasWatchpoint 0\n $editorName;\n\t\t\tif (!$useSceneConfig) {\n\t\t\t\tpanel -e -l $label $panelName;\n\t\t\t}\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"createNodePanel\" (localizedPanelLabel(\"Create Node\")) `;\n" - + "\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Create Node\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"polyTexturePlacementPanel\" (localizedPanelLabel(\"UV Editor\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"UV Editor\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"renderWindowPanel\" (localizedPanelLabel(\"Render View\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Render View\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextPanel \"shapePanel\" (localizedPanelLabel(\"Shape Editor\")) `;\n" - + "\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tshapePanel -edit -l (localizedPanelLabel(\"Shape Editor\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextPanel \"posePanel\" (localizedPanelLabel(\"Pose Editor\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tposePanel -edit -l (localizedPanelLabel(\"Pose Editor\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"dynRelEdPanel\" (localizedPanelLabel(\"Dynamic Relationships\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Dynamic Relationships\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"relationshipPanel\" (localizedPanelLabel(\"Relationship Editor\")) `;\n" - + "\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Relationship Editor\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"referenceEditorPanel\" (localizedPanelLabel(\"Reference Editor\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Reference Editor\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"componentEditorPanel\" (localizedPanelLabel(\"Component Editor\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Component Editor\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"dynPaintScriptedPanelType\" (localizedPanelLabel(\"Paint Effects\")) `;\n" - + "\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Paint Effects\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"scriptEditorPanel\" (localizedPanelLabel(\"Script Editor\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Script Editor\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"profilerPanel\" (localizedPanelLabel(\"Profiler Tool\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Profiler Tool\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"contentBrowserPanel\" (localizedPanelLabel(\"Content Browser\")) `;\n" - + "\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Content Browser\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"Stereo\" (localizedPanelLabel(\"Stereo\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Stereo\")) -mbv $menusOkayInPanels $panelName;\n{ string $editorName = ($panelName+\"Editor\");\n stereoCameraView -e \n -camera \"|persp\" \n -useInteractiveMode 0\n -displayLights \"default\" \n -displayAppearance \"wireframe\" \n -activeOnly 0\n -ignorePanZoom 0\n -wireframeOnShaded 0\n -headsUpDisplay 1\n -holdOuts 1\n -selectionHiliteDisplay 1\n -useDefaultMaterial 0\n -bufferMode \"double\" \n -twoSidedLighting 1\n" - + " -backfaceCulling 0\n -xray 0\n -jointXray 0\n -activeComponentsXray 0\n -displayTextures 0\n -smoothWireframe 0\n -lineWidth 1\n -textureAnisotropic 0\n -textureHilight 1\n -textureSampling 2\n -textureDisplay \"modulate\" \n -textureMaxSize 16384\n -fogging 0\n -fogSource \"fragment\" \n -fogMode \"linear\" \n -fogStart 0\n -fogEnd 100\n -fogDensity 0.1\n -fogColor 0.5 0.5 0.5 1 \n -depthOfFieldPreview 1\n -maxConstantTransparency 1\n -objectFilterShowInHUD 1\n -isFiltered 0\n -colorResolution 4 4 \n -bumpResolution 4 4 \n -textureCompression 0\n -transparencyAlgorithm \"frontAndBackCull\" \n -transpInShadows 0\n -cullingOverride \"none\" \n" - + " -lowQualityLighting 0\n -maximumNumHardwareLights 0\n -occlusionCulling 0\n -shadingModel 0\n -useBaseRenderer 0\n -useReducedRenderer 0\n -smallObjectCulling 0\n -smallObjectThreshold -1 \n -interactiveDisableShadows 0\n -interactiveBackFaceCull 0\n -sortTransparent 1\n -controllers 1\n -nurbsCurves 1\n -nurbsSurfaces 1\n -polymeshes 1\n -subdivSurfaces 1\n -planes 1\n -lights 1\n -cameras 1\n -controlVertices 1\n -hulls 1\n -grid 1\n -imagePlane 1\n -joints 1\n -ikHandles 1\n -deformers 1\n -dynamics 1\n -particleInstancers 1\n -fluids 1\n -hairSystems 1\n -follicles 1\n -nCloths 1\n" - + " -nParticles 1\n -nRigids 1\n -dynamicConstraints 1\n -locators 1\n -manipulators 1\n -pluginShapes 1\n -dimensions 1\n -handles 1\n -pivots 1\n -textures 1\n -strokes 1\n -motionTrails 1\n -clipGhosts 1\n -greasePencils 1\n -shadows 0\n -captureSequenceNumber -1\n -width 0\n -height 0\n -sceneRenderFilter 0\n -displayMode \"centerEye\" \n -viewColor 0 0 0 1 \n -useCustomBackground 1\n $editorName;\n stereoCameraView -e -viewSelected 0 $editorName;\n stereoCameraView -e \n -pluginObjects \"gpuCacheDisplayFilter\" 1 \n $editorName; };\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\tif ($useSceneConfig) {\n string $configName = `getPanel -cwl (localizedPanelLabel(\"Current Layout\"))`;\n" - + " if (\"\" != $configName) {\n\t\t\tpanelConfiguration -edit -label (localizedPanelLabel(\"Current Layout\")) \n\t\t\t\t-userCreated false\n\t\t\t\t-defaultImage \"vacantCell.xP:/\"\n\t\t\t\t-image \"\"\n\t\t\t\t-sc false\n\t\t\t\t-configString \"global string $gMainPane; paneLayout -e -cn \\\"single\\\" -ps 1 100 100 $gMainPane;\"\n\t\t\t\t-removeAllPanels\n\t\t\t\t-ap false\n\t\t\t\t\t(localizedPanelLabel(\"Persp View\")) \n\t\t\t\t\t\"modelPanel\"\n" - + "\t\t\t\t\t\"$panelName = `modelPanel -unParent -l (localizedPanelLabel(\\\"Persp View\\\")) -mbv $menusOkayInPanels `;\\n$editorName = $panelName;\\nmodelEditor -e \\n -cam `findStartUpCamera persp` \\n -useInteractiveMode 0\\n -displayLights \\\"default\\\" \\n -displayAppearance \\\"smoothShaded\\\" \\n -activeOnly 0\\n -ignorePanZoom 0\\n -wireframeOnShaded 0\\n -headsUpDisplay 1\\n -holdOuts 1\\n -selectionHiliteDisplay 1\\n -useDefaultMaterial 0\\n -bufferMode \\\"double\\\" \\n -twoSidedLighting 0\\n -backfaceCulling 0\\n -xray 0\\n -jointXray 0\\n -activeComponentsXray 0\\n -displayTextures 0\\n -smoothWireframe 0\\n -lineWidth 1\\n -textureAnisotropic 0\\n -textureHilight 1\\n -textureSampling 2\\n -textureDisplay \\\"modulate\\\" \\n -textureMaxSize 16384\\n -fogging 0\\n -fogSource \\\"fragment\\\" \\n -fogMode \\\"linear\\\" \\n -fogStart 0\\n -fogEnd 100\\n -fogDensity 0.1\\n -fogColor 0.5 0.5 0.5 1 \\n -depthOfFieldPreview 1\\n -maxConstantTransparency 1\\n -rendererName \\\"vp2Renderer\\\" \\n -objectFilterShowInHUD 1\\n -isFiltered 0\\n -colorResolution 256 256 \\n -bumpResolution 512 512 \\n -textureCompression 0\\n -transparencyAlgorithm \\\"frontAndBackCull\\\" \\n -transpInShadows 0\\n -cullingOverride \\\"none\\\" \\n -lowQualityLighting 0\\n -maximumNumHardwareLights 1\\n -occlusionCulling 0\\n -shadingModel 0\\n -useBaseRenderer 0\\n -useReducedRenderer 0\\n -smallObjectCulling 0\\n -smallObjectThreshold -1 \\n -interactiveDisableShadows 0\\n -interactiveBackFaceCull 0\\n -sortTransparent 1\\n -controllers 1\\n -nurbsCurves 1\\n -nurbsSurfaces 1\\n -polymeshes 1\\n -subdivSurfaces 1\\n -planes 1\\n -lights 1\\n -cameras 1\\n -controlVertices 1\\n -hulls 1\\n -grid 1\\n -imagePlane 1\\n -joints 1\\n -ikHandles 1\\n -deformers 1\\n -dynamics 1\\n -particleInstancers 1\\n -fluids 1\\n -hairSystems 1\\n -follicles 1\\n -nCloths 1\\n -nParticles 1\\n -nRigids 1\\n -dynamicConstraints 1\\n -locators 1\\n -manipulators 1\\n -pluginShapes 1\\n -dimensions 1\\n -handles 1\\n -pivots 1\\n -textures 1\\n -strokes 1\\n -motionTrails 1\\n -clipGhosts 1\\n -greasePencils 1\\n -shadows 0\\n -captureSequenceNumber -1\\n -width 1312\\n -height 732\\n -sceneRenderFilter 0\\n $editorName;\\nmodelEditor -e -viewSelected 0 $editorName;\\nmodelEditor -e \\n -pluginObjects \\\"gpuCacheDisplayFilter\\\" 1 \\n $editorName\"\n" - + "\t\t\t\t\t\"modelPanel -edit -l (localizedPanelLabel(\\\"Persp View\\\")) -mbv $menusOkayInPanels $panelName;\\n$editorName = $panelName;\\nmodelEditor -e \\n -cam `findStartUpCamera persp` \\n -useInteractiveMode 0\\n -displayLights \\\"default\\\" \\n -displayAppearance \\\"smoothShaded\\\" \\n -activeOnly 0\\n -ignorePanZoom 0\\n -wireframeOnShaded 0\\n -headsUpDisplay 1\\n -holdOuts 1\\n -selectionHiliteDisplay 1\\n -useDefaultMaterial 0\\n -bufferMode \\\"double\\\" \\n -twoSidedLighting 0\\n -backfaceCulling 0\\n -xray 0\\n -jointXray 0\\n -activeComponentsXray 0\\n -displayTextures 0\\n -smoothWireframe 0\\n -lineWidth 1\\n -textureAnisotropic 0\\n -textureHilight 1\\n -textureSampling 2\\n -textureDisplay \\\"modulate\\\" \\n -textureMaxSize 16384\\n -fogging 0\\n -fogSource \\\"fragment\\\" \\n -fogMode \\\"linear\\\" \\n -fogStart 0\\n -fogEnd 100\\n -fogDensity 0.1\\n -fogColor 0.5 0.5 0.5 1 \\n -depthOfFieldPreview 1\\n -maxConstantTransparency 1\\n -rendererName \\\"vp2Renderer\\\" \\n -objectFilterShowInHUD 1\\n -isFiltered 0\\n -colorResolution 256 256 \\n -bumpResolution 512 512 \\n -textureCompression 0\\n -transparencyAlgorithm \\\"frontAndBackCull\\\" \\n -transpInShadows 0\\n -cullingOverride \\\"none\\\" \\n -lowQualityLighting 0\\n -maximumNumHardwareLights 1\\n -occlusionCulling 0\\n -shadingModel 0\\n -useBaseRenderer 0\\n -useReducedRenderer 0\\n -smallObjectCulling 0\\n -smallObjectThreshold -1 \\n -interactiveDisableShadows 0\\n -interactiveBackFaceCull 0\\n -sortTransparent 1\\n -controllers 1\\n -nurbsCurves 1\\n -nurbsSurfaces 1\\n -polymeshes 1\\n -subdivSurfaces 1\\n -planes 1\\n -lights 1\\n -cameras 1\\n -controlVertices 1\\n -hulls 1\\n -grid 1\\n -imagePlane 1\\n -joints 1\\n -ikHandles 1\\n -deformers 1\\n -dynamics 1\\n -particleInstancers 1\\n -fluids 1\\n -hairSystems 1\\n -follicles 1\\n -nCloths 1\\n -nParticles 1\\n -nRigids 1\\n -dynamicConstraints 1\\n -locators 1\\n -manipulators 1\\n -pluginShapes 1\\n -dimensions 1\\n -handles 1\\n -pivots 1\\n -textures 1\\n -strokes 1\\n -motionTrails 1\\n -clipGhosts 1\\n -greasePencils 1\\n -shadows 0\\n -captureSequenceNumber -1\\n -width 1312\\n -height 732\\n -sceneRenderFilter 0\\n $editorName;\\nmodelEditor -e -viewSelected 0 $editorName;\\nmodelEditor -e \\n -pluginObjects \\\"gpuCacheDisplayFilter\\\" 1 \\n $editorName\"\n" + + " -hulls 1\n -grid 1\n -imagePlane 1\n -joints 1\n -ikHandles 1\n -deformers 1\n -dynamics 1\n -particleInstancers 1\n -fluids 1\n -hairSystems 1\n -follicles 1\n -nCloths 1\n -nParticles 1\n -nRigids 1\n -dynamicConstraints 1\n -locators 1\n -manipulators 1\n -pluginShapes 1\n -dimensions 1\n -handles 1\n -pivots 1\n -textures 1\n -strokes 1\n -motionTrails 1\n -clipGhosts 1\n -bluePencil 1\n -greasePencils 0\n -shadows 0\n -captureSequenceNumber -1\n -width 477\n -height 276\n -sceneRenderFilter 0\n $editorName;\n modelEditor -e -viewSelected 0 $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextPanel \"modelPanel\" (localizedPanelLabel(\"Side View\")) `;\n" + + "\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tmodelPanel -edit -l (localizedPanelLabel(\"Side View\")) -mbv $menusOkayInPanels $panelName;\n\t\t$editorName = $panelName;\n modelEditor -e \n -camera \"|side\" \n -useInteractiveMode 0\n -displayLights \"default\" \n -displayAppearance \"smoothShaded\" \n -activeOnly 0\n -ignorePanZoom 0\n -wireframeOnShaded 0\n -headsUpDisplay 1\n -holdOuts 1\n -selectionHiliteDisplay 1\n -useDefaultMaterial 0\n -bufferMode \"double\" \n -twoSidedLighting 0\n -backfaceCulling 0\n -xray 0\n -jointXray 0\n -activeComponentsXray 0\n -displayTextures 0\n -smoothWireframe 0\n -lineWidth 1\n -textureAnisotropic 0\n -textureHilight 1\n -textureSampling 2\n -textureDisplay \"modulate\" \n -textureMaxSize 32768\n -fogging 0\n" + + " -fogSource \"fragment\" \n -fogMode \"linear\" \n -fogStart 0\n -fogEnd 100\n -fogDensity 0.1\n -fogColor 0.5 0.5 0.5 1 \n -depthOfFieldPreview 1\n -maxConstantTransparency 1\n -rendererName \"vp2Renderer\" \n -objectFilterShowInHUD 1\n -isFiltered 0\n -colorResolution 256 256 \n -bumpResolution 512 512 \n -textureCompression 0\n -transparencyAlgorithm \"frontAndBackCull\" \n -transpInShadows 0\n -cullingOverride \"none\" \n -lowQualityLighting 0\n -maximumNumHardwareLights 1\n -occlusionCulling 0\n -shadingModel 0\n -useBaseRenderer 0\n -useReducedRenderer 0\n -smallObjectCulling 0\n -smallObjectThreshold -1 \n -interactiveDisableShadows 0\n -interactiveBackFaceCull 0\n -sortTransparent 1\n -controllers 1\n -nurbsCurves 1\n" + + " -nurbsSurfaces 1\n -polymeshes 1\n -subdivSurfaces 1\n -planes 1\n -lights 1\n -cameras 1\n -controlVertices 1\n -hulls 1\n -grid 1\n -imagePlane 1\n -joints 1\n -ikHandles 1\n -deformers 1\n -dynamics 1\n -particleInstancers 1\n -fluids 1\n -hairSystems 1\n -follicles 1\n -nCloths 1\n -nParticles 1\n -nRigids 1\n -dynamicConstraints 1\n -locators 1\n -manipulators 1\n -pluginShapes 1\n -dimensions 1\n -handles 1\n -pivots 1\n -textures 1\n -strokes 1\n -motionTrails 1\n -clipGhosts 1\n -bluePencil 1\n -greasePencils 0\n -shadows 0\n -captureSequenceNumber -1\n -width 476\n -height 276\n -sceneRenderFilter 0\n $editorName;\n" + + " modelEditor -e -viewSelected 0 $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextPanel \"modelPanel\" (localizedPanelLabel(\"Front View\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tmodelPanel -edit -l (localizedPanelLabel(\"Front View\")) -mbv $menusOkayInPanels $panelName;\n\t\t$editorName = $panelName;\n modelEditor -e \n -camera \"|front\" \n -useInteractiveMode 0\n -displayLights \"default\" \n -displayAppearance \"smoothShaded\" \n -activeOnly 0\n -ignorePanZoom 0\n -wireframeOnShaded 0\n -headsUpDisplay 1\n -holdOuts 1\n -selectionHiliteDisplay 1\n -useDefaultMaterial 0\n -bufferMode \"double\" \n -twoSidedLighting 0\n -backfaceCulling 0\n -xray 0\n -jointXray 0\n -activeComponentsXray 0\n -displayTextures 0\n -smoothWireframe 0\n" + + " -lineWidth 1\n -textureAnisotropic 0\n -textureHilight 1\n -textureSampling 2\n -textureDisplay \"modulate\" \n -textureMaxSize 32768\n -fogging 0\n -fogSource \"fragment\" \n -fogMode \"linear\" \n -fogStart 0\n -fogEnd 100\n -fogDensity 0.1\n -fogColor 0.5 0.5 0.5 1 \n -depthOfFieldPreview 1\n -maxConstantTransparency 1\n -rendererName \"vp2Renderer\" \n -objectFilterShowInHUD 1\n -isFiltered 0\n -colorResolution 256 256 \n -bumpResolution 512 512 \n -textureCompression 0\n -transparencyAlgorithm \"frontAndBackCull\" \n -transpInShadows 0\n -cullingOverride \"none\" \n -lowQualityLighting 0\n -maximumNumHardwareLights 1\n -occlusionCulling 0\n -shadingModel 0\n -useBaseRenderer 0\n -useReducedRenderer 0\n -smallObjectCulling 0\n" + + " -smallObjectThreshold -1 \n -interactiveDisableShadows 0\n -interactiveBackFaceCull 0\n -sortTransparent 1\n -controllers 1\n -nurbsCurves 1\n -nurbsSurfaces 1\n -polymeshes 1\n -subdivSurfaces 1\n -planes 1\n -lights 1\n -cameras 1\n -controlVertices 1\n -hulls 1\n -grid 1\n -imagePlane 1\n -joints 1\n -ikHandles 1\n -deformers 1\n -dynamics 1\n -particleInstancers 1\n -fluids 1\n -hairSystems 1\n -follicles 1\n -nCloths 1\n -nParticles 1\n -nRigids 1\n -dynamicConstraints 1\n -locators 1\n -manipulators 1\n -pluginShapes 1\n -dimensions 1\n -handles 1\n -pivots 1\n -textures 1\n -strokes 1\n -motionTrails 1\n -clipGhosts 1\n -bluePencil 1\n" + + " -greasePencils 0\n -shadows 0\n -captureSequenceNumber -1\n -width 477\n -height 276\n -sceneRenderFilter 0\n $editorName;\n modelEditor -e -viewSelected 0 $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextPanel \"modelPanel\" (localizedPanelLabel(\"Persp View\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tmodelPanel -edit -l (localizedPanelLabel(\"Persp View\")) -mbv $menusOkayInPanels $panelName;\n\t\t$editorName = $panelName;\n modelEditor -e \n -camera \"|persp\" \n -useInteractiveMode 0\n -displayLights \"default\" \n -displayAppearance \"smoothShaded\" \n -activeOnly 0\n -ignorePanZoom 0\n -wireframeOnShaded 0\n -headsUpDisplay 1\n -holdOuts 1\n -selectionHiliteDisplay 1\n -useDefaultMaterial 0\n -bufferMode \"double\" \n" + + " -twoSidedLighting 0\n -backfaceCulling 0\n -xray 0\n -jointXray 0\n -activeComponentsXray 0\n -displayTextures 0\n -smoothWireframe 0\n -lineWidth 1\n -textureAnisotropic 0\n -textureHilight 1\n -textureSampling 2\n -textureDisplay \"modulate\" \n -textureMaxSize 32768\n -fogging 0\n -fogSource \"fragment\" \n -fogMode \"linear\" \n -fogStart 0\n -fogEnd 100\n -fogDensity 0.1\n -fogColor 0.5 0.5 0.5 1 \n -depthOfFieldPreview 1\n -maxConstantTransparency 1\n -rendererName \"vp2Renderer\" \n -objectFilterShowInHUD 1\n -isFiltered 0\n -colorResolution 256 256 \n -bumpResolution 512 512 \n -textureCompression 0\n -transparencyAlgorithm \"frontAndBackCull\" \n -transpInShadows 0\n -cullingOverride \"none\" \n -lowQualityLighting 0\n" + + " -maximumNumHardwareLights 1\n -occlusionCulling 0\n -shadingModel 0\n -useBaseRenderer 0\n -useReducedRenderer 0\n -smallObjectCulling 0\n -smallObjectThreshold -1 \n -interactiveDisableShadows 0\n -interactiveBackFaceCull 0\n -sortTransparent 1\n -controllers 1\n -nurbsCurves 1\n -nurbsSurfaces 1\n -polymeshes 1\n -subdivSurfaces 1\n -planes 1\n -lights 1\n -cameras 1\n -controlVertices 1\n -hulls 1\n -grid 1\n -imagePlane 1\n -joints 1\n -ikHandles 1\n -deformers 1\n -dynamics 1\n -particleInstancers 1\n -fluids 1\n -hairSystems 1\n -follicles 1\n -nCloths 1\n -nParticles 1\n -nRigids 1\n -dynamicConstraints 1\n -locators 1\n -manipulators 1\n -pluginShapes 1\n" + + " -dimensions 1\n -handles 1\n -pivots 1\n -textures 1\n -strokes 1\n -motionTrails 1\n -clipGhosts 1\n -bluePencil 1\n -greasePencils 0\n -shadows 0\n -captureSequenceNumber -1\n -width 476\n -height 276\n -sceneRenderFilter 0\n $editorName;\n modelEditor -e -viewSelected 0 $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextPanel \"outlinerPanel\" (localizedPanelLabel(\"ToggledOutliner\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\toutlinerPanel -edit -l (localizedPanelLabel(\"ToggledOutliner\")) -mbv $menusOkayInPanels $panelName;\n\t\t$editorName = $panelName;\n outlinerEditor -e \n -docTag \"isolOutln_fromSeln\" \n -showShapes 0\n -showAssignedMaterials 0\n -showTimeEditor 1\n -showReferenceNodes 1\n -showReferenceMembers 1\n" + + " -showAttributes 0\n -showConnected 0\n -showAnimCurvesOnly 0\n -showMuteInfo 0\n -organizeByLayer 1\n -organizeByClip 1\n -showAnimLayerWeight 1\n -autoExpandLayers 1\n -autoExpand 0\n -showDagOnly 1\n -showAssets 1\n -showContainedOnly 1\n -showPublishedAsConnected 0\n -showParentContainers 0\n -showContainerContents 1\n -ignoreDagHierarchy 0\n -expandConnections 0\n -showUpstreamCurves 1\n -showUnitlessCurves 1\n -showCompounds 1\n -showLeafs 1\n -showNumericAttrsOnly 0\n -highlightActive 1\n -autoSelectNewObjects 0\n -doNotSelectNewObjects 0\n -dropIsParent 1\n -transmitFilters 0\n -setFilter \"defaultSetFilter\" \n -showSetMembers 1\n -allowMultiSelection 1\n -alwaysToggleSelect 0\n -directSelect 0\n" + + " -isSet 0\n -isSetMember 0\n -showUfeItems 1\n -displayMode \"DAG\" \n -expandObjects 0\n -setsIgnoreFilters 1\n -containersIgnoreFilters 0\n -editAttrName 0\n -showAttrValues 0\n -highlightSecondary 0\n -showUVAttrsOnly 0\n -showTextureNodesOnly 0\n -attrAlphaOrder \"default\" \n -animLayerFilterOptions \"allAffecting\" \n -sortOrder \"none\" \n -longNames 0\n -niceNames 1\n -selectCommand \"print(\\\"\\\")\" \n -showNamespace 1\n -showPinIcons 0\n -mapMotionTrails 0\n -ignoreHiddenAttribute 0\n -ignoreOutlinerColor 0\n -renderFilterVisible 0\n -renderFilterIndex 0\n -selectionOrder \"chronological\" \n -expandAttribute 0\n $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextPanel \"outlinerPanel\" (localizedPanelLabel(\"Outliner\")) `;\n" + + "\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\toutlinerPanel -edit -l (localizedPanelLabel(\"Outliner\")) -mbv $menusOkayInPanels $panelName;\n\t\t$editorName = $panelName;\n outlinerEditor -e \n -showShapes 0\n -showAssignedMaterials 0\n -showTimeEditor 1\n -showReferenceNodes 0\n -showReferenceMembers 0\n -showAttributes 0\n -showConnected 0\n -showAnimCurvesOnly 0\n -showMuteInfo 0\n -organizeByLayer 1\n -organizeByClip 1\n -showAnimLayerWeight 1\n -autoExpandLayers 1\n -autoExpand 0\n -showDagOnly 1\n -showAssets 1\n -showContainedOnly 1\n -showPublishedAsConnected 0\n -showParentContainers 0\n -showContainerContents 1\n -ignoreDagHierarchy 0\n -expandConnections 0\n -showUpstreamCurves 1\n -showUnitlessCurves 1\n -showCompounds 1\n -showLeafs 1\n" + + " -showNumericAttrsOnly 0\n -highlightActive 1\n -autoSelectNewObjects 0\n -doNotSelectNewObjects 0\n -dropIsParent 1\n -transmitFilters 0\n -setFilter \"defaultSetFilter\" \n -showSetMembers 1\n -allowMultiSelection 1\n -alwaysToggleSelect 0\n -directSelect 0\n -showUfeItems 1\n -displayMode \"DAG\" \n -expandObjects 0\n -setsIgnoreFilters 1\n -containersIgnoreFilters 0\n -editAttrName 0\n -showAttrValues 0\n -highlightSecondary 0\n -showUVAttrsOnly 0\n -showTextureNodesOnly 0\n -attrAlphaOrder \"default\" \n -animLayerFilterOptions \"allAffecting\" \n -sortOrder \"none\" \n -longNames 0\n -niceNames 1\n -showNamespace 1\n -showPinIcons 0\n -mapMotionTrails 0\n -ignoreHiddenAttribute 0\n -ignoreOutlinerColor 0\n -renderFilterVisible 0\n" + + " $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"graphEditor\" (localizedPanelLabel(\"Graph Editor\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Graph Editor\")) -mbv $menusOkayInPanels $panelName;\n\n\t\t\t$editorName = ($panelName+\"OutlineEd\");\n outlinerEditor -e \n -showShapes 1\n -showAssignedMaterials 0\n -showTimeEditor 1\n -showReferenceNodes 0\n -showReferenceMembers 0\n -showAttributes 1\n -showConnected 1\n -showAnimCurvesOnly 1\n -showMuteInfo 0\n -organizeByLayer 1\n -organizeByClip 1\n -showAnimLayerWeight 1\n -autoExpandLayers 1\n -autoExpand 1\n -showDagOnly 0\n -showAssets 1\n -showContainedOnly 0\n" + + " -showPublishedAsConnected 0\n -showParentContainers 0\n -showContainerContents 0\n -ignoreDagHierarchy 0\n -expandConnections 1\n -showUpstreamCurves 1\n -showUnitlessCurves 1\n -showCompounds 0\n -showLeafs 1\n -showNumericAttrsOnly 1\n -highlightActive 0\n -autoSelectNewObjects 1\n -doNotSelectNewObjects 0\n -dropIsParent 1\n -transmitFilters 1\n -setFilter \"0\" \n -showSetMembers 0\n -allowMultiSelection 1\n -alwaysToggleSelect 0\n -directSelect 0\n -showUfeItems 1\n -displayMode \"DAG\" \n -expandObjects 0\n -setsIgnoreFilters 1\n -containersIgnoreFilters 0\n -editAttrName 0\n -showAttrValues 0\n -highlightSecondary 0\n -showUVAttrsOnly 0\n" + + " -showTextureNodesOnly 0\n -attrAlphaOrder \"default\" \n -animLayerFilterOptions \"allAffecting\" \n -sortOrder \"none\" \n -longNames 0\n -niceNames 1\n -showNamespace 1\n -showPinIcons 1\n -mapMotionTrails 1\n -ignoreHiddenAttribute 0\n -ignoreOutlinerColor 0\n -renderFilterVisible 0\n $editorName;\n\n\t\t\t$editorName = ($panelName+\"GraphEd\");\n animCurveEditor -e \n -displayValues 0\n -snapTime \"integer\" \n -snapValue \"none\" \n -showPlayRangeShades \"on\" \n -lockPlayRangeShades \"off\" \n -smoothness \"fine\" \n -resultSamples 1.041667\n -resultScreenSamples 0\n -resultUpdate \"delayed\" \n -showUpstreamCurves 1\n -keyMinScale 1\n -stackedCurvesMin -1\n -stackedCurvesMax 1\n" + + " -stackedCurvesSpace 0.2\n -preSelectionHighlight 0\n -constrainDrag 0\n -valueLinesToggle 1\n -highlightAffectedCurves 0\n $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"dopeSheetPanel\" (localizedPanelLabel(\"Dope Sheet\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Dope Sheet\")) -mbv $menusOkayInPanels $panelName;\n\n\t\t\t$editorName = ($panelName+\"OutlineEd\");\n outlinerEditor -e \n -showShapes 1\n -showAssignedMaterials 0\n -showTimeEditor 1\n -showReferenceNodes 0\n -showReferenceMembers 0\n -showAttributes 1\n -showConnected 1\n -showAnimCurvesOnly 1\n -showMuteInfo 0\n -organizeByLayer 1\n -organizeByClip 1\n" + + " -showAnimLayerWeight 1\n -autoExpandLayers 1\n -autoExpand 0\n -showDagOnly 0\n -showAssets 1\n -showContainedOnly 0\n -showPublishedAsConnected 0\n -showParentContainers 0\n -showContainerContents 0\n -ignoreDagHierarchy 0\n -expandConnections 1\n -showUpstreamCurves 1\n -showUnitlessCurves 0\n -showCompounds 1\n -showLeafs 1\n -showNumericAttrsOnly 1\n -highlightActive 0\n -autoSelectNewObjects 0\n -doNotSelectNewObjects 1\n -dropIsParent 1\n -transmitFilters 0\n -setFilter \"0\" \n -showSetMembers 0\n -allowMultiSelection 1\n -alwaysToggleSelect 0\n -directSelect 0\n -showUfeItems 1\n -displayMode \"DAG\" \n -expandObjects 0\n" + + " -setsIgnoreFilters 1\n -containersIgnoreFilters 0\n -editAttrName 0\n -showAttrValues 0\n -highlightSecondary 0\n -showUVAttrsOnly 0\n -showTextureNodesOnly 0\n -attrAlphaOrder \"default\" \n -animLayerFilterOptions \"allAffecting\" \n -sortOrder \"none\" \n -longNames 0\n -niceNames 1\n -showNamespace 1\n -showPinIcons 0\n -mapMotionTrails 1\n -ignoreHiddenAttribute 0\n -ignoreOutlinerColor 0\n -renderFilterVisible 0\n $editorName;\n\n\t\t\t$editorName = ($panelName+\"DopeSheetEd\");\n dopeSheetEditor -e \n -displayValues 0\n -snapTime \"integer\" \n -snapValue \"none\" \n -outliner \"dopeSheetPanel1OutlineEd\" \n -showSummary 1\n -showScene 0\n -hierarchyBelow 0\n" + + " -showTicks 1\n -selectionWindow 0 0 0 0 \n $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"timeEditorPanel\" (localizedPanelLabel(\"Time Editor\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Time Editor\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"clipEditorPanel\" (localizedPanelLabel(\"Trax Editor\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Trax Editor\")) -mbv $menusOkayInPanels $panelName;\n\n\t\t\t$editorName = clipEditorNameFromPanel($panelName);\n clipEditor -e \n -displayValues 0\n -snapTime \"none\" \n -snapValue \"none\" \n -initialized 0\n -manageSequencer 0 \n" + + " $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"sequenceEditorPanel\" (localizedPanelLabel(\"Camera Sequencer\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Camera Sequencer\")) -mbv $menusOkayInPanels $panelName;\n\n\t\t\t$editorName = sequenceEditorNameFromPanel($panelName);\n clipEditor -e \n -displayValues 0\n -snapTime \"none\" \n -snapValue \"none\" \n -initialized 0\n -manageSequencer 1 \n $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"hyperGraphPanel\" (localizedPanelLabel(\"Hypergraph Hierarchy\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Hypergraph Hierarchy\")) -mbv $menusOkayInPanels $panelName;\n" + + "\n\t\t\t$editorName = ($panelName+\"HyperGraphEd\");\n hyperGraph -e \n -graphLayoutStyle \"hierarchicalLayout\" \n -orientation \"horiz\" \n -mergeConnections 0\n -zoom 1\n -animateTransition 0\n -showRelationships 1\n -showShapes 0\n -showDeformers 0\n -showExpressions 0\n -showConstraints 0\n -showConnectionFromSelected 0\n -showConnectionToSelected 0\n -showConstraintLabels 0\n -showUnderworld 0\n -showInvisible 0\n -transitionFrames 1\n -opaqueContainers 0\n -freeform 0\n -imagePosition 0 0 \n -imageScale 1\n -imageEnabled 0\n -graphType \"DAG\" \n -heatMapDisplay 0\n -updateSelection 1\n -updateNodeAdded 1\n -useDrawOverrideColor 0\n -limitGraphTraversal -1\n" + + " -range 0 0 \n -iconSize \"smallIcons\" \n -showCachedConnections 0\n $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"hyperShadePanel\" (localizedPanelLabel(\"Hypershade\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Hypershade\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"visorPanel\" (localizedPanelLabel(\"Visor\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Visor\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"nodeEditorPanel\" (localizedPanelLabel(\"Node Editor\")) `;\n\tif ($nodeEditorPanelVisible || $nodeEditorWorkspaceControlOpen) {\n" + + "\t\tif (\"\" == $panelName) {\n\t\t\tif ($useSceneConfig) {\n\t\t\t\t$panelName = `scriptedPanel -unParent -type \"nodeEditorPanel\" -l (localizedPanelLabel(\"Node Editor\")) -mbv $menusOkayInPanels `;\n\n\t\t\t$editorName = ($panelName+\"NodeEditorEd\");\n nodeEditor -e \n -allAttributes 0\n -allNodes 0\n -autoSizeNodes 1\n -consistentNameSize 1\n -createNodeCommand \"nodeEdCreateNodeCommand\" \n -connectNodeOnCreation 0\n -connectOnDrop 0\n -copyConnectionsOnPaste 0\n -connectionStyle \"bezier\" \n -defaultPinnedState 0\n -additiveGraphingMode 1\n -connectedGraphingMode 1\n -settingsChangedCallback \"nodeEdSyncControls\" \n -traversalDepthLimit -1\n -keyPressCommand \"nodeEdKeyPressCommand\" \n -nodeTitleMode \"name\" \n -gridSnap 0\n -gridVisibility 1\n -crosshairOnEdgeDragging 0\n" + + " -popupMenuScript \"nodeEdBuildPanelMenus\" \n -showNamespace 1\n -showShapes 1\n -showSGShapes 0\n -showTransforms 1\n -useAssets 1\n -syncedSelection 1\n -extendToShapes 1\n -showUnitConversions 0\n -editorMode \"default\" \n -hasWatchpoint 0\n $editorName;\n\t\t\t}\n\t\t} else {\n\t\t\t$label = `panel -q -label $panelName`;\n\t\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Node Editor\")) -mbv $menusOkayInPanels $panelName;\n\n\t\t\t$editorName = ($panelName+\"NodeEditorEd\");\n nodeEditor -e \n -allAttributes 0\n -allNodes 0\n -autoSizeNodes 1\n -consistentNameSize 1\n -createNodeCommand \"nodeEdCreateNodeCommand\" \n -connectNodeOnCreation 0\n -connectOnDrop 0\n -copyConnectionsOnPaste 0\n -connectionStyle \"bezier\" \n -defaultPinnedState 0\n" + + " -additiveGraphingMode 1\n -connectedGraphingMode 1\n -settingsChangedCallback \"nodeEdSyncControls\" \n -traversalDepthLimit -1\n -keyPressCommand \"nodeEdKeyPressCommand\" \n -nodeTitleMode \"name\" \n -gridSnap 0\n -gridVisibility 1\n -crosshairOnEdgeDragging 0\n -popupMenuScript \"nodeEdBuildPanelMenus\" \n -showNamespace 1\n -showShapes 1\n -showSGShapes 0\n -showTransforms 1\n -useAssets 1\n -syncedSelection 1\n -extendToShapes 1\n -showUnitConversions 0\n -editorMode \"default\" \n -hasWatchpoint 0\n $editorName;\n\t\t\tif (!$useSceneConfig) {\n\t\t\t\tpanel -e -l $label $panelName;\n\t\t\t}\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"createNodePanel\" (localizedPanelLabel(\"Create Node\")) `;\n\tif (\"\" != $panelName) {\n" + + "\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Create Node\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"polyTexturePlacementPanel\" (localizedPanelLabel(\"UV Editor\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"UV Editor\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"renderWindowPanel\" (localizedPanelLabel(\"Render View\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Render View\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextPanel \"shapePanel\" (localizedPanelLabel(\"Shape Editor\")) `;\n\tif (\"\" != $panelName) {\n" + + "\t\t$label = `panel -q -label $panelName`;\n\t\tshapePanel -edit -l (localizedPanelLabel(\"Shape Editor\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextPanel \"posePanel\" (localizedPanelLabel(\"Pose Editor\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tposePanel -edit -l (localizedPanelLabel(\"Pose Editor\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"dynRelEdPanel\" (localizedPanelLabel(\"Dynamic Relationships\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Dynamic Relationships\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"relationshipPanel\" (localizedPanelLabel(\"Relationship Editor\")) `;\n" + + "\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Relationship Editor\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"referenceEditorPanel\" (localizedPanelLabel(\"Reference Editor\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Reference Editor\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"dynPaintScriptedPanelType\" (localizedPanelLabel(\"Paint Effects\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Paint Effects\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"scriptEditorPanel\" (localizedPanelLabel(\"Script Editor\")) `;\n" + + "\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Script Editor\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"profilerPanel\" (localizedPanelLabel(\"Profiler Tool\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Profiler Tool\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"contentBrowserPanel\" (localizedPanelLabel(\"Content Browser\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Content Browser\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"Stereo\" (localizedPanelLabel(\"Stereo\")) `;\n" + + "\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Stereo\")) -mbv $menusOkayInPanels $panelName;\n{ string $editorName = ($panelName+\"Editor\");\n stereoCameraView -e \n -camera \"|persp\" \n -useInteractiveMode 0\n -displayLights \"default\" \n -displayAppearance \"wireframe\" \n -activeOnly 0\n -ignorePanZoom 0\n -wireframeOnShaded 0\n -headsUpDisplay 1\n -holdOuts 1\n -selectionHiliteDisplay 1\n -useDefaultMaterial 0\n -bufferMode \"double\" \n -twoSidedLighting 1\n -backfaceCulling 0\n -xray 0\n -jointXray 0\n -activeComponentsXray 0\n -displayTextures 0\n -smoothWireframe 0\n -lineWidth 1\n -textureAnisotropic 0\n -textureHilight 1\n -textureSampling 2\n" + + " -textureDisplay \"modulate\" \n -textureMaxSize 32768\n -fogging 0\n -fogSource \"fragment\" \n -fogMode \"linear\" \n -fogStart 0\n -fogEnd 100\n -fogDensity 0.1\n -fogColor 0.5 0.5 0.5 1 \n -depthOfFieldPreview 1\n -maxConstantTransparency 1\n -objectFilterShowInHUD 1\n -isFiltered 0\n -colorResolution 4 4 \n -bumpResolution 4 4 \n -textureCompression 0\n -transparencyAlgorithm \"frontAndBackCull\" \n -transpInShadows 0\n -cullingOverride \"none\" \n -lowQualityLighting 0\n -maximumNumHardwareLights 0\n -occlusionCulling 0\n -shadingModel 0\n -useBaseRenderer 0\n -useReducedRenderer 0\n -smallObjectCulling 0\n -smallObjectThreshold -1 \n -interactiveDisableShadows 0\n" + + " -interactiveBackFaceCull 0\n -sortTransparent 1\n -controllers 1\n -nurbsCurves 1\n -nurbsSurfaces 1\n -polymeshes 1\n -subdivSurfaces 1\n -planes 1\n -lights 1\n -cameras 1\n -controlVertices 1\n -hulls 1\n -grid 1\n -imagePlane 1\n -joints 1\n -ikHandles 1\n -deformers 1\n -dynamics 1\n -particleInstancers 1\n -fluids 1\n -hairSystems 1\n -follicles 1\n -nCloths 1\n -nParticles 1\n -nRigids 1\n -dynamicConstraints 1\n -locators 1\n -manipulators 1\n -pluginShapes 1\n -dimensions 1\n -handles 1\n -pivots 1\n -textures 1\n -strokes 1\n -motionTrails 1\n" + + " -clipGhosts 1\n -bluePencil 1\n -greasePencils 0\n -shadows 0\n -captureSequenceNumber -1\n -width 0\n -height 0\n -sceneRenderFilter 0\n -displayMode \"centerEye\" \n -viewColor 0 0 0 1 \n -useCustomBackground 1\n $editorName;\n stereoCameraView -e -viewSelected 0 $editorName; };\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\tif ($useSceneConfig) {\n string $configName = `getPanel -cwl (localizedPanelLabel(\"Current Layout\"))`;\n if (\"\" != $configName) {\n\t\t\tpanelConfiguration -edit -label (localizedPanelLabel(\"Current Layout\")) \n\t\t\t\t-userCreated false\n\t\t\t\t-defaultImage \"vacantCell.xP:/\"\n\t\t\t\t-image \"\"\n\t\t\t\t-sc false\n\t\t\t\t-configString \"global string $gMainPane; paneLayout -e -cn \\\"quad\\\" -ps 1 50 50 -ps 2 50 50 -ps 3 50 50 -ps 4 50 50 $gMainPane;\"\n\t\t\t\t-removeAllPanels\n\t\t\t\t-ap false\n\t\t\t\t\t(localizedPanelLabel(\"Top View\")) \n" + + "\t\t\t\t\t\"modelPanel\"\n" + + "\t\t\t\t\t\"$panelName = `modelPanel -unParent -l (localizedPanelLabel(\\\"Top View\\\")) -mbv $menusOkayInPanels `;\\n$editorName = $panelName;\\nmodelEditor -e \\n -camera \\\"|top\\\" \\n -useInteractiveMode 0\\n -displayLights \\\"default\\\" \\n -displayAppearance \\\"smoothShaded\\\" \\n -activeOnly 0\\n -ignorePanZoom 0\\n -wireframeOnShaded 0\\n -headsUpDisplay 1\\n -holdOuts 1\\n -selectionHiliteDisplay 1\\n -useDefaultMaterial 0\\n -bufferMode \\\"double\\\" \\n -twoSidedLighting 0\\n -backfaceCulling 0\\n -xray 0\\n -jointXray 0\\n -activeComponentsXray 0\\n -displayTextures 0\\n -smoothWireframe 0\\n -lineWidth 1\\n -textureAnisotropic 0\\n -textureHilight 1\\n -textureSampling 2\\n -textureDisplay \\\"modulate\\\" \\n -textureMaxSize 32768\\n -fogging 0\\n -fogSource \\\"fragment\\\" \\n -fogMode \\\"linear\\\" \\n -fogStart 0\\n -fogEnd 100\\n -fogDensity 0.1\\n -fogColor 0.5 0.5 0.5 1 \\n -depthOfFieldPreview 1\\n -maxConstantTransparency 1\\n -rendererName \\\"vp2Renderer\\\" \\n -objectFilterShowInHUD 1\\n -isFiltered 0\\n -colorResolution 256 256 \\n -bumpResolution 512 512 \\n -textureCompression 0\\n -transparencyAlgorithm \\\"frontAndBackCull\\\" \\n -transpInShadows 0\\n -cullingOverride \\\"none\\\" \\n -lowQualityLighting 0\\n -maximumNumHardwareLights 1\\n -occlusionCulling 0\\n -shadingModel 0\\n -useBaseRenderer 0\\n -useReducedRenderer 0\\n -smallObjectCulling 0\\n -smallObjectThreshold -1 \\n -interactiveDisableShadows 0\\n -interactiveBackFaceCull 0\\n -sortTransparent 1\\n -controllers 1\\n -nurbsCurves 1\\n -nurbsSurfaces 1\\n -polymeshes 1\\n -subdivSurfaces 1\\n -planes 1\\n -lights 1\\n -cameras 1\\n -controlVertices 1\\n -hulls 1\\n -grid 1\\n -imagePlane 1\\n -joints 1\\n -ikHandles 1\\n -deformers 1\\n -dynamics 1\\n -particleInstancers 1\\n -fluids 1\\n -hairSystems 1\\n -follicles 1\\n -nCloths 1\\n -nParticles 1\\n -nRigids 1\\n -dynamicConstraints 1\\n -locators 1\\n -manipulators 1\\n -pluginShapes 1\\n -dimensions 1\\n -handles 1\\n -pivots 1\\n -textures 1\\n -strokes 1\\n -motionTrails 1\\n -clipGhosts 1\\n -bluePencil 1\\n -greasePencils 0\\n -shadows 0\\n -captureSequenceNumber -1\\n -width 477\\n -height 276\\n -sceneRenderFilter 0\\n $editorName;\\nmodelEditor -e -viewSelected 0 $editorName\"\n" + + "\t\t\t\t\t\"modelPanel -edit -l (localizedPanelLabel(\\\"Top View\\\")) -mbv $menusOkayInPanels $panelName;\\n$editorName = $panelName;\\nmodelEditor -e \\n -camera \\\"|top\\\" \\n -useInteractiveMode 0\\n -displayLights \\\"default\\\" \\n -displayAppearance \\\"smoothShaded\\\" \\n -activeOnly 0\\n -ignorePanZoom 0\\n -wireframeOnShaded 0\\n -headsUpDisplay 1\\n -holdOuts 1\\n -selectionHiliteDisplay 1\\n -useDefaultMaterial 0\\n -bufferMode \\\"double\\\" \\n -twoSidedLighting 0\\n -backfaceCulling 0\\n -xray 0\\n -jointXray 0\\n -activeComponentsXray 0\\n -displayTextures 0\\n -smoothWireframe 0\\n -lineWidth 1\\n -textureAnisotropic 0\\n -textureHilight 1\\n -textureSampling 2\\n -textureDisplay \\\"modulate\\\" \\n -textureMaxSize 32768\\n -fogging 0\\n -fogSource \\\"fragment\\\" \\n -fogMode \\\"linear\\\" \\n -fogStart 0\\n -fogEnd 100\\n -fogDensity 0.1\\n -fogColor 0.5 0.5 0.5 1 \\n -depthOfFieldPreview 1\\n -maxConstantTransparency 1\\n -rendererName \\\"vp2Renderer\\\" \\n -objectFilterShowInHUD 1\\n -isFiltered 0\\n -colorResolution 256 256 \\n -bumpResolution 512 512 \\n -textureCompression 0\\n -transparencyAlgorithm \\\"frontAndBackCull\\\" \\n -transpInShadows 0\\n -cullingOverride \\\"none\\\" \\n -lowQualityLighting 0\\n -maximumNumHardwareLights 1\\n -occlusionCulling 0\\n -shadingModel 0\\n -useBaseRenderer 0\\n -useReducedRenderer 0\\n -smallObjectCulling 0\\n -smallObjectThreshold -1 \\n -interactiveDisableShadows 0\\n -interactiveBackFaceCull 0\\n -sortTransparent 1\\n -controllers 1\\n -nurbsCurves 1\\n -nurbsSurfaces 1\\n -polymeshes 1\\n -subdivSurfaces 1\\n -planes 1\\n -lights 1\\n -cameras 1\\n -controlVertices 1\\n -hulls 1\\n -grid 1\\n -imagePlane 1\\n -joints 1\\n -ikHandles 1\\n -deformers 1\\n -dynamics 1\\n -particleInstancers 1\\n -fluids 1\\n -hairSystems 1\\n -follicles 1\\n -nCloths 1\\n -nParticles 1\\n -nRigids 1\\n -dynamicConstraints 1\\n -locators 1\\n -manipulators 1\\n -pluginShapes 1\\n -dimensions 1\\n -handles 1\\n -pivots 1\\n -textures 1\\n -strokes 1\\n -motionTrails 1\\n -clipGhosts 1\\n -bluePencil 1\\n -greasePencils 0\\n -shadows 0\\n -captureSequenceNumber -1\\n -width 477\\n -height 276\\n -sceneRenderFilter 0\\n $editorName;\\nmodelEditor -e -viewSelected 0 $editorName\"\n" + + "\t\t\t\t-ap false\n\t\t\t\t\t(localizedPanelLabel(\"Persp View\")) \n\t\t\t\t\t\"modelPanel\"\n" + + "\t\t\t\t\t\"$panelName = `modelPanel -unParent -l (localizedPanelLabel(\\\"Persp View\\\")) -mbv $menusOkayInPanels `;\\n$editorName = $panelName;\\nmodelEditor -e \\n -cam `findStartUpCamera persp` \\n -useInteractiveMode 0\\n -displayLights \\\"default\\\" \\n -displayAppearance \\\"smoothShaded\\\" \\n -activeOnly 0\\n -ignorePanZoom 0\\n -wireframeOnShaded 0\\n -headsUpDisplay 1\\n -holdOuts 1\\n -selectionHiliteDisplay 1\\n -useDefaultMaterial 0\\n -bufferMode \\\"double\\\" \\n -twoSidedLighting 0\\n -backfaceCulling 0\\n -xray 0\\n -jointXray 0\\n -activeComponentsXray 0\\n -displayTextures 0\\n -smoothWireframe 0\\n -lineWidth 1\\n -textureAnisotropic 0\\n -textureHilight 1\\n -textureSampling 2\\n -textureDisplay \\\"modulate\\\" \\n -textureMaxSize 32768\\n -fogging 0\\n -fogSource \\\"fragment\\\" \\n -fogMode \\\"linear\\\" \\n -fogStart 0\\n -fogEnd 100\\n -fogDensity 0.1\\n -fogColor 0.5 0.5 0.5 1 \\n -depthOfFieldPreview 1\\n -maxConstantTransparency 1\\n -rendererName \\\"vp2Renderer\\\" \\n -objectFilterShowInHUD 1\\n -isFiltered 0\\n -colorResolution 256 256 \\n -bumpResolution 512 512 \\n -textureCompression 0\\n -transparencyAlgorithm \\\"frontAndBackCull\\\" \\n -transpInShadows 0\\n -cullingOverride \\\"none\\\" \\n -lowQualityLighting 0\\n -maximumNumHardwareLights 1\\n -occlusionCulling 0\\n -shadingModel 0\\n -useBaseRenderer 0\\n -useReducedRenderer 0\\n -smallObjectCulling 0\\n -smallObjectThreshold -1 \\n -interactiveDisableShadows 0\\n -interactiveBackFaceCull 0\\n -sortTransparent 1\\n -controllers 1\\n -nurbsCurves 1\\n -nurbsSurfaces 1\\n -polymeshes 1\\n -subdivSurfaces 1\\n -planes 1\\n -lights 1\\n -cameras 1\\n -controlVertices 1\\n -hulls 1\\n -grid 1\\n -imagePlane 1\\n -joints 1\\n -ikHandles 1\\n -deformers 1\\n -dynamics 1\\n -particleInstancers 1\\n -fluids 1\\n -hairSystems 1\\n -follicles 1\\n -nCloths 1\\n -nParticles 1\\n -nRigids 1\\n -dynamicConstraints 1\\n -locators 1\\n -manipulators 1\\n -pluginShapes 1\\n -dimensions 1\\n -handles 1\\n -pivots 1\\n -textures 1\\n -strokes 1\\n -motionTrails 1\\n -clipGhosts 1\\n -bluePencil 1\\n -greasePencils 0\\n -shadows 0\\n -captureSequenceNumber -1\\n -width 476\\n -height 276\\n -sceneRenderFilter 0\\n $editorName;\\nmodelEditor -e -viewSelected 0 $editorName\"\n" + + "\t\t\t\t\t\"modelPanel -edit -l (localizedPanelLabel(\\\"Persp View\\\")) -mbv $menusOkayInPanels $panelName;\\n$editorName = $panelName;\\nmodelEditor -e \\n -cam `findStartUpCamera persp` \\n -useInteractiveMode 0\\n -displayLights \\\"default\\\" \\n -displayAppearance \\\"smoothShaded\\\" \\n -activeOnly 0\\n -ignorePanZoom 0\\n -wireframeOnShaded 0\\n -headsUpDisplay 1\\n -holdOuts 1\\n -selectionHiliteDisplay 1\\n -useDefaultMaterial 0\\n -bufferMode \\\"double\\\" \\n -twoSidedLighting 0\\n -backfaceCulling 0\\n -xray 0\\n -jointXray 0\\n -activeComponentsXray 0\\n -displayTextures 0\\n -smoothWireframe 0\\n -lineWidth 1\\n -textureAnisotropic 0\\n -textureHilight 1\\n -textureSampling 2\\n -textureDisplay \\\"modulate\\\" \\n -textureMaxSize 32768\\n -fogging 0\\n -fogSource \\\"fragment\\\" \\n -fogMode \\\"linear\\\" \\n -fogStart 0\\n -fogEnd 100\\n -fogDensity 0.1\\n -fogColor 0.5 0.5 0.5 1 \\n -depthOfFieldPreview 1\\n -maxConstantTransparency 1\\n -rendererName \\\"vp2Renderer\\\" \\n -objectFilterShowInHUD 1\\n -isFiltered 0\\n -colorResolution 256 256 \\n -bumpResolution 512 512 \\n -textureCompression 0\\n -transparencyAlgorithm \\\"frontAndBackCull\\\" \\n -transpInShadows 0\\n -cullingOverride \\\"none\\\" \\n -lowQualityLighting 0\\n -maximumNumHardwareLights 1\\n -occlusionCulling 0\\n -shadingModel 0\\n -useBaseRenderer 0\\n -useReducedRenderer 0\\n -smallObjectCulling 0\\n -smallObjectThreshold -1 \\n -interactiveDisableShadows 0\\n -interactiveBackFaceCull 0\\n -sortTransparent 1\\n -controllers 1\\n -nurbsCurves 1\\n -nurbsSurfaces 1\\n -polymeshes 1\\n -subdivSurfaces 1\\n -planes 1\\n -lights 1\\n -cameras 1\\n -controlVertices 1\\n -hulls 1\\n -grid 1\\n -imagePlane 1\\n -joints 1\\n -ikHandles 1\\n -deformers 1\\n -dynamics 1\\n -particleInstancers 1\\n -fluids 1\\n -hairSystems 1\\n -follicles 1\\n -nCloths 1\\n -nParticles 1\\n -nRigids 1\\n -dynamicConstraints 1\\n -locators 1\\n -manipulators 1\\n -pluginShapes 1\\n -dimensions 1\\n -handles 1\\n -pivots 1\\n -textures 1\\n -strokes 1\\n -motionTrails 1\\n -clipGhosts 1\\n -bluePencil 1\\n -greasePencils 0\\n -shadows 0\\n -captureSequenceNumber -1\\n -width 476\\n -height 276\\n -sceneRenderFilter 0\\n $editorName;\\nmodelEditor -e -viewSelected 0 $editorName\"\n" + + "\t\t\t\t-ap false\n\t\t\t\t\t(localizedPanelLabel(\"Side View\")) \n\t\t\t\t\t\"modelPanel\"\n" + + "\t\t\t\t\t\"$panelName = `modelPanel -unParent -l (localizedPanelLabel(\\\"Side View\\\")) -mbv $menusOkayInPanels `;\\n$editorName = $panelName;\\nmodelEditor -e \\n -camera \\\"|side\\\" \\n -useInteractiveMode 0\\n -displayLights \\\"default\\\" \\n -displayAppearance \\\"smoothShaded\\\" \\n -activeOnly 0\\n -ignorePanZoom 0\\n -wireframeOnShaded 0\\n -headsUpDisplay 1\\n -holdOuts 1\\n -selectionHiliteDisplay 1\\n -useDefaultMaterial 0\\n -bufferMode \\\"double\\\" \\n -twoSidedLighting 0\\n -backfaceCulling 0\\n -xray 0\\n -jointXray 0\\n -activeComponentsXray 0\\n -displayTextures 0\\n -smoothWireframe 0\\n -lineWidth 1\\n -textureAnisotropic 0\\n -textureHilight 1\\n -textureSampling 2\\n -textureDisplay \\\"modulate\\\" \\n -textureMaxSize 32768\\n -fogging 0\\n -fogSource \\\"fragment\\\" \\n -fogMode \\\"linear\\\" \\n -fogStart 0\\n -fogEnd 100\\n -fogDensity 0.1\\n -fogColor 0.5 0.5 0.5 1 \\n -depthOfFieldPreview 1\\n -maxConstantTransparency 1\\n -rendererName \\\"vp2Renderer\\\" \\n -objectFilterShowInHUD 1\\n -isFiltered 0\\n -colorResolution 256 256 \\n -bumpResolution 512 512 \\n -textureCompression 0\\n -transparencyAlgorithm \\\"frontAndBackCull\\\" \\n -transpInShadows 0\\n -cullingOverride \\\"none\\\" \\n -lowQualityLighting 0\\n -maximumNumHardwareLights 1\\n -occlusionCulling 0\\n -shadingModel 0\\n -useBaseRenderer 0\\n -useReducedRenderer 0\\n -smallObjectCulling 0\\n -smallObjectThreshold -1 \\n -interactiveDisableShadows 0\\n -interactiveBackFaceCull 0\\n -sortTransparent 1\\n -controllers 1\\n -nurbsCurves 1\\n -nurbsSurfaces 1\\n -polymeshes 1\\n -subdivSurfaces 1\\n -planes 1\\n -lights 1\\n -cameras 1\\n -controlVertices 1\\n -hulls 1\\n -grid 1\\n -imagePlane 1\\n -joints 1\\n -ikHandles 1\\n -deformers 1\\n -dynamics 1\\n -particleInstancers 1\\n -fluids 1\\n -hairSystems 1\\n -follicles 1\\n -nCloths 1\\n -nParticles 1\\n -nRigids 1\\n -dynamicConstraints 1\\n -locators 1\\n -manipulators 1\\n -pluginShapes 1\\n -dimensions 1\\n -handles 1\\n -pivots 1\\n -textures 1\\n -strokes 1\\n -motionTrails 1\\n -clipGhosts 1\\n -bluePencil 1\\n -greasePencils 0\\n -shadows 0\\n -captureSequenceNumber -1\\n -width 476\\n -height 276\\n -sceneRenderFilter 0\\n $editorName;\\nmodelEditor -e -viewSelected 0 $editorName\"\n" + + "\t\t\t\t\t\"modelPanel -edit -l (localizedPanelLabel(\\\"Side View\\\")) -mbv $menusOkayInPanels $panelName;\\n$editorName = $panelName;\\nmodelEditor -e \\n -camera \\\"|side\\\" \\n -useInteractiveMode 0\\n -displayLights \\\"default\\\" \\n -displayAppearance \\\"smoothShaded\\\" \\n -activeOnly 0\\n -ignorePanZoom 0\\n -wireframeOnShaded 0\\n -headsUpDisplay 1\\n -holdOuts 1\\n -selectionHiliteDisplay 1\\n -useDefaultMaterial 0\\n -bufferMode \\\"double\\\" \\n -twoSidedLighting 0\\n -backfaceCulling 0\\n -xray 0\\n -jointXray 0\\n -activeComponentsXray 0\\n -displayTextures 0\\n -smoothWireframe 0\\n -lineWidth 1\\n -textureAnisotropic 0\\n -textureHilight 1\\n -textureSampling 2\\n -textureDisplay \\\"modulate\\\" \\n -textureMaxSize 32768\\n -fogging 0\\n -fogSource \\\"fragment\\\" \\n -fogMode \\\"linear\\\" \\n -fogStart 0\\n -fogEnd 100\\n -fogDensity 0.1\\n -fogColor 0.5 0.5 0.5 1 \\n -depthOfFieldPreview 1\\n -maxConstantTransparency 1\\n -rendererName \\\"vp2Renderer\\\" \\n -objectFilterShowInHUD 1\\n -isFiltered 0\\n -colorResolution 256 256 \\n -bumpResolution 512 512 \\n -textureCompression 0\\n -transparencyAlgorithm \\\"frontAndBackCull\\\" \\n -transpInShadows 0\\n -cullingOverride \\\"none\\\" \\n -lowQualityLighting 0\\n -maximumNumHardwareLights 1\\n -occlusionCulling 0\\n -shadingModel 0\\n -useBaseRenderer 0\\n -useReducedRenderer 0\\n -smallObjectCulling 0\\n -smallObjectThreshold -1 \\n -interactiveDisableShadows 0\\n -interactiveBackFaceCull 0\\n -sortTransparent 1\\n -controllers 1\\n -nurbsCurves 1\\n -nurbsSurfaces 1\\n -polymeshes 1\\n -subdivSurfaces 1\\n -planes 1\\n -lights 1\\n -cameras 1\\n -controlVertices 1\\n -hulls 1\\n -grid 1\\n -imagePlane 1\\n -joints 1\\n -ikHandles 1\\n -deformers 1\\n -dynamics 1\\n -particleInstancers 1\\n -fluids 1\\n -hairSystems 1\\n -follicles 1\\n -nCloths 1\\n -nParticles 1\\n -nRigids 1\\n -dynamicConstraints 1\\n -locators 1\\n -manipulators 1\\n -pluginShapes 1\\n -dimensions 1\\n -handles 1\\n -pivots 1\\n -textures 1\\n -strokes 1\\n -motionTrails 1\\n -clipGhosts 1\\n -bluePencil 1\\n -greasePencils 0\\n -shadows 0\\n -captureSequenceNumber -1\\n -width 476\\n -height 276\\n -sceneRenderFilter 0\\n $editorName;\\nmodelEditor -e -viewSelected 0 $editorName\"\n" + + "\t\t\t\t-ap false\n\t\t\t\t\t(localizedPanelLabel(\"Front View\")) \n\t\t\t\t\t\"modelPanel\"\n" + + "\t\t\t\t\t\"$panelName = `modelPanel -unParent -l (localizedPanelLabel(\\\"Front View\\\")) -mbv $menusOkayInPanels `;\\n$editorName = $panelName;\\nmodelEditor -e \\n -cam `findStartUpCamera front` \\n -useInteractiveMode 0\\n -displayLights \\\"default\\\" \\n -displayAppearance \\\"smoothShaded\\\" \\n -activeOnly 0\\n -ignorePanZoom 0\\n -wireframeOnShaded 0\\n -headsUpDisplay 1\\n -holdOuts 1\\n -selectionHiliteDisplay 1\\n -useDefaultMaterial 0\\n -bufferMode \\\"double\\\" \\n -twoSidedLighting 0\\n -backfaceCulling 0\\n -xray 0\\n -jointXray 0\\n -activeComponentsXray 0\\n -displayTextures 0\\n -smoothWireframe 0\\n -lineWidth 1\\n -textureAnisotropic 0\\n -textureHilight 1\\n -textureSampling 2\\n -textureDisplay \\\"modulate\\\" \\n -textureMaxSize 32768\\n -fogging 0\\n -fogSource \\\"fragment\\\" \\n -fogMode \\\"linear\\\" \\n -fogStart 0\\n -fogEnd 100\\n -fogDensity 0.1\\n -fogColor 0.5 0.5 0.5 1 \\n -depthOfFieldPreview 1\\n -maxConstantTransparency 1\\n -rendererName \\\"vp2Renderer\\\" \\n -objectFilterShowInHUD 1\\n -isFiltered 0\\n -colorResolution 256 256 \\n -bumpResolution 512 512 \\n -textureCompression 0\\n -transparencyAlgorithm \\\"frontAndBackCull\\\" \\n -transpInShadows 0\\n -cullingOverride \\\"none\\\" \\n -lowQualityLighting 0\\n -maximumNumHardwareLights 1\\n -occlusionCulling 0\\n -shadingModel 0\\n -useBaseRenderer 0\\n -useReducedRenderer 0\\n -smallObjectCulling 0\\n -smallObjectThreshold -1 \\n -interactiveDisableShadows 0\\n -interactiveBackFaceCull 0\\n -sortTransparent 1\\n -controllers 1\\n -nurbsCurves 1\\n -nurbsSurfaces 1\\n -polymeshes 1\\n -subdivSurfaces 1\\n -planes 1\\n -lights 1\\n -cameras 1\\n -controlVertices 1\\n -hulls 1\\n -grid 1\\n -imagePlane 1\\n -joints 1\\n -ikHandles 1\\n -deformers 1\\n -dynamics 1\\n -particleInstancers 1\\n -fluids 1\\n -hairSystems 1\\n -follicles 1\\n -nCloths 1\\n -nParticles 1\\n -nRigids 1\\n -dynamicConstraints 1\\n -locators 1\\n -manipulators 1\\n -pluginShapes 1\\n -dimensions 1\\n -handles 1\\n -pivots 1\\n -textures 1\\n -strokes 1\\n -motionTrails 1\\n -clipGhosts 1\\n -bluePencil 1\\n -greasePencils 0\\n -shadows 0\\n -captureSequenceNumber -1\\n -width 477\\n -height 276\\n -sceneRenderFilter 0\\n $editorName;\\nmodelEditor -e -viewSelected 0 $editorName\"\n" + + "\t\t\t\t\t\"modelPanel -edit -l (localizedPanelLabel(\\\"Front View\\\")) -mbv $menusOkayInPanels $panelName;\\n$editorName = $panelName;\\nmodelEditor -e \\n -cam `findStartUpCamera front` \\n -useInteractiveMode 0\\n -displayLights \\\"default\\\" \\n -displayAppearance \\\"smoothShaded\\\" \\n -activeOnly 0\\n -ignorePanZoom 0\\n -wireframeOnShaded 0\\n -headsUpDisplay 1\\n -holdOuts 1\\n -selectionHiliteDisplay 1\\n -useDefaultMaterial 0\\n -bufferMode \\\"double\\\" \\n -twoSidedLighting 0\\n -backfaceCulling 0\\n -xray 0\\n -jointXray 0\\n -activeComponentsXray 0\\n -displayTextures 0\\n -smoothWireframe 0\\n -lineWidth 1\\n -textureAnisotropic 0\\n -textureHilight 1\\n -textureSampling 2\\n -textureDisplay \\\"modulate\\\" \\n -textureMaxSize 32768\\n -fogging 0\\n -fogSource \\\"fragment\\\" \\n -fogMode \\\"linear\\\" \\n -fogStart 0\\n -fogEnd 100\\n -fogDensity 0.1\\n -fogColor 0.5 0.5 0.5 1 \\n -depthOfFieldPreview 1\\n -maxConstantTransparency 1\\n -rendererName \\\"vp2Renderer\\\" \\n -objectFilterShowInHUD 1\\n -isFiltered 0\\n -colorResolution 256 256 \\n -bumpResolution 512 512 \\n -textureCompression 0\\n -transparencyAlgorithm \\\"frontAndBackCull\\\" \\n -transpInShadows 0\\n -cullingOverride \\\"none\\\" \\n -lowQualityLighting 0\\n -maximumNumHardwareLights 1\\n -occlusionCulling 0\\n -shadingModel 0\\n -useBaseRenderer 0\\n -useReducedRenderer 0\\n -smallObjectCulling 0\\n -smallObjectThreshold -1 \\n -interactiveDisableShadows 0\\n -interactiveBackFaceCull 0\\n -sortTransparent 1\\n -controllers 1\\n -nurbsCurves 1\\n -nurbsSurfaces 1\\n -polymeshes 1\\n -subdivSurfaces 1\\n -planes 1\\n -lights 1\\n -cameras 1\\n -controlVertices 1\\n -hulls 1\\n -grid 1\\n -imagePlane 1\\n -joints 1\\n -ikHandles 1\\n -deformers 1\\n -dynamics 1\\n -particleInstancers 1\\n -fluids 1\\n -hairSystems 1\\n -follicles 1\\n -nCloths 1\\n -nParticles 1\\n -nRigids 1\\n -dynamicConstraints 1\\n -locators 1\\n -manipulators 1\\n -pluginShapes 1\\n -dimensions 1\\n -handles 1\\n -pivots 1\\n -textures 1\\n -strokes 1\\n -motionTrails 1\\n -clipGhosts 1\\n -bluePencil 1\\n -greasePencils 0\\n -shadows 0\\n -captureSequenceNumber -1\\n -width 477\\n -height 276\\n -sceneRenderFilter 0\\n $editorName;\\nmodelEditor -e -viewSelected 0 $editorName\"\n" + "\t\t\t\t$configName;\n\n setNamedPanelLayout (localizedPanelLabel(\"Current Layout\"));\n }\n\n panelHistory -e -clear mainPanelHistory;\n sceneUIReplacement -clear;\n\t}\n\n\ngrid -spacing 5 -size 12 -divisions 5 -displayAxes yes -displayGridLines yes -displayDivisionLines yes -displayPerspectiveLabels no -displayOrthographicLabels no -displayAxesBold yes -perspectiveLabelPosition axis -orthographicLabelPosition edge;\nviewManip -drawCompass 0 -compassAngle 0 -frontParameters \"\" -homeParameters \"\" -selectionLockParameters \"\";\n}\n"); setAttr ".st" 3; createNode script -n "sceneConfigurationScriptNode"; @@ -273,6 +285,7 @@ createNode aiAOVDriver -s -n "defaultArnoldDisplayDriver"; createNode objectSet -n "workfileMain"; rename -uid "3C9B5D6F-4579-8E3B-5B7D-4C88865A1C68"; addAttr -ci true -sn "cbId" -ln "cbId" -dt "string"; + addAttr -ci true -sn "instance_id" -ln "instance_id" -dt "string"; addAttr -ci true -sn "id" -ln "id" -dt "string"; addAttr -ci true -sn "family" -ln "family" -dt "string"; addAttr -ci true -sn "subset" -ln "subset" -dt "string"; @@ -281,13 +294,14 @@ createNode objectSet -n "workfileMain"; addAttr -ci true -sn "variant" -ln "variant" -dt "string"; addAttr -ci true -sn "asset" -ln "asset" -dt "string"; addAttr -ci true -sn "task" -ln "task" -dt "string"; - addAttr -ci true -sn "instance_id" -ln "instance_id" -dt "string"; addAttr -ci true -sn "publish_attributes" -ln "publish_attributes" -dt "string"; - addAttr -ci true -sn "__creator_attributes_keys" -ln "__creator_attributes_keys" + addAttr -ci true -sn "creator_attributes" -ln "creator_attributes" -dt "string"; + addAttr -ci true -sn "__creator_attributes_keys" -ln "__creator_attributes_keys" -dt "string"; setAttr ".ihi" 0; setAttr ".hio" yes; setAttr ".cbId" -type "string" "60df31e2be2b48bd3695c056:30d256dac64c"; + setAttr ".instance_id" -type "string" "911dc92a-ad29-41e5-bbf9-733d56174fb9"; setAttr ".id" -type "string" "pyblish.avalon.instance"; setAttr ".family" -type "string" "workfile"; setAttr ".subset" -type "string" "workfileTest_task"; @@ -296,16 +310,9 @@ createNode objectSet -n "workfileMain"; setAttr ".variant" -type "string" "Main"; setAttr ".asset" -type "string" "test_asset"; setAttr ".task" -type "string" "test_task"; - setAttr ".instance_id" -type "string" "911dc92a-ad29-41e5-bbf9-733d56174fb9"; - setAttr ".publish_attributes" -type "string" "{\"ExtractImportReference\": {\"active\": false}}"; + setAttr ".publish_attributes" -type "string" "{\"ValidateInstanceInContext\": {\"active\": true}, \"ExtractImportReference\": {\"active\": false}}"; + setAttr ".creator_attributes" -type "string" "{}"; setAttr ".__creator_attributes_keys" -type "string" ""; -createNode objectSet -n "renderingMain"; - rename -uid "8A999C2F-4922-B15D-8D5C-45A16465B69F"; - addAttr -ci true -sn "pre_creator_identifier" -ln "pre_creator_identifier" -dt "string"; - addAttr -ci true -sn "cbId" -ln "cbId" -dt "string"; - setAttr ".ihi" 0; - setAttr ".pre_creator_identifier" -type "string" "io.openpype.creators.maya.renderlayer"; - setAttr ".cbId" -type "string" "60df31e2be2b48bd3695c056:042447475732"; createNode renderSetupLayer -n "Main"; rename -uid "2202E438-4CEF-F64E-737C-F48C65E31126"; addAttr -ci true -sn "es" -ln "expandedState" -min 0 -max 1 -at "bool"; @@ -320,55 +327,6 @@ createNode collection -n "defaultCollection"; createNode simpleSelector -n "defaultCollectionSelector"; rename -uid "7CA2F6D8-483C-B020-BC03-EF9563A52163"; setAttr ".pat" -type "string" "*"; -createNode objectSet -n "_renderingMain:Main"; - rename -uid "1EEC3A3B-49CF-0C79-5340-39805174FB8A"; - addAttr -s false -ci true -sn "renderlayer" -ln "renderlayer" -at "message"; - addAttr -ci true -sn "id" -ln "id" -dt "string"; - addAttr -ci true -sn "family" -ln "family" -dt "string"; - addAttr -ci true -sn "subset" -ln "subset" -dt "string"; - addAttr -ci true -sn "active" -ln "active" -min 0 -max 1 -at "bool"; - addAttr -ci true -sn "creator_identifier" -ln "creator_identifier" -dt "string"; - addAttr -ci true -sn "variant" -ln "variant" -dt "string"; - addAttr -ci true -sn "asset" -ln "asset" -dt "string"; - addAttr -ci true -sn "task" -ln "task" -dt "string"; - addAttr -ci true -sn "instance_id" -ln "instance_id" -dt "string"; - addAttr -ci true -sn "review" -ln "review" -min 0 -max 1 -at "bool"; - addAttr -ci true -sn "extendFrames" -ln "extendFrames" -min 0 -max 1 -at "bool"; - addAttr -ci true -sn "overrideExistingFrame" -ln "overrideExistingFrame" -min 0 - -max 1 -at "bool"; - addAttr -ci true -sn "tileRendering" -ln "tileRendering" -min 0 -max 1 -at "bool"; - addAttr -ci true -sn "tilesX" -ln "tilesX" -at "long"; - addAttr -ci true -sn "tilesY" -ln "tilesY" -at "long"; - addAttr -ci true -sn "convertToScanline" -ln "convertToScanline" -min 0 -max 1 -at "bool"; - addAttr -ci true -sn "useReferencedAovs" -ln "useReferencedAovs" -min 0 -max 1 -at "bool"; - addAttr -ci true -sn "renderSetupIncludeLights" -ln "renderSetupIncludeLights" -min - 0 -max 1 -at "bool"; - addAttr -ci true -sn "publish_attributes" -ln "publish_attributes" -dt "string"; - addAttr -ci true -sn "__creator_attributes_keys" -ln "__creator_attributes_keys" - -dt "string"; - addAttr -ci true -sn "cbId" -ln "cbId" -dt "string"; - setAttr ".ihi" 0; - setAttr ".id" -type "string" "pyblish.avalon.instance"; - setAttr ".family" -type "string" "renderlayer"; - setAttr ".subset" -type "string" "renderMain"; - setAttr -cb on ".active" yes; - setAttr ".creator_identifier" -type "string" "io.openpype.creators.maya.renderlayer"; - setAttr ".variant" -type "string" "Main"; - setAttr ".asset" -type "string" "test_asset"; - setAttr ".task" -type "string" "test_task"; - setAttr ".instance_id" -type "string" "8a9cfb85-9602-4e5e-a4bc-27a2986bae7f"; - setAttr -cb on ".review" yes; - setAttr -cb on ".extendFrames"; - setAttr -cb on ".overrideExistingFrame" yes; - setAttr -cb on ".tileRendering"; - setAttr -cb on ".tilesX" 2; - setAttr -cb on ".tilesY" 2; - setAttr -cb on ".convertToScanline"; - setAttr -cb on ".useReferencedAovs"; - setAttr -cb on ".renderSetupIncludeLights" yes; - setAttr ".publish_attributes" -type "string" "{\"CollectDeadlinePools\": {\"primaryPool\": \"\", \"secondaryPool\": \"\"}, \"ValidateDeadlinePools\": {\"active\": true}, \"ValidateFrameRange\": {\"active\": true}, \"ExtractImportReference\": {\"active\": false}, \"MayaSubmitDeadline\": {\"priority\": 50, \"chunkSize\": 1, \"machineList\": \"\", \"whitelist\": false, \"tile_priority\": 50, \"strict_error_checking\": true}, \"ProcessSubmittedJobOnFarm\": {\"publishJobState\": \"Active\"}}"; - setAttr ".__creator_attributes_keys" -type "string" "review,extendFrames,overrideExistingFrame,tileRendering,tilesX,tilesY,convertToScanline,useReferencedAovs,renderSetupIncludeLights"; - setAttr ".cbId" -type "string" "60df31e2be2b48bd3695c056:69960f336351"; select -ne :time1; setAttr ".o" 1001; setAttr ".unw" 1001; @@ -435,8 +393,6 @@ select -ne :defaultColorMgtGlobals; select -ne :hardwareRenderGlobals; setAttr ".ctrs" 256; setAttr ".btrs" 512; -select -ne :ikSystem; - setAttr -s 4 ".sol"; connectAttr "rs_Main.ri" ":persp.rlio[0]"; connectAttr "rs_Main.ri" ":top.rlio[0]"; connectAttr "rs_Main.ri" ":front.rlio[0]"; @@ -459,7 +415,6 @@ connectAttr ":defaultArnoldDisplayDriver.msg" ":defaultArnoldRenderOptions.drive -na; connectAttr ":defaultArnoldFilter.msg" ":defaultArnoldRenderOptions.filt"; connectAttr ":defaultArnoldDriver.msg" ":defaultArnoldRenderOptions.drvr"; -connectAttr "_renderingMain:Main.msg" "renderingMain.dnsm" -na; connectAttr "rs_Main.msg" "Main.lrl"; connectAttr "renderSetup.lit" "Main.pls"; connectAttr "defaultCollection.msg" "Main.cl"; @@ -468,9 +423,8 @@ connectAttr "renderLayerManager.rlmi[1]" "rs_Main.rlid"; connectAttr "defaultCollectionSelector.c" "defaultCollection.sel"; connectAttr "Main.lit" "defaultCollection.pls"; connectAttr "Main.nic" "defaultCollection.pic"; -connectAttr "Main.msg" "_renderingMain:Main.renderlayer"; connectAttr "defaultRenderLayer.msg" ":defaultRenderingList1.r" -na; connectAttr "rs_Main.msg" ":defaultRenderingList1.r" -na; connectAttr "pSphere1_GEOShape1.iog" ":initialShadingGroup.dsm" -na; connectAttr "pDiscShape1.iog" ":initialShadingGroup.dsm" -na; -// End of test_project_test_asset_test_task_v001.ma +// End of test_project_test_asset_test_task_v002.ma diff --git a/tests/integration/hosts/maya/test_publish_in_maya/expected/test_project/test_asset/work/test_task/renders/maya/test_project_test_asset_workfileTest_task_v001/Main/renderMain_metadata.json b/tests/integration/hosts/maya/test_publish_in_maya/expected/test_project/test_asset/work/test_task/renders/maya/test_project_test_asset_workfileTest_task_v001/Main/renderMain_metadata.json deleted file mode 100644 index 8c9e4de21a..0000000000 --- a/tests/integration/hosts/maya/test_publish_in_maya/expected/test_project/test_asset/work/test_task/renders/maya/test_project_test_asset_workfileTest_task_v001/Main/renderMain_metadata.json +++ /dev/null @@ -1,275 +0,0 @@ -{ - "asset": "test_asset", - "comment": "", - "deadline_publish_job_id": "6540ba7fc27eabc1c1a3d387", - "fps": 25.0, - "frameEnd": 1001, - "frameStart": 1001, - "instances": [ - { - "asset": "test_asset", - "colorspace": null, - "comment": "", - "deadlineUrl": "http://127.0.0.1:8082", - "extendFrames": false, - "families": [ - "render", - "review", - "ftrack" - ], - "family": "render", - "fps": 25.0, - "frameEnd": 1001, - "frameEndHandle": 1001, - "frameStart": 1001, - "frameStartHandle": 1001, - "handleEnd": 0, - "handleStart": 0, - "inputVersions": [], - "jobBatchName": "", - "multipartExr": true, - "overrideExistingFrame": false, - "pixelAspect": 1.0, - "representations": [ - { - "colorspaceData": { - "colorspace": "scene-linear Rec 709/sRGB", - "config": { - "path": "C:/Program Files/Autodesk/Maya2024/resources/OCIO-configs/Maya-legacy/config.ocio", - "template": "C:/Program Files/Autodesk/Maya2024/resources/OCIO-configs/Maya-legacy/config.ocio" - }, - "display": "legacy", - "view": "sRGB gamma" - }, - "ext": "exr", - "files": "Main.1001.exr", - "fps": 25.0, - "frameEnd": 1001, - "frameStart": 1001, - "name": "exr", - "stagingDir": "{root[work]}/test_project/test_asset/work/test_task/renders/maya/test_project_test_asset_workfileTest_task_v001/Main", - "tags": [ - "review" - ] - } - ], - "resolutionHeight": 1080, - "resolutionWidth": 1920, - "review": true, - "source": "{root[work]}/test_project/test_asset/work/test_task/test_project_test_asset_test_task_v001.ma", - "stagingDir_persistent": false, - "subset": "renderMain_beauty", - "subsetGroup": "renderMain", - "useSequenceForReview": true - } - ], - "intent": null, - "job": { - "Aux": [], - "Bad": [], - "ComFra": 0, - "CompletedChunks": 0, - "ConcurrencyToken": null, - "DataSize": -1, - "Date": "2023-10-31T08:27:42.9465949+00:00", - "DateComp": "0001-01-01T00:00:00Z", - "DateStart": "0001-01-01T00:00:00Z", - "Errs": 0, - "ExtraElements": null, - "FailedChunks": 0, - "IsSub": false, - "Mach": "DESKTOP-969549J", - "Main": false, - "MainEnd": 0, - "MainStart": 0, - "OutDir": [ - "C:/Users/TOKEJE~1/AppData/Local/Temp/tmpcjp1zvgv/output/test_project/test_asset/work/test_task/renders/maya/test_project_test_asset_workfileTest_task_v001/Main" - ], - "OutFile": [ - "Main.1001.exr" - ], - "PendingChunks": 0, - "Plug": "MayaBatch", - "Props": { - "AWSPortalAssetFileWhitelist": [], - "AWSPortalAssets": [], - "AutoTime": false, - "AuxSync": false, - "Batch": "test_project_test_asset_test_task_v001.ma31102023082742", - "Chunk": 1, - "Cmmt": "", - "Conc": 1, - "ConcLimt": true, - "Dep": [], - "DepComp": true, - "DepDel": false, - "DepFail": false, - "DepFrame": false, - "DepFrameEnd": 0, - "DepFrameStart": 0, - "DepPer": -1.0, - "Dept": "", - "Env": { - "AVALON_APP_NAME": "maya/2024", - "AVALON_ASSET": "test_asset", - "AVALON_PROJECT": "test_project", - "AVALON_TASK": "test_task", - "FTRACK_SERVER": "https://pype.ftrackapp.com", - "OPENPYPE_LOG_NO_COLORS": "1", - "OPENPYPE_MONGO": "mongodb://localhost:2707/", - "OPENPYPE_RENDER_JOB": "1" - }, - "EnvOnly": false, - "EventDir": "", - "EventOI": [], - "Ex0": "", - "Ex1": "", - "Ex2": "", - "Ex3": "", - "Ex4": "", - "Ex5": "", - "Ex6": "", - "Ex7": "", - "Ex8": "", - "Ex9": "", - "ExDic": {}, - "FrameTimeout": false, - "Frames": "1001", - "FriStart": "-10675199.02:48:05.4775808", - "FriStop": "-10675199.02:48:05.4775808", - "Grp": "none", - "InitializePluginTime": 0, - "Int": false, - "IntPer": 100, - "JobFailErr": 0, - "JobFailOvr": false, - "Limits": [], - "ListedSlaves": [], - "MachLmt": 0, - "MachLmtProg": -1.0, - "MaxTime": 0, - "MinTime": 0, - "MonStart": "-10675199.02:48:05.4775808", - "MonStop": "-10675199.02:48:05.4775808", - "Name": "test_project_test_asset_test_task_v001.ma31102023082742 - renderMain", - "NoBad": false, - "NoEvnt": false, - "NotEmail": [], - "NotNote": "", - "NotOvr": false, - "NotUser": [ - "tokejepsen" - ], - "OnComp": 2, - "OptIns": {}, - "OverAutoClean": false, - "OverClean": false, - "OverCleanDays": 0, - "OverCleanType": 1, - "OvrTaskEINames": false, - "PathMap": [], - "PlugDir": "", - "PlugInfo": { - "OutputFilePath": "C:/Users/TOKEJE~1/AppData/Local/Temp/tmpcjp1zvgv/output/test_project/test_asset/work/test_task/renders/maya", - "OutputFilePrefix": "//", - "ProjectPath": "C:\\Users\\TOKEJE~1\\AppData\\Local\\Temp\\tmpcjp1zvgv\\output\\test_project\\test_asset\\work\\test_task", - "RenderLayer": "rs_Main", - "RenderSetupIncludeLights": "True", - "Renderer": "arnold", - "SceneFile": "C:\\Users\\TOKEJE~1\\AppData\\Local\\Temp\\tmpcjp1zvgv\\output\\test_project\\test_asset\\publish\\workfile\\workfileTest_task\\v001\\test_project_test_asset_workfileTest_task_v001.ma", - "StrictErrorChecking": "True", - "UsingRenderLayers": "True", - "Version": "2024" - }, - "PoJobScrp": "", - "PoTskScrp": "", - "Pool": "none", - "PrJobScrp": "", - "PrTskScrp": "", - "Pri": 50, - "Protect": false, - "Region": "", - "Reload": false, - "RemTmT": 0, - "ReqAss": [ - { - "EndOffset": 0, - "FileName": "C:\\Users\\TOKEJE~1\\AppData\\Local\\Temp\\tmpcjp1zvgv\\output\\test_project\\test_asset\\publish\\workfile\\workfileTest_task\\v001\\test_project_test_asset_workfileTest_task_v001.ma", - "FrameString": "", - "IgnoreFrameOffsets": false, - "IsFrameAware": false, - "Notes": "", - "OverrideFrameOffsets": false, - "StartOffset": 0 - } - ], - "SatStart": "-10675199.02:48:05.4775808", - "SatStop": "-10675199.02:48:05.4775808", - "Schd": 0, - "SchdDate": "2023-10-31T08:27:42.9465593+00:00", - "SchdDays": 1, - "SchdStop": "0001-01-01T00:00:00Z", - "ScrDep": [], - "SecPool": "none", - "Seq": false, - "SndEmail": false, - "SndPopup": false, - "SndWarn": true, - "StartTime": 0, - "SunStart": "-10675199.02:48:05.4775808", - "SunStop": "-10675199.02:48:05.4775808", - "TaskEx0": "", - "TaskEx1": "", - "TaskEx2": "", - "TaskEx3": "", - "TaskEx4": "", - "TaskEx5": "", - "TaskEx6": "", - "TaskEx7": "", - "TaskEx8": "", - "TaskEx9": "", - "Tasks": 1, - "ThuStart": "-10675199.02:48:05.4775808", - "ThuStop": "-10675199.02:48:05.4775808", - "TimeScrpt": false, - "Timeout": 1, - "TskFailErr": 0, - "TskFailOvr": false, - "TueStart": "-10675199.02:48:05.4775808", - "TueStop": "-10675199.02:48:05.4775808", - "User": "tokejepsen", - "WedStart": "-10675199.02:48:05.4775808", - "WedStop": "-10675199.02:48:05.4775808", - "White": false - }, - "Purged": false, - "QueuedChunks": 0, - "RenderingChunks": 0, - "SnglTskPrg": "0 %", - "Stat": 6, - "SuspendedChunks": 0, - "Tile": false, - "TileCount": 0, - "TileFile": [], - "TileFrame": 0, - "TileX": 0, - "TileY": 0, - "_id": "6540ba7ec27eabc1c1a3d386" - }, - "session": { - "AVALON_APP": "maya", - "AVALON_ASSET": "test_asset", - "AVALON_DB": "avalon_tests", - "AVALON_LABEL": "OpenPype", - "AVALON_PROJECT": "test_project", - "AVALON_PROJECTS": "", - "AVALON_SCENEDIR": "", - "AVALON_TASK": "test_task", - "AVALON_TIMEOUT": "3000", - "AVALON_WORKDIR": "C:\\Users\\TOKEJE~1\\AppData\\Local\\Temp\\tmpcjp1zvgv\\output\\test_project\\test_asset\\work\\test_task", - "schema": "openpype:session-3.0" - }, - "source": "{root[work]}/test_project/test_asset/work/test_task/test_project_test_asset_test_task_v001.ma", - "user": "tokejepsen", - "version": 1 -} diff --git a/tests/integration/hosts/maya/test_publish_in_maya/expected/test_project/test_asset/work/test_task/test_project_test_asset_test_task_v001.ma b/tests/integration/hosts/maya/test_publish_in_maya/expected/test_project/test_asset/work/test_task/test_project_test_asset_test_task_v001.ma index e438d80d5f..2cc87c2f48 100644 --- a/tests/integration/hosts/maya/test_publish_in_maya/expected/test_project/test_asset/work/test_task/test_project_test_asset_test_task_v001.ma +++ b/tests/integration/hosts/maya/test_publish_in_maya/expected/test_project/test_asset/work/test_task/test_project_test_asset_test_task_v001.ma @@ -1,22 +1,22 @@ -//Maya ASCII 2022 scene -//Name: test_project_test_asset_test_task_v001.ma -//Last modified: Thu, Sep 14, 2023 06:31:00 PM +//Maya ASCII 2023 scene +//Name: test_project_test_asset_test_task_v002.ma +//Last modified: Thu, Dec 07, 2023 03:53:06 PM //Codeset: 1252 -requires maya "2022"; -requires -nodeType "polyDisc" "modelingToolkit" "0.0.0.0"; -requires "stereoCamera" "10.0"; -requires -nodeType "aiOptions" -nodeType "aiAOVDriver" -nodeType "aiAOVFilter" "mtoa" "5.2.2.1"; +requires maya "2023"; requires -nodeType "simpleSelector" -nodeType "renderSetupLayer" -nodeType "renderSetup" -nodeType "collection" "renderSetup.py" "1.0"; requires "stereoCamera" "10.0"; +requires -nodeType "aiOptions" -nodeType "aiAOVDriver" -nodeType "aiAOVFilter" "mtoa" "5.2.1.1"; +requires -nodeType "polyDisc" "modelingToolkit" "0.0.0.0"; +requires "stereoCamera" "10.0"; currentUnit -l centimeter -a degree -t pal; fileInfo "application" "maya"; -fileInfo "product" "Maya 2022"; -fileInfo "version" "2022"; -fileInfo "cutIdentifier" "202205171752-c25c06f306"; -fileInfo "osv" "Windows 10 Pro v2009 (Build: 19044)"; +fileInfo "product" "Maya 2023"; +fileInfo "version" "2023"; +fileInfo "cutIdentifier" "202211021031-847a9f9623"; +fileInfo "osv" "Windows 10 Pro v2009 (Build: 19045)"; fileInfo "license" "education"; -fileInfo "UUID" "019C7F50-40EF-1435-E27F-729F64685E67"; +fileInfo "UUID" "7A992745-4AD5-777F-5575-B4BFAC62B1D0"; fileInfo "OpenPypeContext" "eyJwdWJsaXNoX2F0dHJpYnV0ZXMiOiB7IlZhbGlkYXRlQ29udGFpbmVycyI6IHsiYWN0aXZlIjogdHJ1ZX19fQ=="; createNode transform -s -n "persp"; rename -uid "D52C935B-47C9-D868-A875-D799DD17B3A1"; @@ -142,19 +142,20 @@ createNode camera -n "perspShape1" -p "persp1"; setAttr ".hc" -type "string" "viewSet -p %camera"; setAttr ".dr" yes; createNode lightLinker -s -n "lightLinker1"; - rename -uid "6B9ADCD4-41B9-5BCC-826D-4A874A278510"; + rename -uid "09465BD3-42E5-18E4-7906-20A99BB2A6C0"; setAttr -s 2 ".lnk"; setAttr -s 2 ".slnk"; createNode shapeEditorManager -n "shapeEditorManager"; - rename -uid "5B4518C5-46C9-6921-690E-EFAF77B21A36"; + rename -uid "9F2E8009-4D69-046B-FCC4-28A8CE8F86DB"; createNode poseInterpolatorManager -n "poseInterpolatorManager"; - rename -uid "8518F293-4F06-BFF2-647A-72A099FBF025"; + rename -uid "6757AD81-40B0-A747-69C3-D9A56259571E"; createNode displayLayerManager -n "layerManager"; - rename -uid "04D880D5-4D86-0C58-CA3D-208ABE3E1E16"; + rename -uid "6F055ED5-4D91-8F85-7951-B4A13543A561"; createNode displayLayer -n "defaultLayer"; rename -uid "4A776D1B-401F-7069-1C74-A7AAE84CEE03"; + setAttr ".ufem" -type "stringArray" 0 ; createNode renderLayerManager -n "renderLayerManager"; - rename -uid "B719B8BE-46BF-12E6-BEBA-B0AD4DBDBA87"; + rename -uid "55626D2B-4FD5-61A1-7AB2-47B13F19D8AA"; setAttr -s 2 ".rlmi[1]" 1; setAttr -s 2 ".rlmi"; createNode renderLayer -n "defaultRenderLayer"; @@ -167,6 +168,7 @@ createNode polySphere -n "polySphere1"; createNode objectSet -n "modelMain"; rename -uid "A76AD4F8-4CF5-AA0D-4E98-BABEE6454CC3"; addAttr -ci true -sn "cbId" -ln "cbId" -dt "string"; + addAttr -ci true -sn "instance_id" -ln "instance_id" -dt "string"; addAttr -ci true -sn "id" -ln "id" -dt "string"; addAttr -ci true -sn "family" -ln "family" -dt "string"; addAttr -ci true -sn "subset" -ln "subset" -dt "string"; @@ -175,18 +177,19 @@ createNode objectSet -n "modelMain"; addAttr -ci true -sn "variant" -ln "variant" -dt "string"; addAttr -ci true -sn "asset" -ln "asset" -dt "string"; addAttr -ci true -sn "task" -ln "task" -dt "string"; - addAttr -ci true -sn "instance_id" -ln "instance_id" -dt "string"; addAttr -ci true -sn "writeColorSets" -ln "writeColorSets" -min 0 -max 1 -at "bool"; addAttr -ci true -sn "writeFaceSets" -ln "writeFaceSets" -min 0 -max 1 -at "bool"; - addAttr -ci true -sn "includeParentHierarchy" -ln "includeParentHierarchy" -min + addAttr -ci true -sn "includeParentHierarchy" -ln "includeParentHierarchy" -min 0 -max 1 -at "bool"; addAttr -ci true -sn "attr" -ln "attr" -dt "string"; addAttr -ci true -sn "attrPrefix" -ln "attrPrefix" -dt "string"; addAttr -ci true -sn "publish_attributes" -ln "publish_attributes" -dt "string"; - addAttr -ci true -sn "__creator_attributes_keys" -ln "__creator_attributes_keys" + addAttr -ci true -sn "creator_attributes" -ln "creator_attributes" -dt "string"; + addAttr -ci true -sn "__creator_attributes_keys" -ln "__creator_attributes_keys" -dt "string"; setAttr ".ihi" 0; setAttr ".cbId" -type "string" "60df31e2be2b48bd3695c056:7364ea6776c9"; + setAttr ".instance_id" -type "string" "6889d3db-b813-43db-96de-9ba555dc4472"; setAttr ".id" -type "string" "pyblish.avalon.instance"; setAttr ".family" -type "string" "model"; setAttr ".subset" -type "string" "modelMain"; @@ -195,59 +198,68 @@ createNode objectSet -n "modelMain"; setAttr ".variant" -type "string" "Main"; setAttr ".asset" -type "string" "test_asset"; setAttr ".task" -type "string" "test_task"; - setAttr ".instance_id" -type "string" "6889d3db-b813-43db-96de-9ba555dc4472"; setAttr -cb on ".writeColorSets"; setAttr -cb on ".writeFaceSets"; setAttr -cb on ".includeParentHierarchy"; setAttr ".attr" -type "string" ""; setAttr ".attrPrefix" -type "string" ""; - setAttr ".publish_attributes" -type "string" "{\"ValidateNodeIDsRelated\": {\"active\": true}, \"ValidateTransformNamingSuffix\": {\"active\": true}, \"ValidateColorSets\": {\"active\": true}, \"ValidateMeshArnoldAttributes\": {\"active\": true}, \"ValidateMeshHasUVs\": {\"active\": true}, \"ValidateMeshNonZeroEdgeLength\": {\"active\": true}, \"ExtractModel\": {\"active\": true}}"; + setAttr ".publish_attributes" -type "string" "{\"ValidateNodeIDsRelated\": {\"active\": true}, \"ValidateInstanceInContext\": {\"active\": true}, \"ValidateTransformNamingSuffix\": {\"active\": true}, \"ValidateColorSets\": {\"active\": true}, \"ValidateMeshHasUVs\": {\"active\": true}, \"ValidateMeshNonZeroEdgeLength\": {\"active\": true}, \"ExtractModel\": {\"active\": true}, \"ValidateMeshArnoldAttributes\": {\"active\": true}}"; + setAttr ".creator_attributes" -type "string" "{}"; setAttr ".__creator_attributes_keys" -type "string" "writeColorSets,writeFaceSets,includeParentHierarchy,attr,attrPrefix"; createNode script -n "uiConfigurationScriptNode"; rename -uid "4B7AFB53-452E-E870-63E1-CCA1DD6EAF13"; setAttr ".b" -type "string" ( "// Maya Mel UI Configuration File.\n//\n// This script is machine generated. Edit at your own risk.\n//\n//\n\nglobal string $gMainPane;\nif (`paneLayout -exists $gMainPane`) {\n\n\tglobal int $gUseScenePanelConfig;\n\tint $useSceneConfig = $gUseScenePanelConfig;\n\tint $nodeEditorPanelVisible = stringArrayContains(\"nodeEditorPanel1\", `getPanel -vis`);\n\tint $nodeEditorWorkspaceControlOpen = (`workspaceControl -exists nodeEditorPanel1Window` && `workspaceControl -q -visible nodeEditorPanel1Window`);\n\tint $menusOkayInPanels = `optionVar -q allowMenusInPanels`;\n\tint $nVisPanes = `paneLayout -q -nvp $gMainPane`;\n\tint $nPanes = 0;\n\tstring $editorName;\n\tstring $panelName;\n\tstring $itemFilterName;\n\tstring $panelConfig;\n\n\t//\n\t// get current state of the UI\n\t//\n\tsceneUIReplacement -update $gMainPane;\n\n\t$panelName = `sceneUIReplacement -getNextPanel \"modelPanel\" (localizedPanelLabel(\"Top View\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tmodelPanel -edit -l (localizedPanelLabel(\"Top View\")) -mbv $menusOkayInPanels $panelName;\n" - + "\t\t$editorName = $panelName;\n modelEditor -e \n -camera \"|top\" \n -useInteractiveMode 0\n -displayLights \"default\" \n -displayAppearance \"smoothShaded\" \n -activeOnly 0\n -ignorePanZoom 0\n -wireframeOnShaded 0\n -headsUpDisplay 1\n -holdOuts 1\n -selectionHiliteDisplay 1\n -useDefaultMaterial 0\n -bufferMode \"double\" \n -twoSidedLighting 0\n -backfaceCulling 0\n -xray 0\n -jointXray 0\n -activeComponentsXray 0\n -displayTextures 0\n -smoothWireframe 0\n -lineWidth 1\n -textureAnisotropic 0\n -textureHilight 1\n -textureSampling 2\n -textureDisplay \"modulate\" \n -textureMaxSize 16384\n -fogging 0\n -fogSource \"fragment\" \n -fogMode \"linear\" \n -fogStart 0\n -fogEnd 100\n -fogDensity 0.1\n -fogColor 0.5 0.5 0.5 1 \n" + + "\t\t$editorName = $panelName;\n modelEditor -e \n -camera \"|top\" \n -useInteractiveMode 0\n -displayLights \"default\" \n -displayAppearance \"smoothShaded\" \n -activeOnly 0\n -ignorePanZoom 0\n -wireframeOnShaded 0\n -headsUpDisplay 1\n -holdOuts 1\n -selectionHiliteDisplay 1\n -useDefaultMaterial 0\n -bufferMode \"double\" \n -twoSidedLighting 0\n -backfaceCulling 0\n -xray 0\n -jointXray 0\n -activeComponentsXray 0\n -displayTextures 0\n -smoothWireframe 0\n -lineWidth 1\n -textureAnisotropic 0\n -textureHilight 1\n -textureSampling 2\n -textureDisplay \"modulate\" \n -textureMaxSize 32768\n -fogging 0\n -fogSource \"fragment\" \n -fogMode \"linear\" \n -fogStart 0\n -fogEnd 100\n -fogDensity 0.1\n -fogColor 0.5 0.5 0.5 1 \n" + " -depthOfFieldPreview 1\n -maxConstantTransparency 1\n -rendererName \"vp2Renderer\" \n -objectFilterShowInHUD 1\n -isFiltered 0\n -colorResolution 256 256 \n -bumpResolution 512 512 \n -textureCompression 0\n -transparencyAlgorithm \"frontAndBackCull\" \n -transpInShadows 0\n -cullingOverride \"none\" \n -lowQualityLighting 0\n -maximumNumHardwareLights 1\n -occlusionCulling 0\n -shadingModel 0\n -useBaseRenderer 0\n -useReducedRenderer 0\n -smallObjectCulling 0\n -smallObjectThreshold -1 \n -interactiveDisableShadows 0\n -interactiveBackFaceCull 0\n -sortTransparent 1\n -controllers 1\n -nurbsCurves 1\n -nurbsSurfaces 1\n -polymeshes 1\n -subdivSurfaces 1\n -planes 1\n -lights 1\n -cameras 1\n -controlVertices 1\n" - + " -hulls 1\n -grid 1\n -imagePlane 1\n -joints 1\n -ikHandles 1\n -deformers 1\n -dynamics 1\n -particleInstancers 1\n -fluids 1\n -hairSystems 1\n -follicles 1\n -nCloths 1\n -nParticles 1\n -nRigids 1\n -dynamicConstraints 1\n -locators 1\n -manipulators 1\n -pluginShapes 1\n -dimensions 1\n -handles 1\n -pivots 1\n -textures 1\n -strokes 1\n -motionTrails 1\n -clipGhosts 1\n -greasePencils 1\n -shadows 0\n -captureSequenceNumber -1\n -width 1\n -height 1\n -sceneRenderFilter 0\n $editorName;\n modelEditor -e -viewSelected 0 $editorName;\n modelEditor -e \n -pluginObjects \"gpuCacheDisplayFilter\" 1 \n $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n" - + "\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextPanel \"modelPanel\" (localizedPanelLabel(\"Side View\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tmodelPanel -edit -l (localizedPanelLabel(\"Side View\")) -mbv $menusOkayInPanels $panelName;\n\t\t$editorName = $panelName;\n modelEditor -e \n -camera \"|side\" \n -useInteractiveMode 0\n -displayLights \"default\" \n -displayAppearance \"smoothShaded\" \n -activeOnly 0\n -ignorePanZoom 0\n -wireframeOnShaded 0\n -headsUpDisplay 1\n -holdOuts 1\n -selectionHiliteDisplay 1\n -useDefaultMaterial 0\n -bufferMode \"double\" \n -twoSidedLighting 0\n -backfaceCulling 0\n -xray 0\n -jointXray 0\n -activeComponentsXray 0\n -displayTextures 0\n -smoothWireframe 0\n -lineWidth 1\n -textureAnisotropic 0\n -textureHilight 1\n -textureSampling 2\n" - + " -textureDisplay \"modulate\" \n -textureMaxSize 16384\n -fogging 0\n -fogSource \"fragment\" \n -fogMode \"linear\" \n -fogStart 0\n -fogEnd 100\n -fogDensity 0.1\n -fogColor 0.5 0.5 0.5 1 \n -depthOfFieldPreview 1\n -maxConstantTransparency 1\n -rendererName \"vp2Renderer\" \n -objectFilterShowInHUD 1\n -isFiltered 0\n -colorResolution 256 256 \n -bumpResolution 512 512 \n -textureCompression 0\n -transparencyAlgorithm \"frontAndBackCull\" \n -transpInShadows 0\n -cullingOverride \"none\" \n -lowQualityLighting 0\n -maximumNumHardwareLights 1\n -occlusionCulling 0\n -shadingModel 0\n -useBaseRenderer 0\n -useReducedRenderer 0\n -smallObjectCulling 0\n -smallObjectThreshold -1 \n -interactiveDisableShadows 0\n -interactiveBackFaceCull 0\n" - + " -sortTransparent 1\n -controllers 1\n -nurbsCurves 1\n -nurbsSurfaces 1\n -polymeshes 1\n -subdivSurfaces 1\n -planes 1\n -lights 1\n -cameras 1\n -controlVertices 1\n -hulls 1\n -grid 1\n -imagePlane 1\n -joints 1\n -ikHandles 1\n -deformers 1\n -dynamics 1\n -particleInstancers 1\n -fluids 1\n -hairSystems 1\n -follicles 1\n -nCloths 1\n -nParticles 1\n -nRigids 1\n -dynamicConstraints 1\n -locators 1\n -manipulators 1\n -pluginShapes 1\n -dimensions 1\n -handles 1\n -pivots 1\n -textures 1\n -strokes 1\n -motionTrails 1\n -clipGhosts 1\n -greasePencils 1\n -shadows 0\n -captureSequenceNumber -1\n -width 1\n -height 1\n" - + " -sceneRenderFilter 0\n $editorName;\n modelEditor -e -viewSelected 0 $editorName;\n modelEditor -e \n -pluginObjects \"gpuCacheDisplayFilter\" 1 \n $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextPanel \"modelPanel\" (localizedPanelLabel(\"Front View\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tmodelPanel -edit -l (localizedPanelLabel(\"Front View\")) -mbv $menusOkayInPanels $panelName;\n\t\t$editorName = $panelName;\n modelEditor -e \n -camera \"|front\" \n -useInteractiveMode 0\n -displayLights \"default\" \n -displayAppearance \"smoothShaded\" \n -activeOnly 0\n -ignorePanZoom 0\n -wireframeOnShaded 0\n -headsUpDisplay 1\n -holdOuts 1\n -selectionHiliteDisplay 1\n -useDefaultMaterial 0\n -bufferMode \"double\" \n -twoSidedLighting 0\n -backfaceCulling 0\n" - + " -xray 0\n -jointXray 0\n -activeComponentsXray 0\n -displayTextures 0\n -smoothWireframe 0\n -lineWidth 1\n -textureAnisotropic 0\n -textureHilight 1\n -textureSampling 2\n -textureDisplay \"modulate\" \n -textureMaxSize 16384\n -fogging 0\n -fogSource \"fragment\" \n -fogMode \"linear\" \n -fogStart 0\n -fogEnd 100\n -fogDensity 0.1\n -fogColor 0.5 0.5 0.5 1 \n -depthOfFieldPreview 1\n -maxConstantTransparency 1\n -rendererName \"vp2Renderer\" \n -objectFilterShowInHUD 1\n -isFiltered 0\n -colorResolution 256 256 \n -bumpResolution 512 512 \n -textureCompression 0\n -transparencyAlgorithm \"frontAndBackCull\" \n -transpInShadows 0\n -cullingOverride \"none\" \n -lowQualityLighting 0\n -maximumNumHardwareLights 1\n -occlusionCulling 0\n" - + " -shadingModel 0\n -useBaseRenderer 0\n -useReducedRenderer 0\n -smallObjectCulling 0\n -smallObjectThreshold -1 \n -interactiveDisableShadows 0\n -interactiveBackFaceCull 0\n -sortTransparent 1\n -controllers 1\n -nurbsCurves 1\n -nurbsSurfaces 1\n -polymeshes 1\n -subdivSurfaces 1\n -planes 1\n -lights 1\n -cameras 1\n -controlVertices 1\n -hulls 1\n -grid 1\n -imagePlane 1\n -joints 1\n -ikHandles 1\n -deformers 1\n -dynamics 1\n -particleInstancers 1\n -fluids 1\n -hairSystems 1\n -follicles 1\n -nCloths 1\n -nParticles 1\n -nRigids 1\n -dynamicConstraints 1\n -locators 1\n -manipulators 1\n -pluginShapes 1\n -dimensions 1\n -handles 1\n -pivots 1\n" - + " -textures 1\n -strokes 1\n -motionTrails 1\n -clipGhosts 1\n -greasePencils 1\n -shadows 0\n -captureSequenceNumber -1\n -width 1\n -height 1\n -sceneRenderFilter 0\n $editorName;\n modelEditor -e -viewSelected 0 $editorName;\n modelEditor -e \n -pluginObjects \"gpuCacheDisplayFilter\" 1 \n $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextPanel \"modelPanel\" (localizedPanelLabel(\"Persp View\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tmodelPanel -edit -l (localizedPanelLabel(\"Persp View\")) -mbv $menusOkayInPanels $panelName;\n\t\t$editorName = $panelName;\n modelEditor -e \n -camera \"|persp\" \n -useInteractiveMode 0\n -displayLights \"default\" \n -displayAppearance \"smoothShaded\" \n -activeOnly 0\n -ignorePanZoom 0\n" - + " -wireframeOnShaded 0\n -headsUpDisplay 1\n -holdOuts 1\n -selectionHiliteDisplay 1\n -useDefaultMaterial 0\n -bufferMode \"double\" \n -twoSidedLighting 0\n -backfaceCulling 0\n -xray 0\n -jointXray 0\n -activeComponentsXray 0\n -displayTextures 0\n -smoothWireframe 0\n -lineWidth 1\n -textureAnisotropic 0\n -textureHilight 1\n -textureSampling 2\n -textureDisplay \"modulate\" \n -textureMaxSize 16384\n -fogging 0\n -fogSource \"fragment\" \n -fogMode \"linear\" \n -fogStart 0\n -fogEnd 100\n -fogDensity 0.1\n -fogColor 0.5 0.5 0.5 1 \n -depthOfFieldPreview 1\n -maxConstantTransparency 1\n -rendererName \"vp2Renderer\" \n -objectFilterShowInHUD 1\n -isFiltered 0\n -colorResolution 256 256 \n -bumpResolution 512 512 \n" - + " -textureCompression 0\n -transparencyAlgorithm \"frontAndBackCull\" \n -transpInShadows 0\n -cullingOverride \"none\" \n -lowQualityLighting 0\n -maximumNumHardwareLights 1\n -occlusionCulling 0\n -shadingModel 0\n -useBaseRenderer 0\n -useReducedRenderer 0\n -smallObjectCulling 0\n -smallObjectThreshold -1 \n -interactiveDisableShadows 0\n -interactiveBackFaceCull 0\n -sortTransparent 1\n -controllers 1\n -nurbsCurves 1\n -nurbsSurfaces 1\n -polymeshes 1\n -subdivSurfaces 1\n -planes 1\n -lights 1\n -cameras 1\n -controlVertices 1\n -hulls 1\n -grid 1\n -imagePlane 1\n -joints 1\n -ikHandles 1\n -deformers 1\n -dynamics 1\n -particleInstancers 1\n -fluids 1\n -hairSystems 1\n -follicles 1\n" - + " -nCloths 1\n -nParticles 1\n -nRigids 1\n -dynamicConstraints 1\n -locators 1\n -manipulators 1\n -pluginShapes 1\n -dimensions 1\n -handles 1\n -pivots 1\n -textures 1\n -strokes 1\n -motionTrails 1\n -clipGhosts 1\n -greasePencils 1\n -shadows 0\n -captureSequenceNumber -1\n -width 1312\n -height 732\n -sceneRenderFilter 0\n $editorName;\n modelEditor -e -viewSelected 0 $editorName;\n modelEditor -e \n -pluginObjects \"gpuCacheDisplayFilter\" 1 \n $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextPanel \"outlinerPanel\" (localizedPanelLabel(\"ToggledOutliner\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\toutlinerPanel -edit -l (localizedPanelLabel(\"ToggledOutliner\")) -mbv $menusOkayInPanels $panelName;\n" - + "\t\t$editorName = $panelName;\n outlinerEditor -e \n -docTag \"isolOutln_fromSeln\" \n -showShapes 0\n -showAssignedMaterials 0\n -showTimeEditor 1\n -showReferenceNodes 1\n -showReferenceMembers 1\n -showAttributes 0\n -showConnected 0\n -showAnimCurvesOnly 0\n -showMuteInfo 0\n -organizeByLayer 1\n -organizeByClip 1\n -showAnimLayerWeight 1\n -autoExpandLayers 1\n -autoExpand 0\n -showDagOnly 1\n -showAssets 1\n -showContainedOnly 1\n -showPublishedAsConnected 0\n -showParentContainers 0\n -showContainerContents 1\n -ignoreDagHierarchy 0\n -expandConnections 0\n -showUpstreamCurves 1\n -showUnitlessCurves 1\n -showCompounds 1\n -showLeafs 1\n -showNumericAttrsOnly 0\n -highlightActive 1\n -autoSelectNewObjects 0\n" - + " -doNotSelectNewObjects 0\n -dropIsParent 1\n -transmitFilters 0\n -setFilter \"defaultSetFilter\" \n -showSetMembers 1\n -allowMultiSelection 1\n -alwaysToggleSelect 0\n -directSelect 0\n -isSet 0\n -isSetMember 0\n -displayMode \"DAG\" \n -expandObjects 0\n -setsIgnoreFilters 1\n -containersIgnoreFilters 0\n -editAttrName 0\n -showAttrValues 0\n -highlightSecondary 0\n -showUVAttrsOnly 0\n -showTextureNodesOnly 0\n -attrAlphaOrder \"default\" \n -animLayerFilterOptions \"allAffecting\" \n -sortOrder \"none\" \n -longNames 0\n -niceNames 1\n -selectCommand \"print(\\\"\\\")\" \n -showNamespace 1\n -showPinIcons 0\n -mapMotionTrails 0\n -ignoreHiddenAttribute 1\n -ignoreOutlinerColor 0\n -renderFilterVisible 0\n -renderFilterIndex 0\n" - + " -selectionOrder \"chronological\" \n -expandAttribute 0\n $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextPanel \"outlinerPanel\" (localizedPanelLabel(\"Outliner\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\toutlinerPanel -edit -l (localizedPanelLabel(\"Outliner\")) -mbv $menusOkayInPanels $panelName;\n\t\t$editorName = $panelName;\n outlinerEditor -e \n -showShapes 0\n -showAssignedMaterials 0\n -showTimeEditor 1\n -showReferenceNodes 0\n -showReferenceMembers 0\n -showAttributes 0\n -showConnected 0\n -showAnimCurvesOnly 0\n -showMuteInfo 0\n -organizeByLayer 1\n -organizeByClip 1\n -showAnimLayerWeight 1\n -autoExpandLayers 1\n -autoExpand 0\n -showDagOnly 1\n -showAssets 1\n -showContainedOnly 1\n -showPublishedAsConnected 0\n" - + " -showParentContainers 0\n -showContainerContents 1\n -ignoreDagHierarchy 0\n -expandConnections 0\n -showUpstreamCurves 1\n -showUnitlessCurves 1\n -showCompounds 1\n -showLeafs 1\n -showNumericAttrsOnly 0\n -highlightActive 1\n -autoSelectNewObjects 0\n -doNotSelectNewObjects 0\n -dropIsParent 1\n -transmitFilters 0\n -setFilter \"defaultSetFilter\" \n -showSetMembers 1\n -allowMultiSelection 1\n -alwaysToggleSelect 0\n -directSelect 0\n -displayMode \"DAG\" \n -expandObjects 0\n -setsIgnoreFilters 1\n -containersIgnoreFilters 0\n -editAttrName 0\n -showAttrValues 0\n -highlightSecondary 0\n -showUVAttrsOnly 0\n -showTextureNodesOnly 0\n -attrAlphaOrder \"default\" \n -animLayerFilterOptions \"allAffecting\" \n -sortOrder \"none\" \n" - + " -longNames 0\n -niceNames 1\n -showNamespace 1\n -showPinIcons 0\n -mapMotionTrails 0\n -ignoreHiddenAttribute 0\n -ignoreOutlinerColor 0\n -renderFilterVisible 0\n $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"graphEditor\" (localizedPanelLabel(\"Graph Editor\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Graph Editor\")) -mbv $menusOkayInPanels $panelName;\n\n\t\t\t$editorName = ($panelName+\"OutlineEd\");\n outlinerEditor -e \n -showShapes 1\n -showAssignedMaterials 0\n -showTimeEditor 1\n -showReferenceNodes 0\n -showReferenceMembers 0\n -showAttributes 1\n -showConnected 1\n -showAnimCurvesOnly 1\n -showMuteInfo 0\n -organizeByLayer 1\n" - + " -organizeByClip 1\n -showAnimLayerWeight 1\n -autoExpandLayers 1\n -autoExpand 1\n -showDagOnly 0\n -showAssets 1\n -showContainedOnly 0\n -showPublishedAsConnected 0\n -showParentContainers 0\n -showContainerContents 0\n -ignoreDagHierarchy 0\n -expandConnections 1\n -showUpstreamCurves 1\n -showUnitlessCurves 1\n -showCompounds 0\n -showLeafs 1\n -showNumericAttrsOnly 1\n -highlightActive 0\n -autoSelectNewObjects 1\n -doNotSelectNewObjects 0\n -dropIsParent 1\n -transmitFilters 1\n -setFilter \"0\" \n -showSetMembers 0\n -allowMultiSelection 1\n -alwaysToggleSelect 0\n -directSelect 0\n -displayMode \"DAG\" \n -expandObjects 0\n" - + " -setsIgnoreFilters 1\n -containersIgnoreFilters 0\n -editAttrName 0\n -showAttrValues 0\n -highlightSecondary 0\n -showUVAttrsOnly 0\n -showTextureNodesOnly 0\n -attrAlphaOrder \"default\" \n -animLayerFilterOptions \"allAffecting\" \n -sortOrder \"none\" \n -longNames 0\n -niceNames 1\n -showNamespace 1\n -showPinIcons 1\n -mapMotionTrails 1\n -ignoreHiddenAttribute 0\n -ignoreOutlinerColor 0\n -renderFilterVisible 0\n $editorName;\n\n\t\t\t$editorName = ($panelName+\"GraphEd\");\n animCurveEditor -e \n -displayValues 0\n -snapTime \"integer\" \n -snapValue \"none\" \n -showPlayRangeShades \"on\" \n -lockPlayRangeShades \"off\" \n -smoothness \"fine\" \n -resultSamples 1.041667\n" - + " -resultScreenSamples 0\n -resultUpdate \"delayed\" \n -showUpstreamCurves 1\n -keyMinScale 1\n -stackedCurvesMin -1\n -stackedCurvesMax 1\n -stackedCurvesSpace 0.2\n -preSelectionHighlight 0\n -constrainDrag 0\n -valueLinesToggle 1\n -highlightAffectedCurves 0\n $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"dopeSheetPanel\" (localizedPanelLabel(\"Dope Sheet\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Dope Sheet\")) -mbv $menusOkayInPanels $panelName;\n\n\t\t\t$editorName = ($panelName+\"OutlineEd\");\n outlinerEditor -e \n -showShapes 1\n -showAssignedMaterials 0\n -showTimeEditor 1\n -showReferenceNodes 0\n -showReferenceMembers 0\n" - + " -showAttributes 1\n -showConnected 1\n -showAnimCurvesOnly 1\n -showMuteInfo 0\n -organizeByLayer 1\n -organizeByClip 1\n -showAnimLayerWeight 1\n -autoExpandLayers 1\n -autoExpand 0\n -showDagOnly 0\n -showAssets 1\n -showContainedOnly 0\n -showPublishedAsConnected 0\n -showParentContainers 0\n -showContainerContents 0\n -ignoreDagHierarchy 0\n -expandConnections 1\n -showUpstreamCurves 1\n -showUnitlessCurves 0\n -showCompounds 1\n -showLeafs 1\n -showNumericAttrsOnly 1\n -highlightActive 0\n -autoSelectNewObjects 0\n -doNotSelectNewObjects 1\n -dropIsParent 1\n -transmitFilters 0\n -setFilter \"0\" \n -showSetMembers 0\n" - + " -allowMultiSelection 1\n -alwaysToggleSelect 0\n -directSelect 0\n -displayMode \"DAG\" \n -expandObjects 0\n -setsIgnoreFilters 1\n -containersIgnoreFilters 0\n -editAttrName 0\n -showAttrValues 0\n -highlightSecondary 0\n -showUVAttrsOnly 0\n -showTextureNodesOnly 0\n -attrAlphaOrder \"default\" \n -animLayerFilterOptions \"allAffecting\" \n -sortOrder \"none\" \n -longNames 0\n -niceNames 1\n -showNamespace 1\n -showPinIcons 0\n -mapMotionTrails 1\n -ignoreHiddenAttribute 0\n -ignoreOutlinerColor 0\n -renderFilterVisible 0\n $editorName;\n\n\t\t\t$editorName = ($panelName+\"DopeSheetEd\");\n dopeSheetEditor -e \n -displayValues 0\n -snapTime \"integer\" \n" - + " -snapValue \"none\" \n -outliner \"dopeSheetPanel1OutlineEd\" \n -showSummary 1\n -showScene 0\n -hierarchyBelow 0\n -showTicks 1\n -selectionWindow 0 0 0 0 \n $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"timeEditorPanel\" (localizedPanelLabel(\"Time Editor\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Time Editor\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"clipEditorPanel\" (localizedPanelLabel(\"Trax Editor\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Trax Editor\")) -mbv $menusOkayInPanels $panelName;\n\n\t\t\t$editorName = clipEditorNameFromPanel($panelName);\n" - + " clipEditor -e \n -displayValues 0\n -snapTime \"none\" \n -snapValue \"none\" \n -initialized 0\n -manageSequencer 0 \n $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"sequenceEditorPanel\" (localizedPanelLabel(\"Camera Sequencer\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Camera Sequencer\")) -mbv $menusOkayInPanels $panelName;\n\n\t\t\t$editorName = sequenceEditorNameFromPanel($panelName);\n clipEditor -e \n -displayValues 0\n -snapTime \"none\" \n -snapValue \"none\" \n -initialized 0\n -manageSequencer 1 \n $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"hyperGraphPanel\" (localizedPanelLabel(\"Hypergraph Hierarchy\")) `;\n" - + "\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Hypergraph Hierarchy\")) -mbv $menusOkayInPanels $panelName;\n\n\t\t\t$editorName = ($panelName+\"HyperGraphEd\");\n hyperGraph -e \n -graphLayoutStyle \"hierarchicalLayout\" \n -orientation \"horiz\" \n -mergeConnections 0\n -zoom 1\n -animateTransition 0\n -showRelationships 1\n -showShapes 0\n -showDeformers 0\n -showExpressions 0\n -showConstraints 0\n -showConnectionFromSelected 0\n -showConnectionToSelected 0\n -showConstraintLabels 0\n -showUnderworld 0\n -showInvisible 0\n -transitionFrames 1\n -opaqueContainers 0\n -freeform 0\n -imagePosition 0 0 \n -imageScale 1\n -imageEnabled 0\n -graphType \"DAG\" \n" - + " -heatMapDisplay 0\n -updateSelection 1\n -updateNodeAdded 1\n -useDrawOverrideColor 0\n -limitGraphTraversal -1\n -range 0 0 \n -iconSize \"smallIcons\" \n -showCachedConnections 0\n $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"hyperShadePanel\" (localizedPanelLabel(\"Hypershade\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Hypershade\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"visorPanel\" (localizedPanelLabel(\"Visor\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Visor\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n" - + "\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"nodeEditorPanel\" (localizedPanelLabel(\"Node Editor\")) `;\n\tif ($nodeEditorPanelVisible || $nodeEditorWorkspaceControlOpen) {\n\t\tif (\"\" == $panelName) {\n\t\t\tif ($useSceneConfig) {\n\t\t\t\t$panelName = `scriptedPanel -unParent -type \"nodeEditorPanel\" -l (localizedPanelLabel(\"Node Editor\")) -mbv $menusOkayInPanels `;\n\n\t\t\t$editorName = ($panelName+\"NodeEditorEd\");\n nodeEditor -e \n -allAttributes 0\n -allNodes 0\n -autoSizeNodes 1\n -consistentNameSize 1\n -createNodeCommand \"nodeEdCreateNodeCommand\" \n -connectNodeOnCreation 0\n -connectOnDrop 0\n -copyConnectionsOnPaste 0\n -connectionStyle \"bezier\" \n -defaultPinnedState 0\n -additiveGraphingMode 0\n -settingsChangedCallback \"nodeEdSyncControls\" \n -traversalDepthLimit -1\n -keyPressCommand \"nodeEdKeyPressCommand\" \n" - + " -nodeTitleMode \"name\" \n -gridSnap 0\n -gridVisibility 1\n -crosshairOnEdgeDragging 0\n -popupMenuScript \"nodeEdBuildPanelMenus\" \n -showNamespace 1\n -showShapes 1\n -showSGShapes 0\n -showTransforms 1\n -useAssets 1\n -syncedSelection 1\n -extendToShapes 1\n -editorMode \"default\" \n -hasWatchpoint 0\n $editorName;\n\t\t\t}\n\t\t} else {\n\t\t\t$label = `panel -q -label $panelName`;\n\t\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Node Editor\")) -mbv $menusOkayInPanels $panelName;\n\n\t\t\t$editorName = ($panelName+\"NodeEditorEd\");\n nodeEditor -e \n -allAttributes 0\n -allNodes 0\n -autoSizeNodes 1\n -consistentNameSize 1\n -createNodeCommand \"nodeEdCreateNodeCommand\" \n -connectNodeOnCreation 0\n -connectOnDrop 0\n" - + " -copyConnectionsOnPaste 0\n -connectionStyle \"bezier\" \n -defaultPinnedState 0\n -additiveGraphingMode 0\n -settingsChangedCallback \"nodeEdSyncControls\" \n -traversalDepthLimit -1\n -keyPressCommand \"nodeEdKeyPressCommand\" \n -nodeTitleMode \"name\" \n -gridSnap 0\n -gridVisibility 1\n -crosshairOnEdgeDragging 0\n -popupMenuScript \"nodeEdBuildPanelMenus\" \n -showNamespace 1\n -showShapes 1\n -showSGShapes 0\n -showTransforms 1\n -useAssets 1\n -syncedSelection 1\n -extendToShapes 1\n -editorMode \"default\" \n -hasWatchpoint 0\n $editorName;\n\t\t\tif (!$useSceneConfig) {\n\t\t\t\tpanel -e -l $label $panelName;\n\t\t\t}\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"createNodePanel\" (localizedPanelLabel(\"Create Node\")) `;\n" - + "\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Create Node\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"polyTexturePlacementPanel\" (localizedPanelLabel(\"UV Editor\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"UV Editor\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"renderWindowPanel\" (localizedPanelLabel(\"Render View\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Render View\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextPanel \"shapePanel\" (localizedPanelLabel(\"Shape Editor\")) `;\n" - + "\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tshapePanel -edit -l (localizedPanelLabel(\"Shape Editor\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextPanel \"posePanel\" (localizedPanelLabel(\"Pose Editor\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tposePanel -edit -l (localizedPanelLabel(\"Pose Editor\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"dynRelEdPanel\" (localizedPanelLabel(\"Dynamic Relationships\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Dynamic Relationships\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"relationshipPanel\" (localizedPanelLabel(\"Relationship Editor\")) `;\n" - + "\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Relationship Editor\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"referenceEditorPanel\" (localizedPanelLabel(\"Reference Editor\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Reference Editor\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"componentEditorPanel\" (localizedPanelLabel(\"Component Editor\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Component Editor\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"dynPaintScriptedPanelType\" (localizedPanelLabel(\"Paint Effects\")) `;\n" - + "\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Paint Effects\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"scriptEditorPanel\" (localizedPanelLabel(\"Script Editor\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Script Editor\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"profilerPanel\" (localizedPanelLabel(\"Profiler Tool\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Profiler Tool\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"contentBrowserPanel\" (localizedPanelLabel(\"Content Browser\")) `;\n" - + "\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Content Browser\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"Stereo\" (localizedPanelLabel(\"Stereo\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Stereo\")) -mbv $menusOkayInPanels $panelName;\n{ string $editorName = ($panelName+\"Editor\");\n stereoCameraView -e \n -camera \"|persp\" \n -useInteractiveMode 0\n -displayLights \"default\" \n -displayAppearance \"wireframe\" \n -activeOnly 0\n -ignorePanZoom 0\n -wireframeOnShaded 0\n -headsUpDisplay 1\n -holdOuts 1\n -selectionHiliteDisplay 1\n -useDefaultMaterial 0\n -bufferMode \"double\" \n -twoSidedLighting 1\n" - + " -backfaceCulling 0\n -xray 0\n -jointXray 0\n -activeComponentsXray 0\n -displayTextures 0\n -smoothWireframe 0\n -lineWidth 1\n -textureAnisotropic 0\n -textureHilight 1\n -textureSampling 2\n -textureDisplay \"modulate\" \n -textureMaxSize 16384\n -fogging 0\n -fogSource \"fragment\" \n -fogMode \"linear\" \n -fogStart 0\n -fogEnd 100\n -fogDensity 0.1\n -fogColor 0.5 0.5 0.5 1 \n -depthOfFieldPreview 1\n -maxConstantTransparency 1\n -objectFilterShowInHUD 1\n -isFiltered 0\n -colorResolution 4 4 \n -bumpResolution 4 4 \n -textureCompression 0\n -transparencyAlgorithm \"frontAndBackCull\" \n -transpInShadows 0\n -cullingOverride \"none\" \n" - + " -lowQualityLighting 0\n -maximumNumHardwareLights 0\n -occlusionCulling 0\n -shadingModel 0\n -useBaseRenderer 0\n -useReducedRenderer 0\n -smallObjectCulling 0\n -smallObjectThreshold -1 \n -interactiveDisableShadows 0\n -interactiveBackFaceCull 0\n -sortTransparent 1\n -controllers 1\n -nurbsCurves 1\n -nurbsSurfaces 1\n -polymeshes 1\n -subdivSurfaces 1\n -planes 1\n -lights 1\n -cameras 1\n -controlVertices 1\n -hulls 1\n -grid 1\n -imagePlane 1\n -joints 1\n -ikHandles 1\n -deformers 1\n -dynamics 1\n -particleInstancers 1\n -fluids 1\n -hairSystems 1\n -follicles 1\n -nCloths 1\n" - + " -nParticles 1\n -nRigids 1\n -dynamicConstraints 1\n -locators 1\n -manipulators 1\n -pluginShapes 1\n -dimensions 1\n -handles 1\n -pivots 1\n -textures 1\n -strokes 1\n -motionTrails 1\n -clipGhosts 1\n -greasePencils 1\n -shadows 0\n -captureSequenceNumber -1\n -width 0\n -height 0\n -sceneRenderFilter 0\n -displayMode \"centerEye\" \n -viewColor 0 0 0 1 \n -useCustomBackground 1\n $editorName;\n stereoCameraView -e -viewSelected 0 $editorName;\n stereoCameraView -e \n -pluginObjects \"gpuCacheDisplayFilter\" 1 \n $editorName; };\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\tif ($useSceneConfig) {\n string $configName = `getPanel -cwl (localizedPanelLabel(\"Current Layout\"))`;\n" - + " if (\"\" != $configName) {\n\t\t\tpanelConfiguration -edit -label (localizedPanelLabel(\"Current Layout\")) \n\t\t\t\t-userCreated false\n\t\t\t\t-defaultImage \"vacantCell.xP:/\"\n\t\t\t\t-image \"\"\n\t\t\t\t-sc false\n\t\t\t\t-configString \"global string $gMainPane; paneLayout -e -cn \\\"single\\\" -ps 1 100 100 $gMainPane;\"\n\t\t\t\t-removeAllPanels\n\t\t\t\t-ap false\n\t\t\t\t\t(localizedPanelLabel(\"Persp View\")) \n\t\t\t\t\t\"modelPanel\"\n" - + "\t\t\t\t\t\"$panelName = `modelPanel -unParent -l (localizedPanelLabel(\\\"Persp View\\\")) -mbv $menusOkayInPanels `;\\n$editorName = $panelName;\\nmodelEditor -e \\n -cam `findStartUpCamera persp` \\n -useInteractiveMode 0\\n -displayLights \\\"default\\\" \\n -displayAppearance \\\"smoothShaded\\\" \\n -activeOnly 0\\n -ignorePanZoom 0\\n -wireframeOnShaded 0\\n -headsUpDisplay 1\\n -holdOuts 1\\n -selectionHiliteDisplay 1\\n -useDefaultMaterial 0\\n -bufferMode \\\"double\\\" \\n -twoSidedLighting 0\\n -backfaceCulling 0\\n -xray 0\\n -jointXray 0\\n -activeComponentsXray 0\\n -displayTextures 0\\n -smoothWireframe 0\\n -lineWidth 1\\n -textureAnisotropic 0\\n -textureHilight 1\\n -textureSampling 2\\n -textureDisplay \\\"modulate\\\" \\n -textureMaxSize 16384\\n -fogging 0\\n -fogSource \\\"fragment\\\" \\n -fogMode \\\"linear\\\" \\n -fogStart 0\\n -fogEnd 100\\n -fogDensity 0.1\\n -fogColor 0.5 0.5 0.5 1 \\n -depthOfFieldPreview 1\\n -maxConstantTransparency 1\\n -rendererName \\\"vp2Renderer\\\" \\n -objectFilterShowInHUD 1\\n -isFiltered 0\\n -colorResolution 256 256 \\n -bumpResolution 512 512 \\n -textureCompression 0\\n -transparencyAlgorithm \\\"frontAndBackCull\\\" \\n -transpInShadows 0\\n -cullingOverride \\\"none\\\" \\n -lowQualityLighting 0\\n -maximumNumHardwareLights 1\\n -occlusionCulling 0\\n -shadingModel 0\\n -useBaseRenderer 0\\n -useReducedRenderer 0\\n -smallObjectCulling 0\\n -smallObjectThreshold -1 \\n -interactiveDisableShadows 0\\n -interactiveBackFaceCull 0\\n -sortTransparent 1\\n -controllers 1\\n -nurbsCurves 1\\n -nurbsSurfaces 1\\n -polymeshes 1\\n -subdivSurfaces 1\\n -planes 1\\n -lights 1\\n -cameras 1\\n -controlVertices 1\\n -hulls 1\\n -grid 1\\n -imagePlane 1\\n -joints 1\\n -ikHandles 1\\n -deformers 1\\n -dynamics 1\\n -particleInstancers 1\\n -fluids 1\\n -hairSystems 1\\n -follicles 1\\n -nCloths 1\\n -nParticles 1\\n -nRigids 1\\n -dynamicConstraints 1\\n -locators 1\\n -manipulators 1\\n -pluginShapes 1\\n -dimensions 1\\n -handles 1\\n -pivots 1\\n -textures 1\\n -strokes 1\\n -motionTrails 1\\n -clipGhosts 1\\n -greasePencils 1\\n -shadows 0\\n -captureSequenceNumber -1\\n -width 1312\\n -height 732\\n -sceneRenderFilter 0\\n $editorName;\\nmodelEditor -e -viewSelected 0 $editorName;\\nmodelEditor -e \\n -pluginObjects \\\"gpuCacheDisplayFilter\\\" 1 \\n $editorName\"\n" - + "\t\t\t\t\t\"modelPanel -edit -l (localizedPanelLabel(\\\"Persp View\\\")) -mbv $menusOkayInPanels $panelName;\\n$editorName = $panelName;\\nmodelEditor -e \\n -cam `findStartUpCamera persp` \\n -useInteractiveMode 0\\n -displayLights \\\"default\\\" \\n -displayAppearance \\\"smoothShaded\\\" \\n -activeOnly 0\\n -ignorePanZoom 0\\n -wireframeOnShaded 0\\n -headsUpDisplay 1\\n -holdOuts 1\\n -selectionHiliteDisplay 1\\n -useDefaultMaterial 0\\n -bufferMode \\\"double\\\" \\n -twoSidedLighting 0\\n -backfaceCulling 0\\n -xray 0\\n -jointXray 0\\n -activeComponentsXray 0\\n -displayTextures 0\\n -smoothWireframe 0\\n -lineWidth 1\\n -textureAnisotropic 0\\n -textureHilight 1\\n -textureSampling 2\\n -textureDisplay \\\"modulate\\\" \\n -textureMaxSize 16384\\n -fogging 0\\n -fogSource \\\"fragment\\\" \\n -fogMode \\\"linear\\\" \\n -fogStart 0\\n -fogEnd 100\\n -fogDensity 0.1\\n -fogColor 0.5 0.5 0.5 1 \\n -depthOfFieldPreview 1\\n -maxConstantTransparency 1\\n -rendererName \\\"vp2Renderer\\\" \\n -objectFilterShowInHUD 1\\n -isFiltered 0\\n -colorResolution 256 256 \\n -bumpResolution 512 512 \\n -textureCompression 0\\n -transparencyAlgorithm \\\"frontAndBackCull\\\" \\n -transpInShadows 0\\n -cullingOverride \\\"none\\\" \\n -lowQualityLighting 0\\n -maximumNumHardwareLights 1\\n -occlusionCulling 0\\n -shadingModel 0\\n -useBaseRenderer 0\\n -useReducedRenderer 0\\n -smallObjectCulling 0\\n -smallObjectThreshold -1 \\n -interactiveDisableShadows 0\\n -interactiveBackFaceCull 0\\n -sortTransparent 1\\n -controllers 1\\n -nurbsCurves 1\\n -nurbsSurfaces 1\\n -polymeshes 1\\n -subdivSurfaces 1\\n -planes 1\\n -lights 1\\n -cameras 1\\n -controlVertices 1\\n -hulls 1\\n -grid 1\\n -imagePlane 1\\n -joints 1\\n -ikHandles 1\\n -deformers 1\\n -dynamics 1\\n -particleInstancers 1\\n -fluids 1\\n -hairSystems 1\\n -follicles 1\\n -nCloths 1\\n -nParticles 1\\n -nRigids 1\\n -dynamicConstraints 1\\n -locators 1\\n -manipulators 1\\n -pluginShapes 1\\n -dimensions 1\\n -handles 1\\n -pivots 1\\n -textures 1\\n -strokes 1\\n -motionTrails 1\\n -clipGhosts 1\\n -greasePencils 1\\n -shadows 0\\n -captureSequenceNumber -1\\n -width 1312\\n -height 732\\n -sceneRenderFilter 0\\n $editorName;\\nmodelEditor -e -viewSelected 0 $editorName;\\nmodelEditor -e \\n -pluginObjects \\\"gpuCacheDisplayFilter\\\" 1 \\n $editorName\"\n" + + " -hulls 1\n -grid 1\n -imagePlane 1\n -joints 1\n -ikHandles 1\n -deformers 1\n -dynamics 1\n -particleInstancers 1\n -fluids 1\n -hairSystems 1\n -follicles 1\n -nCloths 1\n -nParticles 1\n -nRigids 1\n -dynamicConstraints 1\n -locators 1\n -manipulators 1\n -pluginShapes 1\n -dimensions 1\n -handles 1\n -pivots 1\n -textures 1\n -strokes 1\n -motionTrails 1\n -clipGhosts 1\n -bluePencil 1\n -greasePencils 0\n -shadows 0\n -captureSequenceNumber -1\n -width 477\n -height 276\n -sceneRenderFilter 0\n $editorName;\n modelEditor -e -viewSelected 0 $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextPanel \"modelPanel\" (localizedPanelLabel(\"Side View\")) `;\n" + + "\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tmodelPanel -edit -l (localizedPanelLabel(\"Side View\")) -mbv $menusOkayInPanels $panelName;\n\t\t$editorName = $panelName;\n modelEditor -e \n -camera \"|side\" \n -useInteractiveMode 0\n -displayLights \"default\" \n -displayAppearance \"smoothShaded\" \n -activeOnly 0\n -ignorePanZoom 0\n -wireframeOnShaded 0\n -headsUpDisplay 1\n -holdOuts 1\n -selectionHiliteDisplay 1\n -useDefaultMaterial 0\n -bufferMode \"double\" \n -twoSidedLighting 0\n -backfaceCulling 0\n -xray 0\n -jointXray 0\n -activeComponentsXray 0\n -displayTextures 0\n -smoothWireframe 0\n -lineWidth 1\n -textureAnisotropic 0\n -textureHilight 1\n -textureSampling 2\n -textureDisplay \"modulate\" \n -textureMaxSize 32768\n -fogging 0\n" + + " -fogSource \"fragment\" \n -fogMode \"linear\" \n -fogStart 0\n -fogEnd 100\n -fogDensity 0.1\n -fogColor 0.5 0.5 0.5 1 \n -depthOfFieldPreview 1\n -maxConstantTransparency 1\n -rendererName \"vp2Renderer\" \n -objectFilterShowInHUD 1\n -isFiltered 0\n -colorResolution 256 256 \n -bumpResolution 512 512 \n -textureCompression 0\n -transparencyAlgorithm \"frontAndBackCull\" \n -transpInShadows 0\n -cullingOverride \"none\" \n -lowQualityLighting 0\n -maximumNumHardwareLights 1\n -occlusionCulling 0\n -shadingModel 0\n -useBaseRenderer 0\n -useReducedRenderer 0\n -smallObjectCulling 0\n -smallObjectThreshold -1 \n -interactiveDisableShadows 0\n -interactiveBackFaceCull 0\n -sortTransparent 1\n -controllers 1\n -nurbsCurves 1\n" + + " -nurbsSurfaces 1\n -polymeshes 1\n -subdivSurfaces 1\n -planes 1\n -lights 1\n -cameras 1\n -controlVertices 1\n -hulls 1\n -grid 1\n -imagePlane 1\n -joints 1\n -ikHandles 1\n -deformers 1\n -dynamics 1\n -particleInstancers 1\n -fluids 1\n -hairSystems 1\n -follicles 1\n -nCloths 1\n -nParticles 1\n -nRigids 1\n -dynamicConstraints 1\n -locators 1\n -manipulators 1\n -pluginShapes 1\n -dimensions 1\n -handles 1\n -pivots 1\n -textures 1\n -strokes 1\n -motionTrails 1\n -clipGhosts 1\n -bluePencil 1\n -greasePencils 0\n -shadows 0\n -captureSequenceNumber -1\n -width 476\n -height 276\n -sceneRenderFilter 0\n $editorName;\n" + + " modelEditor -e -viewSelected 0 $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextPanel \"modelPanel\" (localizedPanelLabel(\"Front View\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tmodelPanel -edit -l (localizedPanelLabel(\"Front View\")) -mbv $menusOkayInPanels $panelName;\n\t\t$editorName = $panelName;\n modelEditor -e \n -camera \"|front\" \n -useInteractiveMode 0\n -displayLights \"default\" \n -displayAppearance \"smoothShaded\" \n -activeOnly 0\n -ignorePanZoom 0\n -wireframeOnShaded 0\n -headsUpDisplay 1\n -holdOuts 1\n -selectionHiliteDisplay 1\n -useDefaultMaterial 0\n -bufferMode \"double\" \n -twoSidedLighting 0\n -backfaceCulling 0\n -xray 0\n -jointXray 0\n -activeComponentsXray 0\n -displayTextures 0\n -smoothWireframe 0\n" + + " -lineWidth 1\n -textureAnisotropic 0\n -textureHilight 1\n -textureSampling 2\n -textureDisplay \"modulate\" \n -textureMaxSize 32768\n -fogging 0\n -fogSource \"fragment\" \n -fogMode \"linear\" \n -fogStart 0\n -fogEnd 100\n -fogDensity 0.1\n -fogColor 0.5 0.5 0.5 1 \n -depthOfFieldPreview 1\n -maxConstantTransparency 1\n -rendererName \"vp2Renderer\" \n -objectFilterShowInHUD 1\n -isFiltered 0\n -colorResolution 256 256 \n -bumpResolution 512 512 \n -textureCompression 0\n -transparencyAlgorithm \"frontAndBackCull\" \n -transpInShadows 0\n -cullingOverride \"none\" \n -lowQualityLighting 0\n -maximumNumHardwareLights 1\n -occlusionCulling 0\n -shadingModel 0\n -useBaseRenderer 0\n -useReducedRenderer 0\n -smallObjectCulling 0\n" + + " -smallObjectThreshold -1 \n -interactiveDisableShadows 0\n -interactiveBackFaceCull 0\n -sortTransparent 1\n -controllers 1\n -nurbsCurves 1\n -nurbsSurfaces 1\n -polymeshes 1\n -subdivSurfaces 1\n -planes 1\n -lights 1\n -cameras 1\n -controlVertices 1\n -hulls 1\n -grid 1\n -imagePlane 1\n -joints 1\n -ikHandles 1\n -deformers 1\n -dynamics 1\n -particleInstancers 1\n -fluids 1\n -hairSystems 1\n -follicles 1\n -nCloths 1\n -nParticles 1\n -nRigids 1\n -dynamicConstraints 1\n -locators 1\n -manipulators 1\n -pluginShapes 1\n -dimensions 1\n -handles 1\n -pivots 1\n -textures 1\n -strokes 1\n -motionTrails 1\n -clipGhosts 1\n -bluePencil 1\n" + + " -greasePencils 0\n -shadows 0\n -captureSequenceNumber -1\n -width 477\n -height 276\n -sceneRenderFilter 0\n $editorName;\n modelEditor -e -viewSelected 0 $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextPanel \"modelPanel\" (localizedPanelLabel(\"Persp View\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tmodelPanel -edit -l (localizedPanelLabel(\"Persp View\")) -mbv $menusOkayInPanels $panelName;\n\t\t$editorName = $panelName;\n modelEditor -e \n -camera \"|persp\" \n -useInteractiveMode 0\n -displayLights \"default\" \n -displayAppearance \"smoothShaded\" \n -activeOnly 0\n -ignorePanZoom 0\n -wireframeOnShaded 0\n -headsUpDisplay 1\n -holdOuts 1\n -selectionHiliteDisplay 1\n -useDefaultMaterial 0\n -bufferMode \"double\" \n" + + " -twoSidedLighting 0\n -backfaceCulling 0\n -xray 0\n -jointXray 0\n -activeComponentsXray 0\n -displayTextures 0\n -smoothWireframe 0\n -lineWidth 1\n -textureAnisotropic 0\n -textureHilight 1\n -textureSampling 2\n -textureDisplay \"modulate\" \n -textureMaxSize 32768\n -fogging 0\n -fogSource \"fragment\" \n -fogMode \"linear\" \n -fogStart 0\n -fogEnd 100\n -fogDensity 0.1\n -fogColor 0.5 0.5 0.5 1 \n -depthOfFieldPreview 1\n -maxConstantTransparency 1\n -rendererName \"vp2Renderer\" \n -objectFilterShowInHUD 1\n -isFiltered 0\n -colorResolution 256 256 \n -bumpResolution 512 512 \n -textureCompression 0\n -transparencyAlgorithm \"frontAndBackCull\" \n -transpInShadows 0\n -cullingOverride \"none\" \n -lowQualityLighting 0\n" + + " -maximumNumHardwareLights 1\n -occlusionCulling 0\n -shadingModel 0\n -useBaseRenderer 0\n -useReducedRenderer 0\n -smallObjectCulling 0\n -smallObjectThreshold -1 \n -interactiveDisableShadows 0\n -interactiveBackFaceCull 0\n -sortTransparent 1\n -controllers 1\n -nurbsCurves 1\n -nurbsSurfaces 1\n -polymeshes 1\n -subdivSurfaces 1\n -planes 1\n -lights 1\n -cameras 1\n -controlVertices 1\n -hulls 1\n -grid 1\n -imagePlane 1\n -joints 1\n -ikHandles 1\n -deformers 1\n -dynamics 1\n -particleInstancers 1\n -fluids 1\n -hairSystems 1\n -follicles 1\n -nCloths 1\n -nParticles 1\n -nRigids 1\n -dynamicConstraints 1\n -locators 1\n -manipulators 1\n -pluginShapes 1\n" + + " -dimensions 1\n -handles 1\n -pivots 1\n -textures 1\n -strokes 1\n -motionTrails 1\n -clipGhosts 1\n -bluePencil 1\n -greasePencils 0\n -shadows 0\n -captureSequenceNumber -1\n -width 476\n -height 276\n -sceneRenderFilter 0\n $editorName;\n modelEditor -e -viewSelected 0 $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextPanel \"outlinerPanel\" (localizedPanelLabel(\"ToggledOutliner\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\toutlinerPanel -edit -l (localizedPanelLabel(\"ToggledOutliner\")) -mbv $menusOkayInPanels $panelName;\n\t\t$editorName = $panelName;\n outlinerEditor -e \n -docTag \"isolOutln_fromSeln\" \n -showShapes 0\n -showAssignedMaterials 0\n -showTimeEditor 1\n -showReferenceNodes 1\n -showReferenceMembers 1\n" + + " -showAttributes 0\n -showConnected 0\n -showAnimCurvesOnly 0\n -showMuteInfo 0\n -organizeByLayer 1\n -organizeByClip 1\n -showAnimLayerWeight 1\n -autoExpandLayers 1\n -autoExpand 0\n -showDagOnly 1\n -showAssets 1\n -showContainedOnly 1\n -showPublishedAsConnected 0\n -showParentContainers 0\n -showContainerContents 1\n -ignoreDagHierarchy 0\n -expandConnections 0\n -showUpstreamCurves 1\n -showUnitlessCurves 1\n -showCompounds 1\n -showLeafs 1\n -showNumericAttrsOnly 0\n -highlightActive 1\n -autoSelectNewObjects 0\n -doNotSelectNewObjects 0\n -dropIsParent 1\n -transmitFilters 0\n -setFilter \"defaultSetFilter\" \n -showSetMembers 1\n -allowMultiSelection 1\n -alwaysToggleSelect 0\n -directSelect 0\n" + + " -isSet 0\n -isSetMember 0\n -showUfeItems 1\n -displayMode \"DAG\" \n -expandObjects 0\n -setsIgnoreFilters 1\n -containersIgnoreFilters 0\n -editAttrName 0\n -showAttrValues 0\n -highlightSecondary 0\n -showUVAttrsOnly 0\n -showTextureNodesOnly 0\n -attrAlphaOrder \"default\" \n -animLayerFilterOptions \"allAffecting\" \n -sortOrder \"none\" \n -longNames 0\n -niceNames 1\n -selectCommand \"print(\\\"\\\")\" \n -showNamespace 1\n -showPinIcons 0\n -mapMotionTrails 0\n -ignoreHiddenAttribute 0\n -ignoreOutlinerColor 0\n -renderFilterVisible 0\n -renderFilterIndex 0\n -selectionOrder \"chronological\" \n -expandAttribute 0\n $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextPanel \"outlinerPanel\" (localizedPanelLabel(\"Outliner\")) `;\n" + + "\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\toutlinerPanel -edit -l (localizedPanelLabel(\"Outliner\")) -mbv $menusOkayInPanels $panelName;\n\t\t$editorName = $panelName;\n outlinerEditor -e \n -showShapes 0\n -showAssignedMaterials 0\n -showTimeEditor 1\n -showReferenceNodes 0\n -showReferenceMembers 0\n -showAttributes 0\n -showConnected 0\n -showAnimCurvesOnly 0\n -showMuteInfo 0\n -organizeByLayer 1\n -organizeByClip 1\n -showAnimLayerWeight 1\n -autoExpandLayers 1\n -autoExpand 0\n -showDagOnly 1\n -showAssets 1\n -showContainedOnly 1\n -showPublishedAsConnected 0\n -showParentContainers 0\n -showContainerContents 1\n -ignoreDagHierarchy 0\n -expandConnections 0\n -showUpstreamCurves 1\n -showUnitlessCurves 1\n -showCompounds 1\n -showLeafs 1\n" + + " -showNumericAttrsOnly 0\n -highlightActive 1\n -autoSelectNewObjects 0\n -doNotSelectNewObjects 0\n -dropIsParent 1\n -transmitFilters 0\n -setFilter \"defaultSetFilter\" \n -showSetMembers 1\n -allowMultiSelection 1\n -alwaysToggleSelect 0\n -directSelect 0\n -showUfeItems 1\n -displayMode \"DAG\" \n -expandObjects 0\n -setsIgnoreFilters 1\n -containersIgnoreFilters 0\n -editAttrName 0\n -showAttrValues 0\n -highlightSecondary 0\n -showUVAttrsOnly 0\n -showTextureNodesOnly 0\n -attrAlphaOrder \"default\" \n -animLayerFilterOptions \"allAffecting\" \n -sortOrder \"none\" \n -longNames 0\n -niceNames 1\n -showNamespace 1\n -showPinIcons 0\n -mapMotionTrails 0\n -ignoreHiddenAttribute 0\n -ignoreOutlinerColor 0\n -renderFilterVisible 0\n" + + " $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"graphEditor\" (localizedPanelLabel(\"Graph Editor\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Graph Editor\")) -mbv $menusOkayInPanels $panelName;\n\n\t\t\t$editorName = ($panelName+\"OutlineEd\");\n outlinerEditor -e \n -showShapes 1\n -showAssignedMaterials 0\n -showTimeEditor 1\n -showReferenceNodes 0\n -showReferenceMembers 0\n -showAttributes 1\n -showConnected 1\n -showAnimCurvesOnly 1\n -showMuteInfo 0\n -organizeByLayer 1\n -organizeByClip 1\n -showAnimLayerWeight 1\n -autoExpandLayers 1\n -autoExpand 1\n -showDagOnly 0\n -showAssets 1\n -showContainedOnly 0\n" + + " -showPublishedAsConnected 0\n -showParentContainers 0\n -showContainerContents 0\n -ignoreDagHierarchy 0\n -expandConnections 1\n -showUpstreamCurves 1\n -showUnitlessCurves 1\n -showCompounds 0\n -showLeafs 1\n -showNumericAttrsOnly 1\n -highlightActive 0\n -autoSelectNewObjects 1\n -doNotSelectNewObjects 0\n -dropIsParent 1\n -transmitFilters 1\n -setFilter \"0\" \n -showSetMembers 0\n -allowMultiSelection 1\n -alwaysToggleSelect 0\n -directSelect 0\n -showUfeItems 1\n -displayMode \"DAG\" \n -expandObjects 0\n -setsIgnoreFilters 1\n -containersIgnoreFilters 0\n -editAttrName 0\n -showAttrValues 0\n -highlightSecondary 0\n -showUVAttrsOnly 0\n" + + " -showTextureNodesOnly 0\n -attrAlphaOrder \"default\" \n -animLayerFilterOptions \"allAffecting\" \n -sortOrder \"none\" \n -longNames 0\n -niceNames 1\n -showNamespace 1\n -showPinIcons 1\n -mapMotionTrails 1\n -ignoreHiddenAttribute 0\n -ignoreOutlinerColor 0\n -renderFilterVisible 0\n $editorName;\n\n\t\t\t$editorName = ($panelName+\"GraphEd\");\n animCurveEditor -e \n -displayValues 0\n -snapTime \"integer\" \n -snapValue \"none\" \n -showPlayRangeShades \"on\" \n -lockPlayRangeShades \"off\" \n -smoothness \"fine\" \n -resultSamples 1.041667\n -resultScreenSamples 0\n -resultUpdate \"delayed\" \n -showUpstreamCurves 1\n -keyMinScale 1\n -stackedCurvesMin -1\n -stackedCurvesMax 1\n" + + " -stackedCurvesSpace 0.2\n -preSelectionHighlight 0\n -constrainDrag 0\n -valueLinesToggle 1\n -highlightAffectedCurves 0\n $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"dopeSheetPanel\" (localizedPanelLabel(\"Dope Sheet\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Dope Sheet\")) -mbv $menusOkayInPanels $panelName;\n\n\t\t\t$editorName = ($panelName+\"OutlineEd\");\n outlinerEditor -e \n -showShapes 1\n -showAssignedMaterials 0\n -showTimeEditor 1\n -showReferenceNodes 0\n -showReferenceMembers 0\n -showAttributes 1\n -showConnected 1\n -showAnimCurvesOnly 1\n -showMuteInfo 0\n -organizeByLayer 1\n -organizeByClip 1\n" + + " -showAnimLayerWeight 1\n -autoExpandLayers 1\n -autoExpand 0\n -showDagOnly 0\n -showAssets 1\n -showContainedOnly 0\n -showPublishedAsConnected 0\n -showParentContainers 0\n -showContainerContents 0\n -ignoreDagHierarchy 0\n -expandConnections 1\n -showUpstreamCurves 1\n -showUnitlessCurves 0\n -showCompounds 1\n -showLeafs 1\n -showNumericAttrsOnly 1\n -highlightActive 0\n -autoSelectNewObjects 0\n -doNotSelectNewObjects 1\n -dropIsParent 1\n -transmitFilters 0\n -setFilter \"0\" \n -showSetMembers 0\n -allowMultiSelection 1\n -alwaysToggleSelect 0\n -directSelect 0\n -showUfeItems 1\n -displayMode \"DAG\" \n -expandObjects 0\n" + + " -setsIgnoreFilters 1\n -containersIgnoreFilters 0\n -editAttrName 0\n -showAttrValues 0\n -highlightSecondary 0\n -showUVAttrsOnly 0\n -showTextureNodesOnly 0\n -attrAlphaOrder \"default\" \n -animLayerFilterOptions \"allAffecting\" \n -sortOrder \"none\" \n -longNames 0\n -niceNames 1\n -showNamespace 1\n -showPinIcons 0\n -mapMotionTrails 1\n -ignoreHiddenAttribute 0\n -ignoreOutlinerColor 0\n -renderFilterVisible 0\n $editorName;\n\n\t\t\t$editorName = ($panelName+\"DopeSheetEd\");\n dopeSheetEditor -e \n -displayValues 0\n -snapTime \"integer\" \n -snapValue \"none\" \n -outliner \"dopeSheetPanel1OutlineEd\" \n -showSummary 1\n -showScene 0\n -hierarchyBelow 0\n" + + " -showTicks 1\n -selectionWindow 0 0 0 0 \n $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"timeEditorPanel\" (localizedPanelLabel(\"Time Editor\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Time Editor\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"clipEditorPanel\" (localizedPanelLabel(\"Trax Editor\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Trax Editor\")) -mbv $menusOkayInPanels $panelName;\n\n\t\t\t$editorName = clipEditorNameFromPanel($panelName);\n clipEditor -e \n -displayValues 0\n -snapTime \"none\" \n -snapValue \"none\" \n -initialized 0\n -manageSequencer 0 \n" + + " $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"sequenceEditorPanel\" (localizedPanelLabel(\"Camera Sequencer\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Camera Sequencer\")) -mbv $menusOkayInPanels $panelName;\n\n\t\t\t$editorName = sequenceEditorNameFromPanel($panelName);\n clipEditor -e \n -displayValues 0\n -snapTime \"none\" \n -snapValue \"none\" \n -initialized 0\n -manageSequencer 1 \n $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"hyperGraphPanel\" (localizedPanelLabel(\"Hypergraph Hierarchy\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Hypergraph Hierarchy\")) -mbv $menusOkayInPanels $panelName;\n" + + "\n\t\t\t$editorName = ($panelName+\"HyperGraphEd\");\n hyperGraph -e \n -graphLayoutStyle \"hierarchicalLayout\" \n -orientation \"horiz\" \n -mergeConnections 0\n -zoom 1\n -animateTransition 0\n -showRelationships 1\n -showShapes 0\n -showDeformers 0\n -showExpressions 0\n -showConstraints 0\n -showConnectionFromSelected 0\n -showConnectionToSelected 0\n -showConstraintLabels 0\n -showUnderworld 0\n -showInvisible 0\n -transitionFrames 1\n -opaqueContainers 0\n -freeform 0\n -imagePosition 0 0 \n -imageScale 1\n -imageEnabled 0\n -graphType \"DAG\" \n -heatMapDisplay 0\n -updateSelection 1\n -updateNodeAdded 1\n -useDrawOverrideColor 0\n -limitGraphTraversal -1\n" + + " -range 0 0 \n -iconSize \"smallIcons\" \n -showCachedConnections 0\n $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"hyperShadePanel\" (localizedPanelLabel(\"Hypershade\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Hypershade\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"visorPanel\" (localizedPanelLabel(\"Visor\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Visor\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"nodeEditorPanel\" (localizedPanelLabel(\"Node Editor\")) `;\n\tif ($nodeEditorPanelVisible || $nodeEditorWorkspaceControlOpen) {\n" + + "\t\tif (\"\" == $panelName) {\n\t\t\tif ($useSceneConfig) {\n\t\t\t\t$panelName = `scriptedPanel -unParent -type \"nodeEditorPanel\" -l (localizedPanelLabel(\"Node Editor\")) -mbv $menusOkayInPanels `;\n\n\t\t\t$editorName = ($panelName+\"NodeEditorEd\");\n nodeEditor -e \n -allAttributes 0\n -allNodes 0\n -autoSizeNodes 1\n -consistentNameSize 1\n -createNodeCommand \"nodeEdCreateNodeCommand\" \n -connectNodeOnCreation 0\n -connectOnDrop 0\n -copyConnectionsOnPaste 0\n -connectionStyle \"bezier\" \n -defaultPinnedState 0\n -additiveGraphingMode 1\n -connectedGraphingMode 1\n -settingsChangedCallback \"nodeEdSyncControls\" \n -traversalDepthLimit -1\n -keyPressCommand \"nodeEdKeyPressCommand\" \n -nodeTitleMode \"name\" \n -gridSnap 0\n -gridVisibility 1\n -crosshairOnEdgeDragging 0\n" + + " -popupMenuScript \"nodeEdBuildPanelMenus\" \n -showNamespace 1\n -showShapes 1\n -showSGShapes 0\n -showTransforms 1\n -useAssets 1\n -syncedSelection 1\n -extendToShapes 1\n -showUnitConversions 0\n -editorMode \"default\" \n -hasWatchpoint 0\n $editorName;\n\t\t\t}\n\t\t} else {\n\t\t\t$label = `panel -q -label $panelName`;\n\t\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Node Editor\")) -mbv $menusOkayInPanels $panelName;\n\n\t\t\t$editorName = ($panelName+\"NodeEditorEd\");\n nodeEditor -e \n -allAttributes 0\n -allNodes 0\n -autoSizeNodes 1\n -consistentNameSize 1\n -createNodeCommand \"nodeEdCreateNodeCommand\" \n -connectNodeOnCreation 0\n -connectOnDrop 0\n -copyConnectionsOnPaste 0\n -connectionStyle \"bezier\" \n -defaultPinnedState 0\n" + + " -additiveGraphingMode 1\n -connectedGraphingMode 1\n -settingsChangedCallback \"nodeEdSyncControls\" \n -traversalDepthLimit -1\n -keyPressCommand \"nodeEdKeyPressCommand\" \n -nodeTitleMode \"name\" \n -gridSnap 0\n -gridVisibility 1\n -crosshairOnEdgeDragging 0\n -popupMenuScript \"nodeEdBuildPanelMenus\" \n -showNamespace 1\n -showShapes 1\n -showSGShapes 0\n -showTransforms 1\n -useAssets 1\n -syncedSelection 1\n -extendToShapes 1\n -showUnitConversions 0\n -editorMode \"default\" \n -hasWatchpoint 0\n $editorName;\n\t\t\tif (!$useSceneConfig) {\n\t\t\t\tpanel -e -l $label $panelName;\n\t\t\t}\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"createNodePanel\" (localizedPanelLabel(\"Create Node\")) `;\n\tif (\"\" != $panelName) {\n" + + "\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Create Node\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"polyTexturePlacementPanel\" (localizedPanelLabel(\"UV Editor\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"UV Editor\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"renderWindowPanel\" (localizedPanelLabel(\"Render View\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Render View\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextPanel \"shapePanel\" (localizedPanelLabel(\"Shape Editor\")) `;\n\tif (\"\" != $panelName) {\n" + + "\t\t$label = `panel -q -label $panelName`;\n\t\tshapePanel -edit -l (localizedPanelLabel(\"Shape Editor\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextPanel \"posePanel\" (localizedPanelLabel(\"Pose Editor\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tposePanel -edit -l (localizedPanelLabel(\"Pose Editor\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"dynRelEdPanel\" (localizedPanelLabel(\"Dynamic Relationships\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Dynamic Relationships\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"relationshipPanel\" (localizedPanelLabel(\"Relationship Editor\")) `;\n" + + "\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Relationship Editor\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"referenceEditorPanel\" (localizedPanelLabel(\"Reference Editor\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Reference Editor\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"dynPaintScriptedPanelType\" (localizedPanelLabel(\"Paint Effects\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Paint Effects\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"scriptEditorPanel\" (localizedPanelLabel(\"Script Editor\")) `;\n" + + "\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Script Editor\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"profilerPanel\" (localizedPanelLabel(\"Profiler Tool\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Profiler Tool\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"contentBrowserPanel\" (localizedPanelLabel(\"Content Browser\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Content Browser\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"Stereo\" (localizedPanelLabel(\"Stereo\")) `;\n" + + "\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Stereo\")) -mbv $menusOkayInPanels $panelName;\n{ string $editorName = ($panelName+\"Editor\");\n stereoCameraView -e \n -camera \"|persp\" \n -useInteractiveMode 0\n -displayLights \"default\" \n -displayAppearance \"wireframe\" \n -activeOnly 0\n -ignorePanZoom 0\n -wireframeOnShaded 0\n -headsUpDisplay 1\n -holdOuts 1\n -selectionHiliteDisplay 1\n -useDefaultMaterial 0\n -bufferMode \"double\" \n -twoSidedLighting 1\n -backfaceCulling 0\n -xray 0\n -jointXray 0\n -activeComponentsXray 0\n -displayTextures 0\n -smoothWireframe 0\n -lineWidth 1\n -textureAnisotropic 0\n -textureHilight 1\n -textureSampling 2\n" + + " -textureDisplay \"modulate\" \n -textureMaxSize 32768\n -fogging 0\n -fogSource \"fragment\" \n -fogMode \"linear\" \n -fogStart 0\n -fogEnd 100\n -fogDensity 0.1\n -fogColor 0.5 0.5 0.5 1 \n -depthOfFieldPreview 1\n -maxConstantTransparency 1\n -objectFilterShowInHUD 1\n -isFiltered 0\n -colorResolution 4 4 \n -bumpResolution 4 4 \n -textureCompression 0\n -transparencyAlgorithm \"frontAndBackCull\" \n -transpInShadows 0\n -cullingOverride \"none\" \n -lowQualityLighting 0\n -maximumNumHardwareLights 0\n -occlusionCulling 0\n -shadingModel 0\n -useBaseRenderer 0\n -useReducedRenderer 0\n -smallObjectCulling 0\n -smallObjectThreshold -1 \n -interactiveDisableShadows 0\n" + + " -interactiveBackFaceCull 0\n -sortTransparent 1\n -controllers 1\n -nurbsCurves 1\n -nurbsSurfaces 1\n -polymeshes 1\n -subdivSurfaces 1\n -planes 1\n -lights 1\n -cameras 1\n -controlVertices 1\n -hulls 1\n -grid 1\n -imagePlane 1\n -joints 1\n -ikHandles 1\n -deformers 1\n -dynamics 1\n -particleInstancers 1\n -fluids 1\n -hairSystems 1\n -follicles 1\n -nCloths 1\n -nParticles 1\n -nRigids 1\n -dynamicConstraints 1\n -locators 1\n -manipulators 1\n -pluginShapes 1\n -dimensions 1\n -handles 1\n -pivots 1\n -textures 1\n -strokes 1\n -motionTrails 1\n" + + " -clipGhosts 1\n -bluePencil 1\n -greasePencils 0\n -shadows 0\n -captureSequenceNumber -1\n -width 0\n -height 0\n -sceneRenderFilter 0\n -displayMode \"centerEye\" \n -viewColor 0 0 0 1 \n -useCustomBackground 1\n $editorName;\n stereoCameraView -e -viewSelected 0 $editorName; };\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\tif ($useSceneConfig) {\n string $configName = `getPanel -cwl (localizedPanelLabel(\"Current Layout\"))`;\n if (\"\" != $configName) {\n\t\t\tpanelConfiguration -edit -label (localizedPanelLabel(\"Current Layout\")) \n\t\t\t\t-userCreated false\n\t\t\t\t-defaultImage \"vacantCell.xP:/\"\n\t\t\t\t-image \"\"\n\t\t\t\t-sc false\n\t\t\t\t-configString \"global string $gMainPane; paneLayout -e -cn \\\"quad\\\" -ps 1 50 50 -ps 2 50 50 -ps 3 50 50 -ps 4 50 50 $gMainPane;\"\n\t\t\t\t-removeAllPanels\n\t\t\t\t-ap false\n\t\t\t\t\t(localizedPanelLabel(\"Top View\")) \n" + + "\t\t\t\t\t\"modelPanel\"\n" + + "\t\t\t\t\t\"$panelName = `modelPanel -unParent -l (localizedPanelLabel(\\\"Top View\\\")) -mbv $menusOkayInPanels `;\\n$editorName = $panelName;\\nmodelEditor -e \\n -camera \\\"|top\\\" \\n -useInteractiveMode 0\\n -displayLights \\\"default\\\" \\n -displayAppearance \\\"smoothShaded\\\" \\n -activeOnly 0\\n -ignorePanZoom 0\\n -wireframeOnShaded 0\\n -headsUpDisplay 1\\n -holdOuts 1\\n -selectionHiliteDisplay 1\\n -useDefaultMaterial 0\\n -bufferMode \\\"double\\\" \\n -twoSidedLighting 0\\n -backfaceCulling 0\\n -xray 0\\n -jointXray 0\\n -activeComponentsXray 0\\n -displayTextures 0\\n -smoothWireframe 0\\n -lineWidth 1\\n -textureAnisotropic 0\\n -textureHilight 1\\n -textureSampling 2\\n -textureDisplay \\\"modulate\\\" \\n -textureMaxSize 32768\\n -fogging 0\\n -fogSource \\\"fragment\\\" \\n -fogMode \\\"linear\\\" \\n -fogStart 0\\n -fogEnd 100\\n -fogDensity 0.1\\n -fogColor 0.5 0.5 0.5 1 \\n -depthOfFieldPreview 1\\n -maxConstantTransparency 1\\n -rendererName \\\"vp2Renderer\\\" \\n -objectFilterShowInHUD 1\\n -isFiltered 0\\n -colorResolution 256 256 \\n -bumpResolution 512 512 \\n -textureCompression 0\\n -transparencyAlgorithm \\\"frontAndBackCull\\\" \\n -transpInShadows 0\\n -cullingOverride \\\"none\\\" \\n -lowQualityLighting 0\\n -maximumNumHardwareLights 1\\n -occlusionCulling 0\\n -shadingModel 0\\n -useBaseRenderer 0\\n -useReducedRenderer 0\\n -smallObjectCulling 0\\n -smallObjectThreshold -1 \\n -interactiveDisableShadows 0\\n -interactiveBackFaceCull 0\\n -sortTransparent 1\\n -controllers 1\\n -nurbsCurves 1\\n -nurbsSurfaces 1\\n -polymeshes 1\\n -subdivSurfaces 1\\n -planes 1\\n -lights 1\\n -cameras 1\\n -controlVertices 1\\n -hulls 1\\n -grid 1\\n -imagePlane 1\\n -joints 1\\n -ikHandles 1\\n -deformers 1\\n -dynamics 1\\n -particleInstancers 1\\n -fluids 1\\n -hairSystems 1\\n -follicles 1\\n -nCloths 1\\n -nParticles 1\\n -nRigids 1\\n -dynamicConstraints 1\\n -locators 1\\n -manipulators 1\\n -pluginShapes 1\\n -dimensions 1\\n -handles 1\\n -pivots 1\\n -textures 1\\n -strokes 1\\n -motionTrails 1\\n -clipGhosts 1\\n -bluePencil 1\\n -greasePencils 0\\n -shadows 0\\n -captureSequenceNumber -1\\n -width 477\\n -height 276\\n -sceneRenderFilter 0\\n $editorName;\\nmodelEditor -e -viewSelected 0 $editorName\"\n" + + "\t\t\t\t\t\"modelPanel -edit -l (localizedPanelLabel(\\\"Top View\\\")) -mbv $menusOkayInPanels $panelName;\\n$editorName = $panelName;\\nmodelEditor -e \\n -camera \\\"|top\\\" \\n -useInteractiveMode 0\\n -displayLights \\\"default\\\" \\n -displayAppearance \\\"smoothShaded\\\" \\n -activeOnly 0\\n -ignorePanZoom 0\\n -wireframeOnShaded 0\\n -headsUpDisplay 1\\n -holdOuts 1\\n -selectionHiliteDisplay 1\\n -useDefaultMaterial 0\\n -bufferMode \\\"double\\\" \\n -twoSidedLighting 0\\n -backfaceCulling 0\\n -xray 0\\n -jointXray 0\\n -activeComponentsXray 0\\n -displayTextures 0\\n -smoothWireframe 0\\n -lineWidth 1\\n -textureAnisotropic 0\\n -textureHilight 1\\n -textureSampling 2\\n -textureDisplay \\\"modulate\\\" \\n -textureMaxSize 32768\\n -fogging 0\\n -fogSource \\\"fragment\\\" \\n -fogMode \\\"linear\\\" \\n -fogStart 0\\n -fogEnd 100\\n -fogDensity 0.1\\n -fogColor 0.5 0.5 0.5 1 \\n -depthOfFieldPreview 1\\n -maxConstantTransparency 1\\n -rendererName \\\"vp2Renderer\\\" \\n -objectFilterShowInHUD 1\\n -isFiltered 0\\n -colorResolution 256 256 \\n -bumpResolution 512 512 \\n -textureCompression 0\\n -transparencyAlgorithm \\\"frontAndBackCull\\\" \\n -transpInShadows 0\\n -cullingOverride \\\"none\\\" \\n -lowQualityLighting 0\\n -maximumNumHardwareLights 1\\n -occlusionCulling 0\\n -shadingModel 0\\n -useBaseRenderer 0\\n -useReducedRenderer 0\\n -smallObjectCulling 0\\n -smallObjectThreshold -1 \\n -interactiveDisableShadows 0\\n -interactiveBackFaceCull 0\\n -sortTransparent 1\\n -controllers 1\\n -nurbsCurves 1\\n -nurbsSurfaces 1\\n -polymeshes 1\\n -subdivSurfaces 1\\n -planes 1\\n -lights 1\\n -cameras 1\\n -controlVertices 1\\n -hulls 1\\n -grid 1\\n -imagePlane 1\\n -joints 1\\n -ikHandles 1\\n -deformers 1\\n -dynamics 1\\n -particleInstancers 1\\n -fluids 1\\n -hairSystems 1\\n -follicles 1\\n -nCloths 1\\n -nParticles 1\\n -nRigids 1\\n -dynamicConstraints 1\\n -locators 1\\n -manipulators 1\\n -pluginShapes 1\\n -dimensions 1\\n -handles 1\\n -pivots 1\\n -textures 1\\n -strokes 1\\n -motionTrails 1\\n -clipGhosts 1\\n -bluePencil 1\\n -greasePencils 0\\n -shadows 0\\n -captureSequenceNumber -1\\n -width 477\\n -height 276\\n -sceneRenderFilter 0\\n $editorName;\\nmodelEditor -e -viewSelected 0 $editorName\"\n" + + "\t\t\t\t-ap false\n\t\t\t\t\t(localizedPanelLabel(\"Persp View\")) \n\t\t\t\t\t\"modelPanel\"\n" + + "\t\t\t\t\t\"$panelName = `modelPanel -unParent -l (localizedPanelLabel(\\\"Persp View\\\")) -mbv $menusOkayInPanels `;\\n$editorName = $panelName;\\nmodelEditor -e \\n -cam `findStartUpCamera persp` \\n -useInteractiveMode 0\\n -displayLights \\\"default\\\" \\n -displayAppearance \\\"smoothShaded\\\" \\n -activeOnly 0\\n -ignorePanZoom 0\\n -wireframeOnShaded 0\\n -headsUpDisplay 1\\n -holdOuts 1\\n -selectionHiliteDisplay 1\\n -useDefaultMaterial 0\\n -bufferMode \\\"double\\\" \\n -twoSidedLighting 0\\n -backfaceCulling 0\\n -xray 0\\n -jointXray 0\\n -activeComponentsXray 0\\n -displayTextures 0\\n -smoothWireframe 0\\n -lineWidth 1\\n -textureAnisotropic 0\\n -textureHilight 1\\n -textureSampling 2\\n -textureDisplay \\\"modulate\\\" \\n -textureMaxSize 32768\\n -fogging 0\\n -fogSource \\\"fragment\\\" \\n -fogMode \\\"linear\\\" \\n -fogStart 0\\n -fogEnd 100\\n -fogDensity 0.1\\n -fogColor 0.5 0.5 0.5 1 \\n -depthOfFieldPreview 1\\n -maxConstantTransparency 1\\n -rendererName \\\"vp2Renderer\\\" \\n -objectFilterShowInHUD 1\\n -isFiltered 0\\n -colorResolution 256 256 \\n -bumpResolution 512 512 \\n -textureCompression 0\\n -transparencyAlgorithm \\\"frontAndBackCull\\\" \\n -transpInShadows 0\\n -cullingOverride \\\"none\\\" \\n -lowQualityLighting 0\\n -maximumNumHardwareLights 1\\n -occlusionCulling 0\\n -shadingModel 0\\n -useBaseRenderer 0\\n -useReducedRenderer 0\\n -smallObjectCulling 0\\n -smallObjectThreshold -1 \\n -interactiveDisableShadows 0\\n -interactiveBackFaceCull 0\\n -sortTransparent 1\\n -controllers 1\\n -nurbsCurves 1\\n -nurbsSurfaces 1\\n -polymeshes 1\\n -subdivSurfaces 1\\n -planes 1\\n -lights 1\\n -cameras 1\\n -controlVertices 1\\n -hulls 1\\n -grid 1\\n -imagePlane 1\\n -joints 1\\n -ikHandles 1\\n -deformers 1\\n -dynamics 1\\n -particleInstancers 1\\n -fluids 1\\n -hairSystems 1\\n -follicles 1\\n -nCloths 1\\n -nParticles 1\\n -nRigids 1\\n -dynamicConstraints 1\\n -locators 1\\n -manipulators 1\\n -pluginShapes 1\\n -dimensions 1\\n -handles 1\\n -pivots 1\\n -textures 1\\n -strokes 1\\n -motionTrails 1\\n -clipGhosts 1\\n -bluePencil 1\\n -greasePencils 0\\n -shadows 0\\n -captureSequenceNumber -1\\n -width 476\\n -height 276\\n -sceneRenderFilter 0\\n $editorName;\\nmodelEditor -e -viewSelected 0 $editorName\"\n" + + "\t\t\t\t\t\"modelPanel -edit -l (localizedPanelLabel(\\\"Persp View\\\")) -mbv $menusOkayInPanels $panelName;\\n$editorName = $panelName;\\nmodelEditor -e \\n -cam `findStartUpCamera persp` \\n -useInteractiveMode 0\\n -displayLights \\\"default\\\" \\n -displayAppearance \\\"smoothShaded\\\" \\n -activeOnly 0\\n -ignorePanZoom 0\\n -wireframeOnShaded 0\\n -headsUpDisplay 1\\n -holdOuts 1\\n -selectionHiliteDisplay 1\\n -useDefaultMaterial 0\\n -bufferMode \\\"double\\\" \\n -twoSidedLighting 0\\n -backfaceCulling 0\\n -xray 0\\n -jointXray 0\\n -activeComponentsXray 0\\n -displayTextures 0\\n -smoothWireframe 0\\n -lineWidth 1\\n -textureAnisotropic 0\\n -textureHilight 1\\n -textureSampling 2\\n -textureDisplay \\\"modulate\\\" \\n -textureMaxSize 32768\\n -fogging 0\\n -fogSource \\\"fragment\\\" \\n -fogMode \\\"linear\\\" \\n -fogStart 0\\n -fogEnd 100\\n -fogDensity 0.1\\n -fogColor 0.5 0.5 0.5 1 \\n -depthOfFieldPreview 1\\n -maxConstantTransparency 1\\n -rendererName \\\"vp2Renderer\\\" \\n -objectFilterShowInHUD 1\\n -isFiltered 0\\n -colorResolution 256 256 \\n -bumpResolution 512 512 \\n -textureCompression 0\\n -transparencyAlgorithm \\\"frontAndBackCull\\\" \\n -transpInShadows 0\\n -cullingOverride \\\"none\\\" \\n -lowQualityLighting 0\\n -maximumNumHardwareLights 1\\n -occlusionCulling 0\\n -shadingModel 0\\n -useBaseRenderer 0\\n -useReducedRenderer 0\\n -smallObjectCulling 0\\n -smallObjectThreshold -1 \\n -interactiveDisableShadows 0\\n -interactiveBackFaceCull 0\\n -sortTransparent 1\\n -controllers 1\\n -nurbsCurves 1\\n -nurbsSurfaces 1\\n -polymeshes 1\\n -subdivSurfaces 1\\n -planes 1\\n -lights 1\\n -cameras 1\\n -controlVertices 1\\n -hulls 1\\n -grid 1\\n -imagePlane 1\\n -joints 1\\n -ikHandles 1\\n -deformers 1\\n -dynamics 1\\n -particleInstancers 1\\n -fluids 1\\n -hairSystems 1\\n -follicles 1\\n -nCloths 1\\n -nParticles 1\\n -nRigids 1\\n -dynamicConstraints 1\\n -locators 1\\n -manipulators 1\\n -pluginShapes 1\\n -dimensions 1\\n -handles 1\\n -pivots 1\\n -textures 1\\n -strokes 1\\n -motionTrails 1\\n -clipGhosts 1\\n -bluePencil 1\\n -greasePencils 0\\n -shadows 0\\n -captureSequenceNumber -1\\n -width 476\\n -height 276\\n -sceneRenderFilter 0\\n $editorName;\\nmodelEditor -e -viewSelected 0 $editorName\"\n" + + "\t\t\t\t-ap false\n\t\t\t\t\t(localizedPanelLabel(\"Side View\")) \n\t\t\t\t\t\"modelPanel\"\n" + + "\t\t\t\t\t\"$panelName = `modelPanel -unParent -l (localizedPanelLabel(\\\"Side View\\\")) -mbv $menusOkayInPanels `;\\n$editorName = $panelName;\\nmodelEditor -e \\n -camera \\\"|side\\\" \\n -useInteractiveMode 0\\n -displayLights \\\"default\\\" \\n -displayAppearance \\\"smoothShaded\\\" \\n -activeOnly 0\\n -ignorePanZoom 0\\n -wireframeOnShaded 0\\n -headsUpDisplay 1\\n -holdOuts 1\\n -selectionHiliteDisplay 1\\n -useDefaultMaterial 0\\n -bufferMode \\\"double\\\" \\n -twoSidedLighting 0\\n -backfaceCulling 0\\n -xray 0\\n -jointXray 0\\n -activeComponentsXray 0\\n -displayTextures 0\\n -smoothWireframe 0\\n -lineWidth 1\\n -textureAnisotropic 0\\n -textureHilight 1\\n -textureSampling 2\\n -textureDisplay \\\"modulate\\\" \\n -textureMaxSize 32768\\n -fogging 0\\n -fogSource \\\"fragment\\\" \\n -fogMode \\\"linear\\\" \\n -fogStart 0\\n -fogEnd 100\\n -fogDensity 0.1\\n -fogColor 0.5 0.5 0.5 1 \\n -depthOfFieldPreview 1\\n -maxConstantTransparency 1\\n -rendererName \\\"vp2Renderer\\\" \\n -objectFilterShowInHUD 1\\n -isFiltered 0\\n -colorResolution 256 256 \\n -bumpResolution 512 512 \\n -textureCompression 0\\n -transparencyAlgorithm \\\"frontAndBackCull\\\" \\n -transpInShadows 0\\n -cullingOverride \\\"none\\\" \\n -lowQualityLighting 0\\n -maximumNumHardwareLights 1\\n -occlusionCulling 0\\n -shadingModel 0\\n -useBaseRenderer 0\\n -useReducedRenderer 0\\n -smallObjectCulling 0\\n -smallObjectThreshold -1 \\n -interactiveDisableShadows 0\\n -interactiveBackFaceCull 0\\n -sortTransparent 1\\n -controllers 1\\n -nurbsCurves 1\\n -nurbsSurfaces 1\\n -polymeshes 1\\n -subdivSurfaces 1\\n -planes 1\\n -lights 1\\n -cameras 1\\n -controlVertices 1\\n -hulls 1\\n -grid 1\\n -imagePlane 1\\n -joints 1\\n -ikHandles 1\\n -deformers 1\\n -dynamics 1\\n -particleInstancers 1\\n -fluids 1\\n -hairSystems 1\\n -follicles 1\\n -nCloths 1\\n -nParticles 1\\n -nRigids 1\\n -dynamicConstraints 1\\n -locators 1\\n -manipulators 1\\n -pluginShapes 1\\n -dimensions 1\\n -handles 1\\n -pivots 1\\n -textures 1\\n -strokes 1\\n -motionTrails 1\\n -clipGhosts 1\\n -bluePencil 1\\n -greasePencils 0\\n -shadows 0\\n -captureSequenceNumber -1\\n -width 476\\n -height 276\\n -sceneRenderFilter 0\\n $editorName;\\nmodelEditor -e -viewSelected 0 $editorName\"\n" + + "\t\t\t\t\t\"modelPanel -edit -l (localizedPanelLabel(\\\"Side View\\\")) -mbv $menusOkayInPanels $panelName;\\n$editorName = $panelName;\\nmodelEditor -e \\n -camera \\\"|side\\\" \\n -useInteractiveMode 0\\n -displayLights \\\"default\\\" \\n -displayAppearance \\\"smoothShaded\\\" \\n -activeOnly 0\\n -ignorePanZoom 0\\n -wireframeOnShaded 0\\n -headsUpDisplay 1\\n -holdOuts 1\\n -selectionHiliteDisplay 1\\n -useDefaultMaterial 0\\n -bufferMode \\\"double\\\" \\n -twoSidedLighting 0\\n -backfaceCulling 0\\n -xray 0\\n -jointXray 0\\n -activeComponentsXray 0\\n -displayTextures 0\\n -smoothWireframe 0\\n -lineWidth 1\\n -textureAnisotropic 0\\n -textureHilight 1\\n -textureSampling 2\\n -textureDisplay \\\"modulate\\\" \\n -textureMaxSize 32768\\n -fogging 0\\n -fogSource \\\"fragment\\\" \\n -fogMode \\\"linear\\\" \\n -fogStart 0\\n -fogEnd 100\\n -fogDensity 0.1\\n -fogColor 0.5 0.5 0.5 1 \\n -depthOfFieldPreview 1\\n -maxConstantTransparency 1\\n -rendererName \\\"vp2Renderer\\\" \\n -objectFilterShowInHUD 1\\n -isFiltered 0\\n -colorResolution 256 256 \\n -bumpResolution 512 512 \\n -textureCompression 0\\n -transparencyAlgorithm \\\"frontAndBackCull\\\" \\n -transpInShadows 0\\n -cullingOverride \\\"none\\\" \\n -lowQualityLighting 0\\n -maximumNumHardwareLights 1\\n -occlusionCulling 0\\n -shadingModel 0\\n -useBaseRenderer 0\\n -useReducedRenderer 0\\n -smallObjectCulling 0\\n -smallObjectThreshold -1 \\n -interactiveDisableShadows 0\\n -interactiveBackFaceCull 0\\n -sortTransparent 1\\n -controllers 1\\n -nurbsCurves 1\\n -nurbsSurfaces 1\\n -polymeshes 1\\n -subdivSurfaces 1\\n -planes 1\\n -lights 1\\n -cameras 1\\n -controlVertices 1\\n -hulls 1\\n -grid 1\\n -imagePlane 1\\n -joints 1\\n -ikHandles 1\\n -deformers 1\\n -dynamics 1\\n -particleInstancers 1\\n -fluids 1\\n -hairSystems 1\\n -follicles 1\\n -nCloths 1\\n -nParticles 1\\n -nRigids 1\\n -dynamicConstraints 1\\n -locators 1\\n -manipulators 1\\n -pluginShapes 1\\n -dimensions 1\\n -handles 1\\n -pivots 1\\n -textures 1\\n -strokes 1\\n -motionTrails 1\\n -clipGhosts 1\\n -bluePencil 1\\n -greasePencils 0\\n -shadows 0\\n -captureSequenceNumber -1\\n -width 476\\n -height 276\\n -sceneRenderFilter 0\\n $editorName;\\nmodelEditor -e -viewSelected 0 $editorName\"\n" + + "\t\t\t\t-ap false\n\t\t\t\t\t(localizedPanelLabel(\"Front View\")) \n\t\t\t\t\t\"modelPanel\"\n" + + "\t\t\t\t\t\"$panelName = `modelPanel -unParent -l (localizedPanelLabel(\\\"Front View\\\")) -mbv $menusOkayInPanels `;\\n$editorName = $panelName;\\nmodelEditor -e \\n -cam `findStartUpCamera front` \\n -useInteractiveMode 0\\n -displayLights \\\"default\\\" \\n -displayAppearance \\\"smoothShaded\\\" \\n -activeOnly 0\\n -ignorePanZoom 0\\n -wireframeOnShaded 0\\n -headsUpDisplay 1\\n -holdOuts 1\\n -selectionHiliteDisplay 1\\n -useDefaultMaterial 0\\n -bufferMode \\\"double\\\" \\n -twoSidedLighting 0\\n -backfaceCulling 0\\n -xray 0\\n -jointXray 0\\n -activeComponentsXray 0\\n -displayTextures 0\\n -smoothWireframe 0\\n -lineWidth 1\\n -textureAnisotropic 0\\n -textureHilight 1\\n -textureSampling 2\\n -textureDisplay \\\"modulate\\\" \\n -textureMaxSize 32768\\n -fogging 0\\n -fogSource \\\"fragment\\\" \\n -fogMode \\\"linear\\\" \\n -fogStart 0\\n -fogEnd 100\\n -fogDensity 0.1\\n -fogColor 0.5 0.5 0.5 1 \\n -depthOfFieldPreview 1\\n -maxConstantTransparency 1\\n -rendererName \\\"vp2Renderer\\\" \\n -objectFilterShowInHUD 1\\n -isFiltered 0\\n -colorResolution 256 256 \\n -bumpResolution 512 512 \\n -textureCompression 0\\n -transparencyAlgorithm \\\"frontAndBackCull\\\" \\n -transpInShadows 0\\n -cullingOverride \\\"none\\\" \\n -lowQualityLighting 0\\n -maximumNumHardwareLights 1\\n -occlusionCulling 0\\n -shadingModel 0\\n -useBaseRenderer 0\\n -useReducedRenderer 0\\n -smallObjectCulling 0\\n -smallObjectThreshold -1 \\n -interactiveDisableShadows 0\\n -interactiveBackFaceCull 0\\n -sortTransparent 1\\n -controllers 1\\n -nurbsCurves 1\\n -nurbsSurfaces 1\\n -polymeshes 1\\n -subdivSurfaces 1\\n -planes 1\\n -lights 1\\n -cameras 1\\n -controlVertices 1\\n -hulls 1\\n -grid 1\\n -imagePlane 1\\n -joints 1\\n -ikHandles 1\\n -deformers 1\\n -dynamics 1\\n -particleInstancers 1\\n -fluids 1\\n -hairSystems 1\\n -follicles 1\\n -nCloths 1\\n -nParticles 1\\n -nRigids 1\\n -dynamicConstraints 1\\n -locators 1\\n -manipulators 1\\n -pluginShapes 1\\n -dimensions 1\\n -handles 1\\n -pivots 1\\n -textures 1\\n -strokes 1\\n -motionTrails 1\\n -clipGhosts 1\\n -bluePencil 1\\n -greasePencils 0\\n -shadows 0\\n -captureSequenceNumber -1\\n -width 477\\n -height 276\\n -sceneRenderFilter 0\\n $editorName;\\nmodelEditor -e -viewSelected 0 $editorName\"\n" + + "\t\t\t\t\t\"modelPanel -edit -l (localizedPanelLabel(\\\"Front View\\\")) -mbv $menusOkayInPanels $panelName;\\n$editorName = $panelName;\\nmodelEditor -e \\n -cam `findStartUpCamera front` \\n -useInteractiveMode 0\\n -displayLights \\\"default\\\" \\n -displayAppearance \\\"smoothShaded\\\" \\n -activeOnly 0\\n -ignorePanZoom 0\\n -wireframeOnShaded 0\\n -headsUpDisplay 1\\n -holdOuts 1\\n -selectionHiliteDisplay 1\\n -useDefaultMaterial 0\\n -bufferMode \\\"double\\\" \\n -twoSidedLighting 0\\n -backfaceCulling 0\\n -xray 0\\n -jointXray 0\\n -activeComponentsXray 0\\n -displayTextures 0\\n -smoothWireframe 0\\n -lineWidth 1\\n -textureAnisotropic 0\\n -textureHilight 1\\n -textureSampling 2\\n -textureDisplay \\\"modulate\\\" \\n -textureMaxSize 32768\\n -fogging 0\\n -fogSource \\\"fragment\\\" \\n -fogMode \\\"linear\\\" \\n -fogStart 0\\n -fogEnd 100\\n -fogDensity 0.1\\n -fogColor 0.5 0.5 0.5 1 \\n -depthOfFieldPreview 1\\n -maxConstantTransparency 1\\n -rendererName \\\"vp2Renderer\\\" \\n -objectFilterShowInHUD 1\\n -isFiltered 0\\n -colorResolution 256 256 \\n -bumpResolution 512 512 \\n -textureCompression 0\\n -transparencyAlgorithm \\\"frontAndBackCull\\\" \\n -transpInShadows 0\\n -cullingOverride \\\"none\\\" \\n -lowQualityLighting 0\\n -maximumNumHardwareLights 1\\n -occlusionCulling 0\\n -shadingModel 0\\n -useBaseRenderer 0\\n -useReducedRenderer 0\\n -smallObjectCulling 0\\n -smallObjectThreshold -1 \\n -interactiveDisableShadows 0\\n -interactiveBackFaceCull 0\\n -sortTransparent 1\\n -controllers 1\\n -nurbsCurves 1\\n -nurbsSurfaces 1\\n -polymeshes 1\\n -subdivSurfaces 1\\n -planes 1\\n -lights 1\\n -cameras 1\\n -controlVertices 1\\n -hulls 1\\n -grid 1\\n -imagePlane 1\\n -joints 1\\n -ikHandles 1\\n -deformers 1\\n -dynamics 1\\n -particleInstancers 1\\n -fluids 1\\n -hairSystems 1\\n -follicles 1\\n -nCloths 1\\n -nParticles 1\\n -nRigids 1\\n -dynamicConstraints 1\\n -locators 1\\n -manipulators 1\\n -pluginShapes 1\\n -dimensions 1\\n -handles 1\\n -pivots 1\\n -textures 1\\n -strokes 1\\n -motionTrails 1\\n -clipGhosts 1\\n -bluePencil 1\\n -greasePencils 0\\n -shadows 0\\n -captureSequenceNumber -1\\n -width 477\\n -height 276\\n -sceneRenderFilter 0\\n $editorName;\\nmodelEditor -e -viewSelected 0 $editorName\"\n" + "\t\t\t\t$configName;\n\n setNamedPanelLayout (localizedPanelLabel(\"Current Layout\"));\n }\n\n panelHistory -e -clear mainPanelHistory;\n sceneUIReplacement -clear;\n\t}\n\n\ngrid -spacing 5 -size 12 -divisions 5 -displayAxes yes -displayGridLines yes -displayDivisionLines yes -displayPerspectiveLabels no -displayOrthographicLabels no -displayAxesBold yes -perspectiveLabelPosition axis -orthographicLabelPosition edge;\nviewManip -drawCompass 0 -compassAngle 0 -frontParameters \"\" -homeParameters \"\" -selectionLockParameters \"\";\n}\n"); setAttr ".st" 3; createNode script -n "sceneConfigurationScriptNode"; @@ -273,6 +285,7 @@ createNode aiAOVDriver -s -n "defaultArnoldDisplayDriver"; createNode objectSet -n "workfileMain"; rename -uid "3C9B5D6F-4579-8E3B-5B7D-4C88865A1C68"; addAttr -ci true -sn "cbId" -ln "cbId" -dt "string"; + addAttr -ci true -sn "instance_id" -ln "instance_id" -dt "string"; addAttr -ci true -sn "id" -ln "id" -dt "string"; addAttr -ci true -sn "family" -ln "family" -dt "string"; addAttr -ci true -sn "subset" -ln "subset" -dt "string"; @@ -281,13 +294,14 @@ createNode objectSet -n "workfileMain"; addAttr -ci true -sn "variant" -ln "variant" -dt "string"; addAttr -ci true -sn "asset" -ln "asset" -dt "string"; addAttr -ci true -sn "task" -ln "task" -dt "string"; - addAttr -ci true -sn "instance_id" -ln "instance_id" -dt "string"; addAttr -ci true -sn "publish_attributes" -ln "publish_attributes" -dt "string"; - addAttr -ci true -sn "__creator_attributes_keys" -ln "__creator_attributes_keys" + addAttr -ci true -sn "creator_attributes" -ln "creator_attributes" -dt "string"; + addAttr -ci true -sn "__creator_attributes_keys" -ln "__creator_attributes_keys" -dt "string"; setAttr ".ihi" 0; setAttr ".hio" yes; setAttr ".cbId" -type "string" "60df31e2be2b48bd3695c056:30d256dac64c"; + setAttr ".instance_id" -type "string" "911dc92a-ad29-41e5-bbf9-733d56174fb9"; setAttr ".id" -type "string" "pyblish.avalon.instance"; setAttr ".family" -type "string" "workfile"; setAttr ".subset" -type "string" "workfileTest_task"; @@ -296,16 +310,9 @@ createNode objectSet -n "workfileMain"; setAttr ".variant" -type "string" "Main"; setAttr ".asset" -type "string" "test_asset"; setAttr ".task" -type "string" "test_task"; - setAttr ".instance_id" -type "string" "911dc92a-ad29-41e5-bbf9-733d56174fb9"; - setAttr ".publish_attributes" -type "string" "{\"ExtractImportReference\": {\"active\": false}}"; + setAttr ".publish_attributes" -type "string" "{\"ValidateInstanceInContext\": {\"active\": true}, \"ExtractImportReference\": {\"active\": false}}"; + setAttr ".creator_attributes" -type "string" "{}"; setAttr ".__creator_attributes_keys" -type "string" ""; -createNode objectSet -n "renderingMain"; - rename -uid "8A999C2F-4922-B15D-8D5C-45A16465B69F"; - addAttr -ci true -sn "pre_creator_identifier" -ln "pre_creator_identifier" -dt "string"; - addAttr -ci true -sn "cbId" -ln "cbId" -dt "string"; - setAttr ".ihi" 0; - setAttr ".pre_creator_identifier" -type "string" "io.openpype.creators.maya.renderlayer"; - setAttr ".cbId" -type "string" "60df31e2be2b48bd3695c056:042447475732"; createNode renderSetupLayer -n "Main"; rename -uid "2202E438-4CEF-F64E-737C-F48C65E31126"; addAttr -ci true -sn "es" -ln "expandedState" -min 0 -max 1 -at "bool"; @@ -320,55 +327,6 @@ createNode collection -n "defaultCollection"; createNode simpleSelector -n "defaultCollectionSelector"; rename -uid "7CA2F6D8-483C-B020-BC03-EF9563A52163"; setAttr ".pat" -type "string" "*"; -createNode objectSet -n "_renderingMain:Main"; - rename -uid "1EEC3A3B-49CF-0C79-5340-39805174FB8A"; - addAttr -s false -ci true -sn "renderlayer" -ln "renderlayer" -at "message"; - addAttr -ci true -sn "id" -ln "id" -dt "string"; - addAttr -ci true -sn "family" -ln "family" -dt "string"; - addAttr -ci true -sn "subset" -ln "subset" -dt "string"; - addAttr -ci true -sn "active" -ln "active" -min 0 -max 1 -at "bool"; - addAttr -ci true -sn "creator_identifier" -ln "creator_identifier" -dt "string"; - addAttr -ci true -sn "variant" -ln "variant" -dt "string"; - addAttr -ci true -sn "asset" -ln "asset" -dt "string"; - addAttr -ci true -sn "task" -ln "task" -dt "string"; - addAttr -ci true -sn "instance_id" -ln "instance_id" -dt "string"; - addAttr -ci true -sn "review" -ln "review" -min 0 -max 1 -at "bool"; - addAttr -ci true -sn "extendFrames" -ln "extendFrames" -min 0 -max 1 -at "bool"; - addAttr -ci true -sn "overrideExistingFrame" -ln "overrideExistingFrame" -min 0 - -max 1 -at "bool"; - addAttr -ci true -sn "tileRendering" -ln "tileRendering" -min 0 -max 1 -at "bool"; - addAttr -ci true -sn "tilesX" -ln "tilesX" -at "long"; - addAttr -ci true -sn "tilesY" -ln "tilesY" -at "long"; - addAttr -ci true -sn "convertToScanline" -ln "convertToScanline" -min 0 -max 1 -at "bool"; - addAttr -ci true -sn "useReferencedAovs" -ln "useReferencedAovs" -min 0 -max 1 -at "bool"; - addAttr -ci true -sn "renderSetupIncludeLights" -ln "renderSetupIncludeLights" -min - 0 -max 1 -at "bool"; - addAttr -ci true -sn "publish_attributes" -ln "publish_attributes" -dt "string"; - addAttr -ci true -sn "__creator_attributes_keys" -ln "__creator_attributes_keys" - -dt "string"; - addAttr -ci true -sn "cbId" -ln "cbId" -dt "string"; - setAttr ".ihi" 0; - setAttr ".id" -type "string" "pyblish.avalon.instance"; - setAttr ".family" -type "string" "renderlayer"; - setAttr ".subset" -type "string" "renderMain"; - setAttr -cb on ".active" yes; - setAttr ".creator_identifier" -type "string" "io.openpype.creators.maya.renderlayer"; - setAttr ".variant" -type "string" "Main"; - setAttr ".asset" -type "string" "test_asset"; - setAttr ".task" -type "string" "test_task"; - setAttr ".instance_id" -type "string" "8a9cfb85-9602-4e5e-a4bc-27a2986bae7f"; - setAttr -cb on ".review" yes; - setAttr -cb on ".extendFrames"; - setAttr -cb on ".overrideExistingFrame" yes; - setAttr -cb on ".tileRendering"; - setAttr -cb on ".tilesX" 2; - setAttr -cb on ".tilesY" 2; - setAttr -cb on ".convertToScanline"; - setAttr -cb on ".useReferencedAovs"; - setAttr -cb on ".renderSetupIncludeLights" yes; - setAttr ".publish_attributes" -type "string" "{\"CollectDeadlinePools\": {\"primaryPool\": \"\", \"secondaryPool\": \"\"}, \"ValidateDeadlinePools\": {\"active\": true}, \"ValidateFrameRange\": {\"active\": true}, \"ExtractImportReference\": {\"active\": false}, \"MayaSubmitDeadline\": {\"priority\": 50, \"chunkSize\": 1, \"machineList\": \"\", \"whitelist\": false, \"tile_priority\": 50, \"strict_error_checking\": true}, \"ProcessSubmittedJobOnFarm\": {\"publishJobState\": \"Active\"}}"; - setAttr ".__creator_attributes_keys" -type "string" "review,extendFrames,overrideExistingFrame,tileRendering,tilesX,tilesY,convertToScanline,useReferencedAovs,renderSetupIncludeLights"; - setAttr ".cbId" -type "string" "60df31e2be2b48bd3695c056:69960f336351"; select -ne :time1; setAttr ".o" 1001; setAttr ".unw" 1001; @@ -435,8 +393,6 @@ select -ne :defaultColorMgtGlobals; select -ne :hardwareRenderGlobals; setAttr ".ctrs" 256; setAttr ".btrs" 512; -select -ne :ikSystem; - setAttr -s 4 ".sol"; connectAttr "rs_Main.ri" ":persp.rlio[0]"; connectAttr "rs_Main.ri" ":top.rlio[0]"; connectAttr "rs_Main.ri" ":front.rlio[0]"; @@ -459,7 +415,6 @@ connectAttr ":defaultArnoldDisplayDriver.msg" ":defaultArnoldRenderOptions.drive -na; connectAttr ":defaultArnoldFilter.msg" ":defaultArnoldRenderOptions.filt"; connectAttr ":defaultArnoldDriver.msg" ":defaultArnoldRenderOptions.drvr"; -connectAttr "_renderingMain:Main.msg" "renderingMain.dnsm" -na; connectAttr "rs_Main.msg" "Main.lrl"; connectAttr "renderSetup.lit" "Main.pls"; connectAttr "defaultCollection.msg" "Main.cl"; @@ -468,9 +423,8 @@ connectAttr "renderLayerManager.rlmi[1]" "rs_Main.rlid"; connectAttr "defaultCollectionSelector.c" "defaultCollection.sel"; connectAttr "Main.lit" "defaultCollection.pls"; connectAttr "Main.nic" "defaultCollection.pic"; -connectAttr "Main.msg" "_renderingMain:Main.renderlayer"; connectAttr "defaultRenderLayer.msg" ":defaultRenderingList1.r" -na; connectAttr "rs_Main.msg" ":defaultRenderingList1.r" -na; connectAttr "pSphere1_GEOShape1.iog" ":initialShadingGroup.dsm" -na; connectAttr "pDiscShape1.iog" ":initialShadingGroup.dsm" -na; -// End of test_project_test_asset_test_task_v001.ma +// End of test_project_test_asset_test_task_v002.ma diff --git a/tests/integration/hosts/maya/test_publish_in_maya/expected/test_project/test_asset/work/test_task/test_project_test_asset_test_task_v002.ma b/tests/integration/hosts/maya/test_publish_in_maya/expected/test_project/test_asset/work/test_task/test_project_test_asset_test_task_v002.ma index 57bcfdae5b..6bd334466a 100644 --- a/tests/integration/hosts/maya/test_publish_in_maya/expected/test_project/test_asset/work/test_task/test_project_test_asset_test_task_v002.ma +++ b/tests/integration/hosts/maya/test_publish_in_maya/expected/test_project/test_asset/work/test_task/test_project_test_asset_test_task_v002.ma @@ -1,22 +1,22 @@ -//Maya ASCII 2024 scene +//Maya ASCII 2023 scene //Name: test_project_test_asset_test_task_v002.ma -//Last modified: Tue, Oct 31, 2023 08:24:19 AM +//Last modified: Thu, Dec 07, 2023 03:55:12 PM //Codeset: 1252 -requires maya "2024"; -requires -nodeType "polyDisc" "modelingToolkit" "0.0.0.0"; -requires "stereoCamera" "10.0"; -requires -nodeType "aiOptions" -nodeType "aiAOVDriver" -nodeType "aiAOVFilter" "mtoa" "5.3.0"; +requires maya "2023"; requires -nodeType "simpleSelector" -nodeType "renderSetupLayer" -nodeType "renderSetup" -nodeType "collection" "renderSetup.py" "1.0"; requires "stereoCamera" "10.0"; +requires -nodeType "aiOptions" -nodeType "aiAOVDriver" -nodeType "aiAOVFilter" "mtoa" "5.2.1.1"; +requires -nodeType "polyDisc" "modelingToolkit" "0.0.0.0"; +requires "stereoCamera" "10.0"; currentUnit -l centimeter -a degree -t pal; fileInfo "application" "maya"; -fileInfo "product" "Maya 2024"; -fileInfo "version" "2024"; -fileInfo "cutIdentifier" "202302170737-4500172811"; +fileInfo "product" "Maya 2023"; +fileInfo "version" "2023"; +fileInfo "cutIdentifier" "202211021031-847a9f9623"; fileInfo "osv" "Windows 10 Pro v2009 (Build: 19045)"; fileInfo "license" "education"; -fileInfo "UUID" "6C5CC57A-4CC3-7373-4411-B3B80BC40815"; +fileInfo "UUID" "7CC7E6D5-4F37-DB90-8A84-8493449019BF"; fileInfo "OpenPypeContext" "eyJwdWJsaXNoX2F0dHJpYnV0ZXMiOiB7IlZhbGlkYXRlQ29udGFpbmVycyI6IHsiYWN0aXZlIjogdHJ1ZX19fQ=="; createNode transform -s -n "persp"; rename -uid "D52C935B-47C9-D868-A875-D799DD17B3A1"; @@ -142,20 +142,20 @@ createNode camera -n "perspShape1" -p "persp1"; setAttr ".hc" -type "string" "viewSet -p %camera"; setAttr ".dr" yes; createNode lightLinker -s -n "lightLinker1"; - rename -uid "D0EBF10B-4952-5C9F-42A8-D6A660FF173F"; + rename -uid "FBA13844-432C-E5C2-040E-A0925F2F0B8F"; setAttr -s 2 ".lnk"; setAttr -s 2 ".slnk"; createNode shapeEditorManager -n "shapeEditorManager"; - rename -uid "30DE6463-4107-330C-8FE3-4EA1C402A632"; + rename -uid "E3FDBA44-4665-FFBF-74F3-BDBF4F8F7B32"; createNode poseInterpolatorManager -n "poseInterpolatorManager"; - rename -uid "64911358-4E6A-5ACC-75A4-4F965FCD606E"; + rename -uid "8834BA6F-47BE-8E76-4510-E2A7F3525077"; createNode displayLayerManager -n "layerManager"; - rename -uid "B3C9D791-45C2-E529-2A9A-9B88F2D5E17E"; + rename -uid "427D260A-43FC-DC22-4E80-46A0E90839B2"; createNode displayLayer -n "defaultLayer"; rename -uid "4A776D1B-401F-7069-1C74-A7AAE84CEE03"; setAttr ".ufem" -type "stringArray" 0 ; createNode renderLayerManager -n "renderLayerManager"; - rename -uid "68F97550-4CB6-1D4A-99B0-CCA5DBE5D6B1"; + rename -uid "F1B8B519-43D1-5DE5-00F6-42A9514335E8"; setAttr -s 2 ".rlmi[1]" 1; setAttr -s 2 ".rlmi"; createNode renderLayer -n "defaultRenderLayer"; @@ -168,6 +168,7 @@ createNode polySphere -n "polySphere1"; createNode objectSet -n "modelMain"; rename -uid "A76AD4F8-4CF5-AA0D-4E98-BABEE6454CC3"; addAttr -ci true -sn "cbId" -ln "cbId" -dt "string"; + addAttr -ci true -sn "instance_id" -ln "instance_id" -dt "string"; addAttr -ci true -sn "id" -ln "id" -dt "string"; addAttr -ci true -sn "family" -ln "family" -dt "string"; addAttr -ci true -sn "subset" -ln "subset" -dt "string"; @@ -176,18 +177,19 @@ createNode objectSet -n "modelMain"; addAttr -ci true -sn "variant" -ln "variant" -dt "string"; addAttr -ci true -sn "asset" -ln "asset" -dt "string"; addAttr -ci true -sn "task" -ln "task" -dt "string"; - addAttr -ci true -sn "instance_id" -ln "instance_id" -dt "string"; addAttr -ci true -sn "writeColorSets" -ln "writeColorSets" -min 0 -max 1 -at "bool"; addAttr -ci true -sn "writeFaceSets" -ln "writeFaceSets" -min 0 -max 1 -at "bool"; - addAttr -ci true -sn "includeParentHierarchy" -ln "includeParentHierarchy" -min + addAttr -ci true -sn "includeParentHierarchy" -ln "includeParentHierarchy" -min 0 -max 1 -at "bool"; addAttr -ci true -sn "attr" -ln "attr" -dt "string"; addAttr -ci true -sn "attrPrefix" -ln "attrPrefix" -dt "string"; addAttr -ci true -sn "publish_attributes" -ln "publish_attributes" -dt "string"; - addAttr -ci true -sn "__creator_attributes_keys" -ln "__creator_attributes_keys" + addAttr -ci true -sn "creator_attributes" -ln "creator_attributes" -dt "string"; + addAttr -ci true -sn "__creator_attributes_keys" -ln "__creator_attributes_keys" -dt "string"; setAttr ".ihi" 0; setAttr ".cbId" -type "string" "60df31e2be2b48bd3695c056:7364ea6776c9"; + setAttr ".instance_id" -type "string" "6889d3db-b813-43db-96de-9ba555dc4472"; setAttr ".id" -type "string" "pyblish.avalon.instance"; setAttr ".family" -type "string" "model"; setAttr ".subset" -type "string" "modelMain"; @@ -196,59 +198,68 @@ createNode objectSet -n "modelMain"; setAttr ".variant" -type "string" "Main"; setAttr ".asset" -type "string" "test_asset"; setAttr ".task" -type "string" "test_task"; - setAttr ".instance_id" -type "string" "6889d3db-b813-43db-96de-9ba555dc4472"; setAttr -cb on ".writeColorSets"; setAttr -cb on ".writeFaceSets"; setAttr -cb on ".includeParentHierarchy"; setAttr ".attr" -type "string" ""; setAttr ".attrPrefix" -type "string" ""; - setAttr ".publish_attributes" -type "string" "{\"ValidateNodeIDsRelated\": {\"active\": true}, \"ValidateTransformNamingSuffix\": {\"active\": true}, \"ValidateColorSets\": {\"active\": true}, \"ValidateMeshArnoldAttributes\": {\"active\": true}, \"ValidateMeshHasUVs\": {\"active\": true}, \"ValidateMeshNonZeroEdgeLength\": {\"active\": true}, \"ExtractModel\": {\"active\": true}}"; + setAttr ".publish_attributes" -type "string" "{\"ValidateNodeIDsRelated\": {\"active\": true}, \"ValidateInstanceInContext\": {\"active\": true}, \"ValidateTransformNamingSuffix\": {\"active\": true}, \"ValidateColorSets\": {\"active\": true}, \"ValidateMeshHasUVs\": {\"active\": true}, \"ValidateMeshNonZeroEdgeLength\": {\"active\": true}, \"ExtractModel\": {\"active\": true}, \"ValidateMeshArnoldAttributes\": {\"active\": true}}"; + setAttr ".creator_attributes" -type "string" "{}"; setAttr ".__creator_attributes_keys" -type "string" "writeColorSets,writeFaceSets,includeParentHierarchy,attr,attrPrefix"; createNode script -n "uiConfigurationScriptNode"; rename -uid "4B7AFB53-452E-E870-63E1-CCA1DD6EAF13"; setAttr ".b" -type "string" ( "// Maya Mel UI Configuration File.\n//\n// This script is machine generated. Edit at your own risk.\n//\n//\n\nglobal string $gMainPane;\nif (`paneLayout -exists $gMainPane`) {\n\n\tglobal int $gUseScenePanelConfig;\n\tint $useSceneConfig = $gUseScenePanelConfig;\n\tint $nodeEditorPanelVisible = stringArrayContains(\"nodeEditorPanel1\", `getPanel -vis`);\n\tint $nodeEditorWorkspaceControlOpen = (`workspaceControl -exists nodeEditorPanel1Window` && `workspaceControl -q -visible nodeEditorPanel1Window`);\n\tint $menusOkayInPanels = `optionVar -q allowMenusInPanels`;\n\tint $nVisPanes = `paneLayout -q -nvp $gMainPane`;\n\tint $nPanes = 0;\n\tstring $editorName;\n\tstring $panelName;\n\tstring $itemFilterName;\n\tstring $panelConfig;\n\n\t//\n\t// get current state of the UI\n\t//\n\tsceneUIReplacement -update $gMainPane;\n\n\t$panelName = `sceneUIReplacement -getNextPanel \"modelPanel\" (localizedPanelLabel(\"Top View\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tmodelPanel -edit -l (localizedPanelLabel(\"Top View\")) -mbv $menusOkayInPanels $panelName;\n" - + "\t\t$editorName = $panelName;\n modelEditor -e \n -camera \"|top\" \n -useInteractiveMode 0\n -displayLights \"default\" \n -displayAppearance \"smoothShaded\" \n -activeOnly 0\n -ignorePanZoom 0\n -wireframeOnShaded 0\n -headsUpDisplay 1\n -holdOuts 1\n -selectionHiliteDisplay 1\n -useDefaultMaterial 0\n -bufferMode \"double\" \n -twoSidedLighting 0\n -backfaceCulling 0\n -xray 0\n -jointXray 0\n -activeComponentsXray 0\n -displayTextures 0\n -smoothWireframe 0\n -lineWidth 1\n -textureAnisotropic 0\n -textureHilight 1\n -textureSampling 2\n -textureDisplay \"modulate\" \n -textureMaxSize 16384\n -fogging 0\n -fogSource \"fragment\" \n -fogMode \"linear\" \n -fogStart 0\n -fogEnd 100\n -fogDensity 0.1\n -fogColor 0.5 0.5 0.5 1 \n" + + "\t\t$editorName = $panelName;\n modelEditor -e \n -camera \"|top\" \n -useInteractiveMode 0\n -displayLights \"default\" \n -displayAppearance \"smoothShaded\" \n -activeOnly 0\n -ignorePanZoom 0\n -wireframeOnShaded 0\n -headsUpDisplay 1\n -holdOuts 1\n -selectionHiliteDisplay 1\n -useDefaultMaterial 0\n -bufferMode \"double\" \n -twoSidedLighting 0\n -backfaceCulling 0\n -xray 0\n -jointXray 0\n -activeComponentsXray 0\n -displayTextures 0\n -smoothWireframe 0\n -lineWidth 1\n -textureAnisotropic 0\n -textureHilight 1\n -textureSampling 2\n -textureDisplay \"modulate\" \n -textureMaxSize 32768\n -fogging 0\n -fogSource \"fragment\" \n -fogMode \"linear\" \n -fogStart 0\n -fogEnd 100\n -fogDensity 0.1\n -fogColor 0.5 0.5 0.5 1 \n" + " -depthOfFieldPreview 1\n -maxConstantTransparency 1\n -rendererName \"vp2Renderer\" \n -objectFilterShowInHUD 1\n -isFiltered 0\n -colorResolution 256 256 \n -bumpResolution 512 512 \n -textureCompression 0\n -transparencyAlgorithm \"frontAndBackCull\" \n -transpInShadows 0\n -cullingOverride \"none\" \n -lowQualityLighting 0\n -maximumNumHardwareLights 1\n -occlusionCulling 0\n -shadingModel 0\n -useBaseRenderer 0\n -useReducedRenderer 0\n -smallObjectCulling 0\n -smallObjectThreshold -1 \n -interactiveDisableShadows 0\n -interactiveBackFaceCull 0\n -sortTransparent 1\n -controllers 1\n -nurbsCurves 1\n -nurbsSurfaces 1\n -polymeshes 1\n -subdivSurfaces 1\n -planes 1\n -lights 1\n -cameras 1\n -controlVertices 1\n" - + " -hulls 1\n -grid 1\n -imagePlane 1\n -joints 1\n -ikHandles 1\n -deformers 1\n -dynamics 1\n -particleInstancers 1\n -fluids 1\n -hairSystems 1\n -follicles 1\n -nCloths 1\n -nParticles 1\n -nRigids 1\n -dynamicConstraints 1\n -locators 1\n -manipulators 1\n -pluginShapes 1\n -dimensions 1\n -handles 1\n -pivots 1\n -textures 1\n -strokes 1\n -motionTrails 1\n -clipGhosts 1\n -bluePencil 1\n -greasePencils 0\n -excludeObjectPreset \"All\" \n -shadows 0\n -captureSequenceNumber -1\n -width 1\n -height 1\n -sceneRenderFilter 0\n $editorName;\n modelEditor -e -viewSelected 0 $editorName;\n modelEditor -e \n -pluginObjects \"gpuCacheDisplayFilter\" 1 \n $editorName;\n" - + "\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextPanel \"modelPanel\" (localizedPanelLabel(\"Side View\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tmodelPanel -edit -l (localizedPanelLabel(\"Side View\")) -mbv $menusOkayInPanels $panelName;\n\t\t$editorName = $panelName;\n modelEditor -e \n -camera \"|side\" \n -useInteractiveMode 0\n -displayLights \"default\" \n -displayAppearance \"smoothShaded\" \n -activeOnly 0\n -ignorePanZoom 0\n -wireframeOnShaded 0\n -headsUpDisplay 1\n -holdOuts 1\n -selectionHiliteDisplay 1\n -useDefaultMaterial 0\n -bufferMode \"double\" \n -twoSidedLighting 0\n -backfaceCulling 0\n -xray 0\n -jointXray 0\n -activeComponentsXray 0\n -displayTextures 0\n -smoothWireframe 0\n -lineWidth 1\n -textureAnisotropic 0\n" - + " -textureHilight 1\n -textureSampling 2\n -textureDisplay \"modulate\" \n -textureMaxSize 16384\n -fogging 0\n -fogSource \"fragment\" \n -fogMode \"linear\" \n -fogStart 0\n -fogEnd 100\n -fogDensity 0.1\n -fogColor 0.5 0.5 0.5 1 \n -depthOfFieldPreview 1\n -maxConstantTransparency 1\n -rendererName \"vp2Renderer\" \n -objectFilterShowInHUD 1\n -isFiltered 0\n -colorResolution 256 256 \n -bumpResolution 512 512 \n -textureCompression 0\n -transparencyAlgorithm \"frontAndBackCull\" \n -transpInShadows 0\n -cullingOverride \"none\" \n -lowQualityLighting 0\n -maximumNumHardwareLights 1\n -occlusionCulling 0\n -shadingModel 0\n -useBaseRenderer 0\n -useReducedRenderer 0\n -smallObjectCulling 0\n -smallObjectThreshold -1 \n -interactiveDisableShadows 0\n" - + " -interactiveBackFaceCull 0\n -sortTransparent 1\n -controllers 1\n -nurbsCurves 1\n -nurbsSurfaces 1\n -polymeshes 1\n -subdivSurfaces 1\n -planes 1\n -lights 1\n -cameras 1\n -controlVertices 1\n -hulls 1\n -grid 1\n -imagePlane 1\n -joints 1\n -ikHandles 1\n -deformers 1\n -dynamics 1\n -particleInstancers 1\n -fluids 1\n -hairSystems 1\n -follicles 1\n -nCloths 1\n -nParticles 1\n -nRigids 1\n -dynamicConstraints 1\n -locators 1\n -manipulators 1\n -pluginShapes 1\n -dimensions 1\n -handles 1\n -pivots 1\n -textures 1\n -strokes 1\n -motionTrails 1\n -clipGhosts 1\n -bluePencil 1\n -greasePencils 0\n -excludeObjectPreset \"All\" \n" - + " -shadows 0\n -captureSequenceNumber -1\n -width 1\n -height 1\n -sceneRenderFilter 0\n $editorName;\n modelEditor -e -viewSelected 0 $editorName;\n modelEditor -e \n -pluginObjects \"gpuCacheDisplayFilter\" 1 \n $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextPanel \"modelPanel\" (localizedPanelLabel(\"Front View\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tmodelPanel -edit -l (localizedPanelLabel(\"Front View\")) -mbv $menusOkayInPanels $panelName;\n\t\t$editorName = $panelName;\n modelEditor -e \n -camera \"|front\" \n -useInteractiveMode 0\n -displayLights \"default\" \n -displayAppearance \"smoothShaded\" \n -activeOnly 0\n -ignorePanZoom 0\n -wireframeOnShaded 0\n -headsUpDisplay 1\n -holdOuts 1\n -selectionHiliteDisplay 1\n" - + " -useDefaultMaterial 0\n -bufferMode \"double\" \n -twoSidedLighting 0\n -backfaceCulling 0\n -xray 0\n -jointXray 0\n -activeComponentsXray 0\n -displayTextures 0\n -smoothWireframe 0\n -lineWidth 1\n -textureAnisotropic 0\n -textureHilight 1\n -textureSampling 2\n -textureDisplay \"modulate\" \n -textureMaxSize 16384\n -fogging 0\n -fogSource \"fragment\" \n -fogMode \"linear\" \n -fogStart 0\n -fogEnd 100\n -fogDensity 0.1\n -fogColor 0.5 0.5 0.5 1 \n -depthOfFieldPreview 1\n -maxConstantTransparency 1\n -rendererName \"vp2Renderer\" \n -objectFilterShowInHUD 1\n -isFiltered 0\n -colorResolution 256 256 \n -bumpResolution 512 512 \n -textureCompression 0\n -transparencyAlgorithm \"frontAndBackCull\" \n -transpInShadows 0\n" - + " -cullingOverride \"none\" \n -lowQualityLighting 0\n -maximumNumHardwareLights 1\n -occlusionCulling 0\n -shadingModel 0\n -useBaseRenderer 0\n -useReducedRenderer 0\n -smallObjectCulling 0\n -smallObjectThreshold -1 \n -interactiveDisableShadows 0\n -interactiveBackFaceCull 0\n -sortTransparent 1\n -controllers 1\n -nurbsCurves 1\n -nurbsSurfaces 1\n -polymeshes 1\n -subdivSurfaces 1\n -planes 1\n -lights 1\n -cameras 1\n -controlVertices 1\n -hulls 1\n -grid 1\n -imagePlane 1\n -joints 1\n -ikHandles 1\n -deformers 1\n -dynamics 1\n -particleInstancers 1\n -fluids 1\n -hairSystems 1\n -follicles 1\n -nCloths 1\n -nParticles 1\n -nRigids 1\n -dynamicConstraints 1\n" - + " -locators 1\n -manipulators 1\n -pluginShapes 1\n -dimensions 1\n -handles 1\n -pivots 1\n -textures 1\n -strokes 1\n -motionTrails 1\n -clipGhosts 1\n -bluePencil 1\n -greasePencils 0\n -excludeObjectPreset \"All\" \n -shadows 0\n -captureSequenceNumber -1\n -width 1\n -height 1\n -sceneRenderFilter 0\n $editorName;\n modelEditor -e -viewSelected 0 $editorName;\n modelEditor -e \n -pluginObjects \"gpuCacheDisplayFilter\" 1 \n $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextPanel \"modelPanel\" (localizedPanelLabel(\"Persp View\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tmodelPanel -edit -l (localizedPanelLabel(\"Persp View\")) -mbv $menusOkayInPanels $panelName;\n\t\t$editorName = $panelName;\n modelEditor -e \n" - + " -camera \"|persp\" \n -useInteractiveMode 0\n -displayLights \"default\" \n -displayAppearance \"smoothShaded\" \n -activeOnly 0\n -ignorePanZoom 0\n -wireframeOnShaded 0\n -headsUpDisplay 1\n -holdOuts 1\n -selectionHiliteDisplay 1\n -useDefaultMaterial 0\n -bufferMode \"double\" \n -twoSidedLighting 0\n -backfaceCulling 0\n -xray 0\n -jointXray 0\n -activeComponentsXray 0\n -displayTextures 0\n -smoothWireframe 0\n -lineWidth 1\n -textureAnisotropic 0\n -textureHilight 1\n -textureSampling 2\n -textureDisplay \"modulate\" \n -textureMaxSize 16384\n -fogging 0\n -fogSource \"fragment\" \n -fogMode \"linear\" \n -fogStart 0\n -fogEnd 100\n -fogDensity 0.1\n -fogColor 0.5 0.5 0.5 1 \n -depthOfFieldPreview 1\n" - + " -maxConstantTransparency 1\n -rendererName \"vp2Renderer\" \n -objectFilterShowInHUD 1\n -isFiltered 0\n -colorResolution 256 256 \n -bumpResolution 512 512 \n -textureCompression 0\n -transparencyAlgorithm \"frontAndBackCull\" \n -transpInShadows 0\n -cullingOverride \"none\" \n -lowQualityLighting 0\n -maximumNumHardwareLights 1\n -occlusionCulling 0\n -shadingModel 0\n -useBaseRenderer 0\n -useReducedRenderer 0\n -smallObjectCulling 0\n -smallObjectThreshold -1 \n -interactiveDisableShadows 0\n -interactiveBackFaceCull 0\n -sortTransparent 1\n -controllers 1\n -nurbsCurves 1\n -nurbsSurfaces 1\n -polymeshes 1\n -subdivSurfaces 1\n -planes 1\n -lights 1\n -cameras 1\n -controlVertices 1\n -hulls 1\n -grid 1\n" - + " -imagePlane 1\n -joints 1\n -ikHandles 1\n -deformers 1\n -dynamics 1\n -particleInstancers 1\n -fluids 1\n -hairSystems 1\n -follicles 1\n -nCloths 1\n -nParticles 1\n -nRigids 1\n -dynamicConstraints 1\n -locators 1\n -manipulators 1\n -pluginShapes 1\n -dimensions 1\n -handles 1\n -pivots 1\n -textures 1\n -strokes 1\n -motionTrails 1\n -clipGhosts 1\n -bluePencil 1\n -greasePencils 0\n -excludeObjectPreset \"All\" \n -shadows 0\n -captureSequenceNumber -1\n -width 1319\n -height 718\n -sceneRenderFilter 0\n $editorName;\n modelEditor -e -viewSelected 0 $editorName;\n modelEditor -e \n -pluginObjects \"gpuCacheDisplayFilter\" 1 \n $editorName;\n\t\tif (!$useSceneConfig) {\n" - + "\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextPanel \"outlinerPanel\" (localizedPanelLabel(\"ToggledOutliner\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\toutlinerPanel -edit -l (localizedPanelLabel(\"ToggledOutliner\")) -mbv $menusOkayInPanels $panelName;\n\t\t$editorName = $panelName;\n outlinerEditor -e \n -docTag \"isolOutln_fromSeln\" \n -showShapes 0\n -showAssignedMaterials 0\n -showTimeEditor 1\n -showReferenceNodes 1\n -showReferenceMembers 1\n -showAttributes 0\n -showConnected 0\n -showAnimCurvesOnly 0\n -showMuteInfo 0\n -organizeByLayer 1\n -organizeByClip 1\n -showAnimLayerWeight 1\n -autoExpandLayers 1\n -autoExpand 0\n -showDagOnly 1\n -showAssets 1\n -showContainedOnly 1\n -showPublishedAsConnected 0\n -showParentContainers 0\n -showContainerContents 1\n" - + " -ignoreDagHierarchy 0\n -expandConnections 0\n -showUpstreamCurves 1\n -showUnitlessCurves 1\n -showCompounds 1\n -showLeafs 1\n -showNumericAttrsOnly 0\n -highlightActive 1\n -autoSelectNewObjects 0\n -doNotSelectNewObjects 0\n -dropIsParent 1\n -transmitFilters 0\n -setFilter \"defaultSetFilter\" \n -showSetMembers 1\n -allowMultiSelection 1\n -alwaysToggleSelect 0\n -directSelect 0\n -isSet 0\n -isSetMember 0\n -showUfeItems 1\n -displayMode \"DAG\" \n -expandObjects 0\n -setsIgnoreFilters 1\n -containersIgnoreFilters 0\n -editAttrName 0\n -showAttrValues 0\n -highlightSecondary 0\n -showUVAttrsOnly 0\n -showTextureNodesOnly 0\n -attrAlphaOrder \"default\" \n -animLayerFilterOptions \"allAffecting\" \n -sortOrder \"none\" \n" - + " -longNames 0\n -niceNames 1\n -selectCommand \"print(\\\"\\\")\" \n -showNamespace 1\n -showPinIcons 0\n -mapMotionTrails 0\n -ignoreHiddenAttribute 0\n -ignoreOutlinerColor 0\n -renderFilterVisible 0\n -renderFilterIndex 0\n -selectionOrder \"chronological\" \n -expandAttribute 0\n $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextPanel \"outlinerPanel\" (localizedPanelLabel(\"Outliner\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\toutlinerPanel -edit -l (localizedPanelLabel(\"Outliner\")) -mbv $menusOkayInPanels $panelName;\n\t\t$editorName = $panelName;\n outlinerEditor -e \n -showShapes 0\n -showAssignedMaterials 0\n -showTimeEditor 1\n -showReferenceNodes 0\n -showReferenceMembers 0\n -showAttributes 0\n -showConnected 0\n" - + " -showAnimCurvesOnly 0\n -showMuteInfo 0\n -organizeByLayer 1\n -organizeByClip 1\n -showAnimLayerWeight 1\n -autoExpandLayers 1\n -autoExpand 0\n -showDagOnly 1\n -showAssets 1\n -showContainedOnly 1\n -showPublishedAsConnected 0\n -showParentContainers 0\n -showContainerContents 1\n -ignoreDagHierarchy 0\n -expandConnections 0\n -showUpstreamCurves 1\n -showUnitlessCurves 1\n -showCompounds 1\n -showLeafs 1\n -showNumericAttrsOnly 0\n -highlightActive 1\n -autoSelectNewObjects 0\n -doNotSelectNewObjects 0\n -dropIsParent 1\n -transmitFilters 0\n -setFilter \"defaultSetFilter\" \n -showSetMembers 1\n -allowMultiSelection 1\n -alwaysToggleSelect 0\n -directSelect 0\n -showUfeItems 1\n -displayMode \"DAG\" \n" - + " -expandObjects 0\n -setsIgnoreFilters 1\n -containersIgnoreFilters 0\n -editAttrName 0\n -showAttrValues 0\n -highlightSecondary 0\n -showUVAttrsOnly 0\n -showTextureNodesOnly 0\n -attrAlphaOrder \"default\" \n -animLayerFilterOptions \"allAffecting\" \n -sortOrder \"none\" \n -longNames 0\n -niceNames 1\n -showNamespace 1\n -showPinIcons 0\n -mapMotionTrails 0\n -ignoreHiddenAttribute 0\n -ignoreOutlinerColor 0\n -renderFilterVisible 0\n $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"graphEditor\" (localizedPanelLabel(\"Graph Editor\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Graph Editor\")) -mbv $menusOkayInPanels $panelName;\n\n\t\t\t$editorName = ($panelName+\"OutlineEd\");\n" - + " outlinerEditor -e \n -showShapes 1\n -showAssignedMaterials 0\n -showTimeEditor 1\n -showReferenceNodes 0\n -showReferenceMembers 0\n -showAttributes 1\n -showConnected 1\n -showAnimCurvesOnly 1\n -showMuteInfo 0\n -organizeByLayer 1\n -organizeByClip 1\n -showAnimLayerWeight 1\n -autoExpandLayers 1\n -autoExpand 1\n -showDagOnly 0\n -showAssets 1\n -showContainedOnly 0\n -showPublishedAsConnected 0\n -showParentContainers 0\n -showContainerContents 0\n -ignoreDagHierarchy 0\n -expandConnections 1\n -showUpstreamCurves 1\n -showUnitlessCurves 1\n -showCompounds 0\n -showLeafs 1\n -showNumericAttrsOnly 1\n -highlightActive 0\n" - + " -autoSelectNewObjects 1\n -doNotSelectNewObjects 0\n -dropIsParent 1\n -transmitFilters 1\n -setFilter \"0\" \n -showSetMembers 0\n -allowMultiSelection 1\n -alwaysToggleSelect 0\n -directSelect 0\n -showUfeItems 1\n -displayMode \"DAG\" \n -expandObjects 0\n -setsIgnoreFilters 1\n -containersIgnoreFilters 0\n -editAttrName 0\n -showAttrValues 0\n -highlightSecondary 0\n -showUVAttrsOnly 0\n -showTextureNodesOnly 0\n -attrAlphaOrder \"default\" \n -animLayerFilterOptions \"allAffecting\" \n -sortOrder \"none\" \n -longNames 0\n -niceNames 1\n -showNamespace 1\n -showPinIcons 1\n -mapMotionTrails 1\n -ignoreHiddenAttribute 0\n -ignoreOutlinerColor 0\n" - + " -renderFilterVisible 0\n $editorName;\n\n\t\t\t$editorName = ($panelName+\"GraphEd\");\n animCurveEditor -e \n -displayValues 0\n -snapTime \"integer\" \n -snapValue \"none\" \n -showPlayRangeShades \"on\" \n -lockPlayRangeShades \"off\" \n -smoothness \"fine\" \n -resultSamples 1.041667\n -resultScreenSamples 0\n -resultUpdate \"delayed\" \n -showUpstreamCurves 1\n -keyMinScale 1\n -stackedCurvesMin -1\n -stackedCurvesMax 1\n -stackedCurvesSpace 0.2\n -preSelectionHighlight 0\n -constrainDrag 0\n -valueLinesToggle 1\n -highlightAffectedCurves 0\n $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"dopeSheetPanel\" (localizedPanelLabel(\"Dope Sheet\")) `;\n" - + "\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Dope Sheet\")) -mbv $menusOkayInPanels $panelName;\n\n\t\t\t$editorName = ($panelName+\"OutlineEd\");\n outlinerEditor -e \n -showShapes 1\n -showAssignedMaterials 0\n -showTimeEditor 1\n -showReferenceNodes 0\n -showReferenceMembers 0\n -showAttributes 1\n -showConnected 1\n -showAnimCurvesOnly 1\n -showMuteInfo 0\n -organizeByLayer 1\n -organizeByClip 1\n -showAnimLayerWeight 1\n -autoExpandLayers 1\n -autoExpand 0\n -showDagOnly 0\n -showAssets 1\n -showContainedOnly 0\n -showPublishedAsConnected 0\n -showParentContainers 0\n -showContainerContents 0\n -ignoreDagHierarchy 0\n -expandConnections 1\n" - + " -showUpstreamCurves 1\n -showUnitlessCurves 0\n -showCompounds 1\n -showLeafs 1\n -showNumericAttrsOnly 1\n -highlightActive 0\n -autoSelectNewObjects 0\n -doNotSelectNewObjects 1\n -dropIsParent 1\n -transmitFilters 0\n -setFilter \"0\" \n -showSetMembers 0\n -allowMultiSelection 1\n -alwaysToggleSelect 0\n -directSelect 0\n -showUfeItems 1\n -displayMode \"DAG\" \n -expandObjects 0\n -setsIgnoreFilters 1\n -containersIgnoreFilters 0\n -editAttrName 0\n -showAttrValues 0\n -highlightSecondary 0\n -showUVAttrsOnly 0\n -showTextureNodesOnly 0\n -attrAlphaOrder \"default\" \n -animLayerFilterOptions \"allAffecting\" \n -sortOrder \"none\" \n" - + " -longNames 0\n -niceNames 1\n -showNamespace 1\n -showPinIcons 0\n -mapMotionTrails 1\n -ignoreHiddenAttribute 0\n -ignoreOutlinerColor 0\n -renderFilterVisible 0\n $editorName;\n\n\t\t\t$editorName = ($panelName+\"DopeSheetEd\");\n dopeSheetEditor -e \n -displayValues 0\n -snapTime \"integer\" \n -snapValue \"none\" \n -outliner \"dopeSheetPanel1OutlineEd\" \n -showSummary 1\n -showScene 0\n -hierarchyBelow 0\n -showTicks 1\n -selectionWindow 0 0 0 0 \n $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"timeEditorPanel\" (localizedPanelLabel(\"Time Editor\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Time Editor\")) -mbv $menusOkayInPanels $panelName;\n" - + "\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"clipEditorPanel\" (localizedPanelLabel(\"Trax Editor\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Trax Editor\")) -mbv $menusOkayInPanels $panelName;\n\n\t\t\t$editorName = clipEditorNameFromPanel($panelName);\n clipEditor -e \n -displayValues 0\n -snapTime \"none\" \n -snapValue \"none\" \n -initialized 0\n -manageSequencer 0 \n $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"sequenceEditorPanel\" (localizedPanelLabel(\"Camera Sequencer\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Camera Sequencer\")) -mbv $menusOkayInPanels $panelName;\n\n\t\t\t$editorName = sequenceEditorNameFromPanel($panelName);\n" - + " clipEditor -e \n -displayValues 0\n -snapTime \"none\" \n -snapValue \"none\" \n -initialized 0\n -manageSequencer 1 \n $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"hyperGraphPanel\" (localizedPanelLabel(\"Hypergraph Hierarchy\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Hypergraph Hierarchy\")) -mbv $menusOkayInPanels $panelName;\n\n\t\t\t$editorName = ($panelName+\"HyperGraphEd\");\n hyperGraph -e \n -graphLayoutStyle \"hierarchicalLayout\" \n -orientation \"horiz\" \n -mergeConnections 0\n -zoom 1\n -animateTransition 0\n -showRelationships 1\n -showShapes 0\n -showDeformers 0\n -showExpressions 0\n -showConstraints 0\n" - + " -showConnectionFromSelected 0\n -showConnectionToSelected 0\n -showConstraintLabels 0\n -showUnderworld 0\n -showInvisible 0\n -transitionFrames 1\n -opaqueContainers 0\n -freeform 0\n -imagePosition 0 0 \n -imageScale 1\n -imageEnabled 0\n -graphType \"DAG\" \n -heatMapDisplay 0\n -updateSelection 1\n -updateNodeAdded 1\n -useDrawOverrideColor 0\n -limitGraphTraversal -1\n -range 0 0 \n -iconSize \"smallIcons\" \n -showCachedConnections 0\n $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"hyperShadePanel\" (localizedPanelLabel(\"Hypershade\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Hypershade\")) -mbv $menusOkayInPanels $panelName;\n" - + "\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"visorPanel\" (localizedPanelLabel(\"Visor\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Visor\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"nodeEditorPanel\" (localizedPanelLabel(\"Node Editor\")) `;\n\tif ($nodeEditorPanelVisible || $nodeEditorWorkspaceControlOpen) {\n\t\tif (\"\" == $panelName) {\n\t\t\tif ($useSceneConfig) {\n\t\t\t\t$panelName = `scriptedPanel -unParent -type \"nodeEditorPanel\" -l (localizedPanelLabel(\"Node Editor\")) -mbv $menusOkayInPanels `;\n\n\t\t\t$editorName = ($panelName+\"NodeEditorEd\");\n nodeEditor -e \n -allAttributes 0\n -allNodes 0\n -autoSizeNodes 1\n -consistentNameSize 1\n -createNodeCommand \"nodeEdCreateNodeCommand\" \n" - + " -connectNodeOnCreation 0\n -connectOnDrop 0\n -copyConnectionsOnPaste 0\n -connectionStyle \"bezier\" \n -defaultPinnedState 0\n -additiveGraphingMode 0\n -connectedGraphingMode 1\n -settingsChangedCallback \"nodeEdSyncControls\" \n -traversalDepthLimit -1\n -keyPressCommand \"nodeEdKeyPressCommand\" \n -nodeTitleMode \"name\" \n -gridSnap 0\n -gridVisibility 1\n -crosshairOnEdgeDragging 0\n -popupMenuScript \"nodeEdBuildPanelMenus\" \n -showNamespace 1\n -showShapes 1\n -showSGShapes 0\n -showTransforms 1\n -useAssets 1\n -syncedSelection 1\n -extendToShapes 1\n -showUnitConversions 0\n -editorMode \"default\" \n -hasWatchpoint 0\n $editorName;\n\t\t\t}\n\t\t} else {\n\t\t\t$label = `panel -q -label $panelName`;\n" - + "\t\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Node Editor\")) -mbv $menusOkayInPanels $panelName;\n\n\t\t\t$editorName = ($panelName+\"NodeEditorEd\");\n nodeEditor -e \n -allAttributes 0\n -allNodes 0\n -autoSizeNodes 1\n -consistentNameSize 1\n -createNodeCommand \"nodeEdCreateNodeCommand\" \n -connectNodeOnCreation 0\n -connectOnDrop 0\n -copyConnectionsOnPaste 0\n -connectionStyle \"bezier\" \n -defaultPinnedState 0\n -additiveGraphingMode 0\n -connectedGraphingMode 1\n -settingsChangedCallback \"nodeEdSyncControls\" \n -traversalDepthLimit -1\n -keyPressCommand \"nodeEdKeyPressCommand\" \n -nodeTitleMode \"name\" \n -gridSnap 0\n -gridVisibility 1\n -crosshairOnEdgeDragging 0\n -popupMenuScript \"nodeEdBuildPanelMenus\" \n -showNamespace 1\n" - + " -showShapes 1\n -showSGShapes 0\n -showTransforms 1\n -useAssets 1\n -syncedSelection 1\n -extendToShapes 1\n -showUnitConversions 0\n -editorMode \"default\" \n -hasWatchpoint 0\n $editorName;\n\t\t\tif (!$useSceneConfig) {\n\t\t\t\tpanel -e -l $label $panelName;\n\t\t\t}\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"createNodePanel\" (localizedPanelLabel(\"Create Node\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Create Node\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"polyTexturePlacementPanel\" (localizedPanelLabel(\"UV Editor\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"UV Editor\")) -mbv $menusOkayInPanels $panelName;\n" - + "\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"renderWindowPanel\" (localizedPanelLabel(\"Render View\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Render View\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextPanel \"shapePanel\" (localizedPanelLabel(\"Shape Editor\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tshapePanel -edit -l (localizedPanelLabel(\"Shape Editor\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextPanel \"posePanel\" (localizedPanelLabel(\"Pose Editor\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tposePanel -edit -l (localizedPanelLabel(\"Pose Editor\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n" - + "\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"dynRelEdPanel\" (localizedPanelLabel(\"Dynamic Relationships\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Dynamic Relationships\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"relationshipPanel\" (localizedPanelLabel(\"Relationship Editor\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Relationship Editor\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"referenceEditorPanel\" (localizedPanelLabel(\"Reference Editor\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Reference Editor\")) -mbv $menusOkayInPanels $panelName;\n" - + "\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"dynPaintScriptedPanelType\" (localizedPanelLabel(\"Paint Effects\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Paint Effects\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"scriptEditorPanel\" (localizedPanelLabel(\"Script Editor\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Script Editor\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"profilerPanel\" (localizedPanelLabel(\"Profiler Tool\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Profiler Tool\")) -mbv $menusOkayInPanels $panelName;\n" - + "\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"contentBrowserPanel\" (localizedPanelLabel(\"Content Browser\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Content Browser\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"Stereo\" (localizedPanelLabel(\"Stereo\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Stereo\")) -mbv $menusOkayInPanels $panelName;\n{ string $editorName = ($panelName+\"Editor\");\n stereoCameraView -e \n -camera \"|persp\" \n -useInteractiveMode 0\n -displayLights \"default\" \n -displayAppearance \"wireframe\" \n -activeOnly 0\n -ignorePanZoom 0\n -wireframeOnShaded 0\n" - + " -headsUpDisplay 1\n -holdOuts 1\n -selectionHiliteDisplay 1\n -useDefaultMaterial 0\n -bufferMode \"double\" \n -twoSidedLighting 1\n -backfaceCulling 0\n -xray 0\n -jointXray 0\n -activeComponentsXray 0\n -displayTextures 0\n -smoothWireframe 0\n -lineWidth 1\n -textureAnisotropic 0\n -textureHilight 1\n -textureSampling 2\n -textureDisplay \"modulate\" \n -textureMaxSize 16384\n -fogging 0\n -fogSource \"fragment\" \n -fogMode \"linear\" \n -fogStart 0\n -fogEnd 100\n -fogDensity 0.1\n -fogColor 0.5 0.5 0.5 1 \n -depthOfFieldPreview 1\n -maxConstantTransparency 1\n -objectFilterShowInHUD 1\n -isFiltered 0\n -colorResolution 4 4 \n" - + " -bumpResolution 4 4 \n -textureCompression 0\n -transparencyAlgorithm \"frontAndBackCull\" \n -transpInShadows 0\n -cullingOverride \"none\" \n -lowQualityLighting 0\n -maximumNumHardwareLights 0\n -occlusionCulling 0\n -shadingModel 0\n -useBaseRenderer 0\n -useReducedRenderer 0\n -smallObjectCulling 0\n -smallObjectThreshold -1 \n -interactiveDisableShadows 0\n -interactiveBackFaceCull 0\n -sortTransparent 1\n -controllers 1\n -nurbsCurves 1\n -nurbsSurfaces 1\n -polymeshes 1\n -subdivSurfaces 1\n -planes 1\n -lights 1\n -cameras 1\n -controlVertices 1\n -hulls 1\n -grid 1\n -imagePlane 1\n -joints 1\n -ikHandles 1\n" - + " -deformers 1\n -dynamics 1\n -particleInstancers 1\n -fluids 1\n -hairSystems 1\n -follicles 1\n -nCloths 1\n -nParticles 1\n -nRigids 1\n -dynamicConstraints 1\n -locators 1\n -manipulators 1\n -pluginShapes 1\n -dimensions 1\n -handles 1\n -pivots 1\n -textures 1\n -strokes 1\n -motionTrails 1\n -clipGhosts 1\n -bluePencil 1\n -greasePencils 0\n -shadows 0\n -captureSequenceNumber -1\n -width 0\n -height 0\n -sceneRenderFilter 0\n -displayMode \"centerEye\" \n -viewColor 0 0 0 1 \n -useCustomBackground 1\n $editorName;\n stereoCameraView -e -viewSelected 0 $editorName;\n stereoCameraView -e \n" - + " -pluginObjects \"gpuCacheDisplayFilter\" 1 \n $editorName; };\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\tif ($useSceneConfig) {\n string $configName = `getPanel -cwl (localizedPanelLabel(\"Current Layout\"))`;\n if (\"\" != $configName) {\n\t\t\tpanelConfiguration -edit -label (localizedPanelLabel(\"Current Layout\")) \n\t\t\t\t-userCreated false\n\t\t\t\t-defaultImage \"vacantCell.xP:/\"\n\t\t\t\t-image \"\"\n\t\t\t\t-sc false\n\t\t\t\t-configString \"global string $gMainPane; paneLayout -e -cn \\\"single\\\" -ps 1 100 100 $gMainPane;\"\n\t\t\t\t-removeAllPanels\n\t\t\t\t-ap false\n\t\t\t\t\t(localizedPanelLabel(\"Persp View\")) \n\t\t\t\t\t\"modelPanel\"\n" - + "\t\t\t\t\t\"$panelName = `modelPanel -unParent -l (localizedPanelLabel(\\\"Persp View\\\")) -mbv $menusOkayInPanels `;\\n$editorName = $panelName;\\nmodelEditor -e \\n -cam `findStartUpCamera persp` \\n -useInteractiveMode 0\\n -displayLights \\\"default\\\" \\n -displayAppearance \\\"smoothShaded\\\" \\n -activeOnly 0\\n -ignorePanZoom 0\\n -wireframeOnShaded 0\\n -headsUpDisplay 1\\n -holdOuts 1\\n -selectionHiliteDisplay 1\\n -useDefaultMaterial 0\\n -bufferMode \\\"double\\\" \\n -twoSidedLighting 0\\n -backfaceCulling 0\\n -xray 0\\n -jointXray 0\\n -activeComponentsXray 0\\n -displayTextures 0\\n -smoothWireframe 0\\n -lineWidth 1\\n -textureAnisotropic 0\\n -textureHilight 1\\n -textureSampling 2\\n -textureDisplay \\\"modulate\\\" \\n -textureMaxSize 16384\\n -fogging 0\\n -fogSource \\\"fragment\\\" \\n -fogMode \\\"linear\\\" \\n -fogStart 0\\n -fogEnd 100\\n -fogDensity 0.1\\n -fogColor 0.5 0.5 0.5 1 \\n -depthOfFieldPreview 1\\n -maxConstantTransparency 1\\n -rendererName \\\"vp2Renderer\\\" \\n -objectFilterShowInHUD 1\\n -isFiltered 0\\n -colorResolution 256 256 \\n -bumpResolution 512 512 \\n -textureCompression 0\\n -transparencyAlgorithm \\\"frontAndBackCull\\\" \\n -transpInShadows 0\\n -cullingOverride \\\"none\\\" \\n -lowQualityLighting 0\\n -maximumNumHardwareLights 1\\n -occlusionCulling 0\\n -shadingModel 0\\n -useBaseRenderer 0\\n -useReducedRenderer 0\\n -smallObjectCulling 0\\n -smallObjectThreshold -1 \\n -interactiveDisableShadows 0\\n -interactiveBackFaceCull 0\\n -sortTransparent 1\\n -controllers 1\\n -nurbsCurves 1\\n -nurbsSurfaces 1\\n -polymeshes 1\\n -subdivSurfaces 1\\n -planes 1\\n -lights 1\\n -cameras 1\\n -controlVertices 1\\n -hulls 1\\n -grid 1\\n -imagePlane 1\\n -joints 1\\n -ikHandles 1\\n -deformers 1\\n -dynamics 1\\n -particleInstancers 1\\n -fluids 1\\n -hairSystems 1\\n -follicles 1\\n -nCloths 1\\n -nParticles 1\\n -nRigids 1\\n -dynamicConstraints 1\\n -locators 1\\n -manipulators 1\\n -pluginShapes 1\\n -dimensions 1\\n -handles 1\\n -pivots 1\\n -textures 1\\n -strokes 1\\n -motionTrails 1\\n -clipGhosts 1\\n -bluePencil 1\\n -greasePencils 0\\n -excludeObjectPreset \\\"All\\\" \\n -shadows 0\\n -captureSequenceNumber -1\\n -width 1319\\n -height 718\\n -sceneRenderFilter 0\\n $editorName;\\nmodelEditor -e -viewSelected 0 $editorName;\\nmodelEditor -e \\n -pluginObjects \\\"gpuCacheDisplayFilter\\\" 1 \\n $editorName\"\n" - + "\t\t\t\t\t\"modelPanel -edit -l (localizedPanelLabel(\\\"Persp View\\\")) -mbv $menusOkayInPanels $panelName;\\n$editorName = $panelName;\\nmodelEditor -e \\n -cam `findStartUpCamera persp` \\n -useInteractiveMode 0\\n -displayLights \\\"default\\\" \\n -displayAppearance \\\"smoothShaded\\\" \\n -activeOnly 0\\n -ignorePanZoom 0\\n -wireframeOnShaded 0\\n -headsUpDisplay 1\\n -holdOuts 1\\n -selectionHiliteDisplay 1\\n -useDefaultMaterial 0\\n -bufferMode \\\"double\\\" \\n -twoSidedLighting 0\\n -backfaceCulling 0\\n -xray 0\\n -jointXray 0\\n -activeComponentsXray 0\\n -displayTextures 0\\n -smoothWireframe 0\\n -lineWidth 1\\n -textureAnisotropic 0\\n -textureHilight 1\\n -textureSampling 2\\n -textureDisplay \\\"modulate\\\" \\n -textureMaxSize 16384\\n -fogging 0\\n -fogSource \\\"fragment\\\" \\n -fogMode \\\"linear\\\" \\n -fogStart 0\\n -fogEnd 100\\n -fogDensity 0.1\\n -fogColor 0.5 0.5 0.5 1 \\n -depthOfFieldPreview 1\\n -maxConstantTransparency 1\\n -rendererName \\\"vp2Renderer\\\" \\n -objectFilterShowInHUD 1\\n -isFiltered 0\\n -colorResolution 256 256 \\n -bumpResolution 512 512 \\n -textureCompression 0\\n -transparencyAlgorithm \\\"frontAndBackCull\\\" \\n -transpInShadows 0\\n -cullingOverride \\\"none\\\" \\n -lowQualityLighting 0\\n -maximumNumHardwareLights 1\\n -occlusionCulling 0\\n -shadingModel 0\\n -useBaseRenderer 0\\n -useReducedRenderer 0\\n -smallObjectCulling 0\\n -smallObjectThreshold -1 \\n -interactiveDisableShadows 0\\n -interactiveBackFaceCull 0\\n -sortTransparent 1\\n -controllers 1\\n -nurbsCurves 1\\n -nurbsSurfaces 1\\n -polymeshes 1\\n -subdivSurfaces 1\\n -planes 1\\n -lights 1\\n -cameras 1\\n -controlVertices 1\\n -hulls 1\\n -grid 1\\n -imagePlane 1\\n -joints 1\\n -ikHandles 1\\n -deformers 1\\n -dynamics 1\\n -particleInstancers 1\\n -fluids 1\\n -hairSystems 1\\n -follicles 1\\n -nCloths 1\\n -nParticles 1\\n -nRigids 1\\n -dynamicConstraints 1\\n -locators 1\\n -manipulators 1\\n -pluginShapes 1\\n -dimensions 1\\n -handles 1\\n -pivots 1\\n -textures 1\\n -strokes 1\\n -motionTrails 1\\n -clipGhosts 1\\n -bluePencil 1\\n -greasePencils 0\\n -excludeObjectPreset \\\"All\\\" \\n -shadows 0\\n -captureSequenceNumber -1\\n -width 1319\\n -height 718\\n -sceneRenderFilter 0\\n $editorName;\\nmodelEditor -e -viewSelected 0 $editorName;\\nmodelEditor -e \\n -pluginObjects \\\"gpuCacheDisplayFilter\\\" 1 \\n $editorName\"\n" + + " -hulls 1\n -grid 1\n -imagePlane 1\n -joints 1\n -ikHandles 1\n -deformers 1\n -dynamics 1\n -particleInstancers 1\n -fluids 1\n -hairSystems 1\n -follicles 1\n -nCloths 1\n -nParticles 1\n -nRigids 1\n -dynamicConstraints 1\n -locators 1\n -manipulators 1\n -pluginShapes 1\n -dimensions 1\n -handles 1\n -pivots 1\n -textures 1\n -strokes 1\n -motionTrails 1\n -clipGhosts 1\n -bluePencil 1\n -greasePencils 0\n -shadows 0\n -captureSequenceNumber -1\n -width 477\n -height 276\n -sceneRenderFilter 0\n $editorName;\n modelEditor -e -viewSelected 0 $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextPanel \"modelPanel\" (localizedPanelLabel(\"Side View\")) `;\n" + + "\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tmodelPanel -edit -l (localizedPanelLabel(\"Side View\")) -mbv $menusOkayInPanels $panelName;\n\t\t$editorName = $panelName;\n modelEditor -e \n -camera \"|side\" \n -useInteractiveMode 0\n -displayLights \"default\" \n -displayAppearance \"smoothShaded\" \n -activeOnly 0\n -ignorePanZoom 0\n -wireframeOnShaded 0\n -headsUpDisplay 1\n -holdOuts 1\n -selectionHiliteDisplay 1\n -useDefaultMaterial 0\n -bufferMode \"double\" \n -twoSidedLighting 0\n -backfaceCulling 0\n -xray 0\n -jointXray 0\n -activeComponentsXray 0\n -displayTextures 0\n -smoothWireframe 0\n -lineWidth 1\n -textureAnisotropic 0\n -textureHilight 1\n -textureSampling 2\n -textureDisplay \"modulate\" \n -textureMaxSize 32768\n -fogging 0\n" + + " -fogSource \"fragment\" \n -fogMode \"linear\" \n -fogStart 0\n -fogEnd 100\n -fogDensity 0.1\n -fogColor 0.5 0.5 0.5 1 \n -depthOfFieldPreview 1\n -maxConstantTransparency 1\n -rendererName \"vp2Renderer\" \n -objectFilterShowInHUD 1\n -isFiltered 0\n -colorResolution 256 256 \n -bumpResolution 512 512 \n -textureCompression 0\n -transparencyAlgorithm \"frontAndBackCull\" \n -transpInShadows 0\n -cullingOverride \"none\" \n -lowQualityLighting 0\n -maximumNumHardwareLights 1\n -occlusionCulling 0\n -shadingModel 0\n -useBaseRenderer 0\n -useReducedRenderer 0\n -smallObjectCulling 0\n -smallObjectThreshold -1 \n -interactiveDisableShadows 0\n -interactiveBackFaceCull 0\n -sortTransparent 1\n -controllers 1\n -nurbsCurves 1\n" + + " -nurbsSurfaces 1\n -polymeshes 1\n -subdivSurfaces 1\n -planes 1\n -lights 1\n -cameras 1\n -controlVertices 1\n -hulls 1\n -grid 1\n -imagePlane 1\n -joints 1\n -ikHandles 1\n -deformers 1\n -dynamics 1\n -particleInstancers 1\n -fluids 1\n -hairSystems 1\n -follicles 1\n -nCloths 1\n -nParticles 1\n -nRigids 1\n -dynamicConstraints 1\n -locators 1\n -manipulators 1\n -pluginShapes 1\n -dimensions 1\n -handles 1\n -pivots 1\n -textures 1\n -strokes 1\n -motionTrails 1\n -clipGhosts 1\n -bluePencil 1\n -greasePencils 0\n -shadows 0\n -captureSequenceNumber -1\n -width 476\n -height 276\n -sceneRenderFilter 0\n $editorName;\n" + + " modelEditor -e -viewSelected 0 $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextPanel \"modelPanel\" (localizedPanelLabel(\"Front View\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tmodelPanel -edit -l (localizedPanelLabel(\"Front View\")) -mbv $menusOkayInPanels $panelName;\n\t\t$editorName = $panelName;\n modelEditor -e \n -camera \"|front\" \n -useInteractiveMode 0\n -displayLights \"default\" \n -displayAppearance \"smoothShaded\" \n -activeOnly 0\n -ignorePanZoom 0\n -wireframeOnShaded 0\n -headsUpDisplay 1\n -holdOuts 1\n -selectionHiliteDisplay 1\n -useDefaultMaterial 0\n -bufferMode \"double\" \n -twoSidedLighting 0\n -backfaceCulling 0\n -xray 0\n -jointXray 0\n -activeComponentsXray 0\n -displayTextures 0\n -smoothWireframe 0\n" + + " -lineWidth 1\n -textureAnisotropic 0\n -textureHilight 1\n -textureSampling 2\n -textureDisplay \"modulate\" \n -textureMaxSize 32768\n -fogging 0\n -fogSource \"fragment\" \n -fogMode \"linear\" \n -fogStart 0\n -fogEnd 100\n -fogDensity 0.1\n -fogColor 0.5 0.5 0.5 1 \n -depthOfFieldPreview 1\n -maxConstantTransparency 1\n -rendererName \"vp2Renderer\" \n -objectFilterShowInHUD 1\n -isFiltered 0\n -colorResolution 256 256 \n -bumpResolution 512 512 \n -textureCompression 0\n -transparencyAlgorithm \"frontAndBackCull\" \n -transpInShadows 0\n -cullingOverride \"none\" \n -lowQualityLighting 0\n -maximumNumHardwareLights 1\n -occlusionCulling 0\n -shadingModel 0\n -useBaseRenderer 0\n -useReducedRenderer 0\n -smallObjectCulling 0\n" + + " -smallObjectThreshold -1 \n -interactiveDisableShadows 0\n -interactiveBackFaceCull 0\n -sortTransparent 1\n -controllers 1\n -nurbsCurves 1\n -nurbsSurfaces 1\n -polymeshes 1\n -subdivSurfaces 1\n -planes 1\n -lights 1\n -cameras 1\n -controlVertices 1\n -hulls 1\n -grid 1\n -imagePlane 1\n -joints 1\n -ikHandles 1\n -deformers 1\n -dynamics 1\n -particleInstancers 1\n -fluids 1\n -hairSystems 1\n -follicles 1\n -nCloths 1\n -nParticles 1\n -nRigids 1\n -dynamicConstraints 1\n -locators 1\n -manipulators 1\n -pluginShapes 1\n -dimensions 1\n -handles 1\n -pivots 1\n -textures 1\n -strokes 1\n -motionTrails 1\n -clipGhosts 1\n -bluePencil 1\n" + + " -greasePencils 0\n -shadows 0\n -captureSequenceNumber -1\n -width 477\n -height 276\n -sceneRenderFilter 0\n $editorName;\n modelEditor -e -viewSelected 0 $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextPanel \"modelPanel\" (localizedPanelLabel(\"Persp View\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tmodelPanel -edit -l (localizedPanelLabel(\"Persp View\")) -mbv $menusOkayInPanels $panelName;\n\t\t$editorName = $panelName;\n modelEditor -e \n -camera \"|persp\" \n -useInteractiveMode 0\n -displayLights \"default\" \n -displayAppearance \"smoothShaded\" \n -activeOnly 0\n -ignorePanZoom 0\n -wireframeOnShaded 0\n -headsUpDisplay 1\n -holdOuts 1\n -selectionHiliteDisplay 1\n -useDefaultMaterial 0\n -bufferMode \"double\" \n" + + " -twoSidedLighting 0\n -backfaceCulling 0\n -xray 0\n -jointXray 0\n -activeComponentsXray 0\n -displayTextures 0\n -smoothWireframe 0\n -lineWidth 1\n -textureAnisotropic 0\n -textureHilight 1\n -textureSampling 2\n -textureDisplay \"modulate\" \n -textureMaxSize 32768\n -fogging 0\n -fogSource \"fragment\" \n -fogMode \"linear\" \n -fogStart 0\n -fogEnd 100\n -fogDensity 0.1\n -fogColor 0.5 0.5 0.5 1 \n -depthOfFieldPreview 1\n -maxConstantTransparency 1\n -rendererName \"vp2Renderer\" \n -objectFilterShowInHUD 1\n -isFiltered 0\n -colorResolution 256 256 \n -bumpResolution 512 512 \n -textureCompression 0\n -transparencyAlgorithm \"frontAndBackCull\" \n -transpInShadows 0\n -cullingOverride \"none\" \n -lowQualityLighting 0\n" + + " -maximumNumHardwareLights 1\n -occlusionCulling 0\n -shadingModel 0\n -useBaseRenderer 0\n -useReducedRenderer 0\n -smallObjectCulling 0\n -smallObjectThreshold -1 \n -interactiveDisableShadows 0\n -interactiveBackFaceCull 0\n -sortTransparent 1\n -controllers 1\n -nurbsCurves 1\n -nurbsSurfaces 1\n -polymeshes 1\n -subdivSurfaces 1\n -planes 1\n -lights 1\n -cameras 1\n -controlVertices 1\n -hulls 1\n -grid 1\n -imagePlane 1\n -joints 1\n -ikHandles 1\n -deformers 1\n -dynamics 1\n -particleInstancers 1\n -fluids 1\n -hairSystems 1\n -follicles 1\n -nCloths 1\n -nParticles 1\n -nRigids 1\n -dynamicConstraints 1\n -locators 1\n -manipulators 1\n -pluginShapes 1\n" + + " -dimensions 1\n -handles 1\n -pivots 1\n -textures 1\n -strokes 1\n -motionTrails 1\n -clipGhosts 1\n -bluePencil 1\n -greasePencils 0\n -shadows 0\n -captureSequenceNumber -1\n -width 476\n -height 276\n -sceneRenderFilter 0\n $editorName;\n modelEditor -e -viewSelected 0 $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextPanel \"outlinerPanel\" (localizedPanelLabel(\"ToggledOutliner\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\toutlinerPanel -edit -l (localizedPanelLabel(\"ToggledOutliner\")) -mbv $menusOkayInPanels $panelName;\n\t\t$editorName = $panelName;\n outlinerEditor -e \n -docTag \"isolOutln_fromSeln\" \n -showShapes 0\n -showAssignedMaterials 0\n -showTimeEditor 1\n -showReferenceNodes 1\n -showReferenceMembers 1\n" + + " -showAttributes 0\n -showConnected 0\n -showAnimCurvesOnly 0\n -showMuteInfo 0\n -organizeByLayer 1\n -organizeByClip 1\n -showAnimLayerWeight 1\n -autoExpandLayers 1\n -autoExpand 0\n -showDagOnly 1\n -showAssets 1\n -showContainedOnly 1\n -showPublishedAsConnected 0\n -showParentContainers 0\n -showContainerContents 1\n -ignoreDagHierarchy 0\n -expandConnections 0\n -showUpstreamCurves 1\n -showUnitlessCurves 1\n -showCompounds 1\n -showLeafs 1\n -showNumericAttrsOnly 0\n -highlightActive 1\n -autoSelectNewObjects 0\n -doNotSelectNewObjects 0\n -dropIsParent 1\n -transmitFilters 0\n -setFilter \"defaultSetFilter\" \n -showSetMembers 1\n -allowMultiSelection 1\n -alwaysToggleSelect 0\n -directSelect 0\n" + + " -isSet 0\n -isSetMember 0\n -showUfeItems 1\n -displayMode \"DAG\" \n -expandObjects 0\n -setsIgnoreFilters 1\n -containersIgnoreFilters 0\n -editAttrName 0\n -showAttrValues 0\n -highlightSecondary 0\n -showUVAttrsOnly 0\n -showTextureNodesOnly 0\n -attrAlphaOrder \"default\" \n -animLayerFilterOptions \"allAffecting\" \n -sortOrder \"none\" \n -longNames 0\n -niceNames 1\n -selectCommand \"print(\\\"\\\")\" \n -showNamespace 1\n -showPinIcons 0\n -mapMotionTrails 0\n -ignoreHiddenAttribute 0\n -ignoreOutlinerColor 0\n -renderFilterVisible 0\n -renderFilterIndex 0\n -selectionOrder \"chronological\" \n -expandAttribute 0\n $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextPanel \"outlinerPanel\" (localizedPanelLabel(\"Outliner\")) `;\n" + + "\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\toutlinerPanel -edit -l (localizedPanelLabel(\"Outliner\")) -mbv $menusOkayInPanels $panelName;\n\t\t$editorName = $panelName;\n outlinerEditor -e \n -showShapes 0\n -showAssignedMaterials 0\n -showTimeEditor 1\n -showReferenceNodes 0\n -showReferenceMembers 0\n -showAttributes 0\n -showConnected 0\n -showAnimCurvesOnly 0\n -showMuteInfo 0\n -organizeByLayer 1\n -organizeByClip 1\n -showAnimLayerWeight 1\n -autoExpandLayers 1\n -autoExpand 0\n -showDagOnly 1\n -showAssets 1\n -showContainedOnly 1\n -showPublishedAsConnected 0\n -showParentContainers 0\n -showContainerContents 1\n -ignoreDagHierarchy 0\n -expandConnections 0\n -showUpstreamCurves 1\n -showUnitlessCurves 1\n -showCompounds 1\n -showLeafs 1\n" + + " -showNumericAttrsOnly 0\n -highlightActive 1\n -autoSelectNewObjects 0\n -doNotSelectNewObjects 0\n -dropIsParent 1\n -transmitFilters 0\n -setFilter \"defaultSetFilter\" \n -showSetMembers 1\n -allowMultiSelection 1\n -alwaysToggleSelect 0\n -directSelect 0\n -showUfeItems 1\n -displayMode \"DAG\" \n -expandObjects 0\n -setsIgnoreFilters 1\n -containersIgnoreFilters 0\n -editAttrName 0\n -showAttrValues 0\n -highlightSecondary 0\n -showUVAttrsOnly 0\n -showTextureNodesOnly 0\n -attrAlphaOrder \"default\" \n -animLayerFilterOptions \"allAffecting\" \n -sortOrder \"none\" \n -longNames 0\n -niceNames 1\n -showNamespace 1\n -showPinIcons 0\n -mapMotionTrails 0\n -ignoreHiddenAttribute 0\n -ignoreOutlinerColor 0\n -renderFilterVisible 0\n" + + " $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"graphEditor\" (localizedPanelLabel(\"Graph Editor\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Graph Editor\")) -mbv $menusOkayInPanels $panelName;\n\n\t\t\t$editorName = ($panelName+\"OutlineEd\");\n outlinerEditor -e \n -showShapes 1\n -showAssignedMaterials 0\n -showTimeEditor 1\n -showReferenceNodes 0\n -showReferenceMembers 0\n -showAttributes 1\n -showConnected 1\n -showAnimCurvesOnly 1\n -showMuteInfo 0\n -organizeByLayer 1\n -organizeByClip 1\n -showAnimLayerWeight 1\n -autoExpandLayers 1\n -autoExpand 1\n -showDagOnly 0\n -showAssets 1\n -showContainedOnly 0\n" + + " -showPublishedAsConnected 0\n -showParentContainers 0\n -showContainerContents 0\n -ignoreDagHierarchy 0\n -expandConnections 1\n -showUpstreamCurves 1\n -showUnitlessCurves 1\n -showCompounds 0\n -showLeafs 1\n -showNumericAttrsOnly 1\n -highlightActive 0\n -autoSelectNewObjects 1\n -doNotSelectNewObjects 0\n -dropIsParent 1\n -transmitFilters 1\n -setFilter \"0\" \n -showSetMembers 0\n -allowMultiSelection 1\n -alwaysToggleSelect 0\n -directSelect 0\n -showUfeItems 1\n -displayMode \"DAG\" \n -expandObjects 0\n -setsIgnoreFilters 1\n -containersIgnoreFilters 0\n -editAttrName 0\n -showAttrValues 0\n -highlightSecondary 0\n -showUVAttrsOnly 0\n" + + " -showTextureNodesOnly 0\n -attrAlphaOrder \"default\" \n -animLayerFilterOptions \"allAffecting\" \n -sortOrder \"none\" \n -longNames 0\n -niceNames 1\n -showNamespace 1\n -showPinIcons 1\n -mapMotionTrails 1\n -ignoreHiddenAttribute 0\n -ignoreOutlinerColor 0\n -renderFilterVisible 0\n $editorName;\n\n\t\t\t$editorName = ($panelName+\"GraphEd\");\n animCurveEditor -e \n -displayValues 0\n -snapTime \"integer\" \n -snapValue \"none\" \n -showPlayRangeShades \"on\" \n -lockPlayRangeShades \"off\" \n -smoothness \"fine\" \n -resultSamples 1.041667\n -resultScreenSamples 0\n -resultUpdate \"delayed\" \n -showUpstreamCurves 1\n -keyMinScale 1\n -stackedCurvesMin -1\n -stackedCurvesMax 1\n" + + " -stackedCurvesSpace 0.2\n -preSelectionHighlight 0\n -constrainDrag 0\n -valueLinesToggle 1\n -highlightAffectedCurves 0\n $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"dopeSheetPanel\" (localizedPanelLabel(\"Dope Sheet\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Dope Sheet\")) -mbv $menusOkayInPanels $panelName;\n\n\t\t\t$editorName = ($panelName+\"OutlineEd\");\n outlinerEditor -e \n -showShapes 1\n -showAssignedMaterials 0\n -showTimeEditor 1\n -showReferenceNodes 0\n -showReferenceMembers 0\n -showAttributes 1\n -showConnected 1\n -showAnimCurvesOnly 1\n -showMuteInfo 0\n -organizeByLayer 1\n -organizeByClip 1\n" + + " -showAnimLayerWeight 1\n -autoExpandLayers 1\n -autoExpand 0\n -showDagOnly 0\n -showAssets 1\n -showContainedOnly 0\n -showPublishedAsConnected 0\n -showParentContainers 0\n -showContainerContents 0\n -ignoreDagHierarchy 0\n -expandConnections 1\n -showUpstreamCurves 1\n -showUnitlessCurves 0\n -showCompounds 1\n -showLeafs 1\n -showNumericAttrsOnly 1\n -highlightActive 0\n -autoSelectNewObjects 0\n -doNotSelectNewObjects 1\n -dropIsParent 1\n -transmitFilters 0\n -setFilter \"0\" \n -showSetMembers 0\n -allowMultiSelection 1\n -alwaysToggleSelect 0\n -directSelect 0\n -showUfeItems 1\n -displayMode \"DAG\" \n -expandObjects 0\n" + + " -setsIgnoreFilters 1\n -containersIgnoreFilters 0\n -editAttrName 0\n -showAttrValues 0\n -highlightSecondary 0\n -showUVAttrsOnly 0\n -showTextureNodesOnly 0\n -attrAlphaOrder \"default\" \n -animLayerFilterOptions \"allAffecting\" \n -sortOrder \"none\" \n -longNames 0\n -niceNames 1\n -showNamespace 1\n -showPinIcons 0\n -mapMotionTrails 1\n -ignoreHiddenAttribute 0\n -ignoreOutlinerColor 0\n -renderFilterVisible 0\n $editorName;\n\n\t\t\t$editorName = ($panelName+\"DopeSheetEd\");\n dopeSheetEditor -e \n -displayValues 0\n -snapTime \"integer\" \n -snapValue \"none\" \n -outliner \"dopeSheetPanel1OutlineEd\" \n -showSummary 1\n -showScene 0\n -hierarchyBelow 0\n" + + " -showTicks 1\n -selectionWindow 0 0 0 0 \n $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"timeEditorPanel\" (localizedPanelLabel(\"Time Editor\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Time Editor\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"clipEditorPanel\" (localizedPanelLabel(\"Trax Editor\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Trax Editor\")) -mbv $menusOkayInPanels $panelName;\n\n\t\t\t$editorName = clipEditorNameFromPanel($panelName);\n clipEditor -e \n -displayValues 0\n -snapTime \"none\" \n -snapValue \"none\" \n -initialized 0\n -manageSequencer 0 \n" + + " $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"sequenceEditorPanel\" (localizedPanelLabel(\"Camera Sequencer\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Camera Sequencer\")) -mbv $menusOkayInPanels $panelName;\n\n\t\t\t$editorName = sequenceEditorNameFromPanel($panelName);\n clipEditor -e \n -displayValues 0\n -snapTime \"none\" \n -snapValue \"none\" \n -initialized 0\n -manageSequencer 1 \n $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"hyperGraphPanel\" (localizedPanelLabel(\"Hypergraph Hierarchy\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Hypergraph Hierarchy\")) -mbv $menusOkayInPanels $panelName;\n" + + "\n\t\t\t$editorName = ($panelName+\"HyperGraphEd\");\n hyperGraph -e \n -graphLayoutStyle \"hierarchicalLayout\" \n -orientation \"horiz\" \n -mergeConnections 0\n -zoom 1\n -animateTransition 0\n -showRelationships 1\n -showShapes 0\n -showDeformers 0\n -showExpressions 0\n -showConstraints 0\n -showConnectionFromSelected 0\n -showConnectionToSelected 0\n -showConstraintLabels 0\n -showUnderworld 0\n -showInvisible 0\n -transitionFrames 1\n -opaqueContainers 0\n -freeform 0\n -imagePosition 0 0 \n -imageScale 1\n -imageEnabled 0\n -graphType \"DAG\" \n -heatMapDisplay 0\n -updateSelection 1\n -updateNodeAdded 1\n -useDrawOverrideColor 0\n -limitGraphTraversal -1\n" + + " -range 0 0 \n -iconSize \"smallIcons\" \n -showCachedConnections 0\n $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"hyperShadePanel\" (localizedPanelLabel(\"Hypershade\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Hypershade\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"visorPanel\" (localizedPanelLabel(\"Visor\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Visor\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"nodeEditorPanel\" (localizedPanelLabel(\"Node Editor\")) `;\n\tif ($nodeEditorPanelVisible || $nodeEditorWorkspaceControlOpen) {\n" + + "\t\tif (\"\" == $panelName) {\n\t\t\tif ($useSceneConfig) {\n\t\t\t\t$panelName = `scriptedPanel -unParent -type \"nodeEditorPanel\" -l (localizedPanelLabel(\"Node Editor\")) -mbv $menusOkayInPanels `;\n\n\t\t\t$editorName = ($panelName+\"NodeEditorEd\");\n nodeEditor -e \n -allAttributes 0\n -allNodes 0\n -autoSizeNodes 1\n -consistentNameSize 1\n -createNodeCommand \"nodeEdCreateNodeCommand\" \n -connectNodeOnCreation 0\n -connectOnDrop 0\n -copyConnectionsOnPaste 0\n -connectionStyle \"bezier\" \n -defaultPinnedState 0\n -additiveGraphingMode 1\n -connectedGraphingMode 1\n -settingsChangedCallback \"nodeEdSyncControls\" \n -traversalDepthLimit -1\n -keyPressCommand \"nodeEdKeyPressCommand\" \n -nodeTitleMode \"name\" \n -gridSnap 0\n -gridVisibility 1\n -crosshairOnEdgeDragging 0\n" + + " -popupMenuScript \"nodeEdBuildPanelMenus\" \n -showNamespace 1\n -showShapes 1\n -showSGShapes 0\n -showTransforms 1\n -useAssets 1\n -syncedSelection 1\n -extendToShapes 1\n -showUnitConversions 0\n -editorMode \"default\" \n -hasWatchpoint 0\n $editorName;\n\t\t\t}\n\t\t} else {\n\t\t\t$label = `panel -q -label $panelName`;\n\t\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Node Editor\")) -mbv $menusOkayInPanels $panelName;\n\n\t\t\t$editorName = ($panelName+\"NodeEditorEd\");\n nodeEditor -e \n -allAttributes 0\n -allNodes 0\n -autoSizeNodes 1\n -consistentNameSize 1\n -createNodeCommand \"nodeEdCreateNodeCommand\" \n -connectNodeOnCreation 0\n -connectOnDrop 0\n -copyConnectionsOnPaste 0\n -connectionStyle \"bezier\" \n -defaultPinnedState 0\n" + + " -additiveGraphingMode 1\n -connectedGraphingMode 1\n -settingsChangedCallback \"nodeEdSyncControls\" \n -traversalDepthLimit -1\n -keyPressCommand \"nodeEdKeyPressCommand\" \n -nodeTitleMode \"name\" \n -gridSnap 0\n -gridVisibility 1\n -crosshairOnEdgeDragging 0\n -popupMenuScript \"nodeEdBuildPanelMenus\" \n -showNamespace 1\n -showShapes 1\n -showSGShapes 0\n -showTransforms 1\n -useAssets 1\n -syncedSelection 1\n -extendToShapes 1\n -showUnitConversions 0\n -editorMode \"default\" \n -hasWatchpoint 0\n $editorName;\n\t\t\tif (!$useSceneConfig) {\n\t\t\t\tpanel -e -l $label $panelName;\n\t\t\t}\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"createNodePanel\" (localizedPanelLabel(\"Create Node\")) `;\n\tif (\"\" != $panelName) {\n" + + "\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Create Node\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"polyTexturePlacementPanel\" (localizedPanelLabel(\"UV Editor\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"UV Editor\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"renderWindowPanel\" (localizedPanelLabel(\"Render View\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Render View\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextPanel \"shapePanel\" (localizedPanelLabel(\"Shape Editor\")) `;\n\tif (\"\" != $panelName) {\n" + + "\t\t$label = `panel -q -label $panelName`;\n\t\tshapePanel -edit -l (localizedPanelLabel(\"Shape Editor\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextPanel \"posePanel\" (localizedPanelLabel(\"Pose Editor\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tposePanel -edit -l (localizedPanelLabel(\"Pose Editor\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"dynRelEdPanel\" (localizedPanelLabel(\"Dynamic Relationships\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Dynamic Relationships\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"relationshipPanel\" (localizedPanelLabel(\"Relationship Editor\")) `;\n" + + "\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Relationship Editor\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"referenceEditorPanel\" (localizedPanelLabel(\"Reference Editor\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Reference Editor\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"dynPaintScriptedPanelType\" (localizedPanelLabel(\"Paint Effects\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Paint Effects\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"scriptEditorPanel\" (localizedPanelLabel(\"Script Editor\")) `;\n" + + "\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Script Editor\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"profilerPanel\" (localizedPanelLabel(\"Profiler Tool\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Profiler Tool\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"contentBrowserPanel\" (localizedPanelLabel(\"Content Browser\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Content Browser\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"Stereo\" (localizedPanelLabel(\"Stereo\")) `;\n" + + "\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Stereo\")) -mbv $menusOkayInPanels $panelName;\n{ string $editorName = ($panelName+\"Editor\");\n stereoCameraView -e \n -camera \"|persp\" \n -useInteractiveMode 0\n -displayLights \"default\" \n -displayAppearance \"wireframe\" \n -activeOnly 0\n -ignorePanZoom 0\n -wireframeOnShaded 0\n -headsUpDisplay 1\n -holdOuts 1\n -selectionHiliteDisplay 1\n -useDefaultMaterial 0\n -bufferMode \"double\" \n -twoSidedLighting 1\n -backfaceCulling 0\n -xray 0\n -jointXray 0\n -activeComponentsXray 0\n -displayTextures 0\n -smoothWireframe 0\n -lineWidth 1\n -textureAnisotropic 0\n -textureHilight 1\n -textureSampling 2\n" + + " -textureDisplay \"modulate\" \n -textureMaxSize 32768\n -fogging 0\n -fogSource \"fragment\" \n -fogMode \"linear\" \n -fogStart 0\n -fogEnd 100\n -fogDensity 0.1\n -fogColor 0.5 0.5 0.5 1 \n -depthOfFieldPreview 1\n -maxConstantTransparency 1\n -objectFilterShowInHUD 1\n -isFiltered 0\n -colorResolution 4 4 \n -bumpResolution 4 4 \n -textureCompression 0\n -transparencyAlgorithm \"frontAndBackCull\" \n -transpInShadows 0\n -cullingOverride \"none\" \n -lowQualityLighting 0\n -maximumNumHardwareLights 0\n -occlusionCulling 0\n -shadingModel 0\n -useBaseRenderer 0\n -useReducedRenderer 0\n -smallObjectCulling 0\n -smallObjectThreshold -1 \n -interactiveDisableShadows 0\n" + + " -interactiveBackFaceCull 0\n -sortTransparent 1\n -controllers 1\n -nurbsCurves 1\n -nurbsSurfaces 1\n -polymeshes 1\n -subdivSurfaces 1\n -planes 1\n -lights 1\n -cameras 1\n -controlVertices 1\n -hulls 1\n -grid 1\n -imagePlane 1\n -joints 1\n -ikHandles 1\n -deformers 1\n -dynamics 1\n -particleInstancers 1\n -fluids 1\n -hairSystems 1\n -follicles 1\n -nCloths 1\n -nParticles 1\n -nRigids 1\n -dynamicConstraints 1\n -locators 1\n -manipulators 1\n -pluginShapes 1\n -dimensions 1\n -handles 1\n -pivots 1\n -textures 1\n -strokes 1\n -motionTrails 1\n" + + " -clipGhosts 1\n -bluePencil 1\n -greasePencils 0\n -shadows 0\n -captureSequenceNumber -1\n -width 0\n -height 0\n -sceneRenderFilter 0\n -displayMode \"centerEye\" \n -viewColor 0 0 0 1 \n -useCustomBackground 1\n $editorName;\n stereoCameraView -e -viewSelected 0 $editorName; };\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\tif ($useSceneConfig) {\n string $configName = `getPanel -cwl (localizedPanelLabel(\"Current Layout\"))`;\n if (\"\" != $configName) {\n\t\t\tpanelConfiguration -edit -label (localizedPanelLabel(\"Current Layout\")) \n\t\t\t\t-userCreated false\n\t\t\t\t-defaultImage \"vacantCell.xP:/\"\n\t\t\t\t-image \"\"\n\t\t\t\t-sc false\n\t\t\t\t-configString \"global string $gMainPane; paneLayout -e -cn \\\"quad\\\" -ps 1 50 50 -ps 2 50 50 -ps 3 50 50 -ps 4 50 50 $gMainPane;\"\n\t\t\t\t-removeAllPanels\n\t\t\t\t-ap false\n\t\t\t\t\t(localizedPanelLabel(\"Top View\")) \n" + + "\t\t\t\t\t\"modelPanel\"\n" + + "\t\t\t\t\t\"$panelName = `modelPanel -unParent -l (localizedPanelLabel(\\\"Top View\\\")) -mbv $menusOkayInPanels `;\\n$editorName = $panelName;\\nmodelEditor -e \\n -camera \\\"|top\\\" \\n -useInteractiveMode 0\\n -displayLights \\\"default\\\" \\n -displayAppearance \\\"smoothShaded\\\" \\n -activeOnly 0\\n -ignorePanZoom 0\\n -wireframeOnShaded 0\\n -headsUpDisplay 1\\n -holdOuts 1\\n -selectionHiliteDisplay 1\\n -useDefaultMaterial 0\\n -bufferMode \\\"double\\\" \\n -twoSidedLighting 0\\n -backfaceCulling 0\\n -xray 0\\n -jointXray 0\\n -activeComponentsXray 0\\n -displayTextures 0\\n -smoothWireframe 0\\n -lineWidth 1\\n -textureAnisotropic 0\\n -textureHilight 1\\n -textureSampling 2\\n -textureDisplay \\\"modulate\\\" \\n -textureMaxSize 32768\\n -fogging 0\\n -fogSource \\\"fragment\\\" \\n -fogMode \\\"linear\\\" \\n -fogStart 0\\n -fogEnd 100\\n -fogDensity 0.1\\n -fogColor 0.5 0.5 0.5 1 \\n -depthOfFieldPreview 1\\n -maxConstantTransparency 1\\n -rendererName \\\"vp2Renderer\\\" \\n -objectFilterShowInHUD 1\\n -isFiltered 0\\n -colorResolution 256 256 \\n -bumpResolution 512 512 \\n -textureCompression 0\\n -transparencyAlgorithm \\\"frontAndBackCull\\\" \\n -transpInShadows 0\\n -cullingOverride \\\"none\\\" \\n -lowQualityLighting 0\\n -maximumNumHardwareLights 1\\n -occlusionCulling 0\\n -shadingModel 0\\n -useBaseRenderer 0\\n -useReducedRenderer 0\\n -smallObjectCulling 0\\n -smallObjectThreshold -1 \\n -interactiveDisableShadows 0\\n -interactiveBackFaceCull 0\\n -sortTransparent 1\\n -controllers 1\\n -nurbsCurves 1\\n -nurbsSurfaces 1\\n -polymeshes 1\\n -subdivSurfaces 1\\n -planes 1\\n -lights 1\\n -cameras 1\\n -controlVertices 1\\n -hulls 1\\n -grid 1\\n -imagePlane 1\\n -joints 1\\n -ikHandles 1\\n -deformers 1\\n -dynamics 1\\n -particleInstancers 1\\n -fluids 1\\n -hairSystems 1\\n -follicles 1\\n -nCloths 1\\n -nParticles 1\\n -nRigids 1\\n -dynamicConstraints 1\\n -locators 1\\n -manipulators 1\\n -pluginShapes 1\\n -dimensions 1\\n -handles 1\\n -pivots 1\\n -textures 1\\n -strokes 1\\n -motionTrails 1\\n -clipGhosts 1\\n -bluePencil 1\\n -greasePencils 0\\n -shadows 0\\n -captureSequenceNumber -1\\n -width 477\\n -height 276\\n -sceneRenderFilter 0\\n $editorName;\\nmodelEditor -e -viewSelected 0 $editorName\"\n" + + "\t\t\t\t\t\"modelPanel -edit -l (localizedPanelLabel(\\\"Top View\\\")) -mbv $menusOkayInPanels $panelName;\\n$editorName = $panelName;\\nmodelEditor -e \\n -camera \\\"|top\\\" \\n -useInteractiveMode 0\\n -displayLights \\\"default\\\" \\n -displayAppearance \\\"smoothShaded\\\" \\n -activeOnly 0\\n -ignorePanZoom 0\\n -wireframeOnShaded 0\\n -headsUpDisplay 1\\n -holdOuts 1\\n -selectionHiliteDisplay 1\\n -useDefaultMaterial 0\\n -bufferMode \\\"double\\\" \\n -twoSidedLighting 0\\n -backfaceCulling 0\\n -xray 0\\n -jointXray 0\\n -activeComponentsXray 0\\n -displayTextures 0\\n -smoothWireframe 0\\n -lineWidth 1\\n -textureAnisotropic 0\\n -textureHilight 1\\n -textureSampling 2\\n -textureDisplay \\\"modulate\\\" \\n -textureMaxSize 32768\\n -fogging 0\\n -fogSource \\\"fragment\\\" \\n -fogMode \\\"linear\\\" \\n -fogStart 0\\n -fogEnd 100\\n -fogDensity 0.1\\n -fogColor 0.5 0.5 0.5 1 \\n -depthOfFieldPreview 1\\n -maxConstantTransparency 1\\n -rendererName \\\"vp2Renderer\\\" \\n -objectFilterShowInHUD 1\\n -isFiltered 0\\n -colorResolution 256 256 \\n -bumpResolution 512 512 \\n -textureCompression 0\\n -transparencyAlgorithm \\\"frontAndBackCull\\\" \\n -transpInShadows 0\\n -cullingOverride \\\"none\\\" \\n -lowQualityLighting 0\\n -maximumNumHardwareLights 1\\n -occlusionCulling 0\\n -shadingModel 0\\n -useBaseRenderer 0\\n -useReducedRenderer 0\\n -smallObjectCulling 0\\n -smallObjectThreshold -1 \\n -interactiveDisableShadows 0\\n -interactiveBackFaceCull 0\\n -sortTransparent 1\\n -controllers 1\\n -nurbsCurves 1\\n -nurbsSurfaces 1\\n -polymeshes 1\\n -subdivSurfaces 1\\n -planes 1\\n -lights 1\\n -cameras 1\\n -controlVertices 1\\n -hulls 1\\n -grid 1\\n -imagePlane 1\\n -joints 1\\n -ikHandles 1\\n -deformers 1\\n -dynamics 1\\n -particleInstancers 1\\n -fluids 1\\n -hairSystems 1\\n -follicles 1\\n -nCloths 1\\n -nParticles 1\\n -nRigids 1\\n -dynamicConstraints 1\\n -locators 1\\n -manipulators 1\\n -pluginShapes 1\\n -dimensions 1\\n -handles 1\\n -pivots 1\\n -textures 1\\n -strokes 1\\n -motionTrails 1\\n -clipGhosts 1\\n -bluePencil 1\\n -greasePencils 0\\n -shadows 0\\n -captureSequenceNumber -1\\n -width 477\\n -height 276\\n -sceneRenderFilter 0\\n $editorName;\\nmodelEditor -e -viewSelected 0 $editorName\"\n" + + "\t\t\t\t-ap false\n\t\t\t\t\t(localizedPanelLabel(\"Persp View\")) \n\t\t\t\t\t\"modelPanel\"\n" + + "\t\t\t\t\t\"$panelName = `modelPanel -unParent -l (localizedPanelLabel(\\\"Persp View\\\")) -mbv $menusOkayInPanels `;\\n$editorName = $panelName;\\nmodelEditor -e \\n -cam `findStartUpCamera persp` \\n -useInteractiveMode 0\\n -displayLights \\\"default\\\" \\n -displayAppearance \\\"smoothShaded\\\" \\n -activeOnly 0\\n -ignorePanZoom 0\\n -wireframeOnShaded 0\\n -headsUpDisplay 1\\n -holdOuts 1\\n -selectionHiliteDisplay 1\\n -useDefaultMaterial 0\\n -bufferMode \\\"double\\\" \\n -twoSidedLighting 0\\n -backfaceCulling 0\\n -xray 0\\n -jointXray 0\\n -activeComponentsXray 0\\n -displayTextures 0\\n -smoothWireframe 0\\n -lineWidth 1\\n -textureAnisotropic 0\\n -textureHilight 1\\n -textureSampling 2\\n -textureDisplay \\\"modulate\\\" \\n -textureMaxSize 32768\\n -fogging 0\\n -fogSource \\\"fragment\\\" \\n -fogMode \\\"linear\\\" \\n -fogStart 0\\n -fogEnd 100\\n -fogDensity 0.1\\n -fogColor 0.5 0.5 0.5 1 \\n -depthOfFieldPreview 1\\n -maxConstantTransparency 1\\n -rendererName \\\"vp2Renderer\\\" \\n -objectFilterShowInHUD 1\\n -isFiltered 0\\n -colorResolution 256 256 \\n -bumpResolution 512 512 \\n -textureCompression 0\\n -transparencyAlgorithm \\\"frontAndBackCull\\\" \\n -transpInShadows 0\\n -cullingOverride \\\"none\\\" \\n -lowQualityLighting 0\\n -maximumNumHardwareLights 1\\n -occlusionCulling 0\\n -shadingModel 0\\n -useBaseRenderer 0\\n -useReducedRenderer 0\\n -smallObjectCulling 0\\n -smallObjectThreshold -1 \\n -interactiveDisableShadows 0\\n -interactiveBackFaceCull 0\\n -sortTransparent 1\\n -controllers 1\\n -nurbsCurves 1\\n -nurbsSurfaces 1\\n -polymeshes 1\\n -subdivSurfaces 1\\n -planes 1\\n -lights 1\\n -cameras 1\\n -controlVertices 1\\n -hulls 1\\n -grid 1\\n -imagePlane 1\\n -joints 1\\n -ikHandles 1\\n -deformers 1\\n -dynamics 1\\n -particleInstancers 1\\n -fluids 1\\n -hairSystems 1\\n -follicles 1\\n -nCloths 1\\n -nParticles 1\\n -nRigids 1\\n -dynamicConstraints 1\\n -locators 1\\n -manipulators 1\\n -pluginShapes 1\\n -dimensions 1\\n -handles 1\\n -pivots 1\\n -textures 1\\n -strokes 1\\n -motionTrails 1\\n -clipGhosts 1\\n -bluePencil 1\\n -greasePencils 0\\n -shadows 0\\n -captureSequenceNumber -1\\n -width 476\\n -height 276\\n -sceneRenderFilter 0\\n $editorName;\\nmodelEditor -e -viewSelected 0 $editorName\"\n" + + "\t\t\t\t\t\"modelPanel -edit -l (localizedPanelLabel(\\\"Persp View\\\")) -mbv $menusOkayInPanels $panelName;\\n$editorName = $panelName;\\nmodelEditor -e \\n -cam `findStartUpCamera persp` \\n -useInteractiveMode 0\\n -displayLights \\\"default\\\" \\n -displayAppearance \\\"smoothShaded\\\" \\n -activeOnly 0\\n -ignorePanZoom 0\\n -wireframeOnShaded 0\\n -headsUpDisplay 1\\n -holdOuts 1\\n -selectionHiliteDisplay 1\\n -useDefaultMaterial 0\\n -bufferMode \\\"double\\\" \\n -twoSidedLighting 0\\n -backfaceCulling 0\\n -xray 0\\n -jointXray 0\\n -activeComponentsXray 0\\n -displayTextures 0\\n -smoothWireframe 0\\n -lineWidth 1\\n -textureAnisotropic 0\\n -textureHilight 1\\n -textureSampling 2\\n -textureDisplay \\\"modulate\\\" \\n -textureMaxSize 32768\\n -fogging 0\\n -fogSource \\\"fragment\\\" \\n -fogMode \\\"linear\\\" \\n -fogStart 0\\n -fogEnd 100\\n -fogDensity 0.1\\n -fogColor 0.5 0.5 0.5 1 \\n -depthOfFieldPreview 1\\n -maxConstantTransparency 1\\n -rendererName \\\"vp2Renderer\\\" \\n -objectFilterShowInHUD 1\\n -isFiltered 0\\n -colorResolution 256 256 \\n -bumpResolution 512 512 \\n -textureCompression 0\\n -transparencyAlgorithm \\\"frontAndBackCull\\\" \\n -transpInShadows 0\\n -cullingOverride \\\"none\\\" \\n -lowQualityLighting 0\\n -maximumNumHardwareLights 1\\n -occlusionCulling 0\\n -shadingModel 0\\n -useBaseRenderer 0\\n -useReducedRenderer 0\\n -smallObjectCulling 0\\n -smallObjectThreshold -1 \\n -interactiveDisableShadows 0\\n -interactiveBackFaceCull 0\\n -sortTransparent 1\\n -controllers 1\\n -nurbsCurves 1\\n -nurbsSurfaces 1\\n -polymeshes 1\\n -subdivSurfaces 1\\n -planes 1\\n -lights 1\\n -cameras 1\\n -controlVertices 1\\n -hulls 1\\n -grid 1\\n -imagePlane 1\\n -joints 1\\n -ikHandles 1\\n -deformers 1\\n -dynamics 1\\n -particleInstancers 1\\n -fluids 1\\n -hairSystems 1\\n -follicles 1\\n -nCloths 1\\n -nParticles 1\\n -nRigids 1\\n -dynamicConstraints 1\\n -locators 1\\n -manipulators 1\\n -pluginShapes 1\\n -dimensions 1\\n -handles 1\\n -pivots 1\\n -textures 1\\n -strokes 1\\n -motionTrails 1\\n -clipGhosts 1\\n -bluePencil 1\\n -greasePencils 0\\n -shadows 0\\n -captureSequenceNumber -1\\n -width 476\\n -height 276\\n -sceneRenderFilter 0\\n $editorName;\\nmodelEditor -e -viewSelected 0 $editorName\"\n" + + "\t\t\t\t-ap false\n\t\t\t\t\t(localizedPanelLabel(\"Side View\")) \n\t\t\t\t\t\"modelPanel\"\n" + + "\t\t\t\t\t\"$panelName = `modelPanel -unParent -l (localizedPanelLabel(\\\"Side View\\\")) -mbv $menusOkayInPanels `;\\n$editorName = $panelName;\\nmodelEditor -e \\n -camera \\\"|side\\\" \\n -useInteractiveMode 0\\n -displayLights \\\"default\\\" \\n -displayAppearance \\\"smoothShaded\\\" \\n -activeOnly 0\\n -ignorePanZoom 0\\n -wireframeOnShaded 0\\n -headsUpDisplay 1\\n -holdOuts 1\\n -selectionHiliteDisplay 1\\n -useDefaultMaterial 0\\n -bufferMode \\\"double\\\" \\n -twoSidedLighting 0\\n -backfaceCulling 0\\n -xray 0\\n -jointXray 0\\n -activeComponentsXray 0\\n -displayTextures 0\\n -smoothWireframe 0\\n -lineWidth 1\\n -textureAnisotropic 0\\n -textureHilight 1\\n -textureSampling 2\\n -textureDisplay \\\"modulate\\\" \\n -textureMaxSize 32768\\n -fogging 0\\n -fogSource \\\"fragment\\\" \\n -fogMode \\\"linear\\\" \\n -fogStart 0\\n -fogEnd 100\\n -fogDensity 0.1\\n -fogColor 0.5 0.5 0.5 1 \\n -depthOfFieldPreview 1\\n -maxConstantTransparency 1\\n -rendererName \\\"vp2Renderer\\\" \\n -objectFilterShowInHUD 1\\n -isFiltered 0\\n -colorResolution 256 256 \\n -bumpResolution 512 512 \\n -textureCompression 0\\n -transparencyAlgorithm \\\"frontAndBackCull\\\" \\n -transpInShadows 0\\n -cullingOverride \\\"none\\\" \\n -lowQualityLighting 0\\n -maximumNumHardwareLights 1\\n -occlusionCulling 0\\n -shadingModel 0\\n -useBaseRenderer 0\\n -useReducedRenderer 0\\n -smallObjectCulling 0\\n -smallObjectThreshold -1 \\n -interactiveDisableShadows 0\\n -interactiveBackFaceCull 0\\n -sortTransparent 1\\n -controllers 1\\n -nurbsCurves 1\\n -nurbsSurfaces 1\\n -polymeshes 1\\n -subdivSurfaces 1\\n -planes 1\\n -lights 1\\n -cameras 1\\n -controlVertices 1\\n -hulls 1\\n -grid 1\\n -imagePlane 1\\n -joints 1\\n -ikHandles 1\\n -deformers 1\\n -dynamics 1\\n -particleInstancers 1\\n -fluids 1\\n -hairSystems 1\\n -follicles 1\\n -nCloths 1\\n -nParticles 1\\n -nRigids 1\\n -dynamicConstraints 1\\n -locators 1\\n -manipulators 1\\n -pluginShapes 1\\n -dimensions 1\\n -handles 1\\n -pivots 1\\n -textures 1\\n -strokes 1\\n -motionTrails 1\\n -clipGhosts 1\\n -bluePencil 1\\n -greasePencils 0\\n -shadows 0\\n -captureSequenceNumber -1\\n -width 476\\n -height 276\\n -sceneRenderFilter 0\\n $editorName;\\nmodelEditor -e -viewSelected 0 $editorName\"\n" + + "\t\t\t\t\t\"modelPanel -edit -l (localizedPanelLabel(\\\"Side View\\\")) -mbv $menusOkayInPanels $panelName;\\n$editorName = $panelName;\\nmodelEditor -e \\n -camera \\\"|side\\\" \\n -useInteractiveMode 0\\n -displayLights \\\"default\\\" \\n -displayAppearance \\\"smoothShaded\\\" \\n -activeOnly 0\\n -ignorePanZoom 0\\n -wireframeOnShaded 0\\n -headsUpDisplay 1\\n -holdOuts 1\\n -selectionHiliteDisplay 1\\n -useDefaultMaterial 0\\n -bufferMode \\\"double\\\" \\n -twoSidedLighting 0\\n -backfaceCulling 0\\n -xray 0\\n -jointXray 0\\n -activeComponentsXray 0\\n -displayTextures 0\\n -smoothWireframe 0\\n -lineWidth 1\\n -textureAnisotropic 0\\n -textureHilight 1\\n -textureSampling 2\\n -textureDisplay \\\"modulate\\\" \\n -textureMaxSize 32768\\n -fogging 0\\n -fogSource \\\"fragment\\\" \\n -fogMode \\\"linear\\\" \\n -fogStart 0\\n -fogEnd 100\\n -fogDensity 0.1\\n -fogColor 0.5 0.5 0.5 1 \\n -depthOfFieldPreview 1\\n -maxConstantTransparency 1\\n -rendererName \\\"vp2Renderer\\\" \\n -objectFilterShowInHUD 1\\n -isFiltered 0\\n -colorResolution 256 256 \\n -bumpResolution 512 512 \\n -textureCompression 0\\n -transparencyAlgorithm \\\"frontAndBackCull\\\" \\n -transpInShadows 0\\n -cullingOverride \\\"none\\\" \\n -lowQualityLighting 0\\n -maximumNumHardwareLights 1\\n -occlusionCulling 0\\n -shadingModel 0\\n -useBaseRenderer 0\\n -useReducedRenderer 0\\n -smallObjectCulling 0\\n -smallObjectThreshold -1 \\n -interactiveDisableShadows 0\\n -interactiveBackFaceCull 0\\n -sortTransparent 1\\n -controllers 1\\n -nurbsCurves 1\\n -nurbsSurfaces 1\\n -polymeshes 1\\n -subdivSurfaces 1\\n -planes 1\\n -lights 1\\n -cameras 1\\n -controlVertices 1\\n -hulls 1\\n -grid 1\\n -imagePlane 1\\n -joints 1\\n -ikHandles 1\\n -deformers 1\\n -dynamics 1\\n -particleInstancers 1\\n -fluids 1\\n -hairSystems 1\\n -follicles 1\\n -nCloths 1\\n -nParticles 1\\n -nRigids 1\\n -dynamicConstraints 1\\n -locators 1\\n -manipulators 1\\n -pluginShapes 1\\n -dimensions 1\\n -handles 1\\n -pivots 1\\n -textures 1\\n -strokes 1\\n -motionTrails 1\\n -clipGhosts 1\\n -bluePencil 1\\n -greasePencils 0\\n -shadows 0\\n -captureSequenceNumber -1\\n -width 476\\n -height 276\\n -sceneRenderFilter 0\\n $editorName;\\nmodelEditor -e -viewSelected 0 $editorName\"\n" + + "\t\t\t\t-ap false\n\t\t\t\t\t(localizedPanelLabel(\"Front View\")) \n\t\t\t\t\t\"modelPanel\"\n" + + "\t\t\t\t\t\"$panelName = `modelPanel -unParent -l (localizedPanelLabel(\\\"Front View\\\")) -mbv $menusOkayInPanels `;\\n$editorName = $panelName;\\nmodelEditor -e \\n -cam `findStartUpCamera front` \\n -useInteractiveMode 0\\n -displayLights \\\"default\\\" \\n -displayAppearance \\\"smoothShaded\\\" \\n -activeOnly 0\\n -ignorePanZoom 0\\n -wireframeOnShaded 0\\n -headsUpDisplay 1\\n -holdOuts 1\\n -selectionHiliteDisplay 1\\n -useDefaultMaterial 0\\n -bufferMode \\\"double\\\" \\n -twoSidedLighting 0\\n -backfaceCulling 0\\n -xray 0\\n -jointXray 0\\n -activeComponentsXray 0\\n -displayTextures 0\\n -smoothWireframe 0\\n -lineWidth 1\\n -textureAnisotropic 0\\n -textureHilight 1\\n -textureSampling 2\\n -textureDisplay \\\"modulate\\\" \\n -textureMaxSize 32768\\n -fogging 0\\n -fogSource \\\"fragment\\\" \\n -fogMode \\\"linear\\\" \\n -fogStart 0\\n -fogEnd 100\\n -fogDensity 0.1\\n -fogColor 0.5 0.5 0.5 1 \\n -depthOfFieldPreview 1\\n -maxConstantTransparency 1\\n -rendererName \\\"vp2Renderer\\\" \\n -objectFilterShowInHUD 1\\n -isFiltered 0\\n -colorResolution 256 256 \\n -bumpResolution 512 512 \\n -textureCompression 0\\n -transparencyAlgorithm \\\"frontAndBackCull\\\" \\n -transpInShadows 0\\n -cullingOverride \\\"none\\\" \\n -lowQualityLighting 0\\n -maximumNumHardwareLights 1\\n -occlusionCulling 0\\n -shadingModel 0\\n -useBaseRenderer 0\\n -useReducedRenderer 0\\n -smallObjectCulling 0\\n -smallObjectThreshold -1 \\n -interactiveDisableShadows 0\\n -interactiveBackFaceCull 0\\n -sortTransparent 1\\n -controllers 1\\n -nurbsCurves 1\\n -nurbsSurfaces 1\\n -polymeshes 1\\n -subdivSurfaces 1\\n -planes 1\\n -lights 1\\n -cameras 1\\n -controlVertices 1\\n -hulls 1\\n -grid 1\\n -imagePlane 1\\n -joints 1\\n -ikHandles 1\\n -deformers 1\\n -dynamics 1\\n -particleInstancers 1\\n -fluids 1\\n -hairSystems 1\\n -follicles 1\\n -nCloths 1\\n -nParticles 1\\n -nRigids 1\\n -dynamicConstraints 1\\n -locators 1\\n -manipulators 1\\n -pluginShapes 1\\n -dimensions 1\\n -handles 1\\n -pivots 1\\n -textures 1\\n -strokes 1\\n -motionTrails 1\\n -clipGhosts 1\\n -bluePencil 1\\n -greasePencils 0\\n -shadows 0\\n -captureSequenceNumber -1\\n -width 477\\n -height 276\\n -sceneRenderFilter 0\\n $editorName;\\nmodelEditor -e -viewSelected 0 $editorName\"\n" + + "\t\t\t\t\t\"modelPanel -edit -l (localizedPanelLabel(\\\"Front View\\\")) -mbv $menusOkayInPanels $panelName;\\n$editorName = $panelName;\\nmodelEditor -e \\n -cam `findStartUpCamera front` \\n -useInteractiveMode 0\\n -displayLights \\\"default\\\" \\n -displayAppearance \\\"smoothShaded\\\" \\n -activeOnly 0\\n -ignorePanZoom 0\\n -wireframeOnShaded 0\\n -headsUpDisplay 1\\n -holdOuts 1\\n -selectionHiliteDisplay 1\\n -useDefaultMaterial 0\\n -bufferMode \\\"double\\\" \\n -twoSidedLighting 0\\n -backfaceCulling 0\\n -xray 0\\n -jointXray 0\\n -activeComponentsXray 0\\n -displayTextures 0\\n -smoothWireframe 0\\n -lineWidth 1\\n -textureAnisotropic 0\\n -textureHilight 1\\n -textureSampling 2\\n -textureDisplay \\\"modulate\\\" \\n -textureMaxSize 32768\\n -fogging 0\\n -fogSource \\\"fragment\\\" \\n -fogMode \\\"linear\\\" \\n -fogStart 0\\n -fogEnd 100\\n -fogDensity 0.1\\n -fogColor 0.5 0.5 0.5 1 \\n -depthOfFieldPreview 1\\n -maxConstantTransparency 1\\n -rendererName \\\"vp2Renderer\\\" \\n -objectFilterShowInHUD 1\\n -isFiltered 0\\n -colorResolution 256 256 \\n -bumpResolution 512 512 \\n -textureCompression 0\\n -transparencyAlgorithm \\\"frontAndBackCull\\\" \\n -transpInShadows 0\\n -cullingOverride \\\"none\\\" \\n -lowQualityLighting 0\\n -maximumNumHardwareLights 1\\n -occlusionCulling 0\\n -shadingModel 0\\n -useBaseRenderer 0\\n -useReducedRenderer 0\\n -smallObjectCulling 0\\n -smallObjectThreshold -1 \\n -interactiveDisableShadows 0\\n -interactiveBackFaceCull 0\\n -sortTransparent 1\\n -controllers 1\\n -nurbsCurves 1\\n -nurbsSurfaces 1\\n -polymeshes 1\\n -subdivSurfaces 1\\n -planes 1\\n -lights 1\\n -cameras 1\\n -controlVertices 1\\n -hulls 1\\n -grid 1\\n -imagePlane 1\\n -joints 1\\n -ikHandles 1\\n -deformers 1\\n -dynamics 1\\n -particleInstancers 1\\n -fluids 1\\n -hairSystems 1\\n -follicles 1\\n -nCloths 1\\n -nParticles 1\\n -nRigids 1\\n -dynamicConstraints 1\\n -locators 1\\n -manipulators 1\\n -pluginShapes 1\\n -dimensions 1\\n -handles 1\\n -pivots 1\\n -textures 1\\n -strokes 1\\n -motionTrails 1\\n -clipGhosts 1\\n -bluePencil 1\\n -greasePencils 0\\n -shadows 0\\n -captureSequenceNumber -1\\n -width 477\\n -height 276\\n -sceneRenderFilter 0\\n $editorName;\\nmodelEditor -e -viewSelected 0 $editorName\"\n" + "\t\t\t\t$configName;\n\n setNamedPanelLayout (localizedPanelLabel(\"Current Layout\"));\n }\n\n panelHistory -e -clear mainPanelHistory;\n sceneUIReplacement -clear;\n\t}\n\n\ngrid -spacing 5 -size 12 -divisions 5 -displayAxes yes -displayGridLines yes -displayDivisionLines yes -displayPerspectiveLabels no -displayOrthographicLabels no -displayAxesBold yes -perspectiveLabelPosition axis -orthographicLabelPosition edge;\nviewManip -drawCompass 0 -compassAngle 0 -frontParameters \"\" -homeParameters \"\" -selectionLockParameters \"\";\n}\n"); setAttr ".st" 3; createNode script -n "sceneConfigurationScriptNode"; @@ -274,6 +285,7 @@ createNode aiAOVDriver -s -n "defaultArnoldDisplayDriver"; createNode objectSet -n "workfileMain"; rename -uid "3C9B5D6F-4579-8E3B-5B7D-4C88865A1C68"; addAttr -ci true -sn "cbId" -ln "cbId" -dt "string"; + addAttr -ci true -sn "instance_id" -ln "instance_id" -dt "string"; addAttr -ci true -sn "id" -ln "id" -dt "string"; addAttr -ci true -sn "family" -ln "family" -dt "string"; addAttr -ci true -sn "subset" -ln "subset" -dt "string"; @@ -282,13 +294,14 @@ createNode objectSet -n "workfileMain"; addAttr -ci true -sn "variant" -ln "variant" -dt "string"; addAttr -ci true -sn "asset" -ln "asset" -dt "string"; addAttr -ci true -sn "task" -ln "task" -dt "string"; - addAttr -ci true -sn "instance_id" -ln "instance_id" -dt "string"; addAttr -ci true -sn "publish_attributes" -ln "publish_attributes" -dt "string"; - addAttr -ci true -sn "__creator_attributes_keys" -ln "__creator_attributes_keys" + addAttr -ci true -sn "creator_attributes" -ln "creator_attributes" -dt "string"; + addAttr -ci true -sn "__creator_attributes_keys" -ln "__creator_attributes_keys" -dt "string"; setAttr ".ihi" 0; setAttr ".hio" yes; setAttr ".cbId" -type "string" "60df31e2be2b48bd3695c056:30d256dac64c"; + setAttr ".instance_id" -type "string" "911dc92a-ad29-41e5-bbf9-733d56174fb9"; setAttr ".id" -type "string" "pyblish.avalon.instance"; setAttr ".family" -type "string" "workfile"; setAttr ".subset" -type "string" "workfileTest_task"; @@ -297,16 +310,9 @@ createNode objectSet -n "workfileMain"; setAttr ".variant" -type "string" "Main"; setAttr ".asset" -type "string" "test_asset"; setAttr ".task" -type "string" "test_task"; - setAttr ".instance_id" -type "string" "911dc92a-ad29-41e5-bbf9-733d56174fb9"; - setAttr ".publish_attributes" -type "string" "{\"ExtractImportReference\": {\"active\": false}}"; + setAttr ".publish_attributes" -type "string" "{\"ValidateInstanceInContext\": {\"active\": true}, \"ExtractImportReference\": {\"active\": false}}"; + setAttr ".creator_attributes" -type "string" "{}"; setAttr ".__creator_attributes_keys" -type "string" ""; -createNode objectSet -n "renderingMain"; - rename -uid "8A999C2F-4922-B15D-8D5C-45A16465B69F"; - addAttr -ci true -sn "pre_creator_identifier" -ln "pre_creator_identifier" -dt "string"; - addAttr -ci true -sn "cbId" -ln "cbId" -dt "string"; - setAttr ".ihi" 0; - setAttr ".pre_creator_identifier" -type "string" "io.openpype.creators.maya.renderlayer"; - setAttr ".cbId" -type "string" "60df31e2be2b48bd3695c056:042447475732"; createNode renderSetupLayer -n "Main"; rename -uid "2202E438-4CEF-F64E-737C-F48C65E31126"; addAttr -ci true -sn "es" -ln "expandedState" -min 0 -max 1 -at "bool"; @@ -321,55 +327,6 @@ createNode collection -n "defaultCollection"; createNode simpleSelector -n "defaultCollectionSelector"; rename -uid "7CA2F6D8-483C-B020-BC03-EF9563A52163"; setAttr ".pat" -type "string" "*"; -createNode objectSet -n "_renderingMain:Main"; - rename -uid "1EEC3A3B-49CF-0C79-5340-39805174FB8A"; - addAttr -s false -ci true -sn "renderlayer" -ln "renderlayer" -at "message"; - addAttr -ci true -sn "id" -ln "id" -dt "string"; - addAttr -ci true -sn "family" -ln "family" -dt "string"; - addAttr -ci true -sn "subset" -ln "subset" -dt "string"; - addAttr -ci true -sn "active" -ln "active" -min 0 -max 1 -at "bool"; - addAttr -ci true -sn "creator_identifier" -ln "creator_identifier" -dt "string"; - addAttr -ci true -sn "variant" -ln "variant" -dt "string"; - addAttr -ci true -sn "asset" -ln "asset" -dt "string"; - addAttr -ci true -sn "task" -ln "task" -dt "string"; - addAttr -ci true -sn "instance_id" -ln "instance_id" -dt "string"; - addAttr -ci true -sn "review" -ln "review" -min 0 -max 1 -at "bool"; - addAttr -ci true -sn "extendFrames" -ln "extendFrames" -min 0 -max 1 -at "bool"; - addAttr -ci true -sn "overrideExistingFrame" -ln "overrideExistingFrame" -min 0 - -max 1 -at "bool"; - addAttr -ci true -sn "tileRendering" -ln "tileRendering" -min 0 -max 1 -at "bool"; - addAttr -ci true -sn "tilesX" -ln "tilesX" -at "long"; - addAttr -ci true -sn "tilesY" -ln "tilesY" -at "long"; - addAttr -ci true -sn "convertToScanline" -ln "convertToScanline" -min 0 -max 1 -at "bool"; - addAttr -ci true -sn "useReferencedAovs" -ln "useReferencedAovs" -min 0 -max 1 -at "bool"; - addAttr -ci true -sn "renderSetupIncludeLights" -ln "renderSetupIncludeLights" -min - 0 -max 1 -at "bool"; - addAttr -ci true -sn "publish_attributes" -ln "publish_attributes" -dt "string"; - addAttr -ci true -sn "__creator_attributes_keys" -ln "__creator_attributes_keys" - -dt "string"; - addAttr -ci true -sn "cbId" -ln "cbId" -dt "string"; - setAttr ".ihi" 0; - setAttr ".id" -type "string" "pyblish.avalon.instance"; - setAttr ".family" -type "string" "renderlayer"; - setAttr ".subset" -type "string" "renderMain"; - setAttr -cb on ".active" yes; - setAttr ".creator_identifier" -type "string" "io.openpype.creators.maya.renderlayer"; - setAttr ".variant" -type "string" "Main"; - setAttr ".asset" -type "string" "test_asset"; - setAttr ".task" -type "string" "test_task"; - setAttr ".instance_id" -type "string" "8a9cfb85-9602-4e5e-a4bc-27a2986bae7f"; - setAttr -cb on ".review" yes; - setAttr -cb on ".extendFrames"; - setAttr -cb on ".overrideExistingFrame" yes; - setAttr -cb on ".tileRendering"; - setAttr -cb on ".tilesX" 2; - setAttr -cb on ".tilesY" 2; - setAttr -cb on ".convertToScanline"; - setAttr -cb on ".useReferencedAovs"; - setAttr -cb on ".renderSetupIncludeLights" yes; - setAttr ".publish_attributes" -type "string" "{\"CollectDeadlinePools\": {\"primaryPool\": \"\", \"secondaryPool\": \"\"}, \"ValidateDeadlinePools\": {\"active\": true}, \"ValidateFrameRange\": {\"active\": true}, \"ExtractImportReference\": {\"active\": false}, \"MayaSubmitDeadline\": {\"priority\": 50, \"chunkSize\": 1, \"machineList\": \"\", \"whitelist\": false, \"tile_priority\": 50, \"strict_error_checking\": true}, \"ProcessSubmittedJobOnFarm\": {\"publishJobState\": \"Active\"}}"; - setAttr ".__creator_attributes_keys" -type "string" "review,extendFrames,overrideExistingFrame,tileRendering,tilesX,tilesY,convertToScanline,useReferencedAovs,renderSetupIncludeLights"; - setAttr ".cbId" -type "string" "60df31e2be2b48bd3695c056:69960f336351"; select -ne :time1; setAttr ".o" 1001; setAttr ".unw" 1001; @@ -378,9 +335,7 @@ select -ne :hardwareRenderingGlobals; setAttr ".otfva" -type "Int32Array" 22 0 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 ; - setAttr ".dli" 1; setAttr ".fprt" yes; - setAttr ".rtfm" 1; select -ne :renderPartition; setAttr -s 2 ".st"; select -ne :renderGlobalsList1; @@ -394,7 +349,6 @@ select -ne :standardSurface1; setAttr ".b" 0.80000001192092896; setAttr ".bc" -type "float3" 1 1 1 ; setAttr ".s" 0.20000000298023224; - setAttr ".sr" 0.40000000596046448; select -ne :initialShadingGroup; setAttr -s 2 ".dsm"; setAttr ".ro" yes; @@ -439,8 +393,6 @@ select -ne :defaultColorMgtGlobals; select -ne :hardwareRenderGlobals; setAttr ".ctrs" 256; setAttr ".btrs" 512; -select -ne :ikSystem; - setAttr -s 4 ".sol"; connectAttr "rs_Main.ri" ":persp.rlio[0]"; connectAttr "rs_Main.ri" ":top.rlio[0]"; connectAttr "rs_Main.ri" ":front.rlio[0]"; @@ -463,7 +415,6 @@ connectAttr ":defaultArnoldDisplayDriver.msg" ":defaultArnoldRenderOptions.drive -na; connectAttr ":defaultArnoldFilter.msg" ":defaultArnoldRenderOptions.filt"; connectAttr ":defaultArnoldDriver.msg" ":defaultArnoldRenderOptions.drvr"; -connectAttr "_renderingMain:Main.msg" "renderingMain.dnsm" -na; connectAttr "rs_Main.msg" "Main.lrl"; connectAttr "renderSetup.lit" "Main.pls"; connectAttr "defaultCollection.msg" "Main.cl"; @@ -472,7 +423,6 @@ connectAttr "renderLayerManager.rlmi[1]" "rs_Main.rlid"; connectAttr "defaultCollectionSelector.c" "defaultCollection.sel"; connectAttr "Main.lit" "defaultCollection.pls"; connectAttr "Main.nic" "defaultCollection.pic"; -connectAttr "Main.msg" "_renderingMain:Main.renderlayer"; connectAttr "defaultRenderLayer.msg" ":defaultRenderingList1.r" -na; connectAttr "rs_Main.msg" ":defaultRenderingList1.r" -na; connectAttr "pSphere1_GEOShape1.iog" ":initialShadingGroup.dsm" -na; diff --git a/tests/integration/hosts/maya/test_publish_in_maya/input/workfile/test_project_test_asset_test_task_v001.ma b/tests/integration/hosts/maya/test_publish_in_maya/input/workfile/test_project_test_asset_test_task_v001.ma index e438d80d5f..2cc87c2f48 100644 --- a/tests/integration/hosts/maya/test_publish_in_maya/input/workfile/test_project_test_asset_test_task_v001.ma +++ b/tests/integration/hosts/maya/test_publish_in_maya/input/workfile/test_project_test_asset_test_task_v001.ma @@ -1,22 +1,22 @@ -//Maya ASCII 2022 scene -//Name: test_project_test_asset_test_task_v001.ma -//Last modified: Thu, Sep 14, 2023 06:31:00 PM +//Maya ASCII 2023 scene +//Name: test_project_test_asset_test_task_v002.ma +//Last modified: Thu, Dec 07, 2023 03:53:06 PM //Codeset: 1252 -requires maya "2022"; -requires -nodeType "polyDisc" "modelingToolkit" "0.0.0.0"; -requires "stereoCamera" "10.0"; -requires -nodeType "aiOptions" -nodeType "aiAOVDriver" -nodeType "aiAOVFilter" "mtoa" "5.2.2.1"; +requires maya "2023"; requires -nodeType "simpleSelector" -nodeType "renderSetupLayer" -nodeType "renderSetup" -nodeType "collection" "renderSetup.py" "1.0"; requires "stereoCamera" "10.0"; +requires -nodeType "aiOptions" -nodeType "aiAOVDriver" -nodeType "aiAOVFilter" "mtoa" "5.2.1.1"; +requires -nodeType "polyDisc" "modelingToolkit" "0.0.0.0"; +requires "stereoCamera" "10.0"; currentUnit -l centimeter -a degree -t pal; fileInfo "application" "maya"; -fileInfo "product" "Maya 2022"; -fileInfo "version" "2022"; -fileInfo "cutIdentifier" "202205171752-c25c06f306"; -fileInfo "osv" "Windows 10 Pro v2009 (Build: 19044)"; +fileInfo "product" "Maya 2023"; +fileInfo "version" "2023"; +fileInfo "cutIdentifier" "202211021031-847a9f9623"; +fileInfo "osv" "Windows 10 Pro v2009 (Build: 19045)"; fileInfo "license" "education"; -fileInfo "UUID" "019C7F50-40EF-1435-E27F-729F64685E67"; +fileInfo "UUID" "7A992745-4AD5-777F-5575-B4BFAC62B1D0"; fileInfo "OpenPypeContext" "eyJwdWJsaXNoX2F0dHJpYnV0ZXMiOiB7IlZhbGlkYXRlQ29udGFpbmVycyI6IHsiYWN0aXZlIjogdHJ1ZX19fQ=="; createNode transform -s -n "persp"; rename -uid "D52C935B-47C9-D868-A875-D799DD17B3A1"; @@ -142,19 +142,20 @@ createNode camera -n "perspShape1" -p "persp1"; setAttr ".hc" -type "string" "viewSet -p %camera"; setAttr ".dr" yes; createNode lightLinker -s -n "lightLinker1"; - rename -uid "6B9ADCD4-41B9-5BCC-826D-4A874A278510"; + rename -uid "09465BD3-42E5-18E4-7906-20A99BB2A6C0"; setAttr -s 2 ".lnk"; setAttr -s 2 ".slnk"; createNode shapeEditorManager -n "shapeEditorManager"; - rename -uid "5B4518C5-46C9-6921-690E-EFAF77B21A36"; + rename -uid "9F2E8009-4D69-046B-FCC4-28A8CE8F86DB"; createNode poseInterpolatorManager -n "poseInterpolatorManager"; - rename -uid "8518F293-4F06-BFF2-647A-72A099FBF025"; + rename -uid "6757AD81-40B0-A747-69C3-D9A56259571E"; createNode displayLayerManager -n "layerManager"; - rename -uid "04D880D5-4D86-0C58-CA3D-208ABE3E1E16"; + rename -uid "6F055ED5-4D91-8F85-7951-B4A13543A561"; createNode displayLayer -n "defaultLayer"; rename -uid "4A776D1B-401F-7069-1C74-A7AAE84CEE03"; + setAttr ".ufem" -type "stringArray" 0 ; createNode renderLayerManager -n "renderLayerManager"; - rename -uid "B719B8BE-46BF-12E6-BEBA-B0AD4DBDBA87"; + rename -uid "55626D2B-4FD5-61A1-7AB2-47B13F19D8AA"; setAttr -s 2 ".rlmi[1]" 1; setAttr -s 2 ".rlmi"; createNode renderLayer -n "defaultRenderLayer"; @@ -167,6 +168,7 @@ createNode polySphere -n "polySphere1"; createNode objectSet -n "modelMain"; rename -uid "A76AD4F8-4CF5-AA0D-4E98-BABEE6454CC3"; addAttr -ci true -sn "cbId" -ln "cbId" -dt "string"; + addAttr -ci true -sn "instance_id" -ln "instance_id" -dt "string"; addAttr -ci true -sn "id" -ln "id" -dt "string"; addAttr -ci true -sn "family" -ln "family" -dt "string"; addAttr -ci true -sn "subset" -ln "subset" -dt "string"; @@ -175,18 +177,19 @@ createNode objectSet -n "modelMain"; addAttr -ci true -sn "variant" -ln "variant" -dt "string"; addAttr -ci true -sn "asset" -ln "asset" -dt "string"; addAttr -ci true -sn "task" -ln "task" -dt "string"; - addAttr -ci true -sn "instance_id" -ln "instance_id" -dt "string"; addAttr -ci true -sn "writeColorSets" -ln "writeColorSets" -min 0 -max 1 -at "bool"; addAttr -ci true -sn "writeFaceSets" -ln "writeFaceSets" -min 0 -max 1 -at "bool"; - addAttr -ci true -sn "includeParentHierarchy" -ln "includeParentHierarchy" -min + addAttr -ci true -sn "includeParentHierarchy" -ln "includeParentHierarchy" -min 0 -max 1 -at "bool"; addAttr -ci true -sn "attr" -ln "attr" -dt "string"; addAttr -ci true -sn "attrPrefix" -ln "attrPrefix" -dt "string"; addAttr -ci true -sn "publish_attributes" -ln "publish_attributes" -dt "string"; - addAttr -ci true -sn "__creator_attributes_keys" -ln "__creator_attributes_keys" + addAttr -ci true -sn "creator_attributes" -ln "creator_attributes" -dt "string"; + addAttr -ci true -sn "__creator_attributes_keys" -ln "__creator_attributes_keys" -dt "string"; setAttr ".ihi" 0; setAttr ".cbId" -type "string" "60df31e2be2b48bd3695c056:7364ea6776c9"; + setAttr ".instance_id" -type "string" "6889d3db-b813-43db-96de-9ba555dc4472"; setAttr ".id" -type "string" "pyblish.avalon.instance"; setAttr ".family" -type "string" "model"; setAttr ".subset" -type "string" "modelMain"; @@ -195,59 +198,68 @@ createNode objectSet -n "modelMain"; setAttr ".variant" -type "string" "Main"; setAttr ".asset" -type "string" "test_asset"; setAttr ".task" -type "string" "test_task"; - setAttr ".instance_id" -type "string" "6889d3db-b813-43db-96de-9ba555dc4472"; setAttr -cb on ".writeColorSets"; setAttr -cb on ".writeFaceSets"; setAttr -cb on ".includeParentHierarchy"; setAttr ".attr" -type "string" ""; setAttr ".attrPrefix" -type "string" ""; - setAttr ".publish_attributes" -type "string" "{\"ValidateNodeIDsRelated\": {\"active\": true}, \"ValidateTransformNamingSuffix\": {\"active\": true}, \"ValidateColorSets\": {\"active\": true}, \"ValidateMeshArnoldAttributes\": {\"active\": true}, \"ValidateMeshHasUVs\": {\"active\": true}, \"ValidateMeshNonZeroEdgeLength\": {\"active\": true}, \"ExtractModel\": {\"active\": true}}"; + setAttr ".publish_attributes" -type "string" "{\"ValidateNodeIDsRelated\": {\"active\": true}, \"ValidateInstanceInContext\": {\"active\": true}, \"ValidateTransformNamingSuffix\": {\"active\": true}, \"ValidateColorSets\": {\"active\": true}, \"ValidateMeshHasUVs\": {\"active\": true}, \"ValidateMeshNonZeroEdgeLength\": {\"active\": true}, \"ExtractModel\": {\"active\": true}, \"ValidateMeshArnoldAttributes\": {\"active\": true}}"; + setAttr ".creator_attributes" -type "string" "{}"; setAttr ".__creator_attributes_keys" -type "string" "writeColorSets,writeFaceSets,includeParentHierarchy,attr,attrPrefix"; createNode script -n "uiConfigurationScriptNode"; rename -uid "4B7AFB53-452E-E870-63E1-CCA1DD6EAF13"; setAttr ".b" -type "string" ( "// Maya Mel UI Configuration File.\n//\n// This script is machine generated. Edit at your own risk.\n//\n//\n\nglobal string $gMainPane;\nif (`paneLayout -exists $gMainPane`) {\n\n\tglobal int $gUseScenePanelConfig;\n\tint $useSceneConfig = $gUseScenePanelConfig;\n\tint $nodeEditorPanelVisible = stringArrayContains(\"nodeEditorPanel1\", `getPanel -vis`);\n\tint $nodeEditorWorkspaceControlOpen = (`workspaceControl -exists nodeEditorPanel1Window` && `workspaceControl -q -visible nodeEditorPanel1Window`);\n\tint $menusOkayInPanels = `optionVar -q allowMenusInPanels`;\n\tint $nVisPanes = `paneLayout -q -nvp $gMainPane`;\n\tint $nPanes = 0;\n\tstring $editorName;\n\tstring $panelName;\n\tstring $itemFilterName;\n\tstring $panelConfig;\n\n\t//\n\t// get current state of the UI\n\t//\n\tsceneUIReplacement -update $gMainPane;\n\n\t$panelName = `sceneUIReplacement -getNextPanel \"modelPanel\" (localizedPanelLabel(\"Top View\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tmodelPanel -edit -l (localizedPanelLabel(\"Top View\")) -mbv $menusOkayInPanels $panelName;\n" - + "\t\t$editorName = $panelName;\n modelEditor -e \n -camera \"|top\" \n -useInteractiveMode 0\n -displayLights \"default\" \n -displayAppearance \"smoothShaded\" \n -activeOnly 0\n -ignorePanZoom 0\n -wireframeOnShaded 0\n -headsUpDisplay 1\n -holdOuts 1\n -selectionHiliteDisplay 1\n -useDefaultMaterial 0\n -bufferMode \"double\" \n -twoSidedLighting 0\n -backfaceCulling 0\n -xray 0\n -jointXray 0\n -activeComponentsXray 0\n -displayTextures 0\n -smoothWireframe 0\n -lineWidth 1\n -textureAnisotropic 0\n -textureHilight 1\n -textureSampling 2\n -textureDisplay \"modulate\" \n -textureMaxSize 16384\n -fogging 0\n -fogSource \"fragment\" \n -fogMode \"linear\" \n -fogStart 0\n -fogEnd 100\n -fogDensity 0.1\n -fogColor 0.5 0.5 0.5 1 \n" + + "\t\t$editorName = $panelName;\n modelEditor -e \n -camera \"|top\" \n -useInteractiveMode 0\n -displayLights \"default\" \n -displayAppearance \"smoothShaded\" \n -activeOnly 0\n -ignorePanZoom 0\n -wireframeOnShaded 0\n -headsUpDisplay 1\n -holdOuts 1\n -selectionHiliteDisplay 1\n -useDefaultMaterial 0\n -bufferMode \"double\" \n -twoSidedLighting 0\n -backfaceCulling 0\n -xray 0\n -jointXray 0\n -activeComponentsXray 0\n -displayTextures 0\n -smoothWireframe 0\n -lineWidth 1\n -textureAnisotropic 0\n -textureHilight 1\n -textureSampling 2\n -textureDisplay \"modulate\" \n -textureMaxSize 32768\n -fogging 0\n -fogSource \"fragment\" \n -fogMode \"linear\" \n -fogStart 0\n -fogEnd 100\n -fogDensity 0.1\n -fogColor 0.5 0.5 0.5 1 \n" + " -depthOfFieldPreview 1\n -maxConstantTransparency 1\n -rendererName \"vp2Renderer\" \n -objectFilterShowInHUD 1\n -isFiltered 0\n -colorResolution 256 256 \n -bumpResolution 512 512 \n -textureCompression 0\n -transparencyAlgorithm \"frontAndBackCull\" \n -transpInShadows 0\n -cullingOverride \"none\" \n -lowQualityLighting 0\n -maximumNumHardwareLights 1\n -occlusionCulling 0\n -shadingModel 0\n -useBaseRenderer 0\n -useReducedRenderer 0\n -smallObjectCulling 0\n -smallObjectThreshold -1 \n -interactiveDisableShadows 0\n -interactiveBackFaceCull 0\n -sortTransparent 1\n -controllers 1\n -nurbsCurves 1\n -nurbsSurfaces 1\n -polymeshes 1\n -subdivSurfaces 1\n -planes 1\n -lights 1\n -cameras 1\n -controlVertices 1\n" - + " -hulls 1\n -grid 1\n -imagePlane 1\n -joints 1\n -ikHandles 1\n -deformers 1\n -dynamics 1\n -particleInstancers 1\n -fluids 1\n -hairSystems 1\n -follicles 1\n -nCloths 1\n -nParticles 1\n -nRigids 1\n -dynamicConstraints 1\n -locators 1\n -manipulators 1\n -pluginShapes 1\n -dimensions 1\n -handles 1\n -pivots 1\n -textures 1\n -strokes 1\n -motionTrails 1\n -clipGhosts 1\n -greasePencils 1\n -shadows 0\n -captureSequenceNumber -1\n -width 1\n -height 1\n -sceneRenderFilter 0\n $editorName;\n modelEditor -e -viewSelected 0 $editorName;\n modelEditor -e \n -pluginObjects \"gpuCacheDisplayFilter\" 1 \n $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n" - + "\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextPanel \"modelPanel\" (localizedPanelLabel(\"Side View\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tmodelPanel -edit -l (localizedPanelLabel(\"Side View\")) -mbv $menusOkayInPanels $panelName;\n\t\t$editorName = $panelName;\n modelEditor -e \n -camera \"|side\" \n -useInteractiveMode 0\n -displayLights \"default\" \n -displayAppearance \"smoothShaded\" \n -activeOnly 0\n -ignorePanZoom 0\n -wireframeOnShaded 0\n -headsUpDisplay 1\n -holdOuts 1\n -selectionHiliteDisplay 1\n -useDefaultMaterial 0\n -bufferMode \"double\" \n -twoSidedLighting 0\n -backfaceCulling 0\n -xray 0\n -jointXray 0\n -activeComponentsXray 0\n -displayTextures 0\n -smoothWireframe 0\n -lineWidth 1\n -textureAnisotropic 0\n -textureHilight 1\n -textureSampling 2\n" - + " -textureDisplay \"modulate\" \n -textureMaxSize 16384\n -fogging 0\n -fogSource \"fragment\" \n -fogMode \"linear\" \n -fogStart 0\n -fogEnd 100\n -fogDensity 0.1\n -fogColor 0.5 0.5 0.5 1 \n -depthOfFieldPreview 1\n -maxConstantTransparency 1\n -rendererName \"vp2Renderer\" \n -objectFilterShowInHUD 1\n -isFiltered 0\n -colorResolution 256 256 \n -bumpResolution 512 512 \n -textureCompression 0\n -transparencyAlgorithm \"frontAndBackCull\" \n -transpInShadows 0\n -cullingOverride \"none\" \n -lowQualityLighting 0\n -maximumNumHardwareLights 1\n -occlusionCulling 0\n -shadingModel 0\n -useBaseRenderer 0\n -useReducedRenderer 0\n -smallObjectCulling 0\n -smallObjectThreshold -1 \n -interactiveDisableShadows 0\n -interactiveBackFaceCull 0\n" - + " -sortTransparent 1\n -controllers 1\n -nurbsCurves 1\n -nurbsSurfaces 1\n -polymeshes 1\n -subdivSurfaces 1\n -planes 1\n -lights 1\n -cameras 1\n -controlVertices 1\n -hulls 1\n -grid 1\n -imagePlane 1\n -joints 1\n -ikHandles 1\n -deformers 1\n -dynamics 1\n -particleInstancers 1\n -fluids 1\n -hairSystems 1\n -follicles 1\n -nCloths 1\n -nParticles 1\n -nRigids 1\n -dynamicConstraints 1\n -locators 1\n -manipulators 1\n -pluginShapes 1\n -dimensions 1\n -handles 1\n -pivots 1\n -textures 1\n -strokes 1\n -motionTrails 1\n -clipGhosts 1\n -greasePencils 1\n -shadows 0\n -captureSequenceNumber -1\n -width 1\n -height 1\n" - + " -sceneRenderFilter 0\n $editorName;\n modelEditor -e -viewSelected 0 $editorName;\n modelEditor -e \n -pluginObjects \"gpuCacheDisplayFilter\" 1 \n $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextPanel \"modelPanel\" (localizedPanelLabel(\"Front View\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tmodelPanel -edit -l (localizedPanelLabel(\"Front View\")) -mbv $menusOkayInPanels $panelName;\n\t\t$editorName = $panelName;\n modelEditor -e \n -camera \"|front\" \n -useInteractiveMode 0\n -displayLights \"default\" \n -displayAppearance \"smoothShaded\" \n -activeOnly 0\n -ignorePanZoom 0\n -wireframeOnShaded 0\n -headsUpDisplay 1\n -holdOuts 1\n -selectionHiliteDisplay 1\n -useDefaultMaterial 0\n -bufferMode \"double\" \n -twoSidedLighting 0\n -backfaceCulling 0\n" - + " -xray 0\n -jointXray 0\n -activeComponentsXray 0\n -displayTextures 0\n -smoothWireframe 0\n -lineWidth 1\n -textureAnisotropic 0\n -textureHilight 1\n -textureSampling 2\n -textureDisplay \"modulate\" \n -textureMaxSize 16384\n -fogging 0\n -fogSource \"fragment\" \n -fogMode \"linear\" \n -fogStart 0\n -fogEnd 100\n -fogDensity 0.1\n -fogColor 0.5 0.5 0.5 1 \n -depthOfFieldPreview 1\n -maxConstantTransparency 1\n -rendererName \"vp2Renderer\" \n -objectFilterShowInHUD 1\n -isFiltered 0\n -colorResolution 256 256 \n -bumpResolution 512 512 \n -textureCompression 0\n -transparencyAlgorithm \"frontAndBackCull\" \n -transpInShadows 0\n -cullingOverride \"none\" \n -lowQualityLighting 0\n -maximumNumHardwareLights 1\n -occlusionCulling 0\n" - + " -shadingModel 0\n -useBaseRenderer 0\n -useReducedRenderer 0\n -smallObjectCulling 0\n -smallObjectThreshold -1 \n -interactiveDisableShadows 0\n -interactiveBackFaceCull 0\n -sortTransparent 1\n -controllers 1\n -nurbsCurves 1\n -nurbsSurfaces 1\n -polymeshes 1\n -subdivSurfaces 1\n -planes 1\n -lights 1\n -cameras 1\n -controlVertices 1\n -hulls 1\n -grid 1\n -imagePlane 1\n -joints 1\n -ikHandles 1\n -deformers 1\n -dynamics 1\n -particleInstancers 1\n -fluids 1\n -hairSystems 1\n -follicles 1\n -nCloths 1\n -nParticles 1\n -nRigids 1\n -dynamicConstraints 1\n -locators 1\n -manipulators 1\n -pluginShapes 1\n -dimensions 1\n -handles 1\n -pivots 1\n" - + " -textures 1\n -strokes 1\n -motionTrails 1\n -clipGhosts 1\n -greasePencils 1\n -shadows 0\n -captureSequenceNumber -1\n -width 1\n -height 1\n -sceneRenderFilter 0\n $editorName;\n modelEditor -e -viewSelected 0 $editorName;\n modelEditor -e \n -pluginObjects \"gpuCacheDisplayFilter\" 1 \n $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextPanel \"modelPanel\" (localizedPanelLabel(\"Persp View\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tmodelPanel -edit -l (localizedPanelLabel(\"Persp View\")) -mbv $menusOkayInPanels $panelName;\n\t\t$editorName = $panelName;\n modelEditor -e \n -camera \"|persp\" \n -useInteractiveMode 0\n -displayLights \"default\" \n -displayAppearance \"smoothShaded\" \n -activeOnly 0\n -ignorePanZoom 0\n" - + " -wireframeOnShaded 0\n -headsUpDisplay 1\n -holdOuts 1\n -selectionHiliteDisplay 1\n -useDefaultMaterial 0\n -bufferMode \"double\" \n -twoSidedLighting 0\n -backfaceCulling 0\n -xray 0\n -jointXray 0\n -activeComponentsXray 0\n -displayTextures 0\n -smoothWireframe 0\n -lineWidth 1\n -textureAnisotropic 0\n -textureHilight 1\n -textureSampling 2\n -textureDisplay \"modulate\" \n -textureMaxSize 16384\n -fogging 0\n -fogSource \"fragment\" \n -fogMode \"linear\" \n -fogStart 0\n -fogEnd 100\n -fogDensity 0.1\n -fogColor 0.5 0.5 0.5 1 \n -depthOfFieldPreview 1\n -maxConstantTransparency 1\n -rendererName \"vp2Renderer\" \n -objectFilterShowInHUD 1\n -isFiltered 0\n -colorResolution 256 256 \n -bumpResolution 512 512 \n" - + " -textureCompression 0\n -transparencyAlgorithm \"frontAndBackCull\" \n -transpInShadows 0\n -cullingOverride \"none\" \n -lowQualityLighting 0\n -maximumNumHardwareLights 1\n -occlusionCulling 0\n -shadingModel 0\n -useBaseRenderer 0\n -useReducedRenderer 0\n -smallObjectCulling 0\n -smallObjectThreshold -1 \n -interactiveDisableShadows 0\n -interactiveBackFaceCull 0\n -sortTransparent 1\n -controllers 1\n -nurbsCurves 1\n -nurbsSurfaces 1\n -polymeshes 1\n -subdivSurfaces 1\n -planes 1\n -lights 1\n -cameras 1\n -controlVertices 1\n -hulls 1\n -grid 1\n -imagePlane 1\n -joints 1\n -ikHandles 1\n -deformers 1\n -dynamics 1\n -particleInstancers 1\n -fluids 1\n -hairSystems 1\n -follicles 1\n" - + " -nCloths 1\n -nParticles 1\n -nRigids 1\n -dynamicConstraints 1\n -locators 1\n -manipulators 1\n -pluginShapes 1\n -dimensions 1\n -handles 1\n -pivots 1\n -textures 1\n -strokes 1\n -motionTrails 1\n -clipGhosts 1\n -greasePencils 1\n -shadows 0\n -captureSequenceNumber -1\n -width 1312\n -height 732\n -sceneRenderFilter 0\n $editorName;\n modelEditor -e -viewSelected 0 $editorName;\n modelEditor -e \n -pluginObjects \"gpuCacheDisplayFilter\" 1 \n $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextPanel \"outlinerPanel\" (localizedPanelLabel(\"ToggledOutliner\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\toutlinerPanel -edit -l (localizedPanelLabel(\"ToggledOutliner\")) -mbv $menusOkayInPanels $panelName;\n" - + "\t\t$editorName = $panelName;\n outlinerEditor -e \n -docTag \"isolOutln_fromSeln\" \n -showShapes 0\n -showAssignedMaterials 0\n -showTimeEditor 1\n -showReferenceNodes 1\n -showReferenceMembers 1\n -showAttributes 0\n -showConnected 0\n -showAnimCurvesOnly 0\n -showMuteInfo 0\n -organizeByLayer 1\n -organizeByClip 1\n -showAnimLayerWeight 1\n -autoExpandLayers 1\n -autoExpand 0\n -showDagOnly 1\n -showAssets 1\n -showContainedOnly 1\n -showPublishedAsConnected 0\n -showParentContainers 0\n -showContainerContents 1\n -ignoreDagHierarchy 0\n -expandConnections 0\n -showUpstreamCurves 1\n -showUnitlessCurves 1\n -showCompounds 1\n -showLeafs 1\n -showNumericAttrsOnly 0\n -highlightActive 1\n -autoSelectNewObjects 0\n" - + " -doNotSelectNewObjects 0\n -dropIsParent 1\n -transmitFilters 0\n -setFilter \"defaultSetFilter\" \n -showSetMembers 1\n -allowMultiSelection 1\n -alwaysToggleSelect 0\n -directSelect 0\n -isSet 0\n -isSetMember 0\n -displayMode \"DAG\" \n -expandObjects 0\n -setsIgnoreFilters 1\n -containersIgnoreFilters 0\n -editAttrName 0\n -showAttrValues 0\n -highlightSecondary 0\n -showUVAttrsOnly 0\n -showTextureNodesOnly 0\n -attrAlphaOrder \"default\" \n -animLayerFilterOptions \"allAffecting\" \n -sortOrder \"none\" \n -longNames 0\n -niceNames 1\n -selectCommand \"print(\\\"\\\")\" \n -showNamespace 1\n -showPinIcons 0\n -mapMotionTrails 0\n -ignoreHiddenAttribute 1\n -ignoreOutlinerColor 0\n -renderFilterVisible 0\n -renderFilterIndex 0\n" - + " -selectionOrder \"chronological\" \n -expandAttribute 0\n $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextPanel \"outlinerPanel\" (localizedPanelLabel(\"Outliner\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\toutlinerPanel -edit -l (localizedPanelLabel(\"Outliner\")) -mbv $menusOkayInPanels $panelName;\n\t\t$editorName = $panelName;\n outlinerEditor -e \n -showShapes 0\n -showAssignedMaterials 0\n -showTimeEditor 1\n -showReferenceNodes 0\n -showReferenceMembers 0\n -showAttributes 0\n -showConnected 0\n -showAnimCurvesOnly 0\n -showMuteInfo 0\n -organizeByLayer 1\n -organizeByClip 1\n -showAnimLayerWeight 1\n -autoExpandLayers 1\n -autoExpand 0\n -showDagOnly 1\n -showAssets 1\n -showContainedOnly 1\n -showPublishedAsConnected 0\n" - + " -showParentContainers 0\n -showContainerContents 1\n -ignoreDagHierarchy 0\n -expandConnections 0\n -showUpstreamCurves 1\n -showUnitlessCurves 1\n -showCompounds 1\n -showLeafs 1\n -showNumericAttrsOnly 0\n -highlightActive 1\n -autoSelectNewObjects 0\n -doNotSelectNewObjects 0\n -dropIsParent 1\n -transmitFilters 0\n -setFilter \"defaultSetFilter\" \n -showSetMembers 1\n -allowMultiSelection 1\n -alwaysToggleSelect 0\n -directSelect 0\n -displayMode \"DAG\" \n -expandObjects 0\n -setsIgnoreFilters 1\n -containersIgnoreFilters 0\n -editAttrName 0\n -showAttrValues 0\n -highlightSecondary 0\n -showUVAttrsOnly 0\n -showTextureNodesOnly 0\n -attrAlphaOrder \"default\" \n -animLayerFilterOptions \"allAffecting\" \n -sortOrder \"none\" \n" - + " -longNames 0\n -niceNames 1\n -showNamespace 1\n -showPinIcons 0\n -mapMotionTrails 0\n -ignoreHiddenAttribute 0\n -ignoreOutlinerColor 0\n -renderFilterVisible 0\n $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"graphEditor\" (localizedPanelLabel(\"Graph Editor\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Graph Editor\")) -mbv $menusOkayInPanels $panelName;\n\n\t\t\t$editorName = ($panelName+\"OutlineEd\");\n outlinerEditor -e \n -showShapes 1\n -showAssignedMaterials 0\n -showTimeEditor 1\n -showReferenceNodes 0\n -showReferenceMembers 0\n -showAttributes 1\n -showConnected 1\n -showAnimCurvesOnly 1\n -showMuteInfo 0\n -organizeByLayer 1\n" - + " -organizeByClip 1\n -showAnimLayerWeight 1\n -autoExpandLayers 1\n -autoExpand 1\n -showDagOnly 0\n -showAssets 1\n -showContainedOnly 0\n -showPublishedAsConnected 0\n -showParentContainers 0\n -showContainerContents 0\n -ignoreDagHierarchy 0\n -expandConnections 1\n -showUpstreamCurves 1\n -showUnitlessCurves 1\n -showCompounds 0\n -showLeafs 1\n -showNumericAttrsOnly 1\n -highlightActive 0\n -autoSelectNewObjects 1\n -doNotSelectNewObjects 0\n -dropIsParent 1\n -transmitFilters 1\n -setFilter \"0\" \n -showSetMembers 0\n -allowMultiSelection 1\n -alwaysToggleSelect 0\n -directSelect 0\n -displayMode \"DAG\" \n -expandObjects 0\n" - + " -setsIgnoreFilters 1\n -containersIgnoreFilters 0\n -editAttrName 0\n -showAttrValues 0\n -highlightSecondary 0\n -showUVAttrsOnly 0\n -showTextureNodesOnly 0\n -attrAlphaOrder \"default\" \n -animLayerFilterOptions \"allAffecting\" \n -sortOrder \"none\" \n -longNames 0\n -niceNames 1\n -showNamespace 1\n -showPinIcons 1\n -mapMotionTrails 1\n -ignoreHiddenAttribute 0\n -ignoreOutlinerColor 0\n -renderFilterVisible 0\n $editorName;\n\n\t\t\t$editorName = ($panelName+\"GraphEd\");\n animCurveEditor -e \n -displayValues 0\n -snapTime \"integer\" \n -snapValue \"none\" \n -showPlayRangeShades \"on\" \n -lockPlayRangeShades \"off\" \n -smoothness \"fine\" \n -resultSamples 1.041667\n" - + " -resultScreenSamples 0\n -resultUpdate \"delayed\" \n -showUpstreamCurves 1\n -keyMinScale 1\n -stackedCurvesMin -1\n -stackedCurvesMax 1\n -stackedCurvesSpace 0.2\n -preSelectionHighlight 0\n -constrainDrag 0\n -valueLinesToggle 1\n -highlightAffectedCurves 0\n $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"dopeSheetPanel\" (localizedPanelLabel(\"Dope Sheet\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Dope Sheet\")) -mbv $menusOkayInPanels $panelName;\n\n\t\t\t$editorName = ($panelName+\"OutlineEd\");\n outlinerEditor -e \n -showShapes 1\n -showAssignedMaterials 0\n -showTimeEditor 1\n -showReferenceNodes 0\n -showReferenceMembers 0\n" - + " -showAttributes 1\n -showConnected 1\n -showAnimCurvesOnly 1\n -showMuteInfo 0\n -organizeByLayer 1\n -organizeByClip 1\n -showAnimLayerWeight 1\n -autoExpandLayers 1\n -autoExpand 0\n -showDagOnly 0\n -showAssets 1\n -showContainedOnly 0\n -showPublishedAsConnected 0\n -showParentContainers 0\n -showContainerContents 0\n -ignoreDagHierarchy 0\n -expandConnections 1\n -showUpstreamCurves 1\n -showUnitlessCurves 0\n -showCompounds 1\n -showLeafs 1\n -showNumericAttrsOnly 1\n -highlightActive 0\n -autoSelectNewObjects 0\n -doNotSelectNewObjects 1\n -dropIsParent 1\n -transmitFilters 0\n -setFilter \"0\" \n -showSetMembers 0\n" - + " -allowMultiSelection 1\n -alwaysToggleSelect 0\n -directSelect 0\n -displayMode \"DAG\" \n -expandObjects 0\n -setsIgnoreFilters 1\n -containersIgnoreFilters 0\n -editAttrName 0\n -showAttrValues 0\n -highlightSecondary 0\n -showUVAttrsOnly 0\n -showTextureNodesOnly 0\n -attrAlphaOrder \"default\" \n -animLayerFilterOptions \"allAffecting\" \n -sortOrder \"none\" \n -longNames 0\n -niceNames 1\n -showNamespace 1\n -showPinIcons 0\n -mapMotionTrails 1\n -ignoreHiddenAttribute 0\n -ignoreOutlinerColor 0\n -renderFilterVisible 0\n $editorName;\n\n\t\t\t$editorName = ($panelName+\"DopeSheetEd\");\n dopeSheetEditor -e \n -displayValues 0\n -snapTime \"integer\" \n" - + " -snapValue \"none\" \n -outliner \"dopeSheetPanel1OutlineEd\" \n -showSummary 1\n -showScene 0\n -hierarchyBelow 0\n -showTicks 1\n -selectionWindow 0 0 0 0 \n $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"timeEditorPanel\" (localizedPanelLabel(\"Time Editor\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Time Editor\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"clipEditorPanel\" (localizedPanelLabel(\"Trax Editor\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Trax Editor\")) -mbv $menusOkayInPanels $panelName;\n\n\t\t\t$editorName = clipEditorNameFromPanel($panelName);\n" - + " clipEditor -e \n -displayValues 0\n -snapTime \"none\" \n -snapValue \"none\" \n -initialized 0\n -manageSequencer 0 \n $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"sequenceEditorPanel\" (localizedPanelLabel(\"Camera Sequencer\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Camera Sequencer\")) -mbv $menusOkayInPanels $panelName;\n\n\t\t\t$editorName = sequenceEditorNameFromPanel($panelName);\n clipEditor -e \n -displayValues 0\n -snapTime \"none\" \n -snapValue \"none\" \n -initialized 0\n -manageSequencer 1 \n $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"hyperGraphPanel\" (localizedPanelLabel(\"Hypergraph Hierarchy\")) `;\n" - + "\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Hypergraph Hierarchy\")) -mbv $menusOkayInPanels $panelName;\n\n\t\t\t$editorName = ($panelName+\"HyperGraphEd\");\n hyperGraph -e \n -graphLayoutStyle \"hierarchicalLayout\" \n -orientation \"horiz\" \n -mergeConnections 0\n -zoom 1\n -animateTransition 0\n -showRelationships 1\n -showShapes 0\n -showDeformers 0\n -showExpressions 0\n -showConstraints 0\n -showConnectionFromSelected 0\n -showConnectionToSelected 0\n -showConstraintLabels 0\n -showUnderworld 0\n -showInvisible 0\n -transitionFrames 1\n -opaqueContainers 0\n -freeform 0\n -imagePosition 0 0 \n -imageScale 1\n -imageEnabled 0\n -graphType \"DAG\" \n" - + " -heatMapDisplay 0\n -updateSelection 1\n -updateNodeAdded 1\n -useDrawOverrideColor 0\n -limitGraphTraversal -1\n -range 0 0 \n -iconSize \"smallIcons\" \n -showCachedConnections 0\n $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"hyperShadePanel\" (localizedPanelLabel(\"Hypershade\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Hypershade\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"visorPanel\" (localizedPanelLabel(\"Visor\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Visor\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n" - + "\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"nodeEditorPanel\" (localizedPanelLabel(\"Node Editor\")) `;\n\tif ($nodeEditorPanelVisible || $nodeEditorWorkspaceControlOpen) {\n\t\tif (\"\" == $panelName) {\n\t\t\tif ($useSceneConfig) {\n\t\t\t\t$panelName = `scriptedPanel -unParent -type \"nodeEditorPanel\" -l (localizedPanelLabel(\"Node Editor\")) -mbv $menusOkayInPanels `;\n\n\t\t\t$editorName = ($panelName+\"NodeEditorEd\");\n nodeEditor -e \n -allAttributes 0\n -allNodes 0\n -autoSizeNodes 1\n -consistentNameSize 1\n -createNodeCommand \"nodeEdCreateNodeCommand\" \n -connectNodeOnCreation 0\n -connectOnDrop 0\n -copyConnectionsOnPaste 0\n -connectionStyle \"bezier\" \n -defaultPinnedState 0\n -additiveGraphingMode 0\n -settingsChangedCallback \"nodeEdSyncControls\" \n -traversalDepthLimit -1\n -keyPressCommand \"nodeEdKeyPressCommand\" \n" - + " -nodeTitleMode \"name\" \n -gridSnap 0\n -gridVisibility 1\n -crosshairOnEdgeDragging 0\n -popupMenuScript \"nodeEdBuildPanelMenus\" \n -showNamespace 1\n -showShapes 1\n -showSGShapes 0\n -showTransforms 1\n -useAssets 1\n -syncedSelection 1\n -extendToShapes 1\n -editorMode \"default\" \n -hasWatchpoint 0\n $editorName;\n\t\t\t}\n\t\t} else {\n\t\t\t$label = `panel -q -label $panelName`;\n\t\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Node Editor\")) -mbv $menusOkayInPanels $panelName;\n\n\t\t\t$editorName = ($panelName+\"NodeEditorEd\");\n nodeEditor -e \n -allAttributes 0\n -allNodes 0\n -autoSizeNodes 1\n -consistentNameSize 1\n -createNodeCommand \"nodeEdCreateNodeCommand\" \n -connectNodeOnCreation 0\n -connectOnDrop 0\n" - + " -copyConnectionsOnPaste 0\n -connectionStyle \"bezier\" \n -defaultPinnedState 0\n -additiveGraphingMode 0\n -settingsChangedCallback \"nodeEdSyncControls\" \n -traversalDepthLimit -1\n -keyPressCommand \"nodeEdKeyPressCommand\" \n -nodeTitleMode \"name\" \n -gridSnap 0\n -gridVisibility 1\n -crosshairOnEdgeDragging 0\n -popupMenuScript \"nodeEdBuildPanelMenus\" \n -showNamespace 1\n -showShapes 1\n -showSGShapes 0\n -showTransforms 1\n -useAssets 1\n -syncedSelection 1\n -extendToShapes 1\n -editorMode \"default\" \n -hasWatchpoint 0\n $editorName;\n\t\t\tif (!$useSceneConfig) {\n\t\t\t\tpanel -e -l $label $panelName;\n\t\t\t}\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"createNodePanel\" (localizedPanelLabel(\"Create Node\")) `;\n" - + "\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Create Node\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"polyTexturePlacementPanel\" (localizedPanelLabel(\"UV Editor\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"UV Editor\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"renderWindowPanel\" (localizedPanelLabel(\"Render View\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Render View\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextPanel \"shapePanel\" (localizedPanelLabel(\"Shape Editor\")) `;\n" - + "\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tshapePanel -edit -l (localizedPanelLabel(\"Shape Editor\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextPanel \"posePanel\" (localizedPanelLabel(\"Pose Editor\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tposePanel -edit -l (localizedPanelLabel(\"Pose Editor\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"dynRelEdPanel\" (localizedPanelLabel(\"Dynamic Relationships\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Dynamic Relationships\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"relationshipPanel\" (localizedPanelLabel(\"Relationship Editor\")) `;\n" - + "\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Relationship Editor\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"referenceEditorPanel\" (localizedPanelLabel(\"Reference Editor\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Reference Editor\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"componentEditorPanel\" (localizedPanelLabel(\"Component Editor\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Component Editor\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"dynPaintScriptedPanelType\" (localizedPanelLabel(\"Paint Effects\")) `;\n" - + "\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Paint Effects\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"scriptEditorPanel\" (localizedPanelLabel(\"Script Editor\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Script Editor\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"profilerPanel\" (localizedPanelLabel(\"Profiler Tool\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Profiler Tool\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"contentBrowserPanel\" (localizedPanelLabel(\"Content Browser\")) `;\n" - + "\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Content Browser\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"Stereo\" (localizedPanelLabel(\"Stereo\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Stereo\")) -mbv $menusOkayInPanels $panelName;\n{ string $editorName = ($panelName+\"Editor\");\n stereoCameraView -e \n -camera \"|persp\" \n -useInteractiveMode 0\n -displayLights \"default\" \n -displayAppearance \"wireframe\" \n -activeOnly 0\n -ignorePanZoom 0\n -wireframeOnShaded 0\n -headsUpDisplay 1\n -holdOuts 1\n -selectionHiliteDisplay 1\n -useDefaultMaterial 0\n -bufferMode \"double\" \n -twoSidedLighting 1\n" - + " -backfaceCulling 0\n -xray 0\n -jointXray 0\n -activeComponentsXray 0\n -displayTextures 0\n -smoothWireframe 0\n -lineWidth 1\n -textureAnisotropic 0\n -textureHilight 1\n -textureSampling 2\n -textureDisplay \"modulate\" \n -textureMaxSize 16384\n -fogging 0\n -fogSource \"fragment\" \n -fogMode \"linear\" \n -fogStart 0\n -fogEnd 100\n -fogDensity 0.1\n -fogColor 0.5 0.5 0.5 1 \n -depthOfFieldPreview 1\n -maxConstantTransparency 1\n -objectFilterShowInHUD 1\n -isFiltered 0\n -colorResolution 4 4 \n -bumpResolution 4 4 \n -textureCompression 0\n -transparencyAlgorithm \"frontAndBackCull\" \n -transpInShadows 0\n -cullingOverride \"none\" \n" - + " -lowQualityLighting 0\n -maximumNumHardwareLights 0\n -occlusionCulling 0\n -shadingModel 0\n -useBaseRenderer 0\n -useReducedRenderer 0\n -smallObjectCulling 0\n -smallObjectThreshold -1 \n -interactiveDisableShadows 0\n -interactiveBackFaceCull 0\n -sortTransparent 1\n -controllers 1\n -nurbsCurves 1\n -nurbsSurfaces 1\n -polymeshes 1\n -subdivSurfaces 1\n -planes 1\n -lights 1\n -cameras 1\n -controlVertices 1\n -hulls 1\n -grid 1\n -imagePlane 1\n -joints 1\n -ikHandles 1\n -deformers 1\n -dynamics 1\n -particleInstancers 1\n -fluids 1\n -hairSystems 1\n -follicles 1\n -nCloths 1\n" - + " -nParticles 1\n -nRigids 1\n -dynamicConstraints 1\n -locators 1\n -manipulators 1\n -pluginShapes 1\n -dimensions 1\n -handles 1\n -pivots 1\n -textures 1\n -strokes 1\n -motionTrails 1\n -clipGhosts 1\n -greasePencils 1\n -shadows 0\n -captureSequenceNumber -1\n -width 0\n -height 0\n -sceneRenderFilter 0\n -displayMode \"centerEye\" \n -viewColor 0 0 0 1 \n -useCustomBackground 1\n $editorName;\n stereoCameraView -e -viewSelected 0 $editorName;\n stereoCameraView -e \n -pluginObjects \"gpuCacheDisplayFilter\" 1 \n $editorName; };\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\tif ($useSceneConfig) {\n string $configName = `getPanel -cwl (localizedPanelLabel(\"Current Layout\"))`;\n" - + " if (\"\" != $configName) {\n\t\t\tpanelConfiguration -edit -label (localizedPanelLabel(\"Current Layout\")) \n\t\t\t\t-userCreated false\n\t\t\t\t-defaultImage \"vacantCell.xP:/\"\n\t\t\t\t-image \"\"\n\t\t\t\t-sc false\n\t\t\t\t-configString \"global string $gMainPane; paneLayout -e -cn \\\"single\\\" -ps 1 100 100 $gMainPane;\"\n\t\t\t\t-removeAllPanels\n\t\t\t\t-ap false\n\t\t\t\t\t(localizedPanelLabel(\"Persp View\")) \n\t\t\t\t\t\"modelPanel\"\n" - + "\t\t\t\t\t\"$panelName = `modelPanel -unParent -l (localizedPanelLabel(\\\"Persp View\\\")) -mbv $menusOkayInPanels `;\\n$editorName = $panelName;\\nmodelEditor -e \\n -cam `findStartUpCamera persp` \\n -useInteractiveMode 0\\n -displayLights \\\"default\\\" \\n -displayAppearance \\\"smoothShaded\\\" \\n -activeOnly 0\\n -ignorePanZoom 0\\n -wireframeOnShaded 0\\n -headsUpDisplay 1\\n -holdOuts 1\\n -selectionHiliteDisplay 1\\n -useDefaultMaterial 0\\n -bufferMode \\\"double\\\" \\n -twoSidedLighting 0\\n -backfaceCulling 0\\n -xray 0\\n -jointXray 0\\n -activeComponentsXray 0\\n -displayTextures 0\\n -smoothWireframe 0\\n -lineWidth 1\\n -textureAnisotropic 0\\n -textureHilight 1\\n -textureSampling 2\\n -textureDisplay \\\"modulate\\\" \\n -textureMaxSize 16384\\n -fogging 0\\n -fogSource \\\"fragment\\\" \\n -fogMode \\\"linear\\\" \\n -fogStart 0\\n -fogEnd 100\\n -fogDensity 0.1\\n -fogColor 0.5 0.5 0.5 1 \\n -depthOfFieldPreview 1\\n -maxConstantTransparency 1\\n -rendererName \\\"vp2Renderer\\\" \\n -objectFilterShowInHUD 1\\n -isFiltered 0\\n -colorResolution 256 256 \\n -bumpResolution 512 512 \\n -textureCompression 0\\n -transparencyAlgorithm \\\"frontAndBackCull\\\" \\n -transpInShadows 0\\n -cullingOverride \\\"none\\\" \\n -lowQualityLighting 0\\n -maximumNumHardwareLights 1\\n -occlusionCulling 0\\n -shadingModel 0\\n -useBaseRenderer 0\\n -useReducedRenderer 0\\n -smallObjectCulling 0\\n -smallObjectThreshold -1 \\n -interactiveDisableShadows 0\\n -interactiveBackFaceCull 0\\n -sortTransparent 1\\n -controllers 1\\n -nurbsCurves 1\\n -nurbsSurfaces 1\\n -polymeshes 1\\n -subdivSurfaces 1\\n -planes 1\\n -lights 1\\n -cameras 1\\n -controlVertices 1\\n -hulls 1\\n -grid 1\\n -imagePlane 1\\n -joints 1\\n -ikHandles 1\\n -deformers 1\\n -dynamics 1\\n -particleInstancers 1\\n -fluids 1\\n -hairSystems 1\\n -follicles 1\\n -nCloths 1\\n -nParticles 1\\n -nRigids 1\\n -dynamicConstraints 1\\n -locators 1\\n -manipulators 1\\n -pluginShapes 1\\n -dimensions 1\\n -handles 1\\n -pivots 1\\n -textures 1\\n -strokes 1\\n -motionTrails 1\\n -clipGhosts 1\\n -greasePencils 1\\n -shadows 0\\n -captureSequenceNumber -1\\n -width 1312\\n -height 732\\n -sceneRenderFilter 0\\n $editorName;\\nmodelEditor -e -viewSelected 0 $editorName;\\nmodelEditor -e \\n -pluginObjects \\\"gpuCacheDisplayFilter\\\" 1 \\n $editorName\"\n" - + "\t\t\t\t\t\"modelPanel -edit -l (localizedPanelLabel(\\\"Persp View\\\")) -mbv $menusOkayInPanels $panelName;\\n$editorName = $panelName;\\nmodelEditor -e \\n -cam `findStartUpCamera persp` \\n -useInteractiveMode 0\\n -displayLights \\\"default\\\" \\n -displayAppearance \\\"smoothShaded\\\" \\n -activeOnly 0\\n -ignorePanZoom 0\\n -wireframeOnShaded 0\\n -headsUpDisplay 1\\n -holdOuts 1\\n -selectionHiliteDisplay 1\\n -useDefaultMaterial 0\\n -bufferMode \\\"double\\\" \\n -twoSidedLighting 0\\n -backfaceCulling 0\\n -xray 0\\n -jointXray 0\\n -activeComponentsXray 0\\n -displayTextures 0\\n -smoothWireframe 0\\n -lineWidth 1\\n -textureAnisotropic 0\\n -textureHilight 1\\n -textureSampling 2\\n -textureDisplay \\\"modulate\\\" \\n -textureMaxSize 16384\\n -fogging 0\\n -fogSource \\\"fragment\\\" \\n -fogMode \\\"linear\\\" \\n -fogStart 0\\n -fogEnd 100\\n -fogDensity 0.1\\n -fogColor 0.5 0.5 0.5 1 \\n -depthOfFieldPreview 1\\n -maxConstantTransparency 1\\n -rendererName \\\"vp2Renderer\\\" \\n -objectFilterShowInHUD 1\\n -isFiltered 0\\n -colorResolution 256 256 \\n -bumpResolution 512 512 \\n -textureCompression 0\\n -transparencyAlgorithm \\\"frontAndBackCull\\\" \\n -transpInShadows 0\\n -cullingOverride \\\"none\\\" \\n -lowQualityLighting 0\\n -maximumNumHardwareLights 1\\n -occlusionCulling 0\\n -shadingModel 0\\n -useBaseRenderer 0\\n -useReducedRenderer 0\\n -smallObjectCulling 0\\n -smallObjectThreshold -1 \\n -interactiveDisableShadows 0\\n -interactiveBackFaceCull 0\\n -sortTransparent 1\\n -controllers 1\\n -nurbsCurves 1\\n -nurbsSurfaces 1\\n -polymeshes 1\\n -subdivSurfaces 1\\n -planes 1\\n -lights 1\\n -cameras 1\\n -controlVertices 1\\n -hulls 1\\n -grid 1\\n -imagePlane 1\\n -joints 1\\n -ikHandles 1\\n -deformers 1\\n -dynamics 1\\n -particleInstancers 1\\n -fluids 1\\n -hairSystems 1\\n -follicles 1\\n -nCloths 1\\n -nParticles 1\\n -nRigids 1\\n -dynamicConstraints 1\\n -locators 1\\n -manipulators 1\\n -pluginShapes 1\\n -dimensions 1\\n -handles 1\\n -pivots 1\\n -textures 1\\n -strokes 1\\n -motionTrails 1\\n -clipGhosts 1\\n -greasePencils 1\\n -shadows 0\\n -captureSequenceNumber -1\\n -width 1312\\n -height 732\\n -sceneRenderFilter 0\\n $editorName;\\nmodelEditor -e -viewSelected 0 $editorName;\\nmodelEditor -e \\n -pluginObjects \\\"gpuCacheDisplayFilter\\\" 1 \\n $editorName\"\n" + + " -hulls 1\n -grid 1\n -imagePlane 1\n -joints 1\n -ikHandles 1\n -deformers 1\n -dynamics 1\n -particleInstancers 1\n -fluids 1\n -hairSystems 1\n -follicles 1\n -nCloths 1\n -nParticles 1\n -nRigids 1\n -dynamicConstraints 1\n -locators 1\n -manipulators 1\n -pluginShapes 1\n -dimensions 1\n -handles 1\n -pivots 1\n -textures 1\n -strokes 1\n -motionTrails 1\n -clipGhosts 1\n -bluePencil 1\n -greasePencils 0\n -shadows 0\n -captureSequenceNumber -1\n -width 477\n -height 276\n -sceneRenderFilter 0\n $editorName;\n modelEditor -e -viewSelected 0 $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextPanel \"modelPanel\" (localizedPanelLabel(\"Side View\")) `;\n" + + "\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tmodelPanel -edit -l (localizedPanelLabel(\"Side View\")) -mbv $menusOkayInPanels $panelName;\n\t\t$editorName = $panelName;\n modelEditor -e \n -camera \"|side\" \n -useInteractiveMode 0\n -displayLights \"default\" \n -displayAppearance \"smoothShaded\" \n -activeOnly 0\n -ignorePanZoom 0\n -wireframeOnShaded 0\n -headsUpDisplay 1\n -holdOuts 1\n -selectionHiliteDisplay 1\n -useDefaultMaterial 0\n -bufferMode \"double\" \n -twoSidedLighting 0\n -backfaceCulling 0\n -xray 0\n -jointXray 0\n -activeComponentsXray 0\n -displayTextures 0\n -smoothWireframe 0\n -lineWidth 1\n -textureAnisotropic 0\n -textureHilight 1\n -textureSampling 2\n -textureDisplay \"modulate\" \n -textureMaxSize 32768\n -fogging 0\n" + + " -fogSource \"fragment\" \n -fogMode \"linear\" \n -fogStart 0\n -fogEnd 100\n -fogDensity 0.1\n -fogColor 0.5 0.5 0.5 1 \n -depthOfFieldPreview 1\n -maxConstantTransparency 1\n -rendererName \"vp2Renderer\" \n -objectFilterShowInHUD 1\n -isFiltered 0\n -colorResolution 256 256 \n -bumpResolution 512 512 \n -textureCompression 0\n -transparencyAlgorithm \"frontAndBackCull\" \n -transpInShadows 0\n -cullingOverride \"none\" \n -lowQualityLighting 0\n -maximumNumHardwareLights 1\n -occlusionCulling 0\n -shadingModel 0\n -useBaseRenderer 0\n -useReducedRenderer 0\n -smallObjectCulling 0\n -smallObjectThreshold -1 \n -interactiveDisableShadows 0\n -interactiveBackFaceCull 0\n -sortTransparent 1\n -controllers 1\n -nurbsCurves 1\n" + + " -nurbsSurfaces 1\n -polymeshes 1\n -subdivSurfaces 1\n -planes 1\n -lights 1\n -cameras 1\n -controlVertices 1\n -hulls 1\n -grid 1\n -imagePlane 1\n -joints 1\n -ikHandles 1\n -deformers 1\n -dynamics 1\n -particleInstancers 1\n -fluids 1\n -hairSystems 1\n -follicles 1\n -nCloths 1\n -nParticles 1\n -nRigids 1\n -dynamicConstraints 1\n -locators 1\n -manipulators 1\n -pluginShapes 1\n -dimensions 1\n -handles 1\n -pivots 1\n -textures 1\n -strokes 1\n -motionTrails 1\n -clipGhosts 1\n -bluePencil 1\n -greasePencils 0\n -shadows 0\n -captureSequenceNumber -1\n -width 476\n -height 276\n -sceneRenderFilter 0\n $editorName;\n" + + " modelEditor -e -viewSelected 0 $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextPanel \"modelPanel\" (localizedPanelLabel(\"Front View\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tmodelPanel -edit -l (localizedPanelLabel(\"Front View\")) -mbv $menusOkayInPanels $panelName;\n\t\t$editorName = $panelName;\n modelEditor -e \n -camera \"|front\" \n -useInteractiveMode 0\n -displayLights \"default\" \n -displayAppearance \"smoothShaded\" \n -activeOnly 0\n -ignorePanZoom 0\n -wireframeOnShaded 0\n -headsUpDisplay 1\n -holdOuts 1\n -selectionHiliteDisplay 1\n -useDefaultMaterial 0\n -bufferMode \"double\" \n -twoSidedLighting 0\n -backfaceCulling 0\n -xray 0\n -jointXray 0\n -activeComponentsXray 0\n -displayTextures 0\n -smoothWireframe 0\n" + + " -lineWidth 1\n -textureAnisotropic 0\n -textureHilight 1\n -textureSampling 2\n -textureDisplay \"modulate\" \n -textureMaxSize 32768\n -fogging 0\n -fogSource \"fragment\" \n -fogMode \"linear\" \n -fogStart 0\n -fogEnd 100\n -fogDensity 0.1\n -fogColor 0.5 0.5 0.5 1 \n -depthOfFieldPreview 1\n -maxConstantTransparency 1\n -rendererName \"vp2Renderer\" \n -objectFilterShowInHUD 1\n -isFiltered 0\n -colorResolution 256 256 \n -bumpResolution 512 512 \n -textureCompression 0\n -transparencyAlgorithm \"frontAndBackCull\" \n -transpInShadows 0\n -cullingOverride \"none\" \n -lowQualityLighting 0\n -maximumNumHardwareLights 1\n -occlusionCulling 0\n -shadingModel 0\n -useBaseRenderer 0\n -useReducedRenderer 0\n -smallObjectCulling 0\n" + + " -smallObjectThreshold -1 \n -interactiveDisableShadows 0\n -interactiveBackFaceCull 0\n -sortTransparent 1\n -controllers 1\n -nurbsCurves 1\n -nurbsSurfaces 1\n -polymeshes 1\n -subdivSurfaces 1\n -planes 1\n -lights 1\n -cameras 1\n -controlVertices 1\n -hulls 1\n -grid 1\n -imagePlane 1\n -joints 1\n -ikHandles 1\n -deformers 1\n -dynamics 1\n -particleInstancers 1\n -fluids 1\n -hairSystems 1\n -follicles 1\n -nCloths 1\n -nParticles 1\n -nRigids 1\n -dynamicConstraints 1\n -locators 1\n -manipulators 1\n -pluginShapes 1\n -dimensions 1\n -handles 1\n -pivots 1\n -textures 1\n -strokes 1\n -motionTrails 1\n -clipGhosts 1\n -bluePencil 1\n" + + " -greasePencils 0\n -shadows 0\n -captureSequenceNumber -1\n -width 477\n -height 276\n -sceneRenderFilter 0\n $editorName;\n modelEditor -e -viewSelected 0 $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextPanel \"modelPanel\" (localizedPanelLabel(\"Persp View\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tmodelPanel -edit -l (localizedPanelLabel(\"Persp View\")) -mbv $menusOkayInPanels $panelName;\n\t\t$editorName = $panelName;\n modelEditor -e \n -camera \"|persp\" \n -useInteractiveMode 0\n -displayLights \"default\" \n -displayAppearance \"smoothShaded\" \n -activeOnly 0\n -ignorePanZoom 0\n -wireframeOnShaded 0\n -headsUpDisplay 1\n -holdOuts 1\n -selectionHiliteDisplay 1\n -useDefaultMaterial 0\n -bufferMode \"double\" \n" + + " -twoSidedLighting 0\n -backfaceCulling 0\n -xray 0\n -jointXray 0\n -activeComponentsXray 0\n -displayTextures 0\n -smoothWireframe 0\n -lineWidth 1\n -textureAnisotropic 0\n -textureHilight 1\n -textureSampling 2\n -textureDisplay \"modulate\" \n -textureMaxSize 32768\n -fogging 0\n -fogSource \"fragment\" \n -fogMode \"linear\" \n -fogStart 0\n -fogEnd 100\n -fogDensity 0.1\n -fogColor 0.5 0.5 0.5 1 \n -depthOfFieldPreview 1\n -maxConstantTransparency 1\n -rendererName \"vp2Renderer\" \n -objectFilterShowInHUD 1\n -isFiltered 0\n -colorResolution 256 256 \n -bumpResolution 512 512 \n -textureCompression 0\n -transparencyAlgorithm \"frontAndBackCull\" \n -transpInShadows 0\n -cullingOverride \"none\" \n -lowQualityLighting 0\n" + + " -maximumNumHardwareLights 1\n -occlusionCulling 0\n -shadingModel 0\n -useBaseRenderer 0\n -useReducedRenderer 0\n -smallObjectCulling 0\n -smallObjectThreshold -1 \n -interactiveDisableShadows 0\n -interactiveBackFaceCull 0\n -sortTransparent 1\n -controllers 1\n -nurbsCurves 1\n -nurbsSurfaces 1\n -polymeshes 1\n -subdivSurfaces 1\n -planes 1\n -lights 1\n -cameras 1\n -controlVertices 1\n -hulls 1\n -grid 1\n -imagePlane 1\n -joints 1\n -ikHandles 1\n -deformers 1\n -dynamics 1\n -particleInstancers 1\n -fluids 1\n -hairSystems 1\n -follicles 1\n -nCloths 1\n -nParticles 1\n -nRigids 1\n -dynamicConstraints 1\n -locators 1\n -manipulators 1\n -pluginShapes 1\n" + + " -dimensions 1\n -handles 1\n -pivots 1\n -textures 1\n -strokes 1\n -motionTrails 1\n -clipGhosts 1\n -bluePencil 1\n -greasePencils 0\n -shadows 0\n -captureSequenceNumber -1\n -width 476\n -height 276\n -sceneRenderFilter 0\n $editorName;\n modelEditor -e -viewSelected 0 $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextPanel \"outlinerPanel\" (localizedPanelLabel(\"ToggledOutliner\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\toutlinerPanel -edit -l (localizedPanelLabel(\"ToggledOutliner\")) -mbv $menusOkayInPanels $panelName;\n\t\t$editorName = $panelName;\n outlinerEditor -e \n -docTag \"isolOutln_fromSeln\" \n -showShapes 0\n -showAssignedMaterials 0\n -showTimeEditor 1\n -showReferenceNodes 1\n -showReferenceMembers 1\n" + + " -showAttributes 0\n -showConnected 0\n -showAnimCurvesOnly 0\n -showMuteInfo 0\n -organizeByLayer 1\n -organizeByClip 1\n -showAnimLayerWeight 1\n -autoExpandLayers 1\n -autoExpand 0\n -showDagOnly 1\n -showAssets 1\n -showContainedOnly 1\n -showPublishedAsConnected 0\n -showParentContainers 0\n -showContainerContents 1\n -ignoreDagHierarchy 0\n -expandConnections 0\n -showUpstreamCurves 1\n -showUnitlessCurves 1\n -showCompounds 1\n -showLeafs 1\n -showNumericAttrsOnly 0\n -highlightActive 1\n -autoSelectNewObjects 0\n -doNotSelectNewObjects 0\n -dropIsParent 1\n -transmitFilters 0\n -setFilter \"defaultSetFilter\" \n -showSetMembers 1\n -allowMultiSelection 1\n -alwaysToggleSelect 0\n -directSelect 0\n" + + " -isSet 0\n -isSetMember 0\n -showUfeItems 1\n -displayMode \"DAG\" \n -expandObjects 0\n -setsIgnoreFilters 1\n -containersIgnoreFilters 0\n -editAttrName 0\n -showAttrValues 0\n -highlightSecondary 0\n -showUVAttrsOnly 0\n -showTextureNodesOnly 0\n -attrAlphaOrder \"default\" \n -animLayerFilterOptions \"allAffecting\" \n -sortOrder \"none\" \n -longNames 0\n -niceNames 1\n -selectCommand \"print(\\\"\\\")\" \n -showNamespace 1\n -showPinIcons 0\n -mapMotionTrails 0\n -ignoreHiddenAttribute 0\n -ignoreOutlinerColor 0\n -renderFilterVisible 0\n -renderFilterIndex 0\n -selectionOrder \"chronological\" \n -expandAttribute 0\n $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextPanel \"outlinerPanel\" (localizedPanelLabel(\"Outliner\")) `;\n" + + "\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\toutlinerPanel -edit -l (localizedPanelLabel(\"Outliner\")) -mbv $menusOkayInPanels $panelName;\n\t\t$editorName = $panelName;\n outlinerEditor -e \n -showShapes 0\n -showAssignedMaterials 0\n -showTimeEditor 1\n -showReferenceNodes 0\n -showReferenceMembers 0\n -showAttributes 0\n -showConnected 0\n -showAnimCurvesOnly 0\n -showMuteInfo 0\n -organizeByLayer 1\n -organizeByClip 1\n -showAnimLayerWeight 1\n -autoExpandLayers 1\n -autoExpand 0\n -showDagOnly 1\n -showAssets 1\n -showContainedOnly 1\n -showPublishedAsConnected 0\n -showParentContainers 0\n -showContainerContents 1\n -ignoreDagHierarchy 0\n -expandConnections 0\n -showUpstreamCurves 1\n -showUnitlessCurves 1\n -showCompounds 1\n -showLeafs 1\n" + + " -showNumericAttrsOnly 0\n -highlightActive 1\n -autoSelectNewObjects 0\n -doNotSelectNewObjects 0\n -dropIsParent 1\n -transmitFilters 0\n -setFilter \"defaultSetFilter\" \n -showSetMembers 1\n -allowMultiSelection 1\n -alwaysToggleSelect 0\n -directSelect 0\n -showUfeItems 1\n -displayMode \"DAG\" \n -expandObjects 0\n -setsIgnoreFilters 1\n -containersIgnoreFilters 0\n -editAttrName 0\n -showAttrValues 0\n -highlightSecondary 0\n -showUVAttrsOnly 0\n -showTextureNodesOnly 0\n -attrAlphaOrder \"default\" \n -animLayerFilterOptions \"allAffecting\" \n -sortOrder \"none\" \n -longNames 0\n -niceNames 1\n -showNamespace 1\n -showPinIcons 0\n -mapMotionTrails 0\n -ignoreHiddenAttribute 0\n -ignoreOutlinerColor 0\n -renderFilterVisible 0\n" + + " $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"graphEditor\" (localizedPanelLabel(\"Graph Editor\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Graph Editor\")) -mbv $menusOkayInPanels $panelName;\n\n\t\t\t$editorName = ($panelName+\"OutlineEd\");\n outlinerEditor -e \n -showShapes 1\n -showAssignedMaterials 0\n -showTimeEditor 1\n -showReferenceNodes 0\n -showReferenceMembers 0\n -showAttributes 1\n -showConnected 1\n -showAnimCurvesOnly 1\n -showMuteInfo 0\n -organizeByLayer 1\n -organizeByClip 1\n -showAnimLayerWeight 1\n -autoExpandLayers 1\n -autoExpand 1\n -showDagOnly 0\n -showAssets 1\n -showContainedOnly 0\n" + + " -showPublishedAsConnected 0\n -showParentContainers 0\n -showContainerContents 0\n -ignoreDagHierarchy 0\n -expandConnections 1\n -showUpstreamCurves 1\n -showUnitlessCurves 1\n -showCompounds 0\n -showLeafs 1\n -showNumericAttrsOnly 1\n -highlightActive 0\n -autoSelectNewObjects 1\n -doNotSelectNewObjects 0\n -dropIsParent 1\n -transmitFilters 1\n -setFilter \"0\" \n -showSetMembers 0\n -allowMultiSelection 1\n -alwaysToggleSelect 0\n -directSelect 0\n -showUfeItems 1\n -displayMode \"DAG\" \n -expandObjects 0\n -setsIgnoreFilters 1\n -containersIgnoreFilters 0\n -editAttrName 0\n -showAttrValues 0\n -highlightSecondary 0\n -showUVAttrsOnly 0\n" + + " -showTextureNodesOnly 0\n -attrAlphaOrder \"default\" \n -animLayerFilterOptions \"allAffecting\" \n -sortOrder \"none\" \n -longNames 0\n -niceNames 1\n -showNamespace 1\n -showPinIcons 1\n -mapMotionTrails 1\n -ignoreHiddenAttribute 0\n -ignoreOutlinerColor 0\n -renderFilterVisible 0\n $editorName;\n\n\t\t\t$editorName = ($panelName+\"GraphEd\");\n animCurveEditor -e \n -displayValues 0\n -snapTime \"integer\" \n -snapValue \"none\" \n -showPlayRangeShades \"on\" \n -lockPlayRangeShades \"off\" \n -smoothness \"fine\" \n -resultSamples 1.041667\n -resultScreenSamples 0\n -resultUpdate \"delayed\" \n -showUpstreamCurves 1\n -keyMinScale 1\n -stackedCurvesMin -1\n -stackedCurvesMax 1\n" + + " -stackedCurvesSpace 0.2\n -preSelectionHighlight 0\n -constrainDrag 0\n -valueLinesToggle 1\n -highlightAffectedCurves 0\n $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"dopeSheetPanel\" (localizedPanelLabel(\"Dope Sheet\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Dope Sheet\")) -mbv $menusOkayInPanels $panelName;\n\n\t\t\t$editorName = ($panelName+\"OutlineEd\");\n outlinerEditor -e \n -showShapes 1\n -showAssignedMaterials 0\n -showTimeEditor 1\n -showReferenceNodes 0\n -showReferenceMembers 0\n -showAttributes 1\n -showConnected 1\n -showAnimCurvesOnly 1\n -showMuteInfo 0\n -organizeByLayer 1\n -organizeByClip 1\n" + + " -showAnimLayerWeight 1\n -autoExpandLayers 1\n -autoExpand 0\n -showDagOnly 0\n -showAssets 1\n -showContainedOnly 0\n -showPublishedAsConnected 0\n -showParentContainers 0\n -showContainerContents 0\n -ignoreDagHierarchy 0\n -expandConnections 1\n -showUpstreamCurves 1\n -showUnitlessCurves 0\n -showCompounds 1\n -showLeafs 1\n -showNumericAttrsOnly 1\n -highlightActive 0\n -autoSelectNewObjects 0\n -doNotSelectNewObjects 1\n -dropIsParent 1\n -transmitFilters 0\n -setFilter \"0\" \n -showSetMembers 0\n -allowMultiSelection 1\n -alwaysToggleSelect 0\n -directSelect 0\n -showUfeItems 1\n -displayMode \"DAG\" \n -expandObjects 0\n" + + " -setsIgnoreFilters 1\n -containersIgnoreFilters 0\n -editAttrName 0\n -showAttrValues 0\n -highlightSecondary 0\n -showUVAttrsOnly 0\n -showTextureNodesOnly 0\n -attrAlphaOrder \"default\" \n -animLayerFilterOptions \"allAffecting\" \n -sortOrder \"none\" \n -longNames 0\n -niceNames 1\n -showNamespace 1\n -showPinIcons 0\n -mapMotionTrails 1\n -ignoreHiddenAttribute 0\n -ignoreOutlinerColor 0\n -renderFilterVisible 0\n $editorName;\n\n\t\t\t$editorName = ($panelName+\"DopeSheetEd\");\n dopeSheetEditor -e \n -displayValues 0\n -snapTime \"integer\" \n -snapValue \"none\" \n -outliner \"dopeSheetPanel1OutlineEd\" \n -showSummary 1\n -showScene 0\n -hierarchyBelow 0\n" + + " -showTicks 1\n -selectionWindow 0 0 0 0 \n $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"timeEditorPanel\" (localizedPanelLabel(\"Time Editor\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Time Editor\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"clipEditorPanel\" (localizedPanelLabel(\"Trax Editor\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Trax Editor\")) -mbv $menusOkayInPanels $panelName;\n\n\t\t\t$editorName = clipEditorNameFromPanel($panelName);\n clipEditor -e \n -displayValues 0\n -snapTime \"none\" \n -snapValue \"none\" \n -initialized 0\n -manageSequencer 0 \n" + + " $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"sequenceEditorPanel\" (localizedPanelLabel(\"Camera Sequencer\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Camera Sequencer\")) -mbv $menusOkayInPanels $panelName;\n\n\t\t\t$editorName = sequenceEditorNameFromPanel($panelName);\n clipEditor -e \n -displayValues 0\n -snapTime \"none\" \n -snapValue \"none\" \n -initialized 0\n -manageSequencer 1 \n $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"hyperGraphPanel\" (localizedPanelLabel(\"Hypergraph Hierarchy\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Hypergraph Hierarchy\")) -mbv $menusOkayInPanels $panelName;\n" + + "\n\t\t\t$editorName = ($panelName+\"HyperGraphEd\");\n hyperGraph -e \n -graphLayoutStyle \"hierarchicalLayout\" \n -orientation \"horiz\" \n -mergeConnections 0\n -zoom 1\n -animateTransition 0\n -showRelationships 1\n -showShapes 0\n -showDeformers 0\n -showExpressions 0\n -showConstraints 0\n -showConnectionFromSelected 0\n -showConnectionToSelected 0\n -showConstraintLabels 0\n -showUnderworld 0\n -showInvisible 0\n -transitionFrames 1\n -opaqueContainers 0\n -freeform 0\n -imagePosition 0 0 \n -imageScale 1\n -imageEnabled 0\n -graphType \"DAG\" \n -heatMapDisplay 0\n -updateSelection 1\n -updateNodeAdded 1\n -useDrawOverrideColor 0\n -limitGraphTraversal -1\n" + + " -range 0 0 \n -iconSize \"smallIcons\" \n -showCachedConnections 0\n $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"hyperShadePanel\" (localizedPanelLabel(\"Hypershade\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Hypershade\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"visorPanel\" (localizedPanelLabel(\"Visor\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Visor\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"nodeEditorPanel\" (localizedPanelLabel(\"Node Editor\")) `;\n\tif ($nodeEditorPanelVisible || $nodeEditorWorkspaceControlOpen) {\n" + + "\t\tif (\"\" == $panelName) {\n\t\t\tif ($useSceneConfig) {\n\t\t\t\t$panelName = `scriptedPanel -unParent -type \"nodeEditorPanel\" -l (localizedPanelLabel(\"Node Editor\")) -mbv $menusOkayInPanels `;\n\n\t\t\t$editorName = ($panelName+\"NodeEditorEd\");\n nodeEditor -e \n -allAttributes 0\n -allNodes 0\n -autoSizeNodes 1\n -consistentNameSize 1\n -createNodeCommand \"nodeEdCreateNodeCommand\" \n -connectNodeOnCreation 0\n -connectOnDrop 0\n -copyConnectionsOnPaste 0\n -connectionStyle \"bezier\" \n -defaultPinnedState 0\n -additiveGraphingMode 1\n -connectedGraphingMode 1\n -settingsChangedCallback \"nodeEdSyncControls\" \n -traversalDepthLimit -1\n -keyPressCommand \"nodeEdKeyPressCommand\" \n -nodeTitleMode \"name\" \n -gridSnap 0\n -gridVisibility 1\n -crosshairOnEdgeDragging 0\n" + + " -popupMenuScript \"nodeEdBuildPanelMenus\" \n -showNamespace 1\n -showShapes 1\n -showSGShapes 0\n -showTransforms 1\n -useAssets 1\n -syncedSelection 1\n -extendToShapes 1\n -showUnitConversions 0\n -editorMode \"default\" \n -hasWatchpoint 0\n $editorName;\n\t\t\t}\n\t\t} else {\n\t\t\t$label = `panel -q -label $panelName`;\n\t\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Node Editor\")) -mbv $menusOkayInPanels $panelName;\n\n\t\t\t$editorName = ($panelName+\"NodeEditorEd\");\n nodeEditor -e \n -allAttributes 0\n -allNodes 0\n -autoSizeNodes 1\n -consistentNameSize 1\n -createNodeCommand \"nodeEdCreateNodeCommand\" \n -connectNodeOnCreation 0\n -connectOnDrop 0\n -copyConnectionsOnPaste 0\n -connectionStyle \"bezier\" \n -defaultPinnedState 0\n" + + " -additiveGraphingMode 1\n -connectedGraphingMode 1\n -settingsChangedCallback \"nodeEdSyncControls\" \n -traversalDepthLimit -1\n -keyPressCommand \"nodeEdKeyPressCommand\" \n -nodeTitleMode \"name\" \n -gridSnap 0\n -gridVisibility 1\n -crosshairOnEdgeDragging 0\n -popupMenuScript \"nodeEdBuildPanelMenus\" \n -showNamespace 1\n -showShapes 1\n -showSGShapes 0\n -showTransforms 1\n -useAssets 1\n -syncedSelection 1\n -extendToShapes 1\n -showUnitConversions 0\n -editorMode \"default\" \n -hasWatchpoint 0\n $editorName;\n\t\t\tif (!$useSceneConfig) {\n\t\t\t\tpanel -e -l $label $panelName;\n\t\t\t}\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"createNodePanel\" (localizedPanelLabel(\"Create Node\")) `;\n\tif (\"\" != $panelName) {\n" + + "\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Create Node\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"polyTexturePlacementPanel\" (localizedPanelLabel(\"UV Editor\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"UV Editor\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"renderWindowPanel\" (localizedPanelLabel(\"Render View\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Render View\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextPanel \"shapePanel\" (localizedPanelLabel(\"Shape Editor\")) `;\n\tif (\"\" != $panelName) {\n" + + "\t\t$label = `panel -q -label $panelName`;\n\t\tshapePanel -edit -l (localizedPanelLabel(\"Shape Editor\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextPanel \"posePanel\" (localizedPanelLabel(\"Pose Editor\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tposePanel -edit -l (localizedPanelLabel(\"Pose Editor\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"dynRelEdPanel\" (localizedPanelLabel(\"Dynamic Relationships\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Dynamic Relationships\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"relationshipPanel\" (localizedPanelLabel(\"Relationship Editor\")) `;\n" + + "\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Relationship Editor\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"referenceEditorPanel\" (localizedPanelLabel(\"Reference Editor\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Reference Editor\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"dynPaintScriptedPanelType\" (localizedPanelLabel(\"Paint Effects\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Paint Effects\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"scriptEditorPanel\" (localizedPanelLabel(\"Script Editor\")) `;\n" + + "\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Script Editor\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"profilerPanel\" (localizedPanelLabel(\"Profiler Tool\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Profiler Tool\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"contentBrowserPanel\" (localizedPanelLabel(\"Content Browser\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Content Browser\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"Stereo\" (localizedPanelLabel(\"Stereo\")) `;\n" + + "\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Stereo\")) -mbv $menusOkayInPanels $panelName;\n{ string $editorName = ($panelName+\"Editor\");\n stereoCameraView -e \n -camera \"|persp\" \n -useInteractiveMode 0\n -displayLights \"default\" \n -displayAppearance \"wireframe\" \n -activeOnly 0\n -ignorePanZoom 0\n -wireframeOnShaded 0\n -headsUpDisplay 1\n -holdOuts 1\n -selectionHiliteDisplay 1\n -useDefaultMaterial 0\n -bufferMode \"double\" \n -twoSidedLighting 1\n -backfaceCulling 0\n -xray 0\n -jointXray 0\n -activeComponentsXray 0\n -displayTextures 0\n -smoothWireframe 0\n -lineWidth 1\n -textureAnisotropic 0\n -textureHilight 1\n -textureSampling 2\n" + + " -textureDisplay \"modulate\" \n -textureMaxSize 32768\n -fogging 0\n -fogSource \"fragment\" \n -fogMode \"linear\" \n -fogStart 0\n -fogEnd 100\n -fogDensity 0.1\n -fogColor 0.5 0.5 0.5 1 \n -depthOfFieldPreview 1\n -maxConstantTransparency 1\n -objectFilterShowInHUD 1\n -isFiltered 0\n -colorResolution 4 4 \n -bumpResolution 4 4 \n -textureCompression 0\n -transparencyAlgorithm \"frontAndBackCull\" \n -transpInShadows 0\n -cullingOverride \"none\" \n -lowQualityLighting 0\n -maximumNumHardwareLights 0\n -occlusionCulling 0\n -shadingModel 0\n -useBaseRenderer 0\n -useReducedRenderer 0\n -smallObjectCulling 0\n -smallObjectThreshold -1 \n -interactiveDisableShadows 0\n" + + " -interactiveBackFaceCull 0\n -sortTransparent 1\n -controllers 1\n -nurbsCurves 1\n -nurbsSurfaces 1\n -polymeshes 1\n -subdivSurfaces 1\n -planes 1\n -lights 1\n -cameras 1\n -controlVertices 1\n -hulls 1\n -grid 1\n -imagePlane 1\n -joints 1\n -ikHandles 1\n -deformers 1\n -dynamics 1\n -particleInstancers 1\n -fluids 1\n -hairSystems 1\n -follicles 1\n -nCloths 1\n -nParticles 1\n -nRigids 1\n -dynamicConstraints 1\n -locators 1\n -manipulators 1\n -pluginShapes 1\n -dimensions 1\n -handles 1\n -pivots 1\n -textures 1\n -strokes 1\n -motionTrails 1\n" + + " -clipGhosts 1\n -bluePencil 1\n -greasePencils 0\n -shadows 0\n -captureSequenceNumber -1\n -width 0\n -height 0\n -sceneRenderFilter 0\n -displayMode \"centerEye\" \n -viewColor 0 0 0 1 \n -useCustomBackground 1\n $editorName;\n stereoCameraView -e -viewSelected 0 $editorName; };\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\tif ($useSceneConfig) {\n string $configName = `getPanel -cwl (localizedPanelLabel(\"Current Layout\"))`;\n if (\"\" != $configName) {\n\t\t\tpanelConfiguration -edit -label (localizedPanelLabel(\"Current Layout\")) \n\t\t\t\t-userCreated false\n\t\t\t\t-defaultImage \"vacantCell.xP:/\"\n\t\t\t\t-image \"\"\n\t\t\t\t-sc false\n\t\t\t\t-configString \"global string $gMainPane; paneLayout -e -cn \\\"quad\\\" -ps 1 50 50 -ps 2 50 50 -ps 3 50 50 -ps 4 50 50 $gMainPane;\"\n\t\t\t\t-removeAllPanels\n\t\t\t\t-ap false\n\t\t\t\t\t(localizedPanelLabel(\"Top View\")) \n" + + "\t\t\t\t\t\"modelPanel\"\n" + + "\t\t\t\t\t\"$panelName = `modelPanel -unParent -l (localizedPanelLabel(\\\"Top View\\\")) -mbv $menusOkayInPanels `;\\n$editorName = $panelName;\\nmodelEditor -e \\n -camera \\\"|top\\\" \\n -useInteractiveMode 0\\n -displayLights \\\"default\\\" \\n -displayAppearance \\\"smoothShaded\\\" \\n -activeOnly 0\\n -ignorePanZoom 0\\n -wireframeOnShaded 0\\n -headsUpDisplay 1\\n -holdOuts 1\\n -selectionHiliteDisplay 1\\n -useDefaultMaterial 0\\n -bufferMode \\\"double\\\" \\n -twoSidedLighting 0\\n -backfaceCulling 0\\n -xray 0\\n -jointXray 0\\n -activeComponentsXray 0\\n -displayTextures 0\\n -smoothWireframe 0\\n -lineWidth 1\\n -textureAnisotropic 0\\n -textureHilight 1\\n -textureSampling 2\\n -textureDisplay \\\"modulate\\\" \\n -textureMaxSize 32768\\n -fogging 0\\n -fogSource \\\"fragment\\\" \\n -fogMode \\\"linear\\\" \\n -fogStart 0\\n -fogEnd 100\\n -fogDensity 0.1\\n -fogColor 0.5 0.5 0.5 1 \\n -depthOfFieldPreview 1\\n -maxConstantTransparency 1\\n -rendererName \\\"vp2Renderer\\\" \\n -objectFilterShowInHUD 1\\n -isFiltered 0\\n -colorResolution 256 256 \\n -bumpResolution 512 512 \\n -textureCompression 0\\n -transparencyAlgorithm \\\"frontAndBackCull\\\" \\n -transpInShadows 0\\n -cullingOverride \\\"none\\\" \\n -lowQualityLighting 0\\n -maximumNumHardwareLights 1\\n -occlusionCulling 0\\n -shadingModel 0\\n -useBaseRenderer 0\\n -useReducedRenderer 0\\n -smallObjectCulling 0\\n -smallObjectThreshold -1 \\n -interactiveDisableShadows 0\\n -interactiveBackFaceCull 0\\n -sortTransparent 1\\n -controllers 1\\n -nurbsCurves 1\\n -nurbsSurfaces 1\\n -polymeshes 1\\n -subdivSurfaces 1\\n -planes 1\\n -lights 1\\n -cameras 1\\n -controlVertices 1\\n -hulls 1\\n -grid 1\\n -imagePlane 1\\n -joints 1\\n -ikHandles 1\\n -deformers 1\\n -dynamics 1\\n -particleInstancers 1\\n -fluids 1\\n -hairSystems 1\\n -follicles 1\\n -nCloths 1\\n -nParticles 1\\n -nRigids 1\\n -dynamicConstraints 1\\n -locators 1\\n -manipulators 1\\n -pluginShapes 1\\n -dimensions 1\\n -handles 1\\n -pivots 1\\n -textures 1\\n -strokes 1\\n -motionTrails 1\\n -clipGhosts 1\\n -bluePencil 1\\n -greasePencils 0\\n -shadows 0\\n -captureSequenceNumber -1\\n -width 477\\n -height 276\\n -sceneRenderFilter 0\\n $editorName;\\nmodelEditor -e -viewSelected 0 $editorName\"\n" + + "\t\t\t\t\t\"modelPanel -edit -l (localizedPanelLabel(\\\"Top View\\\")) -mbv $menusOkayInPanels $panelName;\\n$editorName = $panelName;\\nmodelEditor -e \\n -camera \\\"|top\\\" \\n -useInteractiveMode 0\\n -displayLights \\\"default\\\" \\n -displayAppearance \\\"smoothShaded\\\" \\n -activeOnly 0\\n -ignorePanZoom 0\\n -wireframeOnShaded 0\\n -headsUpDisplay 1\\n -holdOuts 1\\n -selectionHiliteDisplay 1\\n -useDefaultMaterial 0\\n -bufferMode \\\"double\\\" \\n -twoSidedLighting 0\\n -backfaceCulling 0\\n -xray 0\\n -jointXray 0\\n -activeComponentsXray 0\\n -displayTextures 0\\n -smoothWireframe 0\\n -lineWidth 1\\n -textureAnisotropic 0\\n -textureHilight 1\\n -textureSampling 2\\n -textureDisplay \\\"modulate\\\" \\n -textureMaxSize 32768\\n -fogging 0\\n -fogSource \\\"fragment\\\" \\n -fogMode \\\"linear\\\" \\n -fogStart 0\\n -fogEnd 100\\n -fogDensity 0.1\\n -fogColor 0.5 0.5 0.5 1 \\n -depthOfFieldPreview 1\\n -maxConstantTransparency 1\\n -rendererName \\\"vp2Renderer\\\" \\n -objectFilterShowInHUD 1\\n -isFiltered 0\\n -colorResolution 256 256 \\n -bumpResolution 512 512 \\n -textureCompression 0\\n -transparencyAlgorithm \\\"frontAndBackCull\\\" \\n -transpInShadows 0\\n -cullingOverride \\\"none\\\" \\n -lowQualityLighting 0\\n -maximumNumHardwareLights 1\\n -occlusionCulling 0\\n -shadingModel 0\\n -useBaseRenderer 0\\n -useReducedRenderer 0\\n -smallObjectCulling 0\\n -smallObjectThreshold -1 \\n -interactiveDisableShadows 0\\n -interactiveBackFaceCull 0\\n -sortTransparent 1\\n -controllers 1\\n -nurbsCurves 1\\n -nurbsSurfaces 1\\n -polymeshes 1\\n -subdivSurfaces 1\\n -planes 1\\n -lights 1\\n -cameras 1\\n -controlVertices 1\\n -hulls 1\\n -grid 1\\n -imagePlane 1\\n -joints 1\\n -ikHandles 1\\n -deformers 1\\n -dynamics 1\\n -particleInstancers 1\\n -fluids 1\\n -hairSystems 1\\n -follicles 1\\n -nCloths 1\\n -nParticles 1\\n -nRigids 1\\n -dynamicConstraints 1\\n -locators 1\\n -manipulators 1\\n -pluginShapes 1\\n -dimensions 1\\n -handles 1\\n -pivots 1\\n -textures 1\\n -strokes 1\\n -motionTrails 1\\n -clipGhosts 1\\n -bluePencil 1\\n -greasePencils 0\\n -shadows 0\\n -captureSequenceNumber -1\\n -width 477\\n -height 276\\n -sceneRenderFilter 0\\n $editorName;\\nmodelEditor -e -viewSelected 0 $editorName\"\n" + + "\t\t\t\t-ap false\n\t\t\t\t\t(localizedPanelLabel(\"Persp View\")) \n\t\t\t\t\t\"modelPanel\"\n" + + "\t\t\t\t\t\"$panelName = `modelPanel -unParent -l (localizedPanelLabel(\\\"Persp View\\\")) -mbv $menusOkayInPanels `;\\n$editorName = $panelName;\\nmodelEditor -e \\n -cam `findStartUpCamera persp` \\n -useInteractiveMode 0\\n -displayLights \\\"default\\\" \\n -displayAppearance \\\"smoothShaded\\\" \\n -activeOnly 0\\n -ignorePanZoom 0\\n -wireframeOnShaded 0\\n -headsUpDisplay 1\\n -holdOuts 1\\n -selectionHiliteDisplay 1\\n -useDefaultMaterial 0\\n -bufferMode \\\"double\\\" \\n -twoSidedLighting 0\\n -backfaceCulling 0\\n -xray 0\\n -jointXray 0\\n -activeComponentsXray 0\\n -displayTextures 0\\n -smoothWireframe 0\\n -lineWidth 1\\n -textureAnisotropic 0\\n -textureHilight 1\\n -textureSampling 2\\n -textureDisplay \\\"modulate\\\" \\n -textureMaxSize 32768\\n -fogging 0\\n -fogSource \\\"fragment\\\" \\n -fogMode \\\"linear\\\" \\n -fogStart 0\\n -fogEnd 100\\n -fogDensity 0.1\\n -fogColor 0.5 0.5 0.5 1 \\n -depthOfFieldPreview 1\\n -maxConstantTransparency 1\\n -rendererName \\\"vp2Renderer\\\" \\n -objectFilterShowInHUD 1\\n -isFiltered 0\\n -colorResolution 256 256 \\n -bumpResolution 512 512 \\n -textureCompression 0\\n -transparencyAlgorithm \\\"frontAndBackCull\\\" \\n -transpInShadows 0\\n -cullingOverride \\\"none\\\" \\n -lowQualityLighting 0\\n -maximumNumHardwareLights 1\\n -occlusionCulling 0\\n -shadingModel 0\\n -useBaseRenderer 0\\n -useReducedRenderer 0\\n -smallObjectCulling 0\\n -smallObjectThreshold -1 \\n -interactiveDisableShadows 0\\n -interactiveBackFaceCull 0\\n -sortTransparent 1\\n -controllers 1\\n -nurbsCurves 1\\n -nurbsSurfaces 1\\n -polymeshes 1\\n -subdivSurfaces 1\\n -planes 1\\n -lights 1\\n -cameras 1\\n -controlVertices 1\\n -hulls 1\\n -grid 1\\n -imagePlane 1\\n -joints 1\\n -ikHandles 1\\n -deformers 1\\n -dynamics 1\\n -particleInstancers 1\\n -fluids 1\\n -hairSystems 1\\n -follicles 1\\n -nCloths 1\\n -nParticles 1\\n -nRigids 1\\n -dynamicConstraints 1\\n -locators 1\\n -manipulators 1\\n -pluginShapes 1\\n -dimensions 1\\n -handles 1\\n -pivots 1\\n -textures 1\\n -strokes 1\\n -motionTrails 1\\n -clipGhosts 1\\n -bluePencil 1\\n -greasePencils 0\\n -shadows 0\\n -captureSequenceNumber -1\\n -width 476\\n -height 276\\n -sceneRenderFilter 0\\n $editorName;\\nmodelEditor -e -viewSelected 0 $editorName\"\n" + + "\t\t\t\t\t\"modelPanel -edit -l (localizedPanelLabel(\\\"Persp View\\\")) -mbv $menusOkayInPanels $panelName;\\n$editorName = $panelName;\\nmodelEditor -e \\n -cam `findStartUpCamera persp` \\n -useInteractiveMode 0\\n -displayLights \\\"default\\\" \\n -displayAppearance \\\"smoothShaded\\\" \\n -activeOnly 0\\n -ignorePanZoom 0\\n -wireframeOnShaded 0\\n -headsUpDisplay 1\\n -holdOuts 1\\n -selectionHiliteDisplay 1\\n -useDefaultMaterial 0\\n -bufferMode \\\"double\\\" \\n -twoSidedLighting 0\\n -backfaceCulling 0\\n -xray 0\\n -jointXray 0\\n -activeComponentsXray 0\\n -displayTextures 0\\n -smoothWireframe 0\\n -lineWidth 1\\n -textureAnisotropic 0\\n -textureHilight 1\\n -textureSampling 2\\n -textureDisplay \\\"modulate\\\" \\n -textureMaxSize 32768\\n -fogging 0\\n -fogSource \\\"fragment\\\" \\n -fogMode \\\"linear\\\" \\n -fogStart 0\\n -fogEnd 100\\n -fogDensity 0.1\\n -fogColor 0.5 0.5 0.5 1 \\n -depthOfFieldPreview 1\\n -maxConstantTransparency 1\\n -rendererName \\\"vp2Renderer\\\" \\n -objectFilterShowInHUD 1\\n -isFiltered 0\\n -colorResolution 256 256 \\n -bumpResolution 512 512 \\n -textureCompression 0\\n -transparencyAlgorithm \\\"frontAndBackCull\\\" \\n -transpInShadows 0\\n -cullingOverride \\\"none\\\" \\n -lowQualityLighting 0\\n -maximumNumHardwareLights 1\\n -occlusionCulling 0\\n -shadingModel 0\\n -useBaseRenderer 0\\n -useReducedRenderer 0\\n -smallObjectCulling 0\\n -smallObjectThreshold -1 \\n -interactiveDisableShadows 0\\n -interactiveBackFaceCull 0\\n -sortTransparent 1\\n -controllers 1\\n -nurbsCurves 1\\n -nurbsSurfaces 1\\n -polymeshes 1\\n -subdivSurfaces 1\\n -planes 1\\n -lights 1\\n -cameras 1\\n -controlVertices 1\\n -hulls 1\\n -grid 1\\n -imagePlane 1\\n -joints 1\\n -ikHandles 1\\n -deformers 1\\n -dynamics 1\\n -particleInstancers 1\\n -fluids 1\\n -hairSystems 1\\n -follicles 1\\n -nCloths 1\\n -nParticles 1\\n -nRigids 1\\n -dynamicConstraints 1\\n -locators 1\\n -manipulators 1\\n -pluginShapes 1\\n -dimensions 1\\n -handles 1\\n -pivots 1\\n -textures 1\\n -strokes 1\\n -motionTrails 1\\n -clipGhosts 1\\n -bluePencil 1\\n -greasePencils 0\\n -shadows 0\\n -captureSequenceNumber -1\\n -width 476\\n -height 276\\n -sceneRenderFilter 0\\n $editorName;\\nmodelEditor -e -viewSelected 0 $editorName\"\n" + + "\t\t\t\t-ap false\n\t\t\t\t\t(localizedPanelLabel(\"Side View\")) \n\t\t\t\t\t\"modelPanel\"\n" + + "\t\t\t\t\t\"$panelName = `modelPanel -unParent -l (localizedPanelLabel(\\\"Side View\\\")) -mbv $menusOkayInPanels `;\\n$editorName = $panelName;\\nmodelEditor -e \\n -camera \\\"|side\\\" \\n -useInteractiveMode 0\\n -displayLights \\\"default\\\" \\n -displayAppearance \\\"smoothShaded\\\" \\n -activeOnly 0\\n -ignorePanZoom 0\\n -wireframeOnShaded 0\\n -headsUpDisplay 1\\n -holdOuts 1\\n -selectionHiliteDisplay 1\\n -useDefaultMaterial 0\\n -bufferMode \\\"double\\\" \\n -twoSidedLighting 0\\n -backfaceCulling 0\\n -xray 0\\n -jointXray 0\\n -activeComponentsXray 0\\n -displayTextures 0\\n -smoothWireframe 0\\n -lineWidth 1\\n -textureAnisotropic 0\\n -textureHilight 1\\n -textureSampling 2\\n -textureDisplay \\\"modulate\\\" \\n -textureMaxSize 32768\\n -fogging 0\\n -fogSource \\\"fragment\\\" \\n -fogMode \\\"linear\\\" \\n -fogStart 0\\n -fogEnd 100\\n -fogDensity 0.1\\n -fogColor 0.5 0.5 0.5 1 \\n -depthOfFieldPreview 1\\n -maxConstantTransparency 1\\n -rendererName \\\"vp2Renderer\\\" \\n -objectFilterShowInHUD 1\\n -isFiltered 0\\n -colorResolution 256 256 \\n -bumpResolution 512 512 \\n -textureCompression 0\\n -transparencyAlgorithm \\\"frontAndBackCull\\\" \\n -transpInShadows 0\\n -cullingOverride \\\"none\\\" \\n -lowQualityLighting 0\\n -maximumNumHardwareLights 1\\n -occlusionCulling 0\\n -shadingModel 0\\n -useBaseRenderer 0\\n -useReducedRenderer 0\\n -smallObjectCulling 0\\n -smallObjectThreshold -1 \\n -interactiveDisableShadows 0\\n -interactiveBackFaceCull 0\\n -sortTransparent 1\\n -controllers 1\\n -nurbsCurves 1\\n -nurbsSurfaces 1\\n -polymeshes 1\\n -subdivSurfaces 1\\n -planes 1\\n -lights 1\\n -cameras 1\\n -controlVertices 1\\n -hulls 1\\n -grid 1\\n -imagePlane 1\\n -joints 1\\n -ikHandles 1\\n -deformers 1\\n -dynamics 1\\n -particleInstancers 1\\n -fluids 1\\n -hairSystems 1\\n -follicles 1\\n -nCloths 1\\n -nParticles 1\\n -nRigids 1\\n -dynamicConstraints 1\\n -locators 1\\n -manipulators 1\\n -pluginShapes 1\\n -dimensions 1\\n -handles 1\\n -pivots 1\\n -textures 1\\n -strokes 1\\n -motionTrails 1\\n -clipGhosts 1\\n -bluePencil 1\\n -greasePencils 0\\n -shadows 0\\n -captureSequenceNumber -1\\n -width 476\\n -height 276\\n -sceneRenderFilter 0\\n $editorName;\\nmodelEditor -e -viewSelected 0 $editorName\"\n" + + "\t\t\t\t\t\"modelPanel -edit -l (localizedPanelLabel(\\\"Side View\\\")) -mbv $menusOkayInPanels $panelName;\\n$editorName = $panelName;\\nmodelEditor -e \\n -camera \\\"|side\\\" \\n -useInteractiveMode 0\\n -displayLights \\\"default\\\" \\n -displayAppearance \\\"smoothShaded\\\" \\n -activeOnly 0\\n -ignorePanZoom 0\\n -wireframeOnShaded 0\\n -headsUpDisplay 1\\n -holdOuts 1\\n -selectionHiliteDisplay 1\\n -useDefaultMaterial 0\\n -bufferMode \\\"double\\\" \\n -twoSidedLighting 0\\n -backfaceCulling 0\\n -xray 0\\n -jointXray 0\\n -activeComponentsXray 0\\n -displayTextures 0\\n -smoothWireframe 0\\n -lineWidth 1\\n -textureAnisotropic 0\\n -textureHilight 1\\n -textureSampling 2\\n -textureDisplay \\\"modulate\\\" \\n -textureMaxSize 32768\\n -fogging 0\\n -fogSource \\\"fragment\\\" \\n -fogMode \\\"linear\\\" \\n -fogStart 0\\n -fogEnd 100\\n -fogDensity 0.1\\n -fogColor 0.5 0.5 0.5 1 \\n -depthOfFieldPreview 1\\n -maxConstantTransparency 1\\n -rendererName \\\"vp2Renderer\\\" \\n -objectFilterShowInHUD 1\\n -isFiltered 0\\n -colorResolution 256 256 \\n -bumpResolution 512 512 \\n -textureCompression 0\\n -transparencyAlgorithm \\\"frontAndBackCull\\\" \\n -transpInShadows 0\\n -cullingOverride \\\"none\\\" \\n -lowQualityLighting 0\\n -maximumNumHardwareLights 1\\n -occlusionCulling 0\\n -shadingModel 0\\n -useBaseRenderer 0\\n -useReducedRenderer 0\\n -smallObjectCulling 0\\n -smallObjectThreshold -1 \\n -interactiveDisableShadows 0\\n -interactiveBackFaceCull 0\\n -sortTransparent 1\\n -controllers 1\\n -nurbsCurves 1\\n -nurbsSurfaces 1\\n -polymeshes 1\\n -subdivSurfaces 1\\n -planes 1\\n -lights 1\\n -cameras 1\\n -controlVertices 1\\n -hulls 1\\n -grid 1\\n -imagePlane 1\\n -joints 1\\n -ikHandles 1\\n -deformers 1\\n -dynamics 1\\n -particleInstancers 1\\n -fluids 1\\n -hairSystems 1\\n -follicles 1\\n -nCloths 1\\n -nParticles 1\\n -nRigids 1\\n -dynamicConstraints 1\\n -locators 1\\n -manipulators 1\\n -pluginShapes 1\\n -dimensions 1\\n -handles 1\\n -pivots 1\\n -textures 1\\n -strokes 1\\n -motionTrails 1\\n -clipGhosts 1\\n -bluePencil 1\\n -greasePencils 0\\n -shadows 0\\n -captureSequenceNumber -1\\n -width 476\\n -height 276\\n -sceneRenderFilter 0\\n $editorName;\\nmodelEditor -e -viewSelected 0 $editorName\"\n" + + "\t\t\t\t-ap false\n\t\t\t\t\t(localizedPanelLabel(\"Front View\")) \n\t\t\t\t\t\"modelPanel\"\n" + + "\t\t\t\t\t\"$panelName = `modelPanel -unParent -l (localizedPanelLabel(\\\"Front View\\\")) -mbv $menusOkayInPanels `;\\n$editorName = $panelName;\\nmodelEditor -e \\n -cam `findStartUpCamera front` \\n -useInteractiveMode 0\\n -displayLights \\\"default\\\" \\n -displayAppearance \\\"smoothShaded\\\" \\n -activeOnly 0\\n -ignorePanZoom 0\\n -wireframeOnShaded 0\\n -headsUpDisplay 1\\n -holdOuts 1\\n -selectionHiliteDisplay 1\\n -useDefaultMaterial 0\\n -bufferMode \\\"double\\\" \\n -twoSidedLighting 0\\n -backfaceCulling 0\\n -xray 0\\n -jointXray 0\\n -activeComponentsXray 0\\n -displayTextures 0\\n -smoothWireframe 0\\n -lineWidth 1\\n -textureAnisotropic 0\\n -textureHilight 1\\n -textureSampling 2\\n -textureDisplay \\\"modulate\\\" \\n -textureMaxSize 32768\\n -fogging 0\\n -fogSource \\\"fragment\\\" \\n -fogMode \\\"linear\\\" \\n -fogStart 0\\n -fogEnd 100\\n -fogDensity 0.1\\n -fogColor 0.5 0.5 0.5 1 \\n -depthOfFieldPreview 1\\n -maxConstantTransparency 1\\n -rendererName \\\"vp2Renderer\\\" \\n -objectFilterShowInHUD 1\\n -isFiltered 0\\n -colorResolution 256 256 \\n -bumpResolution 512 512 \\n -textureCompression 0\\n -transparencyAlgorithm \\\"frontAndBackCull\\\" \\n -transpInShadows 0\\n -cullingOverride \\\"none\\\" \\n -lowQualityLighting 0\\n -maximumNumHardwareLights 1\\n -occlusionCulling 0\\n -shadingModel 0\\n -useBaseRenderer 0\\n -useReducedRenderer 0\\n -smallObjectCulling 0\\n -smallObjectThreshold -1 \\n -interactiveDisableShadows 0\\n -interactiveBackFaceCull 0\\n -sortTransparent 1\\n -controllers 1\\n -nurbsCurves 1\\n -nurbsSurfaces 1\\n -polymeshes 1\\n -subdivSurfaces 1\\n -planes 1\\n -lights 1\\n -cameras 1\\n -controlVertices 1\\n -hulls 1\\n -grid 1\\n -imagePlane 1\\n -joints 1\\n -ikHandles 1\\n -deformers 1\\n -dynamics 1\\n -particleInstancers 1\\n -fluids 1\\n -hairSystems 1\\n -follicles 1\\n -nCloths 1\\n -nParticles 1\\n -nRigids 1\\n -dynamicConstraints 1\\n -locators 1\\n -manipulators 1\\n -pluginShapes 1\\n -dimensions 1\\n -handles 1\\n -pivots 1\\n -textures 1\\n -strokes 1\\n -motionTrails 1\\n -clipGhosts 1\\n -bluePencil 1\\n -greasePencils 0\\n -shadows 0\\n -captureSequenceNumber -1\\n -width 477\\n -height 276\\n -sceneRenderFilter 0\\n $editorName;\\nmodelEditor -e -viewSelected 0 $editorName\"\n" + + "\t\t\t\t\t\"modelPanel -edit -l (localizedPanelLabel(\\\"Front View\\\")) -mbv $menusOkayInPanels $panelName;\\n$editorName = $panelName;\\nmodelEditor -e \\n -cam `findStartUpCamera front` \\n -useInteractiveMode 0\\n -displayLights \\\"default\\\" \\n -displayAppearance \\\"smoothShaded\\\" \\n -activeOnly 0\\n -ignorePanZoom 0\\n -wireframeOnShaded 0\\n -headsUpDisplay 1\\n -holdOuts 1\\n -selectionHiliteDisplay 1\\n -useDefaultMaterial 0\\n -bufferMode \\\"double\\\" \\n -twoSidedLighting 0\\n -backfaceCulling 0\\n -xray 0\\n -jointXray 0\\n -activeComponentsXray 0\\n -displayTextures 0\\n -smoothWireframe 0\\n -lineWidth 1\\n -textureAnisotropic 0\\n -textureHilight 1\\n -textureSampling 2\\n -textureDisplay \\\"modulate\\\" \\n -textureMaxSize 32768\\n -fogging 0\\n -fogSource \\\"fragment\\\" \\n -fogMode \\\"linear\\\" \\n -fogStart 0\\n -fogEnd 100\\n -fogDensity 0.1\\n -fogColor 0.5 0.5 0.5 1 \\n -depthOfFieldPreview 1\\n -maxConstantTransparency 1\\n -rendererName \\\"vp2Renderer\\\" \\n -objectFilterShowInHUD 1\\n -isFiltered 0\\n -colorResolution 256 256 \\n -bumpResolution 512 512 \\n -textureCompression 0\\n -transparencyAlgorithm \\\"frontAndBackCull\\\" \\n -transpInShadows 0\\n -cullingOverride \\\"none\\\" \\n -lowQualityLighting 0\\n -maximumNumHardwareLights 1\\n -occlusionCulling 0\\n -shadingModel 0\\n -useBaseRenderer 0\\n -useReducedRenderer 0\\n -smallObjectCulling 0\\n -smallObjectThreshold -1 \\n -interactiveDisableShadows 0\\n -interactiveBackFaceCull 0\\n -sortTransparent 1\\n -controllers 1\\n -nurbsCurves 1\\n -nurbsSurfaces 1\\n -polymeshes 1\\n -subdivSurfaces 1\\n -planes 1\\n -lights 1\\n -cameras 1\\n -controlVertices 1\\n -hulls 1\\n -grid 1\\n -imagePlane 1\\n -joints 1\\n -ikHandles 1\\n -deformers 1\\n -dynamics 1\\n -particleInstancers 1\\n -fluids 1\\n -hairSystems 1\\n -follicles 1\\n -nCloths 1\\n -nParticles 1\\n -nRigids 1\\n -dynamicConstraints 1\\n -locators 1\\n -manipulators 1\\n -pluginShapes 1\\n -dimensions 1\\n -handles 1\\n -pivots 1\\n -textures 1\\n -strokes 1\\n -motionTrails 1\\n -clipGhosts 1\\n -bluePencil 1\\n -greasePencils 0\\n -shadows 0\\n -captureSequenceNumber -1\\n -width 477\\n -height 276\\n -sceneRenderFilter 0\\n $editorName;\\nmodelEditor -e -viewSelected 0 $editorName\"\n" + "\t\t\t\t$configName;\n\n setNamedPanelLayout (localizedPanelLabel(\"Current Layout\"));\n }\n\n panelHistory -e -clear mainPanelHistory;\n sceneUIReplacement -clear;\n\t}\n\n\ngrid -spacing 5 -size 12 -divisions 5 -displayAxes yes -displayGridLines yes -displayDivisionLines yes -displayPerspectiveLabels no -displayOrthographicLabels no -displayAxesBold yes -perspectiveLabelPosition axis -orthographicLabelPosition edge;\nviewManip -drawCompass 0 -compassAngle 0 -frontParameters \"\" -homeParameters \"\" -selectionLockParameters \"\";\n}\n"); setAttr ".st" 3; createNode script -n "sceneConfigurationScriptNode"; @@ -273,6 +285,7 @@ createNode aiAOVDriver -s -n "defaultArnoldDisplayDriver"; createNode objectSet -n "workfileMain"; rename -uid "3C9B5D6F-4579-8E3B-5B7D-4C88865A1C68"; addAttr -ci true -sn "cbId" -ln "cbId" -dt "string"; + addAttr -ci true -sn "instance_id" -ln "instance_id" -dt "string"; addAttr -ci true -sn "id" -ln "id" -dt "string"; addAttr -ci true -sn "family" -ln "family" -dt "string"; addAttr -ci true -sn "subset" -ln "subset" -dt "string"; @@ -281,13 +294,14 @@ createNode objectSet -n "workfileMain"; addAttr -ci true -sn "variant" -ln "variant" -dt "string"; addAttr -ci true -sn "asset" -ln "asset" -dt "string"; addAttr -ci true -sn "task" -ln "task" -dt "string"; - addAttr -ci true -sn "instance_id" -ln "instance_id" -dt "string"; addAttr -ci true -sn "publish_attributes" -ln "publish_attributes" -dt "string"; - addAttr -ci true -sn "__creator_attributes_keys" -ln "__creator_attributes_keys" + addAttr -ci true -sn "creator_attributes" -ln "creator_attributes" -dt "string"; + addAttr -ci true -sn "__creator_attributes_keys" -ln "__creator_attributes_keys" -dt "string"; setAttr ".ihi" 0; setAttr ".hio" yes; setAttr ".cbId" -type "string" "60df31e2be2b48bd3695c056:30d256dac64c"; + setAttr ".instance_id" -type "string" "911dc92a-ad29-41e5-bbf9-733d56174fb9"; setAttr ".id" -type "string" "pyblish.avalon.instance"; setAttr ".family" -type "string" "workfile"; setAttr ".subset" -type "string" "workfileTest_task"; @@ -296,16 +310,9 @@ createNode objectSet -n "workfileMain"; setAttr ".variant" -type "string" "Main"; setAttr ".asset" -type "string" "test_asset"; setAttr ".task" -type "string" "test_task"; - setAttr ".instance_id" -type "string" "911dc92a-ad29-41e5-bbf9-733d56174fb9"; - setAttr ".publish_attributes" -type "string" "{\"ExtractImportReference\": {\"active\": false}}"; + setAttr ".publish_attributes" -type "string" "{\"ValidateInstanceInContext\": {\"active\": true}, \"ExtractImportReference\": {\"active\": false}}"; + setAttr ".creator_attributes" -type "string" "{}"; setAttr ".__creator_attributes_keys" -type "string" ""; -createNode objectSet -n "renderingMain"; - rename -uid "8A999C2F-4922-B15D-8D5C-45A16465B69F"; - addAttr -ci true -sn "pre_creator_identifier" -ln "pre_creator_identifier" -dt "string"; - addAttr -ci true -sn "cbId" -ln "cbId" -dt "string"; - setAttr ".ihi" 0; - setAttr ".pre_creator_identifier" -type "string" "io.openpype.creators.maya.renderlayer"; - setAttr ".cbId" -type "string" "60df31e2be2b48bd3695c056:042447475732"; createNode renderSetupLayer -n "Main"; rename -uid "2202E438-4CEF-F64E-737C-F48C65E31126"; addAttr -ci true -sn "es" -ln "expandedState" -min 0 -max 1 -at "bool"; @@ -320,55 +327,6 @@ createNode collection -n "defaultCollection"; createNode simpleSelector -n "defaultCollectionSelector"; rename -uid "7CA2F6D8-483C-B020-BC03-EF9563A52163"; setAttr ".pat" -type "string" "*"; -createNode objectSet -n "_renderingMain:Main"; - rename -uid "1EEC3A3B-49CF-0C79-5340-39805174FB8A"; - addAttr -s false -ci true -sn "renderlayer" -ln "renderlayer" -at "message"; - addAttr -ci true -sn "id" -ln "id" -dt "string"; - addAttr -ci true -sn "family" -ln "family" -dt "string"; - addAttr -ci true -sn "subset" -ln "subset" -dt "string"; - addAttr -ci true -sn "active" -ln "active" -min 0 -max 1 -at "bool"; - addAttr -ci true -sn "creator_identifier" -ln "creator_identifier" -dt "string"; - addAttr -ci true -sn "variant" -ln "variant" -dt "string"; - addAttr -ci true -sn "asset" -ln "asset" -dt "string"; - addAttr -ci true -sn "task" -ln "task" -dt "string"; - addAttr -ci true -sn "instance_id" -ln "instance_id" -dt "string"; - addAttr -ci true -sn "review" -ln "review" -min 0 -max 1 -at "bool"; - addAttr -ci true -sn "extendFrames" -ln "extendFrames" -min 0 -max 1 -at "bool"; - addAttr -ci true -sn "overrideExistingFrame" -ln "overrideExistingFrame" -min 0 - -max 1 -at "bool"; - addAttr -ci true -sn "tileRendering" -ln "tileRendering" -min 0 -max 1 -at "bool"; - addAttr -ci true -sn "tilesX" -ln "tilesX" -at "long"; - addAttr -ci true -sn "tilesY" -ln "tilesY" -at "long"; - addAttr -ci true -sn "convertToScanline" -ln "convertToScanline" -min 0 -max 1 -at "bool"; - addAttr -ci true -sn "useReferencedAovs" -ln "useReferencedAovs" -min 0 -max 1 -at "bool"; - addAttr -ci true -sn "renderSetupIncludeLights" -ln "renderSetupIncludeLights" -min - 0 -max 1 -at "bool"; - addAttr -ci true -sn "publish_attributes" -ln "publish_attributes" -dt "string"; - addAttr -ci true -sn "__creator_attributes_keys" -ln "__creator_attributes_keys" - -dt "string"; - addAttr -ci true -sn "cbId" -ln "cbId" -dt "string"; - setAttr ".ihi" 0; - setAttr ".id" -type "string" "pyblish.avalon.instance"; - setAttr ".family" -type "string" "renderlayer"; - setAttr ".subset" -type "string" "renderMain"; - setAttr -cb on ".active" yes; - setAttr ".creator_identifier" -type "string" "io.openpype.creators.maya.renderlayer"; - setAttr ".variant" -type "string" "Main"; - setAttr ".asset" -type "string" "test_asset"; - setAttr ".task" -type "string" "test_task"; - setAttr ".instance_id" -type "string" "8a9cfb85-9602-4e5e-a4bc-27a2986bae7f"; - setAttr -cb on ".review" yes; - setAttr -cb on ".extendFrames"; - setAttr -cb on ".overrideExistingFrame" yes; - setAttr -cb on ".tileRendering"; - setAttr -cb on ".tilesX" 2; - setAttr -cb on ".tilesY" 2; - setAttr -cb on ".convertToScanline"; - setAttr -cb on ".useReferencedAovs"; - setAttr -cb on ".renderSetupIncludeLights" yes; - setAttr ".publish_attributes" -type "string" "{\"CollectDeadlinePools\": {\"primaryPool\": \"\", \"secondaryPool\": \"\"}, \"ValidateDeadlinePools\": {\"active\": true}, \"ValidateFrameRange\": {\"active\": true}, \"ExtractImportReference\": {\"active\": false}, \"MayaSubmitDeadline\": {\"priority\": 50, \"chunkSize\": 1, \"machineList\": \"\", \"whitelist\": false, \"tile_priority\": 50, \"strict_error_checking\": true}, \"ProcessSubmittedJobOnFarm\": {\"publishJobState\": \"Active\"}}"; - setAttr ".__creator_attributes_keys" -type "string" "review,extendFrames,overrideExistingFrame,tileRendering,tilesX,tilesY,convertToScanline,useReferencedAovs,renderSetupIncludeLights"; - setAttr ".cbId" -type "string" "60df31e2be2b48bd3695c056:69960f336351"; select -ne :time1; setAttr ".o" 1001; setAttr ".unw" 1001; @@ -435,8 +393,6 @@ select -ne :defaultColorMgtGlobals; select -ne :hardwareRenderGlobals; setAttr ".ctrs" 256; setAttr ".btrs" 512; -select -ne :ikSystem; - setAttr -s 4 ".sol"; connectAttr "rs_Main.ri" ":persp.rlio[0]"; connectAttr "rs_Main.ri" ":top.rlio[0]"; connectAttr "rs_Main.ri" ":front.rlio[0]"; @@ -459,7 +415,6 @@ connectAttr ":defaultArnoldDisplayDriver.msg" ":defaultArnoldRenderOptions.drive -na; connectAttr ":defaultArnoldFilter.msg" ":defaultArnoldRenderOptions.filt"; connectAttr ":defaultArnoldDriver.msg" ":defaultArnoldRenderOptions.drvr"; -connectAttr "_renderingMain:Main.msg" "renderingMain.dnsm" -na; connectAttr "rs_Main.msg" "Main.lrl"; connectAttr "renderSetup.lit" "Main.pls"; connectAttr "defaultCollection.msg" "Main.cl"; @@ -468,9 +423,8 @@ connectAttr "renderLayerManager.rlmi[1]" "rs_Main.rlid"; connectAttr "defaultCollectionSelector.c" "defaultCollection.sel"; connectAttr "Main.lit" "defaultCollection.pls"; connectAttr "Main.nic" "defaultCollection.pic"; -connectAttr "Main.msg" "_renderingMain:Main.renderlayer"; connectAttr "defaultRenderLayer.msg" ":defaultRenderingList1.r" -na; connectAttr "rs_Main.msg" ":defaultRenderingList1.r" -na; connectAttr "pSphere1_GEOShape1.iog" ":initialShadingGroup.dsm" -na; connectAttr "pDiscShape1.iog" ":initialShadingGroup.dsm" -na; -// End of test_project_test_asset_test_task_v001.ma +// End of test_project_test_asset_test_task_v002.ma diff --git a/tests/integration/hosts/nuke/test_deadline_publish_in_nuke.py b/tests/integration/hosts/nuke/test_deadline_publish_in_nuke.py index a4026f195b..586078ead6 100644 --- a/tests/integration/hosts/nuke/test_deadline_publish_in_nuke.py +++ b/tests/integration/hosts/nuke/test_deadline_publish_in_nuke.py @@ -69,7 +69,7 @@ class TestDeadlinePublishInNuke(NukeDeadlinePublishTestClass): name="workfileTest_task")) failures.append( - DBAssert.count_of_types(dbcon, "representation", 4)) + DBAssert.count_of_types(dbcon, "representation", 3)) additional_args = {"context.subset": "workfileTest_task", "context.ext": "nk"} @@ -86,7 +86,7 @@ class TestDeadlinePublishInNuke(NukeDeadlinePublishTestClass): additional_args = {"context.subset": "renderTest_taskMain", "name": "thumbnail"} failures.append( - DBAssert.count_of_types(dbcon, "representation", 1, + DBAssert.count_of_types(dbcon, "representation", 0, additional_args=additional_args)) additional_args = {"context.subset": "renderTest_taskMain", diff --git a/tests/lib/db_handler.py b/tests/lib/db_handler.py index 82e741cc3b..d9a52be5b4 100644 --- a/tests/lib/db_handler.py +++ b/tests/lib/db_handler.py @@ -2,7 +2,7 @@ Helper class for automatic testing, provides dump and restore via command line utilities. - Expect mongodump, mongoimport and mongorestore present at PATH + Expect mongodump, mongoexport, mongoimport and mongorestore present at PATH """ import os import pymongo @@ -148,7 +148,7 @@ class DBHandler: self.client.drop_database(db_name) def backup_to_dump(self, db_name, dump_dir, overwrite=False, - collection=None): + collection=None, format="bson"): """ Helper method for running mongodump for specific 'db_name' """ @@ -160,15 +160,24 @@ class DBHandler: raise RuntimeError("Backup already exists, " "run with overwrite=True") - query = self._dump_query(self.uri, dump_dir, - db_name=db_name, collection=collection) - print("Mongodump query:: {}".format(query)) - subprocess.run(query) + collections = [collection] + if format == "json" and collection is None: + collections = self.client[db_name].list_collection_names() + + for collection in collections: + query = self._dump_query(self.uri, dump_dir, + db_name=db_name, collection=collection, + format=format) + print("Mongodump query:: {}".format(query)) + process = subprocess.run(query) + assert process.returncode == 0, "Mongo dump failed." def _db_exists(self, db_name): return db_name in self.client.list_database_names() - def _dump_query(self, uri, output_path, db_name=None, collection=None): + def _dump_query( + self, uri, output_path, db_name=None, collection=None, format="bson" + ): """Prepares dump query based on 'db_name' or 'collection'.""" db_part = coll_part = "" if db_name: @@ -177,11 +186,22 @@ class DBHandler: if not db_name: raise ValueError("db_name must be present") coll_part = "--collection={}".format(collection) - query = "\"{}\" --uri=\"{}\" --out={} {} {}".format( - "mongodump", uri, output_path, db_part, coll_part - ) - return query + tool = "mongodump" + query = "{} --uri=\"{}\"" + + if format == "json": + assert collection, "Collection is needed for json export." + + query += " --jsonArray --pretty" + tool = "mongoexport" + output_path = os.path.join( + output_path, "{}.{}.json".format(db_name, collection) + ) + + query += " --out={} {} {}" + + return query.format(tool, uri, output_path, db_part, coll_part) def _restore_query(self, uri, dump_dir, db_name=None, db_name_out=None, diff --git a/tests/lib/testing_classes.py b/tests/lib/testing_classes.py index 7dae9a762f..ade38d60c8 100644 --- a/tests/lib/testing_classes.py +++ b/tests/lib/testing_classes.py @@ -70,7 +70,9 @@ class ModuleUnitTest(BaseTest): ) @pytest.fixture(scope="module") - def download_test_data(self, test_data_folder, persist, request): + def download_test_data( + self, test_data_folder, persist, request, dump_databases + ): test_data_folder = test_data_folder or self.TEST_DATA_FOLDER if test_data_folder: print("Using existing folder {}".format(test_data_folder)) @@ -100,13 +102,13 @@ class ModuleUnitTest(BaseTest): if ext and ext.lstrip('.') in handler_class.IMPLEMENTED_ZIP_FORMATS: # noqa: E501 handler_class.unzip(os.path.join(tmpdir, file_name)) - yield tmpdir + yield tmpdir - persist = (persist or self.PERSIST or - self.is_test_failed(request)) - if not persist: - print("Removing {}".format(tmpdir)) - shutil.rmtree(tmpdir) + persist = (persist or self.PERSIST or + self.is_test_failed(request) or dump_databases) + if not persist: + print("Removing {}".format(tmpdir)) + shutil.rmtree(tmpdir) @pytest.fixture(scope="module") def output_folder_url(self, download_test_data): @@ -163,7 +165,7 @@ class ModuleUnitTest(BaseTest): @pytest.fixture(scope="module") def db_setup(self, download_test_data, env_var, monkeypatch_session, - request, mongo_url): + request, mongo_url, dump_databases, persist): """Restore prepared MongoDB dumps into selected DB.""" backup_dir = os.path.join(download_test_data, "input", "dumps") uri = os.environ.get("OPENPYPE_MONGO") @@ -178,7 +180,17 @@ class ModuleUnitTest(BaseTest): yield db_handler - persist = self.PERSIST or self.is_test_failed(request) + if dump_databases: + print("Dumping databases to {}".format(download_test_data)) + output_dir = os.path.join(download_test_data, "output", "dumps") + db_handler.backup_to_dump( + self.TEST_DB_NAME, output_dir, format=dump_databases + ) + db_handler.backup_to_dump( + self.TEST_OPENPYPE_NAME, output_dir, format=dump_databases + ) + + persist = persist or self.PERSIST or self.is_test_failed(request) if not persist: db_handler.teardown(self.TEST_DB_NAME) db_handler.teardown(self.TEST_OPENPYPE_NAME) @@ -218,11 +230,7 @@ class ModuleUnitTest(BaseTest): yield mongo_client[self.TEST_OPENPYPE_NAME]["settings"] def is_test_failed(self, request): - # if request.node doesn't have rep_call, something failed - try: - return request.node.rep_call.failed - except AttributeError: - return True + return getattr(request.node, "module_test_failure", False) class PublishTest(ModuleUnitTest): @@ -473,7 +481,7 @@ class DeadlinePublishTest(PublishTest): while not valid_date_finished: time.sleep(0.5) if time.time() - time_start > timeout: - raise ValueError("Timeout for DL finish reached") + raise ValueError("Timeout for Deadline finish reached") response = requests.get(url, timeout=10) if not response.ok: @@ -483,6 +491,61 @@ class DeadlinePublishTest(PublishTest): if not response.json(): raise ValueError("Couldn't find {}".format(deadline_job_id)) + job = response.json()[0] + + def recursive_dependencies(job, results=None): + if results is None: + results = [] + + for dependency in job["Props"]["Dep"]: + dependency = requests.get( + "{}/api/jobs?JobId={}".format( + deadline_url, dependency["JobID"] + ), + timeout=10 + ).json()[0] + results.append(dependency) + grand_dependencies = recursive_dependencies( + dependency, results=results + ) + for grand_dependency in grand_dependencies: + if grand_dependency not in results: + results.append(grand_dependency) + return results + + job_status = { + 0: "Unknown", + 1: "Active", + 2: "Suspended", + 3: "Completed", + 4: "Failed", + 6: "Pending" + } + + jobs_to_validate = [job] + jobs_to_validate.extend(recursive_dependencies(job)) + failed_jobs = [] + errors = [] + for job in jobs_to_validate: + if "Failed" == job_status[job["Stat"]]: + failed_jobs.append(str(job)) + + resp_error = requests.get( + "{}/api/jobreports?JobID={}&Data=allerrorcontents".format( + deadline_url, job["_id"] + ), + timeout=10 + ) + errors.extend(resp_error.json()) + + msg = "Errors in Deadline:\n" + msg += "\n".join(errors) + assert not errors, msg + + msg = "Failed in Deadline:\n" + msg += "\n".join(failed_jobs) + assert not failed_jobs, msg + # '0001-...' returned until job is finished valid_date_finished = response.json()[0]["DateComp"][:4] != "0001" diff --git a/website/docs/artist_hosts_houdini.md b/website/docs/artist_hosts_houdini.md index 940d5ac351..c4e8293c36 100644 --- a/website/docs/artist_hosts_houdini.md +++ b/website/docs/artist_hosts_houdini.md @@ -83,6 +83,30 @@ select your render camera. All the render outputs are stored in the pyblish/render directory within your project path.\ For Karma-specific render, it also outputs the USD render as default. +## Publishing cache to Deadline +Artist can publish cache to deadline which increases productivity as artist can use local machine +could be used for other tasks. +Caching on the farm is supported for: + +**Arnold ASS (.ass)** +**Pointcache (.bgeo and .abc)** +**VDB (.vdb)** +**Redshift Proxy (.rs)** + +To submit your cache to deadline, you need to create the instance(s) with clicking +**Submitting to Farm** and you can also enable **Use selection** to +select the object for caching in farm. +![Houdini Farm Cache Creator](assets/houdini_farm_cache_creator.png) + +When you go to Publish Tab and click the instance(s), you can set up your preferred +**Frame per task**. +![Houdini Farm Per Task](assets/houdini_frame_per_task.png) + +Once you hit **Publish**, the cache would be submitted and rendered in deadline. +When the render is finished, all the caches would be located in your publish folder. +You can see them in the Loader. +![Houdini Farm Per Task](assets/houdini_farm_cache_loader.png) + ## USD (experimental support) ### Publishing USD You can publish your Solaris Stage as USD file. diff --git a/website/docs/assets/houdini_farm_cache_creator.png b/website/docs/assets/houdini_farm_cache_creator.png new file mode 100644 index 0000000000..bf0af80336 Binary files /dev/null and b/website/docs/assets/houdini_farm_cache_creator.png differ diff --git a/website/docs/assets/houdini_farm_cache_loader.png b/website/docs/assets/houdini_farm_cache_loader.png new file mode 100644 index 0000000000..27b0122fab Binary files /dev/null and b/website/docs/assets/houdini_farm_cache_loader.png differ diff --git a/website/docs/assets/houdini_frame_per_task.png b/website/docs/assets/houdini_frame_per_task.png new file mode 100644 index 0000000000..a7d8b33114 Binary files /dev/null and b/website/docs/assets/houdini_frame_per_task.png differ