From 3a1afe5d1e74a206ae3218164bfb289ef90f978a Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Mon, 30 Sep 2019 11:12:20 +0200 Subject: [PATCH 1/4] support for yeti caches --- pype/plugins/global/publish/integrate.py | 8 ++---- pype/plugins/global/publish/integrate_new.py | 11 +++++--- .../maya/publish/extract_yeti_cache.py | 27 ++++++++++++++++--- 3 files changed, 32 insertions(+), 14 deletions(-) diff --git a/pype/plugins/global/publish/integrate.py b/pype/plugins/global/publish/integrate.py index 8597d4a719..59e05ee2aa 100644 --- a/pype/plugins/global/publish/integrate.py +++ b/pype/plugins/global/publish/integrate.py @@ -1,7 +1,6 @@ import os import logging import shutil -import clique import errno import pyblish.api @@ -25,9 +24,7 @@ class IntegrateAsset(pyblish.api.InstancePlugin): label = "Integrate Asset" order = pyblish.api.IntegratorOrder - families = ["assembly", - "yetiRig", - "yeticache"] + families = ["assembly"] exclude_families = ["clip"] def process(self, instance): @@ -41,7 +38,6 @@ class IntegrateAsset(pyblish.api.InstancePlugin): if instance.data.get('transfer', True): self.integrate(instance) - def register(self, instance): # Required environment variables PROJECT = api.Session["AVALON_PROJECT"] @@ -158,7 +154,7 @@ class IntegrateAsset(pyblish.api.InstancePlugin): "version": int(version["name"]), "hierarchy": hierarchy} - template_publish = project["config"]["template"]["publish"] + # template_publish = project["config"]["template"]["publish"] anatomy = instance.context.data['anatomy'] # Find the representations to transfer amongst the files diff --git a/pype/plugins/global/publish/integrate_new.py b/pype/plugins/global/publish/integrate_new.py index e5d8007d70..6468da03d5 100644 --- a/pype/plugins/global/publish/integrate_new.py +++ b/pype/plugins/global/publish/integrate_new.py @@ -3,7 +3,6 @@ from os.path import getsize import logging import speedcopy import clique -import traceback import errno import pyblish.api from avalon import api, io @@ -64,7 +63,9 @@ class IntegrateAssetNew(pyblish.api.InstancePlugin): "plate", "look", "lut", - "audio" + "audio", + "yetiRig", + "yeticache" ] exclude_families = ["clip"] @@ -110,7 +111,7 @@ class IntegrateAssetNew(pyblish.api.InstancePlugin): # extracted_traceback[1], result["error"] # ) # ) - # assert all(result["success"] for result in context.data["results"]), ( + # assert all(result["success"] for result in context.data["results"]),( # "Atomicity not held, aborting.") # Assemble @@ -328,7 +329,9 @@ class IntegrateAssetNew(pyblish.api.InstancePlugin): self.log.debug("source: {}".format(src)) instance.data["transfers"].append([src, dst]) - repre['published_path'] = "{0}{1}{2}".format(dst_head, dst_padding_exp, dst_tail) + repre['published_path'] = "{0}{1}{2}".format(dst_head, + dst_padding_exp, + dst_tail) # for imagesequence version data hashes = '#' * len(dst_padding) dst = os.path.normpath("{0}{1}{2}".format( diff --git a/pype/plugins/maya/publish/extract_yeti_cache.py b/pype/plugins/maya/publish/extract_yeti_cache.py index cc71052761..fcc733e2ed 100644 --- a/pype/plugins/maya/publish/extract_yeti_cache.py +++ b/pype/plugins/maya/publish/extract_yeti_cache.py @@ -63,10 +63,29 @@ class ExtractYetiCache(pype.api.Extractor): with open(data_file, "w") as fp: json.dump(settings, fp, ensure_ascii=False) - # Ensure files can be stored - if "files" not in instance.data: - instance.data["files"] = list() + # build representations + if "representations" not in instance.data: + instance.data["representations"] = [] - instance.data["files"].extend([cache_files, "yeti.fursettings"]) + self.log.info("cache files: {}".format(cache_files[0])) + instance.data["representations"].append( + { + 'name': cache_files[0].split(".")[0], + 'ext': 'fur', + 'files': cache_files, + 'stagingDir': dirname, + 'anatomy_template': 'publish' + } + ) + + instance.data["representations"].append( + { + 'name': os.path.basename(data_file), + 'ext': 'fursettings', + 'files': os.path.basename(data_file), + 'stagingDir': dirname, + 'anatomy_template': 'publish' + } + ) self.log.info("Extracted {} to {}".format(instance, dirname)) From 2ec11cea9ad0e2b7d462a1c9f10aacce5886aa07 Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Tue, 15 Oct 2019 17:06:01 +0200 Subject: [PATCH 2/4] minor tweaks --- .../maya/publish/extract_yeti_cache.py | 6 ++--- pype/plugins/maya/publish/extract_yeti_rig.py | 26 ++++++++++++++++--- ...te.py => validate_yeti_rig_cache_state.py} | 4 --- 3 files changed, 25 insertions(+), 11 deletions(-) rename pype/plugins/maya/publish/{validate_yetirig_cache_state.py => validate_yeti_rig_cache_state.py} (99%) diff --git a/pype/plugins/maya/publish/extract_yeti_cache.py b/pype/plugins/maya/publish/extract_yeti_cache.py index fcc733e2ed..c313513b3a 100644 --- a/pype/plugins/maya/publish/extract_yeti_cache.py +++ b/pype/plugins/maya/publish/extract_yeti_cache.py @@ -7,11 +7,9 @@ import pype.api class ExtractYetiCache(pype.api.Extractor): - """Produce an alembic of just point positions and normals. - - Positions and normals are preserved, but nothing more, - for plain and predictable point caches. + """Producing Yeti cache files using scene time range. + This will extract Yeti cache file sequence and fur settings. """ label = "Extract Yeti Cache" diff --git a/pype/plugins/maya/publish/extract_yeti_rig.py b/pype/plugins/maya/publish/extract_yeti_rig.py index 904ec2314e..b79c5a17c9 100644 --- a/pype/plugins/maya/publish/extract_yeti_rig.py +++ b/pype/plugins/maya/publish/extract_yeti_rig.py @@ -155,10 +155,30 @@ class ExtractYetiRig(pype.api.Extractor): shader=False) # Ensure files can be stored - if "files" not in instance.data: - instance.data["files"] = list() + # build representations + if "representations" not in instance.data: + instance.data["representations"] = [] - instance.data["files"].extend(["yeti_rig.ma", "yeti.rigsettings"]) + self.log.info("rig file: {}".format("yeti_rig.ma")) + instance.data["representations"].append( + { + 'name': "yeti_rig", + 'ext': 'ma', + 'files': "yeti_rig.ma", + 'stagingDir': dirname, + 'anatomy_template': 'publish' + } + ) + self.log.info("setting file: {}".format("yeti_rig.ma")) + instance.data["representations"].append( + { + 'name': 'yeti.rigsettings', + 'ext': 'rigsettings', + 'files': 'rigsettings', + 'stagingDir': dirname, + 'anatomy_template': 'publish' + } + ) self.log.info("Extracted {} to {}".format(instance, dirname)) diff --git a/pype/plugins/maya/publish/validate_yetirig_cache_state.py b/pype/plugins/maya/publish/validate_yeti_rig_cache_state.py similarity index 99% rename from pype/plugins/maya/publish/validate_yetirig_cache_state.py rename to pype/plugins/maya/publish/validate_yeti_rig_cache_state.py index 405aeb3fd7..250c1c7b2e 100644 --- a/pype/plugins/maya/publish/validate_yetirig_cache_state.py +++ b/pype/plugins/maya/publish/validate_yeti_rig_cache_state.py @@ -1,9 +1,6 @@ import pyblish.api - import pype.action - import maya.cmds as cmds - import pype.maya.action @@ -60,4 +57,3 @@ class ValidateYetiRigCacheState(pyblish.api.InstancePlugin): for node in invalid: cmds.setAttr("%s.fileMode" % node, 0) cmds.setAttr("%s.cacheFileName" % node, "", type="string") - From f549710a64884e01af010bf19d79f99b8fe9ad6b Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Wed, 16 Oct 2019 00:40:27 +0200 Subject: [PATCH 3/4] fixes for Yeti rig and caches, working now --- pype/maya/lib.py | 8 ++++++- pype/plugins/maya/publish/collect_yeti_rig.py | 22 +++++++++++-------- .../maya/publish/extract_yeti_cache.py | 7 +++--- pype/plugins/maya/publish/extract_yeti_rig.py | 8 +++---- .../maya/publish/validate_frame_range.py | 2 +- 5 files changed, 29 insertions(+), 18 deletions(-) diff --git a/pype/maya/lib.py b/pype/maya/lib.py index bd48862721..0ed45d8454 100644 --- a/pype/maya/lib.py +++ b/pype/maya/lib.py @@ -296,7 +296,13 @@ def attribute_values(attr_values): """ - original = [(attr, cmds.getAttr(attr)) for attr in attr_values] + # NOTE(antirotor): this didn't work for some reason for Yeti attributes + # original = [(attr, cmds.getAttr(attr)) for attr in attr_values] + original = [] + for attr in attr_values: + type = cmds.getAttr(attr, type=True) + value = cmds.getAttr(attr) + original.append((attr, str(value) if type == "string" else value)) try: for attr, value in attr_values.items(): if isinstance(value, string_types): diff --git a/pype/plugins/maya/publish/collect_yeti_rig.py b/pype/plugins/maya/publish/collect_yeti_rig.py index a2cd5b2a5f..7ab5649c0b 100644 --- a/pype/plugins/maya/publish/collect_yeti_rig.py +++ b/pype/plugins/maya/publish/collect_yeti_rig.py @@ -45,8 +45,10 @@ class CollectYetiRig(pyblish.api.InstancePlugin): instance.data["resources"] = yeti_resources # Force frame range for export - instance.data["frameStart"] = 1 - instance.data["frameEnd"] = 1 + instance.data["frameStart"] = cmds.playbackOptions( + query=True, animationStartTime=True) + instance.data["frameEnd"] = cmds.playbackOptions( + query=True, animationStartTime=True) def collect_input_connections(self, instance): """Collect the inputs for all nodes in the input_SET""" @@ -114,15 +116,17 @@ class CollectYetiRig(pyblish.api.InstancePlugin): resources = [] image_search_paths = cmds.getAttr("{}.imageSearchPath".format(node)) + texture_filenames = [] + if image_search_paths: - # TODO: Somehow this uses OS environment path separator, `:` vs `;` - # Later on check whether this is pipeline OS cross-compatible. - image_search_paths = [p for p in - image_search_paths.split(os.path.pathsep) if p] + # TODO: Somehow this uses OS environment path separator, `:` vs `;` + # Later on check whether this is pipeline OS cross-compatible. + image_search_paths = [p for p in + image_search_paths.split(os.path.pathsep) if p] - # List all related textures - texture_filenames = cmds.pgYetiCommand(node, listTextures=True) - self.log.info("Found %i texture(s)" % len(texture_filenames)) + # List all related textures + texture_filenames = cmds.pgYetiCommand(node, listTextures=True) + self.log.info("Found %i texture(s)" % len(texture_filenames)) # Get all reference nodes reference_nodes = cmds.pgYetiGraph(node, diff --git a/pype/plugins/maya/publish/extract_yeti_cache.py b/pype/plugins/maya/publish/extract_yeti_cache.py index c313513b3a..7d57578b14 100644 --- a/pype/plugins/maya/publish/extract_yeti_cache.py +++ b/pype/plugins/maya/publish/extract_yeti_cache.py @@ -42,7 +42,8 @@ class ExtractYetiCache(pype.api.Extractor): else: kwargs.update({"samples": samples}) - self.log.info("Writing out cache") + self.log.info( + "Writing out cache {} - {}".format(start_frame, end_frame)) # Start writing the files for snap shot # will be replace by the Yeti node name path = os.path.join(dirname, ".%04d.fur") @@ -70,7 +71,7 @@ class ExtractYetiCache(pype.api.Extractor): { 'name': cache_files[0].split(".")[0], 'ext': 'fur', - 'files': cache_files, + 'files': cache_files[0] if len(cache_files) == 1 else cache_files, 'stagingDir': dirname, 'anatomy_template': 'publish' } @@ -78,7 +79,7 @@ class ExtractYetiCache(pype.api.Extractor): instance.data["representations"].append( { - 'name': os.path.basename(data_file), + 'name': 'fursettings', 'ext': 'fursettings', 'files': os.path.basename(data_file), 'stagingDir': dirname, diff --git a/pype/plugins/maya/publish/extract_yeti_rig.py b/pype/plugins/maya/publish/extract_yeti_rig.py index b79c5a17c9..b575c07cf4 100644 --- a/pype/plugins/maya/publish/extract_yeti_rig.py +++ b/pype/plugins/maya/publish/extract_yeti_rig.py @@ -162,19 +162,19 @@ class ExtractYetiRig(pype.api.Extractor): self.log.info("rig file: {}".format("yeti_rig.ma")) instance.data["representations"].append( { - 'name': "yeti_rig", + 'name': "ma", 'ext': 'ma', 'files': "yeti_rig.ma", 'stagingDir': dirname, 'anatomy_template': 'publish' } ) - self.log.info("setting file: {}".format("yeti_rig.ma")) + self.log.info("settings file: {}".format("yeti.rigsettings")) instance.data["representations"].append( { - 'name': 'yeti.rigsettings', + 'name': 'rigsettings', 'ext': 'rigsettings', - 'files': 'rigsettings', + 'files': 'yeti.rigsettings', 'stagingDir': dirname, 'anatomy_template': 'publish' } diff --git a/pype/plugins/maya/publish/validate_frame_range.py b/pype/plugins/maya/publish/validate_frame_range.py index 57eb40eb7c..d4aad812d5 100644 --- a/pype/plugins/maya/publish/validate_frame_range.py +++ b/pype/plugins/maya/publish/validate_frame_range.py @@ -21,7 +21,7 @@ class ValidateFrameRange(pyblish.api.InstancePlugin): "pointcache", "camera", "renderlayer", - "oolorbleed.vrayproxy"] + "colorbleed.vrayproxy"] def process(self, instance): From 6914371872f0efa65d33016b03994bdc192f70da Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Wed, 16 Oct 2019 13:10:54 +0200 Subject: [PATCH 4/4] fixed cache loader --- pype/plugins/maya/load/load_yeti_cache.py | 21 ++++++++++++------- .../maya/publish/extract_yeti_cache.py | 2 +- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/pype/plugins/maya/load/load_yeti_cache.py b/pype/plugins/maya/load/load_yeti_cache.py index dc976c0c98..a1793cd67d 100644 --- a/pype/plugins/maya/load/load_yeti_cache.py +++ b/pype/plugins/maya/load/load_yeti_cache.py @@ -39,8 +39,10 @@ class YetiCacheLoader(api.Loader): cmds.loadPlugin("pgYetiMaya", quiet=True) # Get JSON - fname, ext = os.path.splitext(self.fname) - settings_fname = "{}.fursettings".format(fname) + fbase = re.search(r'^(.+)\.(\d+|#+)\.fur', self.fname) + if not fbase: + raise RuntimeError('Cannot determine fursettings file path') + settings_fname = "{}.fursettings".format(fbase.group(1)) with open(settings_fname, "r") as fp: fursettings = json.load(fp) @@ -102,7 +104,6 @@ class YetiCacheLoader(api.Loader): namespace = container["namespace"] container_node = container["objectName"] path = api.get_representation_path(representation) - # Get all node data fname, ext = os.path.splitext(path) settings_fname = "{}.fursettings".format(fname) @@ -151,7 +152,8 @@ class YetiCacheLoader(api.Loader): # Update cache file name file_name = data["name"].replace(":", "_") cache_file_path = "{}.%04d.fur".format(file_name) - data["attrs"]["cacheFileName"] = os.path.join(path, cache_file_path) + data["attrs"]["cacheFileName"] = os.path.join( + path, cache_file_path) if cb_id not in scene_lookup: @@ -284,10 +286,15 @@ class YetiCacheLoader(api.Loader): attributes = node_settings["attrs"] # Check if cache file name is stored + + # get number of # in path and convert it to C prinf format + # like %04d expected by Yeti + fbase = re.search(r'^(.+)\.(\d+|#+)\.fur', self.fname) + if not fbase: + raise RuntimeError('Cannot determine file path') + padding = len(fbase.group(2)) if "cacheFileName" not in attributes: - file_name = original_node.replace(":", "_") - cache_name = "{}.%04d.fur".format(file_name) - cache = os.path.join(self.fname, cache_name) + cache = "{}.%0{}d.fur".format(fbase.group(1), padding) self.validate_cache(cache) attributes["cacheFileName"] = cache diff --git a/pype/plugins/maya/publish/extract_yeti_cache.py b/pype/plugins/maya/publish/extract_yeti_cache.py index 7d57578b14..8cb94021ed 100644 --- a/pype/plugins/maya/publish/extract_yeti_cache.py +++ b/pype/plugins/maya/publish/extract_yeti_cache.py @@ -69,7 +69,7 @@ class ExtractYetiCache(pype.api.Extractor): self.log.info("cache files: {}".format(cache_files[0])) instance.data["representations"].append( { - 'name': cache_files[0].split(".")[0], + 'name': 'fur', 'ext': 'fur', 'files': cache_files[0] if len(cache_files) == 1 else cache_files, 'stagingDir': dirname,