diff --git a/openpype/hosts/tvpaint/worker/worker_job.py b/openpype/hosts/tvpaint/worker/worker_job.py index 0d343a6bea..1f30777901 100644 --- a/openpype/hosts/tvpaint/worker/worker_job.py +++ b/openpype/hosts/tvpaint/worker/worker_job.py @@ -136,22 +136,26 @@ class ExecuteGeorgeScript(BaseCommand): name = "execute_george_through_file" def __init__( - self, script, tmp_file_keys=None, root_dir_key=None, data=None + self, script_lines, tmp_file_keys=None, root_dir_key=None, data=None ): data = data or {} if not tmp_file_keys: tmp_file_keys = data.get("tmp_file_keys") or [] - data["script"] = script + data["script_lines"] = script_lines data["tmp_file_keys"] = tmp_file_keys data["root_dir_key"] = root_dir_key - self._script = script + self._script_lines = script_lines self._tmp_file_keys = tmp_file_keys self._root_dir_key = root_dir_key super().__init__(data) def execute(self): filepath_by_key = {} + script = self._script_lines + if isinstance(script, list): + script = "\n".join(script) + for key in self._tmp_file_keys: output_file = tempfile.NamedTemporaryFile( mode="w", prefix=TMP_FILE_PREFIX, suffix=".txt", delete=False @@ -159,15 +163,17 @@ class ExecuteGeorgeScript(BaseCommand): output_file.close() format_key = "{" + key + "}" output_path = output_file.name.replace("\\", "/") - self._script.replace(format_key, output_path) + script = script.replace(format_key, output_path) filepath_by_key[key] = output_path if self._root_dir_key: job_queue_root = self.job_queue_root() format_key = "{" + self._root_dir_key + "}" - self._script.replace(format_key, job_queue_root.replace("\\", "/")) + script = script.replace( + format_key, job_queue_root.replace("\\", "/") + ) - self.execute_george_through_file(self._script) + self.execute_george_through_file(script) result = {} for key, filepath in filepath_by_key.items(): @@ -180,10 +186,10 @@ class ExecuteGeorgeScript(BaseCommand): @classmethod def from_existing(cls, data): - script = data.pop("script") + script_lines = data.pop("script_lines") tmp_file_keys = data.pop("tmp_file_keys", None) root_dir_key = data.pop("root_dir_key", None) - return cls(script, tmp_file_keys, root_dir_key, data) + return cls(script_lines, tmp_file_keys, root_dir_key, data) class CollectSceneData(BaseCommand): diff --git a/openpype/hosts/webpublisher/plugins/publish/collect_tvpaint_instances.py b/openpype/hosts/webpublisher/plugins/publish/collect_tvpaint_instances.py index 890f3cc6af..dd0d421447 100644 --- a/openpype/hosts/webpublisher/plugins/publish/collect_tvpaint_instances.py +++ b/openpype/hosts/webpublisher/plugins/publish/collect_tvpaint_instances.py @@ -15,7 +15,7 @@ from openpype.lib import get_subset_name_with_asset_doc class CollectTVPaintInstances(pyblish.api.ContextPlugin): label = "Collect TVPaint Instances" - order = pyblish.api.CollectorOrder - 0.35 + order = pyblish.api.CollectorOrder + 0.2 hosts = ["webpublisher"] targets = ["tvpaint"] @@ -136,14 +136,10 @@ class CollectTVPaintInstances(pyblish.api.ContextPlugin): new_instances.append(instance) # Set data same for all instances - scene_fps = context.data["sceneData"]["sceneFps"] frame_start = context.data.get("frameStart") frame_end = context.data.get("frameEnd") for instance in new_instances: - if instance.data.get("fps") is None: - instance.data["fps"] = scene_fps - if ( instance.data.get("frameStart") is None or instance.data.get("frameEnd") is None @@ -157,6 +153,12 @@ class CollectTVPaintInstances(pyblish.api.ContextPlugin): if instance.data.get("task") is None: instance.data["task"] = task_name + if "representations" not in instance.data: + instance.data["representations"] = [] + + if "source" not in instance.data: + instance.data["source"] = "webpublisher" + def _create_workfile_instance(self, context, subset_name): workfile_path = context.data["workfilePath"] staging_dir = os.path.dirname(workfile_path) @@ -168,7 +170,7 @@ class CollectTVPaintInstances(pyblish.api.ContextPlugin): "label": subset_name, "subset": subset_name, "family": self.workfile_family, - "families": [self.workfile_family], + "families": [], "stagingDir": staging_dir, "representations": [{ "name": ext.lstrip("."), @@ -179,8 +181,7 @@ class CollectTVPaintInstances(pyblish.api.ContextPlugin): }) def _create_review_instance(self, context, subset_name): - context_staging_dir = context.data["contextStagingDir"] - staging_dir = os.path.join(context_staging_dir, subset_name) + staging_dir = self._create_staging_dir(context, subset_name) layers_data = context.data["layersData"] # Filter hidden layers filtered_layers_data = [ @@ -193,11 +194,13 @@ class CollectTVPaintInstances(pyblish.api.ContextPlugin): "label": subset_name, "subset": subset_name, "family": self.review_family, + "families": [], "layers": filtered_layers_data, "stagingDir": staging_dir }) def _create_render_pass_instance(self, context, layer, subset_name): + staging_dir = self._create_staging_dir(context, subset_name) # Global instance data modifications # Fill families return context.create_instance(**{ @@ -208,10 +211,12 @@ class CollectTVPaintInstances(pyblish.api.ContextPlugin): # Add `review` family for thumbnail integration "families": [self.render_pass_family, "review"], "representations": [], - "layers": [layer] + "layers": [layer], + "stagingDir": staging_dir }) def _create_render_layer_instance(self, context, layers, subset_name): + staging_dir = self._create_staging_dir(context, subset_name) # Global instance data modifications # Fill families return context.create_instance(**{ @@ -222,5 +227,13 @@ class CollectTVPaintInstances(pyblish.api.ContextPlugin): # Add `review` family for thumbnail integration "families": [self.render_pass_family, "review"], "representations": [], - "layers": layers + "layers": layers, + "stagingDir": staging_dir }) + + def _create_staging_dir(self, context, subset_name): + context_staging_dir = context.data["contextStagingDir"] + staging_dir = os.path.join(context_staging_dir, subset_name) + if not os.path.exists(staging_dir): + os.makedirs(staging_dir) + return staging_dir diff --git a/openpype/hosts/webpublisher/plugins/publish/collect_tvpaint_workfile_data.py b/openpype/hosts/webpublisher/plugins/publish/collect_tvpaint_workfile_data.py index 3cfad7c7bd..147b6f3d88 100644 --- a/openpype/hosts/webpublisher/plugins/publish/collect_tvpaint_workfile_data.py +++ b/openpype/hosts/webpublisher/plugins/publish/collect_tvpaint_workfile_data.py @@ -32,10 +32,13 @@ class CollectTVPaintWorkfileData(pyblish.api.ContextPlugin): # Get JobQueue module modules = context.data["openPypeModules"] job_queue_module = modules["job_queue"] + jobs_root = job_queue_module.get_jobs_root() + if not jobs_root: + raise ValueError("Job Queue root is not set.") - context_staging_dir = self._create_context_staging_dir( - job_queue_module - ) + context.data["jobsRoot"] = jobs_root + + context_staging_dir = self._create_context_staging_dir(jobs_root) workfile_path = self._extract_workfile_path( context, context_staging_dir ) @@ -85,11 +88,7 @@ class CollectTVPaintWorkfileData(pyblish.api.ContextPlugin): context.data["layersExposureFrames"] = exposure_frames_by_layer_id context.data["layersPrePostBehavior"] = pre_post_beh_by_layer_id - def _create_context_staging_dir(self, job_queue_module): - jobs_root = job_queue_module.get_jobs_root() - if not jobs_root: - raise ValueError("Job Queue root is not set.") - + def _create_context_staging_dir(self, jobs_root): if not os.path.exists(jobs_root): os.makedirs(jobs_root) diff --git a/openpype/hosts/webpublisher/plugins/publish/extract_tvpaint_workfile.py b/openpype/hosts/webpublisher/plugins/publish/extract_tvpaint_workfile.py index a3db74b66f..3016e9683e 100644 --- a/openpype/hosts/webpublisher/plugins/publish/extract_tvpaint_workfile.py +++ b/openpype/hosts/webpublisher/plugins/publish/extract_tvpaint_workfile.py @@ -24,15 +24,22 @@ from PIL import Image class ExtractTVPaintSequences(pyblish.api.Extractor): label = "Extract TVPaint Sequences" hosts = ["webpublisher"] - families = ["review", "renderPass", "renderLayer"] targets = ["tvpaint"] + # Context plugin does not have families filtering + families_filter = ["review", "renderPass", "renderLayer"] + + job_queue_root_key = "jobs_root" + # Modifiable with settings review_bg = [255, 255, 255, 255] def process(self, context): # Get workfle path workfile_path = context.data["workfilePath"] + jobs_root = context.data["jobsRoot"] + jobs_root_slashed = jobs_root.replace("\\", "/") + # Prepare scene data scene_data = context.data["sceneData"] scene_mark_in = scene_data["sceneMarkIn"] @@ -64,8 +71,20 @@ class ExtractTVPaintSequences(pyblish.api.Extractor): ExecuteSimpleGeorgeScript("tv_startframe 0") ) + root_key_replacement = "{" + self.job_queue_root_key + "}" after_render_instances = [] for instance in context: + instance_families = set(instance.data.get("families", [])) + instance_families.add(instance.data["family"]) + valid = False + for family in instance_families: + if family in self.families_filter: + valid = True + break + + if not valid: + continue + self.log.info("* Preparing commands for instance \"{}\"".format( instance.data["label"] )) @@ -89,12 +108,12 @@ class ExtractTVPaintSequences(pyblish.api.Extractor): ) ) - # TODO handle this whole staging dir properly # Staging dir must be created during collection - output_dir = instance.data["stagingDir"] - src_root = "c:/" - dst_root = "{worker_root}" - work_output_dir = output_dir.replace(src_root, dst_root) + staging_dir = instance.data["stagingDir"].replace("\\", "/") + + job_root_template = staging_dir.replace( + jobs_root_slashed, root_key_replacement + ) # Frame start/end may be stored as float frame_start = int(instance.data["frameStart"]) @@ -126,18 +145,18 @@ class ExtractTVPaintSequences(pyblish.api.Extractor): # ----------------------------------------------------------------- self.log.debug( - "Files will be rendered to folder: {}".format(output_dir) + "Files will be rendered to folder: {}".format(staging_dir) ) output_filepaths_by_frame_idx = {} for frame_idx in range(mark_in, mark_out + 1): filename = filename_template.format(frame=frame_idx) - filepath = os.path.join(output_dir, filename) + filepath = os.path.join(staging_dir, filename) output_filepaths_by_frame_idx[frame_idx] = filepath # Prepare data for post render processing post_render_data = { - "output_dir": output_dir, + "output_dir": staging_dir, "layers": filtered_layers, "output_filepaths_by_frame_idx": output_filepaths_by_frame_idx, "instance": instance, @@ -152,7 +171,7 @@ class ExtractTVPaintSequences(pyblish.api.Extractor): if instance.data["family"] == "review": self.add_render_review_command( tvpaint_commands, mark_in, mark_out, scene_bg_color, - work_output_dir, filename_template + job_root_template, filename_template ) continue @@ -166,7 +185,8 @@ class ExtractTVPaintSequences(pyblish.api.Extractor): ) filepaths_by_layer_id = self.add_render_command( tvpaint_commands, - work_output_dir, + job_root_template, + staging_dir, filtered_layers, extraction_data_by_layer_id ) @@ -325,7 +345,7 @@ class ExtractTVPaintSequences(pyblish.api.Extractor): mark_in, mark_out, scene_bg_color, - work_output_dir, + job_root_template, filename_template ): """ Export images from TVPaint using `tv_savesequence` command. @@ -340,15 +360,17 @@ class ExtractTVPaintSequences(pyblish.api.Extractor): self.log.debug("Preparing data for rendering.") bg_color = self._get_review_bg_color() first_frame_filepath = "/".join([ - work_output_dir, + job_root_template, filename_template.format(frame=mark_in) - ]).replace("\\", "/") + ]) george_script_lines = [ # Change bg color to color from settings "tv_background \"color\" {} {} {}".format(*bg_color), "tv_SaveMode \"PNG\"", - "export_path = \"{}\"".format(first_frame_filepath), + "export_path = \"{}\"".format( + first_frame_filepath.replace("\\", "/") + ), "tv_savesequence '\"'export_path'\"' {} {}".format( mark_in, mark_out ) @@ -366,13 +388,17 @@ class ExtractTVPaintSequences(pyblish.api.Extractor): george_script_lines.append(" ".join(orig_color_command)) tvpaint_commands.add_command( - ExecuteGeorgeScript("\n".join(george_script_lines)) + ExecuteGeorgeScript( + george_script_lines, + root_dir_key=self.job_queue_root_key + ) ) def add_render_command( self, tvpaint_commands, - work_output_dir, + job_root_template, + staging_dir, layers, extraction_data_by_layer_id ): @@ -402,20 +428,26 @@ class ExtractTVPaintSequences(pyblish.api.Extractor): filenames_by_frame_index = render_data["filenames_by_frame_index"] filepaths_by_frame = {} + command_filepath_by_frame = {} for frame_idx, ref_idx in frame_references.items(): # None reference is skipped because does not have source if ref_idx is None: filepaths_by_frame[frame_idx] = None continue filename = filenames_by_frame_index[frame_idx] - dst_path = "/".join([work_output_dir, filename]) - filepaths_by_frame[frame_idx] = dst_path - if frame_idx != ref_idx: - continue - filepaths_by_layer_id[layer_id] = self._add_render_layer_command( - tvpaint_commands, layer, filepaths_by_frame + filepaths_by_frame[frame_idx] = os.path.join( + staging_dir, filename + ) + if frame_idx == ref_idx: + command_filepath_by_frame[frame_idx] = "/".join( + [job_root_template, filename] + ) + + self._add_render_layer_command( + tvpaint_commands, layer, command_filepath_by_frame ) + filepaths_by_layer_id[layer_id] = filepaths_by_frame return filepaths_by_layer_id @@ -430,7 +462,6 @@ class ExtractTVPaintSequences(pyblish.api.Extractor): "tv_SaveMode \"PNG\"" ] - filepaths_by_frame = {} for frame_idx, filepath in filepaths_by_frame.items(): if filepath is None: continue @@ -438,12 +469,16 @@ class ExtractTVPaintSequences(pyblish.api.Extractor): # Go to frame george_script_lines.append("tv_layerImage {}".format(frame_idx)) # Store image to output - george_script_lines.append("tv_saveimage \"{}\"".format(filepath)) + george_script_lines.append( + "tv_saveimage \"{}\"".format(filepath.replace("\\", "/")) + ) tvpaint_commands.add_command( - ExecuteGeorgeScript("\n".join(george_script_lines)) + ExecuteGeorgeScript( + george_script_lines, + root_dir_key=self.job_queue_root_key + ) ) - return filepaths_by_frame def _finish_layer_render( self,