mirror of
https://github.com/ynput/ayon-core.git
synced 2026-01-01 16:34:53 +01:00
setting up deadline for 3dsmax
This commit is contained in:
parent
9965e6b991
commit
95aff1808f
10 changed files with 565 additions and 2 deletions
|
|
@ -120,3 +120,36 @@ def get_all_children(parent, node_type=None):
|
||||||
|
|
||||||
return ([x for x in child_list if rt.superClassOf(x) == node_type]
|
return ([x for x in child_list if rt.superClassOf(x) == node_type]
|
||||||
if node_type else child_list)
|
if node_type else child_list)
|
||||||
|
|
||||||
|
|
||||||
|
def get_current_renderer():
|
||||||
|
"""get current renderer"""
|
||||||
|
return rt.renderers.production
|
||||||
|
|
||||||
|
|
||||||
|
def get_default_render_folder(project_setting=None):
|
||||||
|
return (project_setting["max"]
|
||||||
|
["RenderSettings"]
|
||||||
|
["default_render_image_folder"]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
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
|
||||||
|
rt.rendTimeType = 4
|
||||||
|
if startFrame is not None and endFrame is not None:
|
||||||
|
frameRange = "{0}-{1}".format(startFrame, endFrame)
|
||||||
|
rt.rendPickupFrames = frameRange
|
||||||
|
|
||||||
|
|
|
||||||
102
openpype/hosts/max/api/lib_renderproducts.py
Normal file
102
openpype/hosts/max/api/lib_renderproducts.py
Normal file
|
|
@ -0,0 +1,102 @@
|
||||||
|
# Render Element Example : For scanline render, VRay
|
||||||
|
# https://help.autodesk.com/view/MAXDEV/2022/ENU/?guid=GUID-E8F75D47-B998-4800-A3A5-610E22913CFC
|
||||||
|
# arnold
|
||||||
|
# https://help.autodesk.com/view/ARNOL/ENU/?guid=arnold_for_3ds_max_ax_maxscript_commands_ax_renderview_commands_html
|
||||||
|
import os
|
||||||
|
from pymxs import runtime as rt
|
||||||
|
from openpype.hosts.max.api.lib import (
|
||||||
|
get_current_renderer,
|
||||||
|
get_default_render_folder
|
||||||
|
)
|
||||||
|
from openpype.pipeline.context_tools import get_current_project_asset
|
||||||
|
from openpype.settings import get_project_settings
|
||||||
|
from openpype.pipeline import legacy_io
|
||||||
|
|
||||||
|
|
||||||
|
class RenderProducts(object):
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def __init__(self, project_settings=None):
|
||||||
|
self._project_settings = project_settings
|
||||||
|
if not self._project_settings:
|
||||||
|
self._project_settings = get_project_settings(
|
||||||
|
legacy_io.Session["AVALON_PROJECT"]
|
||||||
|
)
|
||||||
|
|
||||||
|
def render_product(self, container):
|
||||||
|
folder = rt.maxFilePath
|
||||||
|
folder = folder.replace("\\", "/")
|
||||||
|
setting = self._project_settings
|
||||||
|
render_folder = get_default_render_folder(setting)
|
||||||
|
|
||||||
|
output_file = os.path.join(folder, render_folder, 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"]
|
||||||
|
full_render_list = self.beauty_render_product(output_file,
|
||||||
|
startFrame,
|
||||||
|
endFrame,
|
||||||
|
img_fmt)
|
||||||
|
renderer_class = get_current_renderer()
|
||||||
|
renderer = str(renderer_class).split(":")[0]
|
||||||
|
|
||||||
|
if renderer == "VUE_File_Renderer":
|
||||||
|
return full_render_list
|
||||||
|
|
||||||
|
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 = self.render_elements_product(output_file,
|
||||||
|
startFrame,
|
||||||
|
endFrame,
|
||||||
|
img_fmt)
|
||||||
|
for render_elem in render_elem_list:
|
||||||
|
full_render_list.append(render_elem)
|
||||||
|
return full_render_list
|
||||||
|
|
||||||
|
if renderer == "Arnold":
|
||||||
|
return full_render_list
|
||||||
|
|
||||||
|
|
||||||
|
def beauty_render_product(self, folder, startFrame, endFrame, fmt):
|
||||||
|
# get the beauty
|
||||||
|
beauty_frame_range = list()
|
||||||
|
|
||||||
|
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
|
||||||
|
def render_elements_product(self, folder, startFrame, endFrame, fmt):
|
||||||
|
"""Get all the render element output files. """
|
||||||
|
render_dirname = list()
|
||||||
|
|
||||||
|
render_elem = rt.maxOps.GetCurRenderElementMgr()
|
||||||
|
render_elem_num = render_elem.NumRenderElements()
|
||||||
|
# get render elements from the renders
|
||||||
|
for i in range(render_elem_num):
|
||||||
|
renderlayer_name = render_elem.GetRenderElement(i)
|
||||||
|
target, renderpass = str(renderlayer_name).split(":")
|
||||||
|
|
||||||
|
render_dir = os.path.join(folder, renderpass)
|
||||||
|
if renderlayer_name.enabled:
|
||||||
|
for f in range(startFrame, endFrame):
|
||||||
|
render_element = "{0}.{1}.{2}".format(render_dir, str(f), fmt)
|
||||||
|
render_element = render_element.replace("\\", "/")
|
||||||
|
render_dirname.append(render_element)
|
||||||
|
|
||||||
|
return render_dirname
|
||||||
|
|
||||||
|
def image_format(self):
|
||||||
|
img_fmt = self._project_settings["max"]["RenderSettings"]["image_format"]
|
||||||
|
return img_fmt
|
||||||
125
openpype/hosts/max/api/lib_rendersettings.py
Normal file
125
openpype/hosts/max/api/lib_rendersettings.py
Normal file
|
|
@ -0,0 +1,125 @@
|
||||||
|
import os
|
||||||
|
from pymxs import runtime as rt
|
||||||
|
from openpype.lib import Logger
|
||||||
|
from openpype.settings import get_project_settings
|
||||||
|
from openpype.pipeline import legacy_io
|
||||||
|
from openpype.pipeline.context_tools import get_current_project_asset
|
||||||
|
|
||||||
|
from openpype.hosts.max.api.lib import (
|
||||||
|
set_framerange,
|
||||||
|
get_current_renderer,
|
||||||
|
get_default_render_folder
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class RenderSettings(object):
|
||||||
|
|
||||||
|
log = Logger.get_logger("RenderSettings")
|
||||||
|
|
||||||
|
_aov_chars = {
|
||||||
|
"dot": ".",
|
||||||
|
"dash": "-",
|
||||||
|
"underscore": "_"
|
||||||
|
}
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def __init__(self, project_settings=None):
|
||||||
|
self._project_settings = project_settings
|
||||||
|
if not self._project_settings:
|
||||||
|
self._project_settings = get_project_settings(
|
||||||
|
legacy_io.Session["AVALON_PROJECT"]
|
||||||
|
)
|
||||||
|
|
||||||
|
def set_render_camera(self, selection):
|
||||||
|
for sel in selection:
|
||||||
|
# to avoid Attribute Error from pymxs wrapper
|
||||||
|
found = False
|
||||||
|
if rt.classOf(sel) in rt.Camera.classes:
|
||||||
|
found = True
|
||||||
|
rt.viewport.setCamera(sel)
|
||||||
|
break
|
||||||
|
if not found:
|
||||||
|
raise RuntimeError("Camera not found")
|
||||||
|
|
||||||
|
|
||||||
|
def set_renderoutput(self, container):
|
||||||
|
folder = rt.maxFilePath
|
||||||
|
# hard-coded, should be customized in the setting
|
||||||
|
folder = folder.replace("\\", "/")
|
||||||
|
# hard-coded, set the renderoutput path
|
||||||
|
setting = self._project_settings
|
||||||
|
render_folder = get_default_render_folder(setting)
|
||||||
|
output_dir = os.path.join(folder, render_folder)
|
||||||
|
if not os.path.exists(output_dir):
|
||||||
|
os.makedirs(output_dir)
|
||||||
|
# hard-coded, should be customized in the setting
|
||||||
|
context = get_current_project_asset()
|
||||||
|
|
||||||
|
# get project reoslution
|
||||||
|
width = context["data"].get("resolutionWidth")
|
||||||
|
height = context["data"].get("resolutionHeight")
|
||||||
|
# Set Frame Range
|
||||||
|
startFrame = context["data"].get("frameStart")
|
||||||
|
endFrame = context["data"].get("frameEnd")
|
||||||
|
set_framerange(startFrame, endFrame)
|
||||||
|
# get the production render
|
||||||
|
renderer_class = get_current_renderer()
|
||||||
|
renderer = str(renderer_class).split(":")[0]
|
||||||
|
|
||||||
|
img_fmt = self._project_settings["max"]["RenderSettings"]["image_format"]
|
||||||
|
output = os.path.join(output_dir, container)
|
||||||
|
try:
|
||||||
|
aov_separator = self._aov_chars[(
|
||||||
|
self._project_settings["maya"]
|
||||||
|
["RenderSettings"]
|
||||||
|
["aov_separator"]
|
||||||
|
)]
|
||||||
|
except KeyError:
|
||||||
|
aov_separator = "."
|
||||||
|
outputFilename = "{0}.{1}".format(output, img_fmt)
|
||||||
|
outputFilename = outputFilename.replace("{aov_separator}", aov_separator)
|
||||||
|
rt.rendOutputFilename = outputFilename
|
||||||
|
if renderer == "VUE_File_Renderer":
|
||||||
|
return
|
||||||
|
# TODO: Finish the arnold render setup
|
||||||
|
if renderer == "Arnold":
|
||||||
|
return
|
||||||
|
|
||||||
|
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"
|
||||||
|
):
|
||||||
|
self.render_element_layer(output, width, height, img_fmt)
|
||||||
|
|
||||||
|
rt.rendSaveFile= True
|
||||||
|
|
||||||
|
|
||||||
|
def render_element_layer(self, dir, width, height, ext):
|
||||||
|
"""For Renderers with render elements"""
|
||||||
|
rt.renderWidth = width
|
||||||
|
rt.renderHeight = height
|
||||||
|
render_elem = rt.maxOps.GetCurRenderElementMgr()
|
||||||
|
render_elem_num = render_elem.NumRenderElements()
|
||||||
|
if render_elem_num < 0:
|
||||||
|
return
|
||||||
|
|
||||||
|
for i in range(render_elem_num):
|
||||||
|
renderlayer_name = render_elem.GetRenderElement(i)
|
||||||
|
target, renderpass = str(renderlayer_name).split(":")
|
||||||
|
render_element = os.path.join(dir, renderpass)
|
||||||
|
aov_name = "{0}.{1}".format(render_element, ext)
|
||||||
|
try:
|
||||||
|
aov_separator = self._aov_chars[(
|
||||||
|
self._project_settings["maya"]
|
||||||
|
["RenderSettings"]
|
||||||
|
["aov_separator"]
|
||||||
|
)]
|
||||||
|
except KeyError:
|
||||||
|
aov_separator = "."
|
||||||
|
|
||||||
|
aov_name = aov_name.replace("{aov_separator}", aov_separator)
|
||||||
|
render_elem.SetRenderElementFileName(i, aov_name)
|
||||||
33
openpype/hosts/max/plugins/create/create_render.py
Normal file
33
openpype/hosts/max/plugins/create/create_render.py
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""Creator plugin for creating camera."""
|
||||||
|
from openpype.hosts.max.api import plugin
|
||||||
|
from openpype.pipeline import CreatedInstance
|
||||||
|
from openpype.hosts.max.api.lib_rendersettings import RenderSettings
|
||||||
|
|
||||||
|
|
||||||
|
class CreateRender(plugin.MaxCreator):
|
||||||
|
identifier = "io.openpype.creators.max.render"
|
||||||
|
label = "Render"
|
||||||
|
family = "maxrender"
|
||||||
|
icon = "gear"
|
||||||
|
|
||||||
|
def create(self, subset_name, instance_data, pre_create_data):
|
||||||
|
from pymxs import runtime as rt
|
||||||
|
sel_obj = list(rt.selection)
|
||||||
|
instance = super(CreateRender, self).create(
|
||||||
|
subset_name,
|
||||||
|
instance_data,
|
||||||
|
pre_create_data) # type: CreatedInstance
|
||||||
|
container_name = instance.data.get("instance_node")
|
||||||
|
container = rt.getNodeByName(container_name)
|
||||||
|
# TODO: Disable "Add to Containers?" Panel
|
||||||
|
# parent the selected cameras into the container
|
||||||
|
for obj in sel_obj:
|
||||||
|
obj.parent = container
|
||||||
|
# for additional work on the node:
|
||||||
|
# instance_node = rt.getNodeByName(instance.get("instance_node"))
|
||||||
|
|
||||||
|
# set viewport camera for rendering(mandatory for deadline)
|
||||||
|
RenderSettings().set_render_camera(sel_obj)
|
||||||
|
# set output paths for rendering(mandatory for deadline)
|
||||||
|
RenderSettings().set_renderoutput(container_name)
|
||||||
72
openpype/hosts/max/plugins/publish/collect_render.py
Normal file
72
openpype/hosts/max/plugins/publish/collect_render.py
Normal file
|
|
@ -0,0 +1,72 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""Collect Render"""
|
||||||
|
import os
|
||||||
|
import pyblish.api
|
||||||
|
|
||||||
|
from pymxs import runtime as rt
|
||||||
|
from openpype.pipeline import legacy_io
|
||||||
|
from openpype.hosts.max.api.lib import get_current_renderer
|
||||||
|
from openpype.hosts.max.api.lib_renderproducts import RenderProducts
|
||||||
|
|
||||||
|
|
||||||
|
class CollectRender(pyblish.api.InstancePlugin):
|
||||||
|
"""Collect Render for Deadline"""
|
||||||
|
|
||||||
|
order = pyblish.api.CollectorOrder + 0.01
|
||||||
|
label = "Collect 3dmax Render Layers"
|
||||||
|
hosts = ['max']
|
||||||
|
families = ["maxrender"]
|
||||||
|
|
||||||
|
def process(self, instance):
|
||||||
|
context = instance.context
|
||||||
|
folder = rt.maxFilePath
|
||||||
|
file = rt.maxFileName
|
||||||
|
current_file = os.path.join(folder, file)
|
||||||
|
filepath = current_file.replace("\\", "/")
|
||||||
|
|
||||||
|
context.data['currentFile'] = current_file
|
||||||
|
asset = legacy_io.Session["AVALON_ASSET"]
|
||||||
|
|
||||||
|
render_layer_files = RenderProducts().render_product(instance.name)
|
||||||
|
folder = folder.replace("\\", "/")
|
||||||
|
|
||||||
|
imgFormat = RenderProducts().image_format()
|
||||||
|
renderer_class = get_current_renderer()
|
||||||
|
renderer_name = str(renderer_class).split(":")[0]
|
||||||
|
# setup the plugin as 3dsmax for the internal renderer
|
||||||
|
if (
|
||||||
|
renderer_name == "ART_Renderer" or
|
||||||
|
renderer_name == "Default_Scanline_Renderer" or
|
||||||
|
renderer_name == "Quicksilver_Hardware_Renderer"
|
||||||
|
):
|
||||||
|
plugin = "3dsmax"
|
||||||
|
|
||||||
|
if (
|
||||||
|
renderer_name == "V_Ray_6_Hotfix_3" or
|
||||||
|
renderer_name == "V_Ray_GPU_6_Hotfix_3"
|
||||||
|
):
|
||||||
|
plugin = "Vray"
|
||||||
|
|
||||||
|
if renderer_name == "Redshift Renderer":
|
||||||
|
plugin = "redshift"
|
||||||
|
|
||||||
|
if renderer_name == "Arnold":
|
||||||
|
plugin = "arnold"
|
||||||
|
|
||||||
|
# https://forums.autodesk.com/t5/3ds-max-programming/pymxs-quickrender-animation-range/td-p/11216183
|
||||||
|
|
||||||
|
data = {
|
||||||
|
"subset": instance.name,
|
||||||
|
"asset": asset,
|
||||||
|
"publish": True,
|
||||||
|
"imageFormat": imgFormat,
|
||||||
|
"family": 'maxrender',
|
||||||
|
"families": ['maxrender'],
|
||||||
|
"source": filepath,
|
||||||
|
"files": render_layer_files,
|
||||||
|
"plugin": plugin,
|
||||||
|
"frameStart": context.data['frameStart'],
|
||||||
|
"frameEnd": context.data['frameEnd']
|
||||||
|
}
|
||||||
|
self.log.info("data: {0}".format(data))
|
||||||
|
instance.data.update(data)
|
||||||
|
|
@ -184,7 +184,6 @@ class CollectMayaRender(pyblish.api.ContextPlugin):
|
||||||
self.log.info("multipart: {}".format(
|
self.log.info("multipart: {}".format(
|
||||||
multipart))
|
multipart))
|
||||||
assert exp_files, "no file names were generated, this is bug"
|
assert exp_files, "no file names were generated, this is bug"
|
||||||
self.log.info(exp_files)
|
|
||||||
|
|
||||||
# if we want to attach render to subset, check if we have AOV's
|
# 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
|
# in expectedFiles. If so, raise error as we cannot attach AOV
|
||||||
|
|
@ -320,7 +319,6 @@ class CollectMayaRender(pyblish.api.ContextPlugin):
|
||||||
"renderSetupIncludeLights"
|
"renderSetupIncludeLights"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
# Collect Deadline url if Deadline module is enabled
|
# Collect Deadline url if Deadline module is enabled
|
||||||
deadline_settings = (
|
deadline_settings = (
|
||||||
context.data["system_settings"]["modules"]["deadline"]
|
context.data["system_settings"]["modules"]["deadline"]
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,137 @@
|
||||||
|
import os
|
||||||
|
import json
|
||||||
|
import getpass
|
||||||
|
|
||||||
|
import requests
|
||||||
|
import pyblish.api
|
||||||
|
|
||||||
|
|
||||||
|
from openpype.pipeline import legacy_io
|
||||||
|
|
||||||
|
|
||||||
|
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"]
|
||||||
|
|
||||||
|
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"])
|
||||||
|
)
|
||||||
|
|
||||||
|
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"],
|
||||||
|
"Pool": instance.data.get("primaryPool"),
|
||||||
|
"secondaryPool": instance.data.get("secondaryPool"),
|
||||||
|
"Frames": frames,
|
||||||
|
"ChunkSize" : instance.data.get("chunkSize", 10),
|
||||||
|
"Comment": comment
|
||||||
|
},
|
||||||
|
"PluginInfo": {
|
||||||
|
# Input
|
||||||
|
"SceneFile": instance.data["source"],
|
||||||
|
"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["files"]):
|
||||||
|
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)
|
||||||
|
|
||||||
|
payload["JobInfo"].update(output_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, verify=False)
|
||||||
|
if not response.ok:
|
||||||
|
raise Exception(response.text)
|
||||||
|
# Store output dir for unified publisher (filesequence)
|
||||||
|
expected_files = instance.data["files"]
|
||||||
|
self.log.info("exp:{}".format(expected_files))
|
||||||
|
output_dir = os.path.dirname(expected_files[0])
|
||||||
|
instance.data["outputDir"] = output_dir
|
||||||
|
instance.data["deadlineSubmissionJob"] = response.json()
|
||||||
7
openpype/settings/defaults/project_settings/max.json
Normal file
7
openpype/settings/defaults/project_settings/max.json
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
"RenderSettings": {
|
||||||
|
"default_render_image_folder": "renders/max",
|
||||||
|
"aov_separator": "underscore",
|
||||||
|
"image_format": "exr"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -82,6 +82,10 @@
|
||||||
"type": "schema",
|
"type": "schema",
|
||||||
"name": "schema_project_slack"
|
"name": "schema_project_slack"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "schema",
|
||||||
|
"name": "schema_project_max"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "schema",
|
"type": "schema",
|
||||||
"name": "schema_project_maya"
|
"name": "schema_project_maya"
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,52 @@
|
||||||
|
{
|
||||||
|
"type": "dict",
|
||||||
|
"collapsible": true,
|
||||||
|
"key": "max",
|
||||||
|
"label": "Max",
|
||||||
|
"is_file": true,
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"type": "dict",
|
||||||
|
"collapsible": true,
|
||||||
|
"key": "RenderSettings",
|
||||||
|
"label": "Render Settings",
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"key": "default_render_image_folder",
|
||||||
|
"label": "Default render image folder"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "aov_separator",
|
||||||
|
"label": "AOV Separator character",
|
||||||
|
"type": "enum",
|
||||||
|
"multiselection": false,
|
||||||
|
"default": "underscore",
|
||||||
|
"enum_items": [
|
||||||
|
{"dash": "- (dash)"},
|
||||||
|
{"underscore": "_ (underscore)"},
|
||||||
|
{"dot": ". (dot)"}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "image_format",
|
||||||
|
"label": "Output Image Format",
|
||||||
|
"type": "enum",
|
||||||
|
"multiselection": false,
|
||||||
|
"defaults": "exr",
|
||||||
|
"enum_items": [
|
||||||
|
{"avi": "avi"},
|
||||||
|
{"bmp": "bmp"},
|
||||||
|
{"exr": "exr"},
|
||||||
|
{"tif": "tif"},
|
||||||
|
{"tiff": "tiff"},
|
||||||
|
{"jpg": "jpg"},
|
||||||
|
{"png": "png"},
|
||||||
|
{"tga": "tga"},
|
||||||
|
{"dds": "dds"}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue