fixed redshift support

This commit is contained in:
Ondrej Samohel 2020-02-19 13:29:14 +01:00
parent f572d97fe0
commit 022862d632
No known key found for this signature in database
GPG key ID: 8A29C663C672C2B7
2 changed files with 190 additions and 87 deletions

View file

@ -59,6 +59,7 @@ 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|_<aov>|_<renderpass>', 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)
@ -160,6 +161,7 @@ class CollectMayaRender(pyblish.api.ContextPlugin):
# return all expected files for all cameras and aovs in given
# frame range
exp_files = ExpectedFiles().get(renderer, layer_name)
assert exp_files, ("no file names were generated, this is bug")
# if we want to attach render to subset, check if we have AOV's
# in expectedFiles. If so, raise error as we cannot attach AOV
@ -173,16 +175,32 @@ class CollectMayaRender(pyblish.api.ContextPlugin):
full_exp_files = []
aov_dict = {}
for aov, files in exp_files[0].items():
# we either get AOVs or just list of files. List of files can
# mean two things - there are no AOVs enabled or multipass EXR
# is produced. In either case we treat those as `beauty`.
if isinstance(exp_files[0], dict):
for aov, files in exp_files[0].items():
full_paths = []
for ef in files:
full_path = os.path.join(workspace, "renders", ef)
full_path = full_path.replace("\\", "/")
full_paths.append(full_path)
aov_dict[aov] = full_paths
else:
full_paths = []
for ef in files:
for ef in exp_files:
full_path = os.path.join(workspace, "renders", ef)
full_path = full_path.replace("\\", "/")
full_paths.append(full_path)
aov_dict[aov] = full_paths
aov_dict["beauty"] = full_paths
full_exp_files.append(aov_dict)
from pprint import pprint
print("=" * 40)
pprint(full_exp_files)
print("=" * 40)
self.log.info("collecting layer: {}".format(layer_name))
# Get layer specific settings, might be overrides
data = {
@ -363,7 +381,15 @@ class AExpectedFiles:
def get_aovs(self):
pass
def get_files(self):
def get_renderer_prefix(self):
try:
file_prefix = cmds.getAttr(ImagePrefixes[self.renderer])
except KeyError:
raise UnsupportedRendererException(
"Unsupported renderer {}".format(self.renderer))
return file_prefix
def _get_layer_data(self):
# ______________________________________________
# ____________________/ ____________________________________________/
# 1 - get scene name /__________________/
@ -381,11 +407,7 @@ class AExpectedFiles:
# __________________/ ______________________________________________/
# 3 - image prefix /__________________/
# __________________/
try:
file_prefix = cmds.getAttr(ImagePrefixes[renderer])
except KeyError:
raise UnsupportedRendererException(
"Unsupported renderer {}".format(renderer))
file_prefix = self.get_renderer_prefix()
if not file_prefix:
raise RuntimeError("Image prefix not set")
@ -397,6 +419,9 @@ class AExpectedFiles:
# 4 - get renderable cameras_____________/
# __________________/
# if we have <camera> token in prefix path we'll expect output for
# every renderable camera in layer.
renderable_cameras = self.get_renderable_cameras()
# ________________________________________________
# __________________/ ______________________________________________/
@ -404,11 +429,11 @@ class AExpectedFiles:
# __________________/
enabled_aovs = self.get_aovs()
from pprint import pprint
print("-" * 40)
pprint(enabled_aovs)
print("-" * 40)
# if we have <camera> token in prefix path we'll expect output for
# every renderable camera in layer.
expected_files = []
layer_name = self.layer
if self.layer.startswith("rs_"):
layer_name = self.layer[3:]
@ -417,62 +442,104 @@ class AExpectedFiles:
frame_step = int(self.get_render_attribute('byFrameStep'))
padding = int(self.get_render_attribute('extensionPadding'))
resolved_path = file_prefix
if enabled_aovs:
aov_file_list = {}
for aov in enabled_aovs:
for cam in renderable_cameras:
scene_data = {
"frameStart": start_frame,
"frameEnd": end_frame,
"frameStep": frame_step,
"padding": padding,
"cameras": renderable_cameras,
"sceneName": scene_name,
"layerName": layer_name,
"renderer": renderer,
"defaultExt": default_ext,
"filePrefix": file_prefix,
"enabledAOVs": enabled_aovs
}
return scene_data
mappings = (
(R_SUBSTITUTE_SCENE_TOKEN, scene_name),
(R_SUBSTITUTE_LAYER_TOKEN, layer_name),
(R_SUBSTITUTE_CAMERA_TOKEN, cam),
(R_SUBSTITUTE_AOV_TOKEN, aov[0])
)
def _generate_single_file_sequence(self, layer_data):
expected_files = []
file_prefix = layer_data["filePrefix"]
for cam in layer_data["cameras"]:
mappings = (
(R_SUBSTITUTE_SCENE_TOKEN, layer_data["sceneName"]),
(R_SUBSTITUTE_LAYER_TOKEN, layer_data["layerName"]),
(R_SUBSTITUTE_CAMERA_TOKEN, cam),
# this is required to remove unfilled aov token, for example
# in Redshift
(R_REMOVE_AOV_TOKEN, "")
)
for regex, value in mappings:
file_prefix = re.sub(regex, value, file_prefix)
for regex, value in mappings:
file_prefix = re.sub(regex, value, file_prefix)
aov_files = []
for frame in range(
int(start_frame),
int(end_frame) + 1,
int(frame_step)):
aov_files.append(
'{}.{}.{}'.format(
file_prefix,
str(frame).rjust(padding, "0"),
aov[1]))
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
# if we have more then one renderable camera, append
# camera name to AOV to allow per camera AOVs.
aov_name = aov[0]
if len(renderable_cameras) > 1:
aov_name = "{}_{}".format(aov[0], cam)
def _generate_aov_file_sequences(self, layer_data):
expected_files = []
aov_file_list = {}
file_prefix = layer_data["filePrefix"]
for aov in layer_data["enabledAOVs"]:
for cam in layer_data["cameras"]:
aov_file_list[aov_name] = aov_files
file_prefix = resolved_path
expected_files.append(aov_file_list)
else:
for cam in renderable_cameras:
mappings = (
(R_SUBSTITUTE_SCENE_TOKEN, scene_name),
(R_SUBSTITUTE_LAYER_TOKEN, layer_name),
(R_SUBSTITUTE_CAMERA_TOKEN, cam)
(R_SUBSTITUTE_SCENE_TOKEN, layer_data["sceneName"]),
(R_SUBSTITUTE_LAYER_TOKEN, layer_data["layerName"]),
(R_SUBSTITUTE_CAMERA_TOKEN, cam),
(R_SUBSTITUTE_AOV_TOKEN, aov[0])
)
for regex, value in mappings:
file_prefix = re.sub(regex, value, file_prefix)
aov_files = []
for frame in range(
int(start_frame),
int(end_frame) + 1,
int(frame_step)):
expected_files.append(
'{}.{}.{}'.format(file_prefix,
str(frame).rjust(padding, "0"),
default_ext))
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], 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):
"""
This method will 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.get("enabledAOVs"):
expected_files = self._generate_aov_file_sequences(layer_data)
else:
expected_files = self._generate_single_file_sequence(layer_data)
return expected_files
@ -656,13 +723,53 @@ class ExpectedFilesVray(AExpectedFiles):
class ExpectedFilesRedshift(AExpectedFiles):
# mapping redshift extension dropdown values to strings
ext_mapping = ['iff', 'exr', 'tif', 'png', 'tga', 'jpg']
def __init__(self, layer):
super(ExpectedFilesRedshift, self).__init__(layer)
self.renderer = 'redshift'
def get_renderer_prefix(self):
prefix = super(ExpectedFilesRedshift, self).get_renderer_prefix()
prefix = "{}_<aov>".format(prefix)
return prefix
def get_files(self):
expected_files = super(ExpectedFilesRedshift, self).get_files()
# we need to add one sequence for plain beauty if AOVs are enabled.
# as redshift output beauty without 'beauty' in filename.
layer_data = self._get_layer_data()
if layer_data.get("enabledAOVs"):
expected_files[0][u"beauty"] = self._generate_single_file_sequence(layer_data) # noqa: E501
return expected_files
def get_aovs(self):
enabled_aovs = []
default_ext = cmds.getAttr('defaultRenderGlobals.imfPluginKey')
try:
if self.maya_is_true(
cmds.getAttr("redshiftOptions.exrForceMultilayer")):
# AOVs are merged in mutli-channel file
print("*" * 40)
print(cmds.getAttr("redshiftOptions.exrForceMultilayer"))
print("*" * 40)
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.
print("+" * 40)
return enabled_aovs
default_ext = self.ext_mapping[
cmds.getAttr('redshiftOptions.imageFormat')
]
rs_aovs = [n for n in cmds.ls(type='RedshiftAOV')]
# todo: find out how to detect multichannel exr for redshift
@ -674,7 +781,6 @@ class ExpectedFilesRedshift(AExpectedFiles):
enabled = self.maya_is_true(override)
if enabled:
# todo: find how redshift set format for AOVs
enabled_aovs.append(
(
cmds.getAttr('%s.name' % aov),

View file

@ -48,6 +48,13 @@ class ValidateRenderSettings(pyblish.api.InstancePlugin):
'redshift': 'defaultRenderGlobals.imageFilePrefix'
}
ImagePrefixTokens = {
'arnold': 'maya/<Scene>/<RenderLayer>/<RenderLayer>_<RenderPass',
'redshift': 'maya/<Scene>/<RenderLayer>/<RenderLayer>',
'vray': 'maya/<scene>/<Layer>/<Layer>'
}
R_AOV_TOKEN = re.compile(
r'%a|<aov>|<renderpass>', re.IGNORECASE)
R_LAYER_TOKEN = re.compile(
@ -99,26 +106,31 @@ class ValidateRenderSettings(pyblish.api.InstancePlugin):
"doesn't have: '<renderlayer>' or "
"'<layer>' token".format(prefix))
if not re.search(cls.R_AOV_TOKEN, prefix):
invalid = True
cls.log.error("Wrong image prefix [ {} ] - "
"doesn't have: '<renderpass>' or "
"'<aov>' token".format(prefix))
if len(cameras) > 1:
if not re.search(cls.R_CAMERA_TOKEN, prefix):
invalid = True
cls.log.error("Wrong image prefix [ {} ] - "
"doesn't have: '<camera>' token".format(prefix))
# renderer specific checks
if renderer == "vray":
if prefix.lower() != cls.VRAY_PREFIX.lower():
cls.log.warning("warning: prefix differs from "
"recommended {}".format(cls.VRAY_PREFIX))
# no vray checks implemented yet
pass
elif renderer == "redshift":
# no redshift check implemented yet
pass
else:
if prefix.lower() != cls.DEFAULT_PREFIX.lower():
cls.log.warning("warning: prefix differs from "
"recommended {}".format(cls.DEFAULT_PREFIX))
if not re.search(cls.R_AOV_TOKEN, prefix):
invalid = True
cls.log.error("Wrong image prefix [ {} ] - "
"doesn't have: '<renderpass>' or "
"token".format(prefix))
# prefix check
if prefix.lower() != cls.ImagePrefixTokens[renderer].lower():
cls.log.warning("warning: prefix differs from "
"recommended {}".format(
cls.ImagePrefixTokens[renderer]))
if padding != cls.DEFAULT_PADDING:
invalid = True
@ -127,21 +139,6 @@ class ValidateRenderSettings(pyblish.api.InstancePlugin):
return invalid
@classmethod
def get_prefix(cls, renderer):
prefix = cls.RENDERER_PREFIX.get(renderer, cls.DEFAULT_PREFIX)
# maya.cmds and pymel.core return only default project directory and
# not the current one but only default.
output_path = os.path.join(
mel.eval("workspace -q -rd;"), pm.workspace.fileRules["images"]
)
# Workfile paths can be configured to have host name in file path.
# In this case we want to avoid duplicate folder names.
if "maya" in output_path.lower():
prefix = prefix.replace("maya/", "")
return prefix
@classmethod
def repair(cls, instance):
@ -156,7 +153,7 @@ class ValidateRenderSettings(pyblish.api.InstancePlugin):
node = render_attrs["node"]
prefix_attr = render_attrs["prefix"]
fname_prefix = cls.get_prefix(renderer)
fname_prefix = cls.ImagePrefixTokens[renderer]
cmds.setAttr("{}.{}".format(node, prefix_attr),
fname_prefix, type="string")