diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index bc0e00f740..c01ab5122c 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -35,6 +35,9 @@ body: label: Version description: What version are you running? Look to OpenPype Tray options: + - 3.18.8-nightly.1 + - 3.18.7 + - 3.18.7-nightly.5 - 3.18.7-nightly.4 - 3.18.7-nightly.3 - 3.18.7-nightly.2 @@ -132,9 +135,6 @@ body: - 3.15.11-nightly.3 - 3.15.11-nightly.2 - 3.15.11-nightly.1 - - 3.15.10 - - 3.15.10-nightly.2 - - 3.15.10-nightly.1 validations: required: true - type: dropdown diff --git a/CHANGELOG.md b/CHANGELOG.md index 009150ae7d..4ec3448570 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,407 @@ # Changelog +## [3.18.7](https://github.com/ynput/OpenPype/tree/3.18.7) + + +[Full Changelog](https://github.com/ynput/OpenPype/compare/3.18.6...3.18.7) + +### **🆕 New features** + + +
+Chore: Wrapper for click proposal #5928 + +This is a proposal how to resolve issues with `click` python module. Issue https://github.com/ynput/OpenPype/issues/5921 reported that in Houdini 20+ is our click clashing with click in houdini, where is expected higher version. We can't update our version to support older pythons (NOTE older Python 3). + + +___ + +
+ +### **🚀 Enhancements** + + +
+Maya: Add repair action to hidden joints validator #6214 + +Joints Hidden is missing repair action, this adds it back + + +___ + +
+ + +
+Blender: output node and EXR #6086 + +Output node now works correctly for Multilayer EXR and keeps existing links. The output now is handled entirely by the compositor node tree. + + +___ + +
+ + +
+AYON Switch tool: Keep version after switch #6104 + +Keep version if only representation did change. The AYON variant of https://github.com/ynput/OpenPype/pull/4629 + + +___ + +
+ + +
+Loader AYON: Reset loader window on open #6170 + +Make sure loader tool is reset on each show. + + +___ + +
+ + +
+Publisher: Show message with error on action failure #6179 + +This PR adds support for the publisher to show error message from running actions.Errors from actions will otherwise be hidden from user in various console outputs.Also include card for when action is finished. + + +___ + +
+ + +
+AYON Applications: Remove djvview group from default applications #6188 + +The djv does not have group defined in models so the values are not used anywhere. + + +___ + +
+ + +
+General: added fallback for broken ffprobe return #6189 + +Customer provided .exr returned width and height equal to 0 which caused error in `extract_thumbnail`. This tries to use oiiotool to get metadata about file, in our case it read it correctly. + + +___ + +
+ + +
+Photoshop: High scaling in UIs #6190 + +Use `get_openpype_qt_app` to create `QApplication` in Photoshop. + + +___ + +
+ + +
+Ftrack: Status update settings are not case insensitive. #6195 + +Make values for project_settings/ftrack/events/status_update case insensitive. + + +___ + +
+ + +
+Thumbnail product filtering #6197 + +This PR introduces subset filtering for thumbnail extraction. This is to skip passes like zdepth which is not needed and can cause issues with extraction. Also speeds up publishing. + + +___ + +
+ + +
+TimersManager: Idle dialog always on top #6201 + +Make stop timer dialog always on tophttps://app.clickup.com/t/6658547/OP-8033 + + +___ + +
+ + +
+AfterEffects: added toggle for applying values from DB during creation #6204 + +Previously values (resolution, duration) from Asset (eg. DB) were applied explicitly when instance of `render` product type was created. This PR adds toggle to Settings to disable this. (This allows artist to publish non standard length of composition, disabling of `Validate Scene Settings` is still required.) + + +___ + +
+ + +
+Unreal: Update plugin commit #6208 + +Updated unreal plugin to latest main. + + +___ + +
+ +### **🐛 Bug fixes** + + +
+Traypublisher: editorial avoid audio tracks processing #6038 + +Avoiding audio tracks from EDL editorial publishing. + + +___ + +
+ + +
+Resolve Inventory offsets clips when swapping versions #6128 + +Swapped version retain the offset and IDT of the timelime clip.closes: https://github.com/ynput/OpenPype/issues/6125 + + +___ + +
+ + +
+Publisher window as dialog #6176 + +Changing back Publisher window to QDialog. + + +___ + +
+ + +
+Nuke: Validate write node fix error report - OP-8088 #6183 + +Report error was not printing the expected values from settings, but instead the values on the write node, leading to confusing messages like: +``` +Traceback (most recent call last): + File "C:\Users\tokejepsen\AppData\Local\Ynput\AYON\dependency_packages\ayon_2310271602_windows.zip\dependencies\pyblish\plugin.py", line 527, in __explicit_process + runner(*args) + File "C:\Users\tokejepsen\OpenPype\openpype\hosts\nuke\plugins\publish\validate_write_nodes.py", line 135, in process + self._make_error(check) + File "C:\Users\tokejepsen\OpenPype\openpype\hosts\nuke\plugins\publish\validate_write_nodes.py", line 149, in _make_error + raise PublishXmlValidationError( +openpype.pipeline.publish.publish_plugins.PublishXmlValidationError: Write node's knobs values are not correct! +Knob 'channels' > Correct: `rgb` > Wrong: `rgb` +``` +This PR changes the error report to: +``` +Traceback (most recent call last): + File "C:\Users\tokejepsen\AppData\Local\Ynput\AYON\dependency_packages\ayon_2310271602_windows.zip\dependencies\pyblish\plugin.py", line 527, in __explicit_process + runner(*args) + File "C:\Users\tokejepsen\OpenPype\openpype\hosts\nuke\plugins\publish\validate_write_nodes.py", line 135, in process + self._make_error(check) + File "C:\Users\tokejepsen\OpenPype\openpype\hosts\nuke\plugins\publish\validate_write_nodes.py", line 149, in _make_error + raise PublishXmlValidationError( +openpype.pipeline.publish.publish_plugins.PublishXmlValidationError: Write node's knobs values are not correct! +Knob 'channels' > Expected: `['rg']` > Current: `rgb` +``` + + + +___ + +
+ + +
+Nuke: Camera product type loaded is not updating - OP-7973 #6184 + +When updating the camera this error would appear: +``` +(...)openpype/hosts/nuke/plugins/load/load_camera_abc.py", line 142, in update + camera_node = nuke.toNode(object_name) +TypeError: toNode() argument 1 must be str, not Node +``` + + + +___ + +
+ + +
+AYON settings: Use bundle name as variant in dev mode #6187 + +Make sure the bundle name is used in dev mode for settings variant. + + +___ + +
+ + +
+Fusion: fix unwanted change to field name in Settings #6193 + +It should be `image_format` but in previous refactoring PR it fell back to original `output_formats` which caused enum not to show up and propagate into plugin. + + +___ + +
+ + +
+Bugfix: AYON menu disappeared when the workspace has been changed in 3dsMax #6200 + +AYON plugins are not correctly registered when switching to different workspaces. + + +___ + +
+ + +
+TrayPublisher: adding settings category to base creator classes #6202 + +Settings are resolving correctly as they suppose to. + + +___ + +
+ + +
+Nuke: expose knobs backward compatibility fix - OP-8164 #6211 + +Fix backwards compatibility for settings `project_settings/nuke/create/CreateWriteRender/exposed_knobs`. + + +___ + +
+ + +
+AE: fix local render doesn't push thumbnail to Ftrack #6212 + +Without thumbnail review is not clickable from main Versions list + + +___ + +
+ + +
+Nuke: openpype expose knobs validator - OP-8166 #6213 + +Fix exposed knobs validator for backwards compatibility with missing settings. + + +___ + +
+ + +
+Ftrack: Post-launch hook fix value lowering #6221 + +Fix lowerin of values in status mapping. + + +___ + +
+ +### **🔀 Refactored code** + + +
+Maya: Remove `shelf` class and shelf build on maya `userSetup.py` #5837 + +Remove shelf builder logic. It appeared to be unused and had bugs. + + +___ + +
+ +### **Merged pull requests** + + +
+Max: updated implementation of save_scene + small QOL improvements to host #6186 + +- Removed `has_unsaved_changes` from Max host as it looks to have been unused and unimplemented. +- Added and implemented `workfile_has_unsaved_changes` to Max host. +- Mirrored the Houdini host to implement the above into `save_scene` publish for Max. +- Added a line to `startup.ms` which opens the usual 'default' menu inside of Max (see screenshots).Current (Likely opens this menu due to one or more of the startup scripts used to insert OP menu):New: + + +___ + +
+ + +
+Fusion: Use better resolution of Ayon apps on 4k display #6199 + +Changes size (makes it smaller) of Ayon apps (Workfiles, Loader) in Fusion on high definitions displays. + + +___ + +
+ + +
+Update CONTRIBUTING.md #6210 + +Updating contributing guidelines to reflect the EOL state of repository +___ + +
+ + +
+Deadline: Remove redundant instance_skeleton_data code - OP-8269 #6219 + +This PR https://github.com/ynput/OpenPype/pull/5186 re-introduced code about for the `instance_skeleton_data` but its actually not used since this variable gets overwritten later. + + +___ + +
+ + + + ## [3.18.6](https://github.com/ynput/OpenPype/tree/3.18.6) diff --git a/openpype/hosts/blender/api/render_lib.py b/openpype/hosts/blender/api/render_lib.py index b437078ad8..c09cfce502 100644 --- a/openpype/hosts/blender/api/render_lib.py +++ b/openpype/hosts/blender/api/render_lib.py @@ -2,6 +2,7 @@ from pathlib import Path import bpy +from openpype import AYON_SERVER_ENABLED from openpype.settings import get_project_settings from openpype.pipeline import get_current_project_name @@ -47,6 +48,22 @@ def get_multilayer(settings): ["multilayer_exr"]) +def get_renderer(settings): + """Get renderer from blender settings.""" + + return (settings["blender"] + ["RenderSettings"] + ["renderer"]) + + +def get_compositing(settings): + """Get compositing from blender settings.""" + + return (settings["blender"] + ["RenderSettings"] + ["compositing"]) + + def get_render_product(output_path, name, aov_sep): """ Generate the path to the render product. Blender interprets the `#` @@ -91,66 +108,121 @@ def set_render_format(ext, multilayer): image_settings.file_format = "TIFF" -def set_render_passes(settings): - aov_list = (settings["blender"] - ["RenderSettings"] - ["aov_list"]) - - custom_passes = (settings["blender"] - ["RenderSettings"] - ["custom_passes"]) +def set_render_passes(settings, renderer): + aov_list = set(settings["blender"]["RenderSettings"]["aov_list"]) + custom_passes = settings["blender"]["RenderSettings"]["custom_passes"] + # Common passes for both renderers vl = bpy.context.view_layer + # Data Passes vl.use_pass_combined = "combined" in aov_list vl.use_pass_z = "z" in aov_list vl.use_pass_mist = "mist" in aov_list vl.use_pass_normal = "normal" in aov_list + + # Light Passes vl.use_pass_diffuse_direct = "diffuse_light" in aov_list vl.use_pass_diffuse_color = "diffuse_color" in aov_list vl.use_pass_glossy_direct = "specular_light" in aov_list vl.use_pass_glossy_color = "specular_color" in aov_list - vl.eevee.use_pass_volume_direct = "volume_light" in aov_list vl.use_pass_emit = "emission" in aov_list vl.use_pass_environment = "environment" in aov_list - vl.use_pass_shadow = "shadow" in aov_list vl.use_pass_ambient_occlusion = "ao" in aov_list - cycles = vl.cycles + # Cryptomatte Passes + vl.use_pass_cryptomatte_object = "cryptomatte_object" in aov_list + vl.use_pass_cryptomatte_material = "cryptomatte_material" in aov_list + vl.use_pass_cryptomatte_asset = "cryptomatte_asset" in aov_list - cycles.denoising_store_passes = "denoising" in aov_list - cycles.use_pass_volume_direct = "volume_direct" in aov_list - cycles.use_pass_volume_indirect = "volume_indirect" in aov_list + if renderer == "BLENDER_EEVEE": + # Eevee exclusive passes + eevee = vl.eevee + + # Light Passes + vl.use_pass_shadow = "shadow" in aov_list + eevee.use_pass_volume_direct = "volume_light" in aov_list + + # Effects Passes + eevee.use_pass_bloom = "bloom" in aov_list + eevee.use_pass_transparent = "transparent" in aov_list + + # Cryptomatte Passes + vl.use_pass_cryptomatte_accurate = "cryptomatte_accurate" in aov_list + elif renderer == "CYCLES": + # Cycles exclusive passes + cycles = vl.cycles + + # Data Passes + vl.use_pass_position = "position" in aov_list + vl.use_pass_vector = "vector" in aov_list + vl.use_pass_uv = "uv" in aov_list + cycles.denoising_store_passes = "denoising" in aov_list + vl.use_pass_object_index = "object_index" in aov_list + vl.use_pass_material_index = "material_index" in aov_list + cycles.pass_debug_sample_count = "sample_count" in aov_list + + # Light Passes + vl.use_pass_diffuse_indirect = "diffuse_indirect" in aov_list + vl.use_pass_glossy_indirect = "specular_indirect" in aov_list + vl.use_pass_transmission_direct = "transmission_direct" in aov_list + vl.use_pass_transmission_indirect = "transmission_indirect" in aov_list + vl.use_pass_transmission_color = "transmission_color" in aov_list + cycles.use_pass_volume_direct = "volume_light" in aov_list + cycles.use_pass_volume_indirect = "volume_indirect" in aov_list + cycles.use_pass_shadow_catcher = "shadow" in aov_list aovs_names = [aov.name for aov in vl.aovs] for cp in custom_passes: - cp_name = cp[0] + cp_name = cp["attribute"] if AYON_SERVER_ENABLED else cp[0] if cp_name not in aovs_names: aov = vl.aovs.add() aov.name = cp_name else: aov = vl.aovs[cp_name] - aov.type = cp[1].get("type", "VALUE") + aov.type = (cp["value"] + if AYON_SERVER_ENABLED else cp[1].get("type", "VALUE")) - return aov_list, custom_passes + return list(aov_list), custom_passes -def set_node_tree(output_path, name, aov_sep, ext, multilayer): +def _create_aov_slot(name, aov_sep, slots, rpass_name, multi_exr, output_path): + filename = f"{name}{aov_sep}{rpass_name}.####" + slot = slots.new(rpass_name if multi_exr else filename) + filepath = str(output_path / filename.lstrip("/")) + + return slot, filepath + + +def set_node_tree( + output_path, render_product, name, aov_sep, ext, multilayer, compositing +): # Set the scene to use the compositor node tree to render bpy.context.scene.use_nodes = True tree = bpy.context.scene.node_tree - # Get the Render Layers node - rl_node = None + comp_layer_type = "CompositorNodeRLayers" + output_type = "CompositorNodeOutputFile" + compositor_type = "CompositorNodeComposite" + + # Get the Render Layer, Composite and the previous output nodes + render_layer_node = None + composite_node = None + old_output_node = None for node in tree.nodes: - if node.bl_idname == "CompositorNodeRLayers": - rl_node = node + if node.bl_idname == comp_layer_type: + render_layer_node = node + elif node.bl_idname == compositor_type: + composite_node = node + elif node.bl_idname == output_type and "AYON" in node.name: + old_output_node = node + if render_layer_node and composite_node and old_output_node: break # If there's not a Render Layers node, we create it - if not rl_node: - rl_node = tree.nodes.new("CompositorNodeRLayers") + if not render_layer_node: + render_layer_node = tree.nodes.new(comp_layer_type) # Get the enabled output sockets, that are the active passes for the # render. @@ -158,48 +230,81 @@ def set_node_tree(output_path, name, aov_sep, ext, multilayer): exclude_sockets = ["Image", "Alpha", "Noisy Image"] passes = [ socket - for socket in rl_node.outputs + for socket in render_layer_node.outputs if socket.enabled and socket.name not in exclude_sockets ] - # Remove all output nodes - for node in tree.nodes: - if node.bl_idname == "CompositorNodeOutputFile": - tree.nodes.remove(node) - # Create a new output node - output = tree.nodes.new("CompositorNodeOutputFile") + output = tree.nodes.new(output_type) image_settings = bpy.context.scene.render.image_settings output.format.file_format = image_settings.file_format + slots = None + # In case of a multilayer exr, we don't need to use the output node, # because the blender render already outputs a multilayer exr. - if ext == "exr" and multilayer: - output.layer_slots.clear() - return [] + multi_exr = ext == "exr" and multilayer + slots = output.layer_slots if multi_exr else output.file_slots + output.base_path = render_product if multi_exr else str(output_path) - output.file_slots.clear() - output.base_path = str(output_path) + slots.clear() aov_file_products = [] + old_links = { + link.from_socket.name: link for link in tree.links + if link.to_node == old_output_node} + + # Create a new socket for the beauty output + pass_name = "rgba" if multi_exr else "beauty" + slot, _ = _create_aov_slot( + name, aov_sep, slots, pass_name, multi_exr, output_path) + tree.links.new(render_layer_node.outputs["Image"], slot) + + if compositing: + # Create a new socket for the composite output + pass_name = "composite" + comp_socket, filepath = _create_aov_slot( + name, aov_sep, slots, pass_name, multi_exr, output_path) + aov_file_products.append(("Composite", filepath)) + # For each active render pass, we add a new socket to the output node # and link it - for render_pass in passes: - filepath = f"{name}{aov_sep}{render_pass.name}.####" + for rpass in passes: + slot, filepath = _create_aov_slot( + name, aov_sep, slots, rpass.name, multi_exr, output_path) + aov_file_products.append((rpass.name, filepath)) - output.file_slots.new(filepath) + # If the rpass was not connected with the old output node, we connect + # it with the new one. + if not old_links.get(rpass.name): + tree.links.new(rpass, slot) - filename = str(output_path / filepath.lstrip("/")) + for link in list(old_links.values()): + # Check if the socket is still available in the new output node. + socket = output.inputs.get(link.to_socket.name) + # If it is, we connect it with the new output node. + if socket: + tree.links.new(link.from_socket, socket) + # Then, we remove the old link. + tree.links.remove(link) - aov_file_products.append((render_pass.name, filename)) + # If there's a composite node, we connect its input with the new output + if compositing and composite_node: + for link in tree.links: + if link.to_node == composite_node: + tree.links.new(link.from_socket, comp_socket) + break - node_input = output.inputs[-1] + if old_output_node: + output.location = old_output_node.location + tree.nodes.remove(old_output_node) - tree.links.new(render_pass, node_input) + output.name = "AYON File Output" + output.label = "AYON File Output" - return aov_file_products + return [] if multi_exr else aov_file_products def imprint_render_settings(node, data): @@ -228,17 +333,23 @@ def prepare_rendering(asset_group): aov_sep = get_aov_separator(settings) ext = get_image_format(settings) multilayer = get_multilayer(settings) + renderer = get_renderer(settings) + compositing = get_compositing(settings) set_render_format(ext, multilayer) - aov_list, custom_passes = set_render_passes(settings) + bpy.context.scene.render.engine = renderer + aov_list, custom_passes = set_render_passes(settings, renderer) 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( - output_path, name, aov_sep, ext, multilayer) + output_path, render_product, name, aov_sep, + ext, multilayer, compositing) - bpy.context.scene.render.filepath = render_product + # Clear the render filepath, so that the output is handled only by the + # output node in the compositor. + bpy.context.scene.render.filepath = "" render_settings = { "render_folder": render_folder, diff --git a/openpype/hosts/blender/plugins/create/create_render.py b/openpype/hosts/blender/plugins/create/create_render.py index 7fb3e5eb00..e728579286 100644 --- a/openpype/hosts/blender/plugins/create/create_render.py +++ b/openpype/hosts/blender/plugins/create/create_render.py @@ -1,8 +1,10 @@ """Create render.""" import bpy +from openpype.lib import version_up from openpype.hosts.blender.api import plugin from openpype.hosts.blender.api.render_lib import prepare_rendering +from openpype.hosts.blender.api.workio import save_file class CreateRenderlayer(plugin.BaseCreator): @@ -37,6 +39,7 @@ class CreateRenderlayer(plugin.BaseCreator): # settings. Even the validator to check that the file is saved will # detect the file as saved, even if it isn't. The only solution for # now it is to force the file to be saved. - bpy.ops.wm.save_as_mainfile(filepath=bpy.data.filepath) + filepath = version_up(bpy.data.filepath) + save_file(filepath, copy=False) return collection diff --git a/openpype/hosts/blender/plugins/publish/validate_deadline_publish.py b/openpype/hosts/blender/plugins/publish/validate_deadline_publish.py index bb243f08cc..f7860dd75d 100644 --- a/openpype/hosts/blender/plugins/publish/validate_deadline_publish.py +++ b/openpype/hosts/blender/plugins/publish/validate_deadline_publish.py @@ -28,15 +28,27 @@ class ValidateDeadlinePublish(pyblish.api.InstancePlugin, def process(self, instance): if not self.is_active(instance.data): return + + tree = bpy.context.scene.node_tree + output_type = "CompositorNodeOutputFile" + output_node = None + # Remove all output nodes that inlcude "AYON" in the name. + # There should be only one. + for node in tree.nodes: + if node.bl_idname == output_type and "AYON" in node.name: + output_node = node + break + if not output_node: + raise PublishValidationError( + "No output node found in the compositor tree." + ) filepath = bpy.data.filepath file = os.path.basename(filepath) filename, ext = os.path.splitext(file) - if filename not in bpy.context.scene.render.filepath: + if filename not in output_node.base_path: raise PublishValidationError( - "Render output folder " - "doesn't match the blender scene name! " - "Use Repair action to " - "fix the folder file path." + "Render output folder doesn't match the blender scene name! " + "Use Repair action to fix the folder file path." ) @classmethod diff --git a/openpype/modules/deadline/plugins/publish/submit_publish_job.py b/openpype/modules/deadline/plugins/publish/submit_publish_job.py index 82971daee5..4e9df976cd 100644 --- a/openpype/modules/deadline/plugins/publish/submit_publish_job.py +++ b/openpype/modules/deadline/plugins/publish/submit_publish_job.py @@ -321,7 +321,6 @@ class ProcessSubmittedJobOnFarm(pyblish.api.InstancePlugin, return deadline_publish_job_id - def process(self, instance): # type: (pyblish.api.Instance) -> None """Process plugin. @@ -338,151 +337,6 @@ class ProcessSubmittedJobOnFarm(pyblish.api.InstancePlugin, self.log.debug("Skipping local instance.") return - data = instance.data.copy() - context = instance.context - self.context = context - self.anatomy = instance.context.data["anatomy"] - - asset = data.get("asset") or context.data["asset"] - subset = data.get("subset") - - start = instance.data.get("frameStart") - if start is None: - start = context.data["frameStart"] - - end = instance.data.get("frameEnd") - if end is None: - end = context.data["frameEnd"] - - handle_start = instance.data.get("handleStart") - if handle_start is None: - handle_start = context.data["handleStart"] - - handle_end = instance.data.get("handleEnd") - if handle_end is None: - handle_end = context.data["handleEnd"] - - fps = instance.data.get("fps") - if fps is None: - fps = context.data["fps"] - - if data.get("extendFrames", False): - start, end = self._extend_frames( - asset, - subset, - start, - end, - data["overrideExistingFrame"]) - - try: - source = data["source"] - except KeyError: - source = context.data["currentFile"] - - success, rootless_path = ( - self.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 - self.log.warning(( - "Could not find root path for remapping \"{}\"." - " This may cause issues." - ).format(source)) - - family = "render" - if ("prerender" in instance.data["families"] or - "prerender.farm" in instance.data["families"]): - family = "prerender" - families = [family] - - # pass review to families if marked as review - do_not_add_review = False - if data.get("review"): - families.append("review") - elif data.get("review") is False: - self.log.debug("Instance has review explicitly disabled.") - do_not_add_review = True - - instance_skeleton_data = { - "family": family, - "subset": subset, - "families": families, - "asset": asset, - "frameStart": start, - "frameEnd": end, - "handleStart": handle_start, - "handleEnd": handle_end, - "frameStartHandle": start - handle_start, - "frameEndHandle": end + handle_end, - "comment": instance.data["comment"], - "fps": fps, - "source": source, - "extendFrames": data.get("extendFrames"), - "overrideExistingFrame": data.get("overrideExistingFrame"), - "pixelAspect": data.get("pixelAspect", 1), - "resolutionWidth": data.get("resolutionWidth", 1920), - "resolutionHeight": data.get("resolutionHeight", 1080), - "multipartExr": data.get("multipartExr", False), - "jobBatchName": data.get("jobBatchName", ""), - "useSequenceForReview": data.get("useSequenceForReview", True), - # map inputVersions `ObjectId` -> `str` so json supports it - "inputVersions": list(map(str, data.get("inputVersions", []))), - "colorspace": instance.data.get("colorspace"), - "stagingDir_persistent": instance.data.get( - "stagingDir_persistent", False - ) - } - - # skip locking version if we are creating v01 - instance_version = instance.data.get("version") # take this if exists - if instance_version != 1: - instance_skeleton_data["version"] = instance_version - - # transfer specific families from original instance to new render - for item in self.families_transfer: - if item in instance.data.get("families", []): - instance_skeleton_data["families"] += [item] - - # transfer specific properties from original instance based on - # mapping dictionary `instance_transfer` - for key, values in self.instance_transfer.items(): - if key in instance.data.get("families", []): - for v in values: - instance_skeleton_data[v] = instance.data.get(v) - - # look into instance data if representations are not having any - # which are having tag `publish_on_farm` and include them - for repre in instance.data.get("representations", []): - staging_dir = repre.get("stagingDir") - if staging_dir: - success, rootless_staging_dir = ( - self.anatomy.find_root_template_from_path( - staging_dir - ) - ) - if success: - repre["stagingDir"] = rootless_staging_dir - else: - self.log.warning(( - "Could not find root path for remapping \"{}\"." - " This may cause issues on farm." - ).format(staging_dir)) - repre["stagingDir"] = staging_dir - - if "publish_on_farm" in repre.get("tags"): - # create representations attribute of not there - if "representations" not in instance_skeleton_data.keys(): - instance_skeleton_data["representations"] = [] - - instance_skeleton_data["representations"].append(repre) - - instances = None - assert data.get("expectedFiles"), ("Submission from old Pype version" - " - missing expectedFiles") - anatomy = instance.context.data["anatomy"] instance_skeleton_data = create_skeleton_instance( diff --git a/openpype/modules/ftrack/launch_hooks/post_ftrack_changes.py b/openpype/modules/ftrack/launch_hooks/post_ftrack_changes.py index 5c780a51c4..1876ff20eb 100644 --- a/openpype/modules/ftrack/launch_hooks/post_ftrack_changes.py +++ b/openpype/modules/ftrack/launch_hooks/post_ftrack_changes.py @@ -132,7 +132,7 @@ class PostFtrackHook(PostLaunchHook): if key in already_tested: continue - value = value.lower() + value = [i.lower() for i in value] if actual_status in value or "__any__" in value: if key != "__ignore__": next_status_name = key diff --git a/openpype/settings/defaults/project_settings/blender.json b/openpype/settings/defaults/project_settings/blender.json index 385e97ef91..03a5400ced 100644 --- a/openpype/settings/defaults/project_settings/blender.json +++ b/openpype/settings/defaults/project_settings/blender.json @@ -22,7 +22,9 @@ "aov_separator": "underscore", "image_format": "exr", "multilayer_exr": true, - "aov_list": [], + "renderer": "CYCLES", + "compositing": true, + "aov_list": ["combined"], "custom_passes": [] }, "workfile_builder": { diff --git a/openpype/settings/entities/schemas/projects_schema/schema_project_blender.json b/openpype/settings/entities/schemas/projects_schema/schema_project_blender.json index 535d9434a3..2ffdc6070d 100644 --- a/openpype/settings/entities/schemas/projects_schema/schema_project_blender.json +++ b/openpype/settings/entities/schemas/projects_schema/schema_project_blender.json @@ -103,6 +103,22 @@ "type": "label", "label": "Note: Multilayer EXR is only used when output format type set to EXR." }, + { + "key": "renderer", + "label": "Renderer", + "type": "enum", + "multiselection": false, + "defaults": "CYCLES", + "enum_items": [ + {"CYCLES": "Cycles"}, + {"BLENDER_EEVEE": "Eevee"} + ] + }, + { + "key": "compositing", + "type": "boolean", + "label": "Enable Compositing" + }, { "key": "aov_list", "label": "AOVs to create", @@ -110,23 +126,38 @@ "multiselection": true, "defaults": "empty", "enum_items": [ - {"empty": "< empty >"}, {"combined": "Combined"}, {"z": "Z"}, {"mist": "Mist"}, {"normal": "Normal"}, - {"diffuse_light": "Diffuse Light"}, + {"position": "Position (Cycles Only)"}, + {"vector": "Vector (Cycles Only)"}, + {"uv": "UV (Cycles Only)"}, + {"denoising": "Denoising Data (Cycles Only)"}, + {"object_index": "Object Index (Cycles Only)"}, + {"material_index": "Material Index (Cycles Only)"}, + {"sample_count": "Sample Count (Cycles Only)"}, + {"diffuse_light": "Diffuse Light/Direct"}, + {"diffuse_indirect": "Diffuse Indirect (Cycles Only)"}, {"diffuse_color": "Diffuse Color"}, - {"specular_light": "Specular Light"}, - {"specular_color": "Specular Color"}, - {"volume_light": "Volume Light"}, + {"specular_light": "Specular (Glossy) Light/Direct"}, + {"specular_indirect": "Specular (Glossy) Indirect (Cycles Only)"}, + {"specular_color": "Specular (Glossy) Color"}, + {"transmission_light": "Transmission Light/Direct (Cycles Only)"}, + {"transmission_indirect": "Transmission Indirect (Cycles Only)"}, + {"transmission_color": "Transmission Color (Cycles Only)"}, + {"volume_light": "Volume Light/Direct"}, + {"volume_indirect": "Volume Indirect (Cycles Only)"}, {"emission": "Emission"}, {"environment": "Environment"}, - {"shadow": "Shadow"}, + {"shadow": "Shadow/Shadow Catcher"}, {"ao": "Ambient Occlusion"}, - {"denoising": "Denoising"}, - {"volume_direct": "Direct Volumetric Scattering"}, - {"volume_indirect": "Indirect Volumetric Scattering"} + {"bloom": "Bloom (Eevee Only)"}, + {"transparent": "Transparent (Eevee Only)"}, + {"cryptomatte_object": "Cryptomatte Object"}, + {"cryptomatte_material": "Cryptomatte Material"}, + {"cryptomatte_asset": "Cryptomatte Asset"}, + {"cryptomatte_accurate": "Cryptomatte Accurate Mode (Eevee Only)"} ] }, { diff --git a/openpype/version.py b/openpype/version.py index 9e1bd39b3a..95203e17c9 100644 --- a/openpype/version.py +++ b/openpype/version.py @@ -1,3 +1,3 @@ # -*- coding: utf-8 -*- """Package declaring Pype version.""" -__version__ = "3.18.7-nightly.4" +__version__ = "3.18.8-nightly.1" diff --git a/pyproject.toml b/pyproject.toml index 453833aae2..eef6a2e978 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "OpenPype" -version = "3.18.6" # OpenPype +version = "3.18.7" # OpenPype description = "Open VFX and Animation pipeline with support." authors = ["OpenPype Team "] license = "MIT License" diff --git a/server_addon/blender/server/settings/render_settings.py b/server_addon/blender/server/settings/render_settings.py index f91ba1627a..f992ea6fcc 100644 --- a/server_addon/blender/server/settings/render_settings.py +++ b/server_addon/blender/server/settings/render_settings.py @@ -23,6 +23,13 @@ def image_format_enum(): ] +def renderers_enum(): + return [ + {"value": "CYCLES", "label": "Cycles"}, + {"value": "BLENDER_EEVEE", "label": "Eevee"}, + ] + + def aov_list_enum(): return [ {"value": "empty", "label": "< none >"}, @@ -30,18 +37,52 @@ def aov_list_enum(): {"value": "z", "label": "Z"}, {"value": "mist", "label": "Mist"}, {"value": "normal", "label": "Normal"}, - {"value": "diffuse_light", "label": "Diffuse Light"}, + {"value": "position", "label": "Position (Cycles Only)"}, + {"value": "vector", "label": "Vector (Cycles Only)"}, + {"value": "uv", "label": "UV (Cycles Only)"}, + {"value": "denoising", "label": "Denoising Data (Cycles Only)"}, + {"value": "object_index", "label": "Object Index (Cycles Only)"}, + {"value": "material_index", "label": "Material Index (Cycles Only)"}, + {"value": "sample_count", "label": "Sample Count (Cycles Only)"}, + {"value": "diffuse_light", "label": "Diffuse Light/Direct"}, + { + "value": "diffuse_indirect", + "label": "Diffuse Indirect (Cycles Only)" + }, {"value": "diffuse_color", "label": "Diffuse Color"}, - {"value": "specular_light", "label": "Specular Light"}, - {"value": "specular_color", "label": "Specular Color"}, - {"value": "volume_light", "label": "Volume Light"}, + {"value": "specular_light", "label": "Specular (Glossy) Light/Direct"}, + { + "value": "specular_indirect", + "label": "Specular (Glossy) Indirect (Cycles Only)" + }, + {"value": "specular_color", "label": "Specular (Glossy) Color"}, + { + "value": "transmission_light", + "label": "Transmission Light/Direct (Cycles Only)" + }, + { + "value": "transmission_indirect", + "label": "Transmission Indirect (Cycles Only)" + }, + { + "value": "transmission_color", + "label": "Transmission Color (Cycles Only)" + }, + {"value": "volume_light", "label": "Volume Light/Direct"}, + {"value": "volume_indirect", "label": "Volume Indirect (Cycles Only)"}, {"value": "emission", "label": "Emission"}, {"value": "environment", "label": "Environment"}, - {"value": "shadow", "label": "Shadow"}, + {"value": "shadow", "label": "Shadow/Shadow Catcher"}, {"value": "ao", "label": "Ambient Occlusion"}, - {"value": "denoising", "label": "Denoising"}, - {"value": "volume_direct", "label": "Direct Volumetric Scattering"}, - {"value": "volume_indirect", "label": "Indirect Volumetric Scattering"} + {"value": "bloom", "label": "Bloom (Eevee Only)"}, + {"value": "transparent", "label": "Transparent (Eevee Only)"}, + {"value": "cryptomatte_object", "label": "Cryptomatte Object"}, + {"value": "cryptomatte_material", "label": "Cryptomatte Material"}, + {"value": "cryptomatte_asset", "label": "Cryptomatte Asset"}, + { + "value": "cryptomatte_accurate", + "label": "Cryptomatte Accurate Mode (Eevee Only)" + }, ] @@ -81,6 +122,14 @@ class RenderSettingsModel(BaseSettingsModel): multilayer_exr: bool = SettingsField( title="Multilayer (EXR)" ) + renderer: str = SettingsField( + "CYCLES", + title="Renderer", + enum_resolver=renderers_enum + ) + compositing: bool = SettingsField( + title="Enable Compositing" + ) aov_list: list[str] = SettingsField( default_factory=list, enum_resolver=aov_list_enum, @@ -102,6 +151,8 @@ DEFAULT_RENDER_SETTINGS = { "aov_separator": "underscore", "image_format": "exr", "multilayer_exr": True, - "aov_list": [], + "renderer": "CYCLES", + "compositing": True, + "aov_list": ["combined"], "custom_passes": [] } diff --git a/server_addon/blender/server/version.py b/server_addon/blender/server/version.py index 1276d0254f..0a8da88258 100644 --- a/server_addon/blender/server/version.py +++ b/server_addon/blender/server/version.py @@ -1 +1 @@ -__version__ = "0.1.5" +__version__ = "0.1.6"