mirror of
https://github.com/ynput/ayon-core.git
synced 2026-01-01 16:34:53 +01:00
style fix
This commit is contained in:
parent
281d53bb01
commit
8002dc4f4f
9 changed files with 275 additions and 306 deletions
|
|
@ -134,19 +134,21 @@ def get_default_render_folder(project_setting=None):
|
||||||
|
|
||||||
|
|
||||||
def set_framerange(startFrame, endFrame):
|
def set_framerange(startFrame, endFrame):
|
||||||
"""Get/set the type of time range to be rendered.
|
|
||||||
|
|
||||||
Possible values are:
|
|
||||||
|
|
||||||
1 -Single frame.
|
|
||||||
|
|
||||||
2 -Active time segment ( animationRange ).
|
|
||||||
|
|
||||||
3 -User specified Range.
|
|
||||||
|
|
||||||
4 -User specified Frame pickup string (for example "1,3,5-12").
|
|
||||||
"""
|
"""
|
||||||
# hard-code, there should be a custom setting for this
|
Args:
|
||||||
|
start_frame (int): Start frame number.
|
||||||
|
end_frame (int): End frame number.
|
||||||
|
Note:
|
||||||
|
Frame range can be specified in different types. Possible values are:
|
||||||
|
|
||||||
|
* `1` - Single frame.
|
||||||
|
* `2` - Active time segment ( animationRange ).
|
||||||
|
* `3` - User specified Range.
|
||||||
|
* `4` - User specified Frame pickup string (for example `1,3,5-12`).
|
||||||
|
|
||||||
|
Todo:
|
||||||
|
Current type is hard-coded, there should be a custom setting for this.
|
||||||
|
"""
|
||||||
rt.rendTimeType = 4
|
rt.rendTimeType = 4
|
||||||
if startFrame is not None and endFrame is not None:
|
if startFrame is not None and endFrame is not None:
|
||||||
frameRange = "{0}-{1}".format(startFrame, endFrame)
|
frameRange = "{0}-{1}".format(startFrame, endFrame)
|
||||||
|
|
@ -157,3 +159,15 @@ def get_multipass_setting(project_setting=None):
|
||||||
return (project_setting["max"]
|
return (project_setting["max"]
|
||||||
["RenderSettings"]
|
["RenderSettings"]
|
||||||
["multipass"])
|
["multipass"])
|
||||||
|
|
||||||
|
def get_max_version():
|
||||||
|
"""
|
||||||
|
Args:
|
||||||
|
get max version date for deadline
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
#(25000, 62, 0, 25, 0, 0, 997, 2023, "")
|
||||||
|
max_info[7] = max version date
|
||||||
|
"""
|
||||||
|
max_info = rt.maxversion()
|
||||||
|
return max_info[7]
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,6 @@ from openpype.pipeline import legacy_io
|
||||||
|
|
||||||
class RenderProducts(object):
|
class RenderProducts(object):
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def __init__(self, project_settings=None):
|
def __init__(self, project_settings=None):
|
||||||
self._project_settings = project_settings
|
self._project_settings = project_settings
|
||||||
if not self._project_settings:
|
if not self._project_settings:
|
||||||
|
|
@ -36,15 +35,11 @@ class RenderProducts(object):
|
||||||
filename,
|
filename,
|
||||||
container)
|
container)
|
||||||
|
|
||||||
context = get_current_project_asset()
|
|
||||||
startFrame = context["data"].get("frameStart")
|
|
||||||
endFrame = context["data"].get("frameEnd") + 1
|
|
||||||
|
|
||||||
img_fmt = self._project_settings["max"]["RenderSettings"]["image_format"] # noqa
|
img_fmt = self._project_settings["max"]["RenderSettings"]["image_format"] # noqa
|
||||||
full_render_list = self.beauty_render_product(output_file,
|
full_render_list = []
|
||||||
startFrame,
|
beauty = self.beauty_render_product(output_file, img_fmt)
|
||||||
endFrame,
|
full_render_list.append(beauty)
|
||||||
img_fmt)
|
|
||||||
renderer_class = get_current_renderer()
|
renderer_class = get_current_renderer()
|
||||||
renderer = str(renderer_class).split(":")[0]
|
renderer = str(renderer_class).split(":")[0]
|
||||||
|
|
||||||
|
|
@ -60,41 +55,29 @@ class RenderProducts(object):
|
||||||
renderer == "Quicksilver_Hardware_Renderer"
|
renderer == "Quicksilver_Hardware_Renderer"
|
||||||
):
|
):
|
||||||
render_elem_list = self.render_elements_product(output_file,
|
render_elem_list = self.render_elements_product(output_file,
|
||||||
startFrame,
|
|
||||||
endFrame,
|
|
||||||
img_fmt)
|
img_fmt)
|
||||||
for render_elem in render_elem_list:
|
if render_elem_list:
|
||||||
full_render_list.append(render_elem)
|
for render_elem in render_elem_list:
|
||||||
|
full_render_list.append(render_elem)
|
||||||
|
|
||||||
return full_render_list
|
return full_render_list
|
||||||
|
|
||||||
if renderer == "Arnold":
|
if renderer == "Arnold":
|
||||||
aov_list = self.arnold_render_product(output_file,
|
aov_list = self.arnold_render_product(output_file,
|
||||||
startFrame,
|
|
||||||
endFrame,
|
|
||||||
img_fmt)
|
img_fmt)
|
||||||
if aov_list:
|
if aov_list:
|
||||||
for aov in aov_list:
|
for aov in aov_list:
|
||||||
full_render_list.append(aov)
|
full_render_list.append(aov)
|
||||||
return full_render_list
|
return full_render_list
|
||||||
|
|
||||||
def beauty_render_product(self, folder, startFrame, endFrame, fmt):
|
def beauty_render_product(self, folder, fmt):
|
||||||
# get the beauty
|
beauty_output = f"{folder}.####.{fmt}"
|
||||||
beauty_frame_range = list()
|
beauty_output = beauty_output.replace("\\", "/")
|
||||||
|
return beauty_output
|
||||||
for f in range(startFrame, endFrame):
|
|
||||||
beauty = "{0}.{1}.{2}".format(folder,
|
|
||||||
str(f),
|
|
||||||
fmt)
|
|
||||||
beauty = beauty.replace("\\", "/")
|
|
||||||
beauty_frame_range.append(beauty)
|
|
||||||
|
|
||||||
return beauty_frame_range
|
|
||||||
|
|
||||||
# TODO: Get the arnold render product
|
# TODO: Get the arnold render product
|
||||||
def arnold_render_product(self, folder, startFrame, endFrame, fmt):
|
def arnold_render_product(self, folder, fmt):
|
||||||
"""Get all the Arnold AOVs"""
|
"""Get all the Arnold AOVs"""
|
||||||
aovs = list()
|
aovs = []
|
||||||
|
|
||||||
amw = rt.MaxtoAOps.AOVsManagerWindow()
|
amw = rt.MaxtoAOps.AOVsManagerWindow()
|
||||||
aov_mgr = rt.renderers.current.AOVManager
|
aov_mgr = rt.renderers.current.AOVManager
|
||||||
|
|
@ -105,21 +88,17 @@ class RenderProducts(object):
|
||||||
for i in range(aov_group_num):
|
for i in range(aov_group_num):
|
||||||
# get the specific AOV group
|
# get the specific AOV group
|
||||||
for aov in aov_mgr.drivers[i].aov_list:
|
for aov in aov_mgr.drivers[i].aov_list:
|
||||||
for f in range(startFrame, endFrame):
|
render_element = f"{folder}_{aov.name}.####.{fmt}"
|
||||||
render_element = "{0}_{1}.{2}.{3}".format(folder,
|
render_element = render_element.replace("\\", "/")
|
||||||
str(aov.name),
|
aovs.append(render_element)
|
||||||
str(f),
|
|
||||||
fmt)
|
|
||||||
render_element = render_element.replace("\\", "/")
|
|
||||||
aovs.append(render_element)
|
|
||||||
# close the AOVs manager window
|
# close the AOVs manager window
|
||||||
amw.close()
|
amw.close()
|
||||||
|
|
||||||
return aovs
|
return aovs
|
||||||
|
|
||||||
def render_elements_product(self, folder, startFrame, endFrame, fmt):
|
def render_elements_product(self, folder, fmt):
|
||||||
"""Get all the render element output files. """
|
"""Get all the render element output files. """
|
||||||
render_dirname = list()
|
render_dirname = []
|
||||||
|
|
||||||
render_elem = rt.maxOps.GetCurRenderElementMgr()
|
render_elem = rt.maxOps.GetCurRenderElementMgr()
|
||||||
render_elem_num = render_elem.NumRenderElements()
|
render_elem_num = render_elem.NumRenderElements()
|
||||||
|
|
@ -128,16 +107,11 @@ class RenderProducts(object):
|
||||||
renderlayer_name = render_elem.GetRenderElement(i)
|
renderlayer_name = render_elem.GetRenderElement(i)
|
||||||
target, renderpass = str(renderlayer_name).split(":")
|
target, renderpass = str(renderlayer_name).split(":")
|
||||||
if renderlayer_name.enabled:
|
if renderlayer_name.enabled:
|
||||||
for f in range(startFrame, endFrame):
|
render_element = f"{folder}_{renderpass}.####.{fmt}"
|
||||||
render_element = "{0}_{1}.{2}.{3}".format(folder,
|
render_element = render_element.replace("\\", "/")
|
||||||
renderpass,
|
render_dirname.append(render_element)
|
||||||
str(f),
|
|
||||||
fmt)
|
|
||||||
render_element = render_element.replace("\\", "/")
|
|
||||||
render_dirname.append(render_element)
|
|
||||||
|
|
||||||
return render_dirname
|
return render_dirname
|
||||||
|
|
||||||
def image_format(self):
|
def image_format(self):
|
||||||
img_fmt = self._project_settings["max"]["RenderSettings"]["image_format"] # noqa
|
return self._project_settings["max"]["RenderSettings"]["image_format"] # noqa
|
||||||
return img_fmt
|
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,6 @@ class RenderSettings(object):
|
||||||
"underscore": "_"
|
"underscore": "_"
|
||||||
}
|
}
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def __init__(self, project_settings=None):
|
def __init__(self, project_settings=None):
|
||||||
self._project_settings = project_settings
|
self._project_settings = project_settings
|
||||||
if not self._project_settings:
|
if not self._project_settings:
|
||||||
|
|
@ -41,7 +40,7 @@ class RenderSettings(object):
|
||||||
if not found:
|
if not found:
|
||||||
raise RuntimeError("Camera not found")
|
raise RuntimeError("Camera not found")
|
||||||
|
|
||||||
def set_renderoutput(self, container):
|
def render_output(self, container):
|
||||||
folder = rt.maxFilePath
|
folder = rt.maxFilePath
|
||||||
# hard-coded, should be customized in the setting
|
# hard-coded, should be customized in the setting
|
||||||
file = rt.maxFileName
|
file = rt.maxFileName
|
||||||
|
|
@ -144,7 +143,7 @@ class RenderSettings(object):
|
||||||
aov_name = "{0}_{1}..{2}".format(dir, renderpass, ext)
|
aov_name = "{0}_{1}..{2}".format(dir, renderpass, ext)
|
||||||
render_elem.SetRenderElementFileName(i, aov_name)
|
render_elem.SetRenderElementFileName(i, aov_name)
|
||||||
|
|
||||||
def get_renderoutput(self, container, output_dir):
|
def get_render_output(self, container, output_dir):
|
||||||
output = os.path.join(output_dir, container)
|
output = os.path.join(output_dir, container)
|
||||||
img_fmt = self._project_settings["max"]["RenderSettings"]["image_format"] # noqa
|
img_fmt = self._project_settings["max"]["RenderSettings"]["image_format"] # noqa
|
||||||
outputFilename = "{0}..{1}".format(output, img_fmt)
|
outputFilename = "{0}..{1}".format(output, img_fmt)
|
||||||
|
|
|
||||||
|
|
@ -30,4 +30,4 @@ class CreateRender(plugin.MaxCreator):
|
||||||
# set viewport camera for rendering(mandatory for deadline)
|
# set viewport camera for rendering(mandatory for deadline)
|
||||||
RenderSettings().set_render_camera(sel_obj)
|
RenderSettings().set_render_camera(sel_obj)
|
||||||
# set output paths for rendering(mandatory for deadline)
|
# set output paths for rendering(mandatory for deadline)
|
||||||
RenderSettings().set_renderoutput(container_name)
|
RenderSettings().render_output(container_name)
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,8 @@ import os
|
||||||
import pyblish.api
|
import pyblish.api
|
||||||
|
|
||||||
from pymxs import runtime as rt
|
from pymxs import runtime as rt
|
||||||
from openpype.pipeline import legacy_io
|
from openpype.pipeline import get_current_asset_name
|
||||||
|
from openpype.hosts.max.api.lib import get_max_version
|
||||||
from openpype.hosts.max.api.lib_renderproducts import RenderProducts
|
from openpype.hosts.max.api.lib_renderproducts import RenderProducts
|
||||||
from openpype.client import get_last_version_by_subset_name
|
from openpype.client import get_last_version_by_subset_name
|
||||||
|
|
||||||
|
|
@ -25,7 +26,7 @@ class CollectRender(pyblish.api.InstancePlugin):
|
||||||
filepath = current_file.replace("\\", "/")
|
filepath = current_file.replace("\\", "/")
|
||||||
|
|
||||||
context.data['currentFile'] = current_file
|
context.data['currentFile'] = current_file
|
||||||
asset = legacy_io.Session["AVALON_ASSET"]
|
asset = get_current_asset_name()
|
||||||
|
|
||||||
render_layer_files = RenderProducts().render_product(instance.name)
|
render_layer_files = RenderProducts().render_product(instance.name)
|
||||||
folder = folder.replace("\\", "/")
|
folder = folder.replace("\\", "/")
|
||||||
|
|
@ -51,6 +52,7 @@ class CollectRender(pyblish.api.InstancePlugin):
|
||||||
"subset": instance.name,
|
"subset": instance.name,
|
||||||
"asset": asset,
|
"asset": asset,
|
||||||
"publish": True,
|
"publish": True,
|
||||||
|
"maxversion": str(get_max_version()),
|
||||||
"imageFormat": imgFormat,
|
"imageFormat": imgFormat,
|
||||||
"family": 'maxrender',
|
"family": 'maxrender',
|
||||||
"families": ['maxrender'],
|
"families": ['maxrender'],
|
||||||
|
|
|
||||||
|
|
@ -1,237 +0,0 @@
|
||||||
import os
|
|
||||||
import json
|
|
||||||
import getpass
|
|
||||||
|
|
||||||
import requests
|
|
||||||
import pyblish.api
|
|
||||||
|
|
||||||
from openpype.pipeline import legacy_io
|
|
||||||
from openpype.settings import get_project_settings
|
|
||||||
from openpype.hosts.max.api.lib import (
|
|
||||||
get_current_renderer,
|
|
||||||
get_multipass_setting
|
|
||||||
)
|
|
||||||
from openpype.hosts.max.api.lib_rendersettings import RenderSettings
|
|
||||||
|
|
||||||
|
|
||||||
class MaxSubmitRenderDeadline(pyblish.api.InstancePlugin):
|
|
||||||
"""
|
|
||||||
3DMax File Submit Render Deadline
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
label = "Submit 3DsMax Render to Deadline"
|
|
||||||
order = pyblish.api.IntegratorOrder
|
|
||||||
hosts = ["max"]
|
|
||||||
families = ["maxrender"]
|
|
||||||
targets = ["local"]
|
|
||||||
use_published = True
|
|
||||||
priority = 50
|
|
||||||
chunk_size = 1
|
|
||||||
group = None
|
|
||||||
deadline_pool = None
|
|
||||||
deadline_pool_secondary = None
|
|
||||||
framePerTask = 1
|
|
||||||
|
|
||||||
def process(self, instance):
|
|
||||||
context = instance.context
|
|
||||||
filepath = context.data["currentFile"]
|
|
||||||
filename = os.path.basename(filepath)
|
|
||||||
comment = context.data.get("comment", "")
|
|
||||||
deadline_user = context.data.get("deadlineUser", getpass.getuser())
|
|
||||||
jobname = "{0} - {1}".format(filename, instance.name)
|
|
||||||
|
|
||||||
# StartFrame to EndFrame
|
|
||||||
frames = "{start}-{end}".format(
|
|
||||||
start=int(instance.data["frameStart"]),
|
|
||||||
end=int(instance.data["frameEnd"])
|
|
||||||
)
|
|
||||||
if self.use_published:
|
|
||||||
for item in context:
|
|
||||||
if "workfile" in item.data["families"]:
|
|
||||||
msg = "Workfile (scene) must be published along"
|
|
||||||
assert item.data["publish"] is True, msg
|
|
||||||
|
|
||||||
template_data = item.data.get("anatomyData")
|
|
||||||
rep = item.data.get("representations")[0].get("name")
|
|
||||||
template_data["representation"] = rep
|
|
||||||
template_data["ext"] = rep
|
|
||||||
template_data["comment"] = None
|
|
||||||
anatomy_data = context.data["anatomy"]
|
|
||||||
anatomy_filled = anatomy_data.format(template_data)
|
|
||||||
template_filled = anatomy_filled["publish"]["path"]
|
|
||||||
filepath = os.path.normpath(template_filled)
|
|
||||||
filepath = filepath.replace("\\", "/")
|
|
||||||
self.log.info(
|
|
||||||
"Using published scene for render {}".format(filepath)
|
|
||||||
)
|
|
||||||
if not os.path.exists(filepath):
|
|
||||||
self.log.error("published scene does not exist!")
|
|
||||||
|
|
||||||
new_scene = self._clean_name(filepath)
|
|
||||||
# use the anatomy data for setting up the path of the files
|
|
||||||
orig_scene = self._clean_name(instance.context.data["currentFile"])
|
|
||||||
expected_files = instance.data.get("expectedFiles")
|
|
||||||
|
|
||||||
new_exp = []
|
|
||||||
for file in expected_files:
|
|
||||||
new_file = str(file).replace(orig_scene, new_scene)
|
|
||||||
new_exp.append(new_file)
|
|
||||||
|
|
||||||
instance.data["expectedFiles"] = new_exp
|
|
||||||
|
|
||||||
metadata_folder = instance.data.get("publishRenderMetadataFolder")
|
|
||||||
if metadata_folder:
|
|
||||||
metadata_folder = metadata_folder.replace(orig_scene,
|
|
||||||
new_scene)
|
|
||||||
instance.data["publishRenderMetadataFolder"] = metadata_folder
|
|
||||||
|
|
||||||
payload = {
|
|
||||||
"JobInfo": {
|
|
||||||
# Top-level group name
|
|
||||||
"BatchName": filename,
|
|
||||||
|
|
||||||
# Job name, as seen in Monitor
|
|
||||||
"Name": jobname,
|
|
||||||
|
|
||||||
# Arbitrary username, for visualisation in Monitor
|
|
||||||
"UserName": deadline_user,
|
|
||||||
|
|
||||||
"Plugin": instance.data["plugin"],
|
|
||||||
"Group": self.group,
|
|
||||||
"Pool": self.deadline_pool,
|
|
||||||
"secondaryPool": self.deadline_pool_secondary,
|
|
||||||
"Frames": frames,
|
|
||||||
"ChunkSize": self.chunk_size,
|
|
||||||
"Priority": instance.data.get("priority", self.priority),
|
|
||||||
"Comment": comment,
|
|
||||||
"FramesPerTask": self.framePerTask
|
|
||||||
},
|
|
||||||
"PluginInfo": {
|
|
||||||
# Input
|
|
||||||
"SceneFile": filepath,
|
|
||||||
"Version": "2023",
|
|
||||||
"SaveFile": True,
|
|
||||||
# Mandatory for Deadline
|
|
||||||
# Houdini version without patch number
|
|
||||||
|
|
||||||
"IgnoreInputs": True
|
|
||||||
},
|
|
||||||
|
|
||||||
# Mandatory for Deadline, may be empty
|
|
||||||
"AuxFiles": []
|
|
||||||
}
|
|
||||||
# Include critical environment variables with submission + api.Session
|
|
||||||
keys = [
|
|
||||||
# Submit along the current Avalon tool setup that we launched
|
|
||||||
# this application with so the Render Slave can build its own
|
|
||||||
# similar environment using it, e.g. "maya2018;vray4.x;yeti3.1.9"
|
|
||||||
"AVALON_TOOLS",
|
|
||||||
"OPENPYPE_VERSION"
|
|
||||||
]
|
|
||||||
# Add mongo url if it's enabled
|
|
||||||
if context.data.get("deadlinePassMongoUrl"):
|
|
||||||
keys.append("OPENPYPE_MONGO")
|
|
||||||
|
|
||||||
environment = dict({key: os.environ[key] for key in keys
|
|
||||||
if key in os.environ}, **legacy_io.Session)
|
|
||||||
|
|
||||||
payload["JobInfo"].update({
|
|
||||||
"EnvironmentKeyValue%d" % index: "{key}={value}".format(
|
|
||||||
key=key,
|
|
||||||
value=environment[key]
|
|
||||||
) for index, key in enumerate(environment)
|
|
||||||
})
|
|
||||||
|
|
||||||
# Include OutputFilename entries
|
|
||||||
# The first entry also enables double-click to preview rendered
|
|
||||||
# frames from Deadline Monitor
|
|
||||||
output_data = {}
|
|
||||||
# need to be fixed
|
|
||||||
for i, filepath in enumerate(instance.data["expectedFiles"]):
|
|
||||||
dirname = os.path.dirname(filepath)
|
|
||||||
fname = os.path.basename(filepath)
|
|
||||||
output_data["OutputDirectory%d" % i] = dirname.replace("\\", "/")
|
|
||||||
output_data["OutputFilename%d" % i] = fname
|
|
||||||
|
|
||||||
if not os.path.exists(dirname):
|
|
||||||
self.log.info("Ensuring output directory exists: %s" %
|
|
||||||
dirname)
|
|
||||||
os.makedirs(dirname)
|
|
||||||
|
|
||||||
plugin_data = {}
|
|
||||||
project_setting = get_project_settings(
|
|
||||||
legacy_io.Session["AVALON_PROJECT"]
|
|
||||||
)
|
|
||||||
|
|
||||||
multipass = get_multipass_setting(project_setting)
|
|
||||||
if multipass:
|
|
||||||
plugin_data["DisableMultipass"] = 0
|
|
||||||
else:
|
|
||||||
plugin_data["DisableMultipass"] = 1
|
|
||||||
|
|
||||||
if self.use_published:
|
|
||||||
old_output_dir = os.path.dirname(expected_files[0])
|
|
||||||
output_beauty = RenderSettings().get_renderoutput(instance.name,
|
|
||||||
old_output_dir)
|
|
||||||
output_beauty = output_beauty.replace(orig_scene, new_scene)
|
|
||||||
output_beauty = output_beauty.replace("\\", "/")
|
|
||||||
plugin_data["RenderOutput"] = output_beauty
|
|
||||||
|
|
||||||
renderer_class = get_current_renderer()
|
|
||||||
renderer = str(renderer_class).split(":")[0]
|
|
||||||
if (
|
|
||||||
renderer == "ART_Renderer" or
|
|
||||||
renderer == "Redshift_Renderer" or
|
|
||||||
renderer == "V_Ray_6_Hotfix_3" or
|
|
||||||
renderer == "V_Ray_GPU_6_Hotfix_3" or
|
|
||||||
renderer == "Default_Scanline_Renderer" or
|
|
||||||
renderer == "Quicksilver_Hardware_Renderer"
|
|
||||||
):
|
|
||||||
render_elem_list = RenderSettings().get_render_element()
|
|
||||||
for i, element in enumerate(render_elem_list):
|
|
||||||
element = element.replace(orig_scene, new_scene)
|
|
||||||
plugin_data["RenderElementOutputFilename%d" % i] = element # noqa
|
|
||||||
|
|
||||||
self.log.debug("plugin data:{}".format(plugin_data))
|
|
||||||
self.log.info("Scene name was switched {} -> {}".format(
|
|
||||||
orig_scene, new_scene
|
|
||||||
))
|
|
||||||
|
|
||||||
payload["JobInfo"].update(output_data)
|
|
||||||
payload["PluginInfo"].update(plugin_data)
|
|
||||||
|
|
||||||
self.submit(instance, payload)
|
|
||||||
|
|
||||||
def submit(self, instance, payload):
|
|
||||||
|
|
||||||
context = instance.context
|
|
||||||
deadline_url = context.data.get("defaultDeadline")
|
|
||||||
deadline_url = instance.data.get(
|
|
||||||
"deadlineUrl", deadline_url)
|
|
||||||
|
|
||||||
assert deadline_url, "Requires Deadline Webservice URL"
|
|
||||||
|
|
||||||
plugin = payload["JobInfo"]["Plugin"]
|
|
||||||
self.log.info("Using Render Plugin : {}".format(plugin))
|
|
||||||
|
|
||||||
self.log.info("Submitting..")
|
|
||||||
self.log.debug(json.dumps(payload, indent=4, sort_keys=True))
|
|
||||||
|
|
||||||
# E.g. http://192.168.0.1:8082/api/jobs
|
|
||||||
url = "{}/api/jobs".format(deadline_url)
|
|
||||||
response = requests.post(url, json=payload)
|
|
||||||
if not response.ok:
|
|
||||||
raise Exception(response.text)
|
|
||||||
# Store output dir for unified publisher (expectedFilesequence)
|
|
||||||
expected_files = instance.data["expectedFiles"]
|
|
||||||
output_dir = os.path.dirname(expected_files[0])
|
|
||||||
instance.data["toBeRenderedOn"] = "deadline"
|
|
||||||
instance.data["outputDir"] = output_dir
|
|
||||||
instance.data["deadlineSubmissionJob"] = response.json()
|
|
||||||
|
|
||||||
def rename_render_element(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def _clean_name(self, path):
|
|
||||||
return os.path.splitext(os.path.basename(path))[0]
|
|
||||||
217
openpype/modules/deadline/plugins/publish/submit_max_deadline.py
Normal file
217
openpype/modules/deadline/plugins/publish/submit_max_deadline.py
Normal file
|
|
@ -0,0 +1,217 @@
|
||||||
|
import os
|
||||||
|
import getpass
|
||||||
|
import copy
|
||||||
|
|
||||||
|
import attr
|
||||||
|
from openpype.pipeline import legacy_io
|
||||||
|
from openpype.settings import get_project_settings
|
||||||
|
from openpype.hosts.max.api.lib import (
|
||||||
|
get_current_renderer,
|
||||||
|
get_multipass_setting
|
||||||
|
)
|
||||||
|
from openpype.hosts.max.api.lib_rendersettings import RenderSettings
|
||||||
|
from openpype_modules.deadline import abstract_submit_deadline
|
||||||
|
from openpype_modules.deadline.abstract_submit_deadline import DeadlineJobInfo
|
||||||
|
|
||||||
|
|
||||||
|
@attr.s
|
||||||
|
class MaxPluginInfo(object):
|
||||||
|
SceneFile = attr.ib(default=None) # Input
|
||||||
|
Version = attr.ib(default=None) # Mandatory for Deadline
|
||||||
|
SaveFile = attr.ib(default=True)
|
||||||
|
IgnoreInputs = attr.ib(default=True)
|
||||||
|
|
||||||
|
|
||||||
|
class MaxSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline):
|
||||||
|
|
||||||
|
label = "Submit Render to Deadline"
|
||||||
|
hosts = ["max"]
|
||||||
|
families = ["maxrender"]
|
||||||
|
targets = ["local"]
|
||||||
|
|
||||||
|
use_published = True
|
||||||
|
priority = 50
|
||||||
|
tile_priority = 50
|
||||||
|
chunk_size = 1
|
||||||
|
jobInfo = {}
|
||||||
|
pluginInfo = {}
|
||||||
|
group = None
|
||||||
|
deadline_pool = None
|
||||||
|
deadline_pool_secondary = None
|
||||||
|
framePerTask = 1
|
||||||
|
|
||||||
|
def get_job_info(self):
|
||||||
|
job_info = DeadlineJobInfo(Plugin="3dsmax")
|
||||||
|
|
||||||
|
# todo: test whether this works for existing production cases
|
||||||
|
# where custom jobInfo was stored in the project settings
|
||||||
|
job_info.update(self.jobInfo)
|
||||||
|
|
||||||
|
instance = self._instance
|
||||||
|
context = instance.context
|
||||||
|
|
||||||
|
# Always use the original work file name for the Job name even when
|
||||||
|
# rendering is done from the published Work File. The original work
|
||||||
|
# file name is clearer because it can also have subversion strings,
|
||||||
|
# etc. which are stripped for the published file.
|
||||||
|
src_filepath = context.data["currentFile"]
|
||||||
|
src_filename = os.path.basename(src_filepath)
|
||||||
|
|
||||||
|
job_info.Name = "%s - %s" % (src_filename, instance.name)
|
||||||
|
job_info.BatchName = src_filename
|
||||||
|
job_info.Plugin = instance.data["plugin"]
|
||||||
|
job_info.UserName = context.data.get("deadlineUser", getpass.getuser())
|
||||||
|
|
||||||
|
# Deadline requires integers in frame range
|
||||||
|
frames = "{start}-{end}".format(
|
||||||
|
start=int(instance.data["frameStart"]),
|
||||||
|
end=int(instance.data["frameEnd"])
|
||||||
|
)
|
||||||
|
job_info.Frames = frames
|
||||||
|
|
||||||
|
job_info.Pool = instance.data.get("primaryPool")
|
||||||
|
job_info.SecondaryPool = instance.data.get("secondaryPool")
|
||||||
|
job_info.ChunkSize = instance.data.get("chunkSize", 1)
|
||||||
|
job_info.Comment = context.data.get("comment")
|
||||||
|
job_info.Priority = instance.data.get("priority", self.priority)
|
||||||
|
job_info.FramesPerTask = instance.data.get("framesPerTask", 1)
|
||||||
|
|
||||||
|
if self.group:
|
||||||
|
job_info.Group = self.group
|
||||||
|
|
||||||
|
# Add options from RenderGlobals
|
||||||
|
render_globals = instance.data.get("renderGlobals", {})
|
||||||
|
job_info.update(render_globals)
|
||||||
|
|
||||||
|
keys = [
|
||||||
|
"FTRACK_API_KEY",
|
||||||
|
"FTRACK_API_USER",
|
||||||
|
"FTRACK_SERVER",
|
||||||
|
"OPENPYPE_SG_USER",
|
||||||
|
"AVALON_PROJECT",
|
||||||
|
"AVALON_ASSET",
|
||||||
|
"AVALON_TASK",
|
||||||
|
"AVALON_APP_NAME",
|
||||||
|
"OPENPYPE_DEV",
|
||||||
|
"OPENPYPE_VERSION",
|
||||||
|
"IS_TEST"
|
||||||
|
]
|
||||||
|
# Add mongo url if it's enabled
|
||||||
|
if self._instance.context.data.get("deadlinePassMongoUrl"):
|
||||||
|
keys.append("OPENPYPE_MONGO")
|
||||||
|
|
||||||
|
environment = dict({key: os.environ[key] for key in keys
|
||||||
|
if key in os.environ}, **legacy_io.Session)
|
||||||
|
|
||||||
|
for key in keys:
|
||||||
|
value = environment.get(key)
|
||||||
|
if not value:
|
||||||
|
continue
|
||||||
|
job_info.EnvironmentKeyValue[key] = value
|
||||||
|
|
||||||
|
# to recognize job from PYPE for turning Event On/Off
|
||||||
|
job_info.EnvironmentKeyValue["OPENPYPE_RENDER_JOB"] = "1"
|
||||||
|
job_info.EnvironmentKeyValue["OPENPYPE_LOG_NO_COLORS"] = "1"
|
||||||
|
|
||||||
|
# Add list of expected files to job
|
||||||
|
# ---------------------------------
|
||||||
|
exp = instance.data.get("expectedFiles")
|
||||||
|
for filepath in exp:
|
||||||
|
job_info.OutputDirectory += os.path.dirname(filepath)
|
||||||
|
job_info.OutputFilename += os.path.basename(filepath)
|
||||||
|
|
||||||
|
return job_info
|
||||||
|
|
||||||
|
def get_plugin_info(self):
|
||||||
|
instance = self._instance
|
||||||
|
|
||||||
|
plugin_info = MaxPluginInfo(
|
||||||
|
SceneFile=self.scene_path,
|
||||||
|
Version=instance.data["maxversion"],
|
||||||
|
SaveFile = True,
|
||||||
|
IgnoreInputs = True
|
||||||
|
)
|
||||||
|
|
||||||
|
plugin_payload = attr.asdict(plugin_info)
|
||||||
|
|
||||||
|
# Patching with pluginInfo from settings
|
||||||
|
for key, value in self.pluginInfo.items():
|
||||||
|
plugin_payload[key] = value
|
||||||
|
|
||||||
|
return plugin_payload
|
||||||
|
|
||||||
|
def process_submission(self):
|
||||||
|
|
||||||
|
instance = self._instance
|
||||||
|
context = instance.context
|
||||||
|
filepath = self.scene_path
|
||||||
|
|
||||||
|
expected_files = instance.data["expectedFiles"]
|
||||||
|
if not expected_files:
|
||||||
|
raise RuntimeError("No Render Elements found!")
|
||||||
|
output_dir = os.path.dirname(expected_files[0])
|
||||||
|
instance.data["outputDir"] = output_dir
|
||||||
|
instance.data["toBeRenderedOn"] = "deadline"
|
||||||
|
|
||||||
|
filename = os.path.basename(filepath)
|
||||||
|
|
||||||
|
payload_data = {
|
||||||
|
"filename": filename,
|
||||||
|
"dirname": output_dir
|
||||||
|
}
|
||||||
|
|
||||||
|
self.log.debug("Submitting 3dsMax render..")
|
||||||
|
payload = self._use_puhlished_name(payload_data)
|
||||||
|
job_info, plugin_info = payload
|
||||||
|
self.submit(self.assemble_payload(job_info, plugin_info))
|
||||||
|
|
||||||
|
def _use_puhlished_name(self, data):
|
||||||
|
instance = self._instance
|
||||||
|
job_info = copy.deepcopy(self.job_info)
|
||||||
|
plugin_info = copy.deepcopy(self.plugin_info)
|
||||||
|
plugin_data = {}
|
||||||
|
project_setting = get_project_settings(
|
||||||
|
legacy_io.Session["AVALON_PROJECT"]
|
||||||
|
)
|
||||||
|
|
||||||
|
multipass = get_multipass_setting(project_setting)
|
||||||
|
if multipass:
|
||||||
|
plugin_data["DisableMultipass"] = 0
|
||||||
|
else:
|
||||||
|
plugin_data["DisableMultipass"] = 1
|
||||||
|
|
||||||
|
expected_files = instance.data.get("expectedFiles")
|
||||||
|
if not expected_files:
|
||||||
|
raise RuntimeError("No render elements found")
|
||||||
|
old_output_dir = os.path.dirname(expected_files[0])
|
||||||
|
output_beauty = RenderSettings().get_render_output(instance.name,
|
||||||
|
old_output_dir)
|
||||||
|
filepath = self.from_published_scene()
|
||||||
|
def _clean_name(path):
|
||||||
|
return os.path.splitext(os.path.basename(path))[0]
|
||||||
|
new_scene = _clean_name(filepath)
|
||||||
|
orig_scene = _clean_name(instance.context.data["currentFile"])
|
||||||
|
|
||||||
|
output_beauty = output_beauty.replace(orig_scene, new_scene)
|
||||||
|
output_beauty = output_beauty.replace("\\", "/")
|
||||||
|
plugin_data["RenderOutput"] = output_beauty
|
||||||
|
|
||||||
|
renderer_class = get_current_renderer()
|
||||||
|
renderer = str(renderer_class).split(":")[0]
|
||||||
|
if (
|
||||||
|
renderer == "ART_Renderer" or
|
||||||
|
renderer == "Redshift_Renderer" or
|
||||||
|
renderer == "V_Ray_6_Hotfix_3" or
|
||||||
|
renderer == "V_Ray_GPU_6_Hotfix_3" or
|
||||||
|
renderer == "Default_Scanline_Renderer" or
|
||||||
|
renderer == "Quicksilver_Hardware_Renderer"
|
||||||
|
):
|
||||||
|
render_elem_list = RenderSettings().get_render_element()
|
||||||
|
for i, element in enumerate(render_elem_list):
|
||||||
|
element = element.replace(orig_scene, new_scene)
|
||||||
|
plugin_data["RenderElementOutputFilename%d" % i] = element # noqa
|
||||||
|
|
||||||
|
self.log.debug("plugin data:{}".format(plugin_data))
|
||||||
|
plugin_info.update(plugin_data)
|
||||||
|
|
||||||
|
return job_info, plugin_info
|
||||||
|
|
@ -36,7 +36,7 @@
|
||||||
"scene_patches": [],
|
"scene_patches": [],
|
||||||
"strict_error_checking": true
|
"strict_error_checking": true
|
||||||
},
|
},
|
||||||
"MaxSubmitRenderDeadline": {
|
"MaxSubmitDeadline": {
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"optional": false,
|
"optional": false,
|
||||||
"active": true,
|
"active": true,
|
||||||
|
|
|
||||||
|
|
@ -207,7 +207,7 @@
|
||||||
{
|
{
|
||||||
"type": "dict",
|
"type": "dict",
|
||||||
"collapsible": true,
|
"collapsible": true,
|
||||||
"key": "MaxSubmitRenderDeadline",
|
"key": "MaxSubmitDeadline",
|
||||||
"label": "3dsMax Submit to Deadline",
|
"label": "3dsMax Submit to Deadline",
|
||||||
"checkbox_key": "enabled",
|
"checkbox_key": "enabled",
|
||||||
"children": [
|
"children": [
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue