mirror of
https://github.com/ynput/ayon-core.git
synced 2026-01-02 00:44:52 +01:00
remove old expected files
This commit is contained in:
parent
070baad607
commit
f37319965a
2 changed files with 0 additions and 946 deletions
|
|
@ -1,945 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""Module handling expected render output from Maya.
|
||||
|
||||
This module is used in :mod:`collect_render` and :mod:`collect_vray_scene`.
|
||||
|
||||
Note:
|
||||
To implement new renderer, just create new class inheriting from
|
||||
:class:`AExpectedFiles` and add it to :func:`ExpectedFiles.get()`.
|
||||
|
||||
Attributes:
|
||||
R_SINGLE_FRAME (:class:`re.Pattern`): Find single frame number.
|
||||
R_FRAME_RANGE (:class:`re.Pattern`): Find frame range.
|
||||
R_FRAME_NUMBER (:class:`re.Pattern`): Find frame number in string.
|
||||
R_LAYER_TOKEN (:class:`re.Pattern`): Find layer token in image prefixes.
|
||||
R_AOV_TOKEN (:class:`re.Pattern`): Find AOV token in image prefixes.
|
||||
R_SUBSTITUTE_AOV_TOKEN (:class:`re.Pattern`): Find and substitute AOV token
|
||||
in image prefixes.
|
||||
R_REMOVE_AOV_TOKEN (:class:`re.Pattern`): Find and remove AOV token in
|
||||
image prefixes.
|
||||
R_CLEAN_FRAME_TOKEN (:class:`re.Pattern`): Find and remove unfilled
|
||||
Renderman frame token in image prefix.
|
||||
R_CLEAN_EXT_TOKEN (:class:`re.Pattern`): Find and remove unfilled Renderman
|
||||
extension token in image prefix.
|
||||
R_SUBSTITUTE_LAYER_TOKEN (:class:`re.Pattern`): Find and substitute render
|
||||
layer token in image prefixes.
|
||||
R_SUBSTITUTE_SCENE_TOKEN (:class:`re.Pattern`): Find and substitute scene
|
||||
token in image prefixes.
|
||||
R_SUBSTITUTE_CAMERA_TOKEN (:class:`re.Pattern`): Find and substitute camera
|
||||
token in image prefixes.
|
||||
RENDERER_NAMES (dict): Renderer names mapping between reported name and
|
||||
*human readable* name.
|
||||
IMAGE_PREFIXES (dict): Mapping between renderers and their respective
|
||||
image prefix attribute names.
|
||||
|
||||
Todo:
|
||||
Determine `multipart` from render instance.
|
||||
|
||||
"""
|
||||
|
||||
import types
|
||||
import re
|
||||
import os
|
||||
from abc import ABCMeta, abstractmethod
|
||||
|
||||
import six
|
||||
import attr
|
||||
|
||||
import openpype.hosts.maya.api.lib as lib
|
||||
|
||||
from maya import cmds
|
||||
import maya.app.renderSetup.model.renderSetup as renderSetup
|
||||
|
||||
|
||||
R_SINGLE_FRAME = re.compile(r"^(-?)\d+$")
|
||||
R_FRAME_RANGE = re.compile(r"^(?P<sf>(-?)\d+)-(?P<ef>(-?)\d+)$")
|
||||
R_FRAME_NUMBER = re.compile(r".+\.(?P<frame>[0-9]+)\..+")
|
||||
R_LAYER_TOKEN = re.compile(
|
||||
r".*((?:%l)|(?:<layer>)|(?:<renderlayer>)).*", re.IGNORECASE
|
||||
)
|
||||
R_AOV_TOKEN = re.compile(r".*%a.*|.*<aov>.*|.*<renderpass>.*", re.IGNORECASE)
|
||||
R_SUBSTITUTE_AOV_TOKEN = re.compile(r"%a|<aov>|<renderpass>", re.IGNORECASE)
|
||||
R_REMOVE_AOV_TOKEN = re.compile(
|
||||
r"_%a|\.%a|_<aov>|\.<aov>|_<renderpass>|\.<renderpass>", re.IGNORECASE)
|
||||
# to remove unused renderman tokens
|
||||
R_CLEAN_FRAME_TOKEN = re.compile(r"\.?<f\d>\.?", re.IGNORECASE)
|
||||
R_CLEAN_EXT_TOKEN = re.compile(r"\.?<ext>\.?", re.IGNORECASE)
|
||||
|
||||
R_SUBSTITUTE_LAYER_TOKEN = re.compile(
|
||||
r"%l|<layer>|<renderlayer>", re.IGNORECASE
|
||||
)
|
||||
R_SUBSTITUTE_CAMERA_TOKEN = re.compile(r"%c|<camera>", re.IGNORECASE)
|
||||
R_SUBSTITUTE_SCENE_TOKEN = re.compile(r"%s|<scene>", re.IGNORECASE)
|
||||
|
||||
RENDERER_NAMES = {
|
||||
"mentalray": "MentalRay",
|
||||
"vray": "V-Ray",
|
||||
"arnold": "Arnold",
|
||||
"renderman": "Renderman",
|
||||
"redshift": "Redshift",
|
||||
}
|
||||
|
||||
# not sure about the renderman image prefix
|
||||
IMAGE_PREFIXES = {
|
||||
"mentalray": "defaultRenderGlobals.imageFilePrefix",
|
||||
"vray": "vraySettings.fileNamePrefix",
|
||||
"arnold": "defaultRenderGlobals.imageFilePrefix",
|
||||
"renderman": "rmanGlobals.imageFileFormat",
|
||||
"redshift": "defaultRenderGlobals.imageFilePrefix",
|
||||
}
|
||||
|
||||
|
||||
@attr.s
|
||||
class LayerMetadata(object):
|
||||
"""Data class for Render Layer metadata."""
|
||||
frameStart = attr.ib()
|
||||
frameEnd = attr.ib()
|
||||
cameras = attr.ib()
|
||||
sceneName = attr.ib()
|
||||
layerName = attr.ib()
|
||||
renderer = attr.ib()
|
||||
defaultExt = attr.ib()
|
||||
filePrefix = attr.ib()
|
||||
enabledAOVs = attr.ib()
|
||||
frameStep = attr.ib(default=1)
|
||||
padding = attr.ib(default=4)
|
||||
|
||||
|
||||
class ExpectedFiles:
|
||||
"""Class grouping functionality for all supported renderers.
|
||||
|
||||
Attributes:
|
||||
multipart (bool): Flag if multipart exrs are used.
|
||||
|
||||
"""
|
||||
multipart = False
|
||||
|
||||
def __init__(self, render_instance):
|
||||
"""Constructor."""
|
||||
self._render_instance = render_instance
|
||||
|
||||
def get(self, renderer, layer):
|
||||
"""Get expected files for given renderer and render layer.
|
||||
|
||||
Args:
|
||||
renderer (str): Name of renderer
|
||||
layer (str): Name of render layer
|
||||
|
||||
Returns:
|
||||
dict: Expected rendered files by AOV
|
||||
|
||||
Raises:
|
||||
:exc:`UnsupportedRendererException`: If requested renderer
|
||||
is not supported. It needs to be implemented by extending
|
||||
:class:`AExpectedFiles` and added to this methods ``if``
|
||||
statement.
|
||||
|
||||
"""
|
||||
renderSetup.instance().switchToLayerUsingLegacyName(layer)
|
||||
|
||||
if renderer.lower() == "arnold":
|
||||
return self._get_files(ExpectedFilesArnold(layer,
|
||||
self._render_instance))
|
||||
if renderer.lower() == "vray":
|
||||
return self._get_files(ExpectedFilesVray(
|
||||
layer, self._render_instance))
|
||||
if renderer.lower() == "redshift":
|
||||
return self._get_files(ExpectedFilesRedshift(
|
||||
layer, self._render_instance))
|
||||
if renderer.lower() == "mentalray":
|
||||
return self._get_files(ExpectedFilesMentalray(
|
||||
layer, self._render_instance))
|
||||
if renderer.lower() == "renderman":
|
||||
return self._get_files(ExpectedFilesRenderman(
|
||||
layer, self._render_instance))
|
||||
|
||||
raise UnsupportedRendererException(
|
||||
"unsupported {}".format(renderer)
|
||||
)
|
||||
|
||||
def _get_files(self, renderer):
|
||||
# type: (AExpectedFiles) -> list
|
||||
files = renderer.get_files()
|
||||
self.multipart = renderer.multipart
|
||||
return files
|
||||
|
||||
|
||||
@six.add_metaclass(ABCMeta)
|
||||
class AExpectedFiles:
|
||||
"""Abstract class with common code for all renderers.
|
||||
|
||||
Attributes:
|
||||
renderer (str): name of renderer.
|
||||
layer (str): name of render layer.
|
||||
multipart (bool): flag for multipart exrs.
|
||||
|
||||
"""
|
||||
|
||||
renderer = None
|
||||
layer = None
|
||||
multipart = False
|
||||
|
||||
def __init__(self, layer, render_instance):
|
||||
"""Constructor."""
|
||||
self.layer = layer
|
||||
self.render_instance = render_instance
|
||||
|
||||
@abstractmethod
|
||||
def get_aovs(self):
|
||||
"""To be implemented by renderer class."""
|
||||
|
||||
@staticmethod
|
||||
def sanitize_camera_name(camera):
|
||||
"""Sanitize camera name.
|
||||
|
||||
Remove Maya illegal characters from camera name.
|
||||
|
||||
Args:
|
||||
camera (str): Maya camera name.
|
||||
|
||||
Returns:
|
||||
(str): sanitized camera name
|
||||
|
||||
Example:
|
||||
>>> AExpectedFiles.sanizite_camera_name('test:camera_01')
|
||||
test_camera_01
|
||||
|
||||
"""
|
||||
return re.sub('[^0-9a-zA-Z_]+', '_', camera)
|
||||
|
||||
def get_renderer_prefix(self):
|
||||
"""Return prefix for specific renderer.
|
||||
|
||||
This is for most renderers the same and can be overridden if needed.
|
||||
|
||||
Returns:
|
||||
str: String with image prefix containing tokens
|
||||
|
||||
Raises:
|
||||
:exc:`UnsupportedRendererException`: If we requested image
|
||||
prefix for renderer we know nothing about.
|
||||
See :data:`IMAGE_PREFIXES` for mapping of renderers and
|
||||
image prefixes.
|
||||
|
||||
"""
|
||||
try:
|
||||
file_prefix = cmds.getAttr(IMAGE_PREFIXES[self.renderer])
|
||||
except KeyError:
|
||||
raise UnsupportedRendererException(
|
||||
"Unsupported renderer {}".format(self.renderer)
|
||||
)
|
||||
return file_prefix
|
||||
|
||||
def _get_layer_data(self):
|
||||
# type: () -> LayerMetadata
|
||||
# ______________________________________________
|
||||
# ____________________/ ____________________________________________/
|
||||
# 1 - get scene name /__________________/
|
||||
# ____________________/
|
||||
_, scene_basename = os.path.split(cmds.file(q=True, loc=True))
|
||||
scene_name, _ = os.path.splitext(scene_basename)
|
||||
|
||||
file_prefix = self.get_renderer_prefix()
|
||||
|
||||
if not file_prefix:
|
||||
raise RuntimeError("Image prefix not set")
|
||||
|
||||
layer_name = self.layer
|
||||
if self.layer.startswith("rs_"):
|
||||
layer_name = self.layer[3:]
|
||||
|
||||
return LayerMetadata(
|
||||
frameStart=int(self.get_render_attribute("startFrame")),
|
||||
frameEnd=int(self.get_render_attribute("endFrame")),
|
||||
frameStep=int(self.get_render_attribute("byFrameStep")),
|
||||
padding=int(self.get_render_attribute("extensionPadding")),
|
||||
# if we have <camera> token in prefix path we'll expect output for
|
||||
# every renderable camera in layer.
|
||||
cameras=self.get_renderable_cameras(),
|
||||
sceneName=scene_name,
|
||||
layerName=layer_name,
|
||||
renderer=self.renderer,
|
||||
defaultExt=cmds.getAttr("defaultRenderGlobals.imfPluginKey"),
|
||||
filePrefix=file_prefix,
|
||||
enabledAOVs=self.get_aovs()
|
||||
)
|
||||
|
||||
def _generate_single_file_sequence(
|
||||
self, layer_data, force_aov_name=None):
|
||||
# type: (LayerMetadata, str) -> list
|
||||
expected_files = []
|
||||
for cam in layer_data.cameras:
|
||||
file_prefix = layer_data.filePrefix
|
||||
mappings = (
|
||||
(R_SUBSTITUTE_SCENE_TOKEN, layer_data.sceneName),
|
||||
(R_SUBSTITUTE_LAYER_TOKEN, layer_data.layerName),
|
||||
(R_SUBSTITUTE_CAMERA_TOKEN, self.sanitize_camera_name(cam)),
|
||||
# this is required to remove unfilled aov token, for example
|
||||
# in Redshift
|
||||
(R_REMOVE_AOV_TOKEN, "") if not force_aov_name \
|
||||
else (R_SUBSTITUTE_AOV_TOKEN, force_aov_name),
|
||||
|
||||
(R_CLEAN_FRAME_TOKEN, ""),
|
||||
(R_CLEAN_EXT_TOKEN, ""),
|
||||
)
|
||||
|
||||
for regex, value in mappings:
|
||||
file_prefix = re.sub(regex, value, file_prefix)
|
||||
|
||||
for frame in range(
|
||||
int(layer_data.frameStart),
|
||||
int(layer_data.frameEnd) + 1,
|
||||
int(layer_data.frameStep),
|
||||
):
|
||||
expected_files.append(
|
||||
"{}.{}.{}".format(
|
||||
file_prefix,
|
||||
str(frame).rjust(layer_data.padding, "0"),
|
||||
layer_data.defaultExt,
|
||||
)
|
||||
)
|
||||
return expected_files
|
||||
|
||||
def _generate_aov_file_sequences(self, layer_data):
|
||||
# type: (LayerMetadata) -> list
|
||||
expected_files = []
|
||||
aov_file_list = {}
|
||||
for aov in layer_data.enabledAOVs:
|
||||
for cam in layer_data.cameras:
|
||||
file_prefix = layer_data.filePrefix
|
||||
|
||||
mappings = (
|
||||
(R_SUBSTITUTE_SCENE_TOKEN, layer_data.sceneName),
|
||||
(R_SUBSTITUTE_LAYER_TOKEN, layer_data.layerName),
|
||||
(R_SUBSTITUTE_CAMERA_TOKEN,
|
||||
self.sanitize_camera_name(cam)),
|
||||
(R_SUBSTITUTE_AOV_TOKEN, aov[0]),
|
||||
(R_CLEAN_FRAME_TOKEN, ""),
|
||||
(R_CLEAN_EXT_TOKEN, ""),
|
||||
)
|
||||
|
||||
for regex, value in mappings:
|
||||
file_prefix = re.sub(regex, value, file_prefix)
|
||||
|
||||
aov_files = []
|
||||
for frame in range(
|
||||
int(layer_data.frameStart),
|
||||
int(layer_data.frameEnd) + 1,
|
||||
int(layer_data.frameStep),
|
||||
):
|
||||
aov_files.append(
|
||||
"{}.{}.{}".format(
|
||||
file_prefix,
|
||||
str(frame).rjust(layer_data.padding, "0"),
|
||||
aov[1],
|
||||
)
|
||||
)
|
||||
|
||||
# if we have more then one renderable camera, append
|
||||
# camera name to AOV to allow per camera AOVs.
|
||||
aov_name = aov[0]
|
||||
if len(layer_data.cameras) > 1:
|
||||
aov_name = "{}_{}".format(aov[0],
|
||||
self.sanitize_camera_name(cam))
|
||||
|
||||
aov_file_list[aov_name] = aov_files
|
||||
file_prefix = layer_data.filePrefix
|
||||
|
||||
expected_files.append(aov_file_list)
|
||||
return expected_files
|
||||
|
||||
def get_files(self):
|
||||
"""Return list of expected files.
|
||||
|
||||
It will translate render token strings ('<RenderPass>', etc.) to
|
||||
their values. This task is tricky as every renderer deals with this
|
||||
differently. It depends on `get_aovs()` abstract method implemented
|
||||
for every supported renderer.
|
||||
|
||||
"""
|
||||
layer_data = self._get_layer_data()
|
||||
|
||||
expected_files = []
|
||||
if layer_data.enabledAOVs:
|
||||
return self._generate_aov_file_sequences(layer_data)
|
||||
else:
|
||||
return self._generate_single_file_sequence(layer_data)
|
||||
|
||||
def get_renderable_cameras(self):
|
||||
# type: () -> list
|
||||
"""Get all renderable cameras.
|
||||
|
||||
Returns:
|
||||
list: list of renderable cameras.
|
||||
|
||||
"""
|
||||
cam_parents = [
|
||||
cmds.listRelatives(x, ap=True)[-1] for x in cmds.ls(cameras=True)
|
||||
]
|
||||
|
||||
return [
|
||||
cam
|
||||
for cam in cam_parents
|
||||
if self.maya_is_true(cmds.getAttr("{}.renderable".format(cam)))
|
||||
]
|
||||
|
||||
@staticmethod
|
||||
def maya_is_true(attr_val):
|
||||
"""Whether a Maya attr evaluates to True.
|
||||
|
||||
When querying an attribute value from an ambiguous object the
|
||||
Maya API will return a list of values, which need to be properly
|
||||
handled to evaluate properly.
|
||||
|
||||
Args:
|
||||
attr_val (mixed): Maya attribute to be evaluated as bool.
|
||||
|
||||
Returns:
|
||||
bool: cast Maya attribute to Pythons boolean value.
|
||||
|
||||
"""
|
||||
if isinstance(attr_val, types.BooleanType):
|
||||
return attr_val
|
||||
if isinstance(attr_val, (types.ListType, types.GeneratorType)):
|
||||
return any(attr_val)
|
||||
|
||||
return bool(attr_val)
|
||||
|
||||
@staticmethod
|
||||
def get_layer_overrides(attribute):
|
||||
"""Get overrides for attribute on current render layer.
|
||||
|
||||
Args:
|
||||
attribute (str): Maya attribute name.
|
||||
|
||||
Returns:
|
||||
Value of attribute override.
|
||||
|
||||
"""
|
||||
connections = cmds.listConnections(attribute, plugs=True)
|
||||
if connections:
|
||||
for connection in connections:
|
||||
if connection:
|
||||
# node_name = connection.split(".")[0]
|
||||
|
||||
attr_name = "%s.value" % ".".join(
|
||||
connection.split(".")[:-1]
|
||||
)
|
||||
yield cmds.getAttr(attr_name)
|
||||
|
||||
def get_render_attribute(self, attribute):
|
||||
"""Get attribute from render options.
|
||||
|
||||
Args:
|
||||
attribute (str): name of attribute to be looked up.
|
||||
|
||||
Returns:
|
||||
Attribute value
|
||||
|
||||
"""
|
||||
return lib.get_attr_in_layer(
|
||||
"defaultRenderGlobals.{}".format(attribute), layer=self.layer
|
||||
)
|
||||
|
||||
|
||||
class ExpectedFilesArnold(AExpectedFiles):
|
||||
"""Expected files for Arnold renderer.
|
||||
|
||||
Attributes:
|
||||
aiDriverExtension (dict): Arnold AOV driver extension mapping.
|
||||
Is there a better way?
|
||||
renderer (str): name of renderer.
|
||||
|
||||
"""
|
||||
|
||||
aiDriverExtension = {
|
||||
"jpeg": "jpg",
|
||||
"exr": "exr",
|
||||
"deepexr": "exr",
|
||||
"png": "png",
|
||||
"tiff": "tif",
|
||||
"mtoa_shaders": "ass", # TODO: research what those last two should be
|
||||
"maya": "",
|
||||
}
|
||||
|
||||
def __init__(self, layer, render_instance):
|
||||
"""Constructor."""
|
||||
super(ExpectedFilesArnold, self).__init__(layer, render_instance)
|
||||
self.renderer = "arnold"
|
||||
|
||||
def get_aovs(self):
|
||||
"""Get all AOVs.
|
||||
|
||||
See Also:
|
||||
:func:`AExpectedFiles.get_aovs()`
|
||||
|
||||
Raises:
|
||||
:class:`AOVError`: If AOV cannot be determined.
|
||||
|
||||
"""
|
||||
enabled_aovs = []
|
||||
try:
|
||||
if not (
|
||||
cmds.getAttr("defaultArnoldRenderOptions.aovMode")
|
||||
and not cmds.getAttr("defaultArnoldDriver.mergeAOVs") # noqa: W503, E501
|
||||
):
|
||||
# AOVs are merged in mutli-channel file
|
||||
self.multipart = True
|
||||
return enabled_aovs
|
||||
except ValueError:
|
||||
# this occurs when Render Setting windows was not opened yet. In
|
||||
# such case there are no Arnold options created so query for AOVs
|
||||
# will fail. We terminate here as there are no AOVs specified then.
|
||||
# This state will most probably fail later on some Validator
|
||||
# anyway.
|
||||
return enabled_aovs
|
||||
|
||||
# AOVs are set to be rendered separately. We should expect
|
||||
# <RenderPass> token in path.
|
||||
|
||||
# handle aovs from references
|
||||
use_ref_aovs = self.render_instance.data.get(
|
||||
"useReferencedAovs", False) or False
|
||||
|
||||
ai_aovs = cmds.ls(type="aiAOV")
|
||||
if not use_ref_aovs:
|
||||
ref_aovs = cmds.ls(type="aiAOV", referencedNodes=True)
|
||||
ai_aovs = list(set(ai_aovs) - set(ref_aovs))
|
||||
|
||||
for aov in ai_aovs:
|
||||
enabled = self.maya_is_true(cmds.getAttr("{}.enabled".format(aov)))
|
||||
ai_driver = cmds.listConnections("{}.outputs".format(aov))[0]
|
||||
ai_translator = cmds.getAttr("{}.aiTranslator".format(ai_driver))
|
||||
try:
|
||||
aov_ext = self.aiDriverExtension[ai_translator]
|
||||
except KeyError:
|
||||
msg = (
|
||||
"Unrecognized arnold " "driver format for AOV - {}"
|
||||
).format(cmds.getAttr("{}.name".format(aov)))
|
||||
raise AOVError(msg)
|
||||
|
||||
for override in self.get_layer_overrides(
|
||||
"{}.enabled".format(aov)
|
||||
):
|
||||
enabled = self.maya_is_true(override)
|
||||
if enabled:
|
||||
# If aov RGBA is selected, arnold will translate it to `beauty`
|
||||
aov_name = cmds.getAttr("%s.name" % aov)
|
||||
if aov_name == "RGBA":
|
||||
aov_name = "beauty"
|
||||
enabled_aovs.append((aov_name, aov_ext))
|
||||
# Append 'beauty' as this is arnolds
|
||||
# default. If <RenderPass> token is specified and no AOVs are
|
||||
# defined, this will be used.
|
||||
enabled_aovs.append(
|
||||
(u"beauty", cmds.getAttr("defaultRenderGlobals.imfPluginKey"))
|
||||
)
|
||||
return enabled_aovs
|
||||
|
||||
|
||||
class ExpectedFilesVray(AExpectedFiles):
|
||||
"""Expected files for V-Ray renderer."""
|
||||
|
||||
def __init__(self, layer, render_instance):
|
||||
"""Constructor."""
|
||||
super(ExpectedFilesVray, self).__init__(layer, render_instance)
|
||||
self.renderer = "vray"
|
||||
|
||||
def get_renderer_prefix(self):
|
||||
"""Get image prefix for V-Ray.
|
||||
|
||||
This overrides :func:`AExpectedFiles.get_renderer_prefix()` as
|
||||
we must add `<aov>` token manually.
|
||||
|
||||
See also:
|
||||
:func:`AExpectedFiles.get_renderer_prefix()`
|
||||
|
||||
"""
|
||||
prefix = super(ExpectedFilesVray, self).get_renderer_prefix()
|
||||
prefix = "{}_<aov>".format(prefix)
|
||||
return prefix
|
||||
|
||||
def _get_layer_data(self):
|
||||
# type: () -> LayerMetadata
|
||||
"""Override to get vray specific extension."""
|
||||
layer_data = super(ExpectedFilesVray, self)._get_layer_data()
|
||||
default_ext = cmds.getAttr("vraySettings.imageFormatStr")
|
||||
if default_ext in ["exr (multichannel)", "exr (deep)"]:
|
||||
default_ext = "exr"
|
||||
layer_data.defaultExt = default_ext
|
||||
layer_data.padding = cmds.getAttr("vraySettings.fileNamePadding")
|
||||
return layer_data
|
||||
|
||||
def get_files(self):
|
||||
"""Get expected files.
|
||||
|
||||
This overrides :func:`AExpectedFiles.get_files()` as we
|
||||
we need to add one sequence for plain beauty if AOVs are enabled
|
||||
as vray output beauty without 'beauty' in filename.
|
||||
|
||||
"""
|
||||
expected_files = super(ExpectedFilesVray, self).get_files()
|
||||
|
||||
layer_data = self._get_layer_data()
|
||||
# remove 'beauty' from filenames as vray doesn't output it
|
||||
update = {}
|
||||
if layer_data.enabledAOVs:
|
||||
for aov, seqs in expected_files[0].items():
|
||||
if aov.startswith("beauty"):
|
||||
new_list = []
|
||||
for seq in seqs:
|
||||
new_list.append(seq.replace("_beauty", ""))
|
||||
update[aov] = new_list
|
||||
|
||||
expected_files[0].update(update)
|
||||
return expected_files
|
||||
|
||||
def get_aovs(self):
|
||||
"""Get all AOVs.
|
||||
|
||||
See Also:
|
||||
:func:`AExpectedFiles.get_aovs()`
|
||||
|
||||
"""
|
||||
enabled_aovs = []
|
||||
|
||||
try:
|
||||
# really? do we set it in vray just by selecting multichannel exr?
|
||||
if (
|
||||
cmds.getAttr("vraySettings.imageFormatStr")
|
||||
== "exr (multichannel)" # noqa: W503
|
||||
):
|
||||
# AOVs are merged in mutli-channel file
|
||||
self.multipart = True
|
||||
return enabled_aovs
|
||||
except ValueError:
|
||||
# this occurs when Render Setting windows was not opened yet. In
|
||||
# such case there are no VRay options created so query for AOVs
|
||||
# will fail. We terminate here as there are no AOVs specified then.
|
||||
# This state will most probably fail later on some Validator
|
||||
# anyway.
|
||||
return enabled_aovs
|
||||
|
||||
default_ext = cmds.getAttr("vraySettings.imageFormatStr")
|
||||
if default_ext in ["exr (multichannel)", "exr (deep)"]:
|
||||
default_ext = "exr"
|
||||
|
||||
# add beauty as default
|
||||
enabled_aovs.append(
|
||||
(u"beauty", default_ext)
|
||||
)
|
||||
|
||||
# handle aovs from references
|
||||
use_ref_aovs = self.render_instance.data.get(
|
||||
"useReferencedAovs", False) or False
|
||||
|
||||
# this will have list of all aovs no matter if they are coming from
|
||||
# reference or not.
|
||||
vr_aovs = cmds.ls(
|
||||
type=["VRayRenderElement", "VRayRenderElementSet"]) or []
|
||||
if not use_ref_aovs:
|
||||
ref_aovs = cmds.ls(
|
||||
type=["VRayRenderElement", "VRayRenderElementSet"],
|
||||
referencedNodes=True) or []
|
||||
# get difference
|
||||
vr_aovs = list(set(vr_aovs) - set(ref_aovs))
|
||||
|
||||
for aov in vr_aovs:
|
||||
enabled = self.maya_is_true(cmds.getAttr("{}.enabled".format(aov)))
|
||||
for override in self.get_layer_overrides(
|
||||
"{}.enabled".format(aov)
|
||||
):
|
||||
enabled = self.maya_is_true(override)
|
||||
|
||||
if enabled:
|
||||
enabled_aovs.append(
|
||||
(self._get_vray_aov_name(aov), default_ext))
|
||||
|
||||
return enabled_aovs
|
||||
|
||||
@staticmethod
|
||||
def _get_vray_aov_name(node):
|
||||
"""Get AOVs name from Vray.
|
||||
|
||||
Args:
|
||||
node (str): aov node name.
|
||||
|
||||
Returns:
|
||||
str: aov name.
|
||||
|
||||
"""
|
||||
vray_name = None
|
||||
vray_explicit_name = None
|
||||
vray_file_name = None
|
||||
for node_attr in cmds.listAttr(node):
|
||||
if node_attr.startswith("vray_filename"):
|
||||
vray_file_name = cmds.getAttr("{}.{}".format(node, node_attr))
|
||||
elif node_attr.startswith("vray_name"):
|
||||
vray_name = cmds.getAttr("{}.{}".format(node, node_attr))
|
||||
elif node_attr.startswith("vray_explicit_name"):
|
||||
vray_explicit_name = cmds.getAttr(
|
||||
"{}.{}".format(node, node_attr))
|
||||
|
||||
if vray_file_name is not None and vray_file_name != "":
|
||||
final_name = vray_file_name
|
||||
elif vray_explicit_name is not None and vray_explicit_name != "":
|
||||
final_name = vray_explicit_name
|
||||
elif vray_name is not None and vray_name != "":
|
||||
final_name = vray_name
|
||||
else:
|
||||
continue
|
||||
# special case for Material Select elements - these are named
|
||||
# based on the materia they are connected to.
|
||||
if "vray_mtl_mtlselect" in cmds.listAttr(node):
|
||||
connections = cmds.listConnections(
|
||||
"{}.vray_mtl_mtlselect".format(node))
|
||||
if connections:
|
||||
final_name += '_{}'.format(str(connections[0]))
|
||||
|
||||
return final_name
|
||||
|
||||
|
||||
class ExpectedFilesRedshift(AExpectedFiles):
|
||||
"""Expected files for Redshift renderer.
|
||||
|
||||
Attributes:
|
||||
|
||||
unmerged_aovs (list): Name of aovs that are not merged into resulting
|
||||
exr and we need them specified in expectedFiles output.
|
||||
|
||||
"""
|
||||
|
||||
unmerged_aovs = ["Cryptomatte"]
|
||||
|
||||
def __init__(self, layer, render_instance):
|
||||
"""Construtor."""
|
||||
super(ExpectedFilesRedshift, self).__init__(layer, render_instance)
|
||||
self.renderer = "redshift"
|
||||
|
||||
def get_renderer_prefix(self):
|
||||
"""Get image prefix for Redshift.
|
||||
|
||||
This overrides :func:`AExpectedFiles.get_renderer_prefix()` as
|
||||
we must add `<aov>` token manually.
|
||||
|
||||
See also:
|
||||
:func:`AExpectedFiles.get_renderer_prefix()`
|
||||
|
||||
"""
|
||||
prefix = super(ExpectedFilesRedshift, self).get_renderer_prefix()
|
||||
prefix = "{}.<aov>".format(prefix)
|
||||
return prefix
|
||||
|
||||
def get_files(self):
|
||||
"""Get expected files.
|
||||
|
||||
This overrides :func:`AExpectedFiles.get_files()` as we
|
||||
we need to add one sequence for plain beauty if AOVs are enabled
|
||||
as vray output beauty without 'beauty' in filename.
|
||||
|
||||
"""
|
||||
expected_files = super(ExpectedFilesRedshift, self).get_files()
|
||||
layer_data = self._get_layer_data()
|
||||
|
||||
# Redshift doesn't merge Cryptomatte AOV to final exr. We need to check
|
||||
# for such condition and add it to list of expected files.
|
||||
|
||||
for aov in layer_data.enabledAOVs:
|
||||
if aov[0].lower() == "cryptomatte":
|
||||
aov_name = aov[0]
|
||||
expected_files.append(
|
||||
{aov_name: self._generate_single_file_sequence(layer_data)}
|
||||
)
|
||||
|
||||
if layer_data.get("enabledAOVs"):
|
||||
# because if Beauty is added manually, it will be rendered as
|
||||
# 'Beauty_other' in file name and "standard" beauty will have
|
||||
# 'Beauty' in its name. When disabled, standard output will be
|
||||
# without `Beauty`.
|
||||
if expected_files[0].get(u"Beauty"):
|
||||
expected_files[0][u"Beauty_other"] = expected_files[0].pop(
|
||||
u"Beauty")
|
||||
new_list = [
|
||||
seq.replace(".Beauty", ".Beauty_other")
|
||||
for seq in expected_files[0][u"Beauty_other"]
|
||||
]
|
||||
|
||||
expected_files[0][u"Beauty_other"] = new_list
|
||||
expected_files[0][u"Beauty"] = self._generate_single_file_sequence( # noqa: E501
|
||||
layer_data, force_aov_name="Beauty"
|
||||
)
|
||||
else:
|
||||
expected_files[0][u"Beauty"] = self._generate_single_file_sequence( # noqa: E501
|
||||
layer_data
|
||||
)
|
||||
|
||||
return expected_files
|
||||
|
||||
def get_aovs(self):
|
||||
"""Get all AOVs.
|
||||
|
||||
See Also:
|
||||
:func:`AExpectedFiles.get_aovs()`
|
||||
|
||||
"""
|
||||
enabled_aovs = []
|
||||
|
||||
try:
|
||||
if self.maya_is_true(
|
||||
cmds.getAttr("redshiftOptions.exrForceMultilayer")
|
||||
):
|
||||
# AOVs are merged in mutli-channel file
|
||||
self.multipart = True
|
||||
return enabled_aovs
|
||||
except ValueError:
|
||||
# this occurs when Render Setting windows was not opened yet. In
|
||||
# such case there are no Redshift options created so query for AOVs
|
||||
# will fail. We terminate here as there are no AOVs specified then.
|
||||
# This state will most probably fail later on some Validator
|
||||
# anyway.
|
||||
return enabled_aovs
|
||||
|
||||
default_ext = cmds.getAttr(
|
||||
"redshiftOptions.imageFormat", asString=True)
|
||||
rs_aovs = cmds.ls(type="RedshiftAOV", referencedNodes=False)
|
||||
|
||||
for aov in rs_aovs:
|
||||
enabled = self.maya_is_true(cmds.getAttr("{}.enabled".format(aov)))
|
||||
for override in self.get_layer_overrides(
|
||||
"{}.enabled".format(aov)
|
||||
):
|
||||
enabled = self.maya_is_true(override)
|
||||
|
||||
if enabled:
|
||||
# If AOVs are merged into multipart exr, append AOV only if it
|
||||
# is in the list of AOVs that renderer cannot (or will not)
|
||||
# merge into final exr.
|
||||
if self.maya_is_true(
|
||||
cmds.getAttr("redshiftOptions.exrForceMultilayer")
|
||||
):
|
||||
if cmds.getAttr("%s.name" % aov) in self.unmerged_aovs:
|
||||
enabled_aovs.append(
|
||||
(cmds.getAttr("%s.name" % aov), default_ext)
|
||||
)
|
||||
else:
|
||||
enabled_aovs.append(
|
||||
(cmds.getAttr("%s.name" % aov), default_ext)
|
||||
)
|
||||
|
||||
if self.maya_is_true(
|
||||
cmds.getAttr("redshiftOptions.exrForceMultilayer")
|
||||
):
|
||||
# AOVs are merged in mutli-channel file
|
||||
self.multipart = True
|
||||
|
||||
return enabled_aovs
|
||||
|
||||
|
||||
class ExpectedFilesRenderman(AExpectedFiles):
|
||||
"""Expected files for Renderman renderer.
|
||||
|
||||
Warning:
|
||||
This is very rudimentary and needs more love and testing.
|
||||
"""
|
||||
|
||||
def __init__(self, layer, render_instance):
|
||||
"""Constructor."""
|
||||
super(ExpectedFilesRenderman, self).__init__(layer, render_instance)
|
||||
self.renderer = "renderman"
|
||||
|
||||
def get_aovs(self):
|
||||
"""Get all AOVs.
|
||||
|
||||
See Also:
|
||||
:func:`AExpectedFiles.get_aovs()`
|
||||
|
||||
"""
|
||||
enabled_aovs = []
|
||||
|
||||
default_ext = "exr"
|
||||
displays = cmds.listConnections("rmanGlobals.displays")
|
||||
for aov in displays:
|
||||
aov_name = str(aov)
|
||||
if aov_name == "rmanDefaultDisplay":
|
||||
aov_name = "beauty"
|
||||
|
||||
enabled = self.maya_is_true(cmds.getAttr("{}.enable".format(aov)))
|
||||
for override in self.get_layer_overrides(
|
||||
"{}.enable".format(aov)
|
||||
):
|
||||
enabled = self.maya_is_true(override)
|
||||
|
||||
if enabled:
|
||||
enabled_aovs.append((aov_name, default_ext))
|
||||
|
||||
return enabled_aovs
|
||||
|
||||
def get_files(self):
|
||||
"""Get expected files.
|
||||
|
||||
This overrides :func:`AExpectedFiles.get_files()` as we
|
||||
we need to add one sequence for plain beauty if AOVs are enabled
|
||||
as vray output beauty without 'beauty' in filename.
|
||||
|
||||
In renderman we hack it with prepending path. This path would
|
||||
normally be translated from `rmanGlobals.imageOutputDir`. We skip
|
||||
this and hardcode prepend path we expect. There is no place for user
|
||||
to mess around with this settings anyway and it is enforced in
|
||||
render settings validator.
|
||||
"""
|
||||
layer_data = self._get_layer_data()
|
||||
new_aovs = {}
|
||||
|
||||
expected_files = super(ExpectedFilesRenderman, self).get_files()
|
||||
# we always get beauty
|
||||
for aov, files in expected_files[0].items():
|
||||
new_files = []
|
||||
for file in files:
|
||||
new_file = "{}/{}/{}".format(
|
||||
layer_data["sceneName"], layer_data["layerName"], file
|
||||
)
|
||||
new_files.append(new_file)
|
||||
new_aovs[aov] = new_files
|
||||
|
||||
return [new_aovs]
|
||||
|
||||
|
||||
class ExpectedFilesMentalray(AExpectedFiles):
|
||||
"""Skeleton unimplemented class for Mentalray renderer."""
|
||||
|
||||
def __init__(self, layer, render_instance):
|
||||
"""Constructor.
|
||||
|
||||
Raises:
|
||||
:exc:`UnimplementedRendererException`: as it is not implemented.
|
||||
|
||||
"""
|
||||
super(ExpectedFilesMentalray, self).__init__(layer, render_instance)
|
||||
raise UnimplementedRendererException("Mentalray not implemented")
|
||||
|
||||
def get_aovs(self):
|
||||
"""Get all AOVs.
|
||||
|
||||
See Also:
|
||||
:func:`AExpectedFiles.get_aovs()`
|
||||
|
||||
"""
|
||||
return []
|
||||
|
||||
|
||||
class AOVError(Exception):
|
||||
"""Custom exception for determining AOVs."""
|
||||
|
||||
|
||||
class UnsupportedRendererException(Exception):
|
||||
"""Custom exception.
|
||||
|
||||
Raised when requesting data from unsupported renderer.
|
||||
"""
|
||||
|
||||
|
||||
class UnimplementedRendererException(Exception):
|
||||
"""Custom exception.
|
||||
|
||||
Raised when requesting data from renderer that is not implemented yet.
|
||||
"""
|
||||
|
|
@ -49,7 +49,6 @@ import maya.app.renderSetup.model.renderSetup as renderSetup
|
|||
import pyblish.api
|
||||
|
||||
from avalon import maya, api
|
||||
from openpype.hosts.maya.api.expected_files import ExpectedFiles
|
||||
from openpype.hosts.maya.api.lib_renderproducts import get as get_layer_render_products # noqa: E501
|
||||
from openpype.hosts.maya.api import lib
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue