mirror of
https://github.com/ynput/ayon-core.git
synced 2025-12-26 13:52:15 +01:00
Merge branch 'REN-44' of https://github.com/aardschok/colorbleed-config into REN-44b
This commit is contained in:
commit
0ebd3fa873
6 changed files with 453 additions and 8 deletions
|
|
@ -123,7 +123,9 @@ class SubmitDependentImageSequenceJobDeadline(pyblish.api.InstancePlugin):
|
|||
label = "Submit image sequence jobs to Deadline"
|
||||
order = pyblish.api.IntegratorOrder + 0.1
|
||||
hosts = ["fusion", "maya"]
|
||||
families = ["colorbleed.saver.deadline", "colorbleed.renderlayer"]
|
||||
families = ["colorbleed.saver.deadline",
|
||||
"colorbleed.renderlayer",
|
||||
"colorbleed.vrayscene"]
|
||||
|
||||
def process(self, instance):
|
||||
|
||||
|
|
@ -134,8 +136,10 @@ class SubmitDependentImageSequenceJobDeadline(pyblish.api.InstancePlugin):
|
|||
# Get a submission job
|
||||
job = instance.data.get("deadlineSubmissionJob")
|
||||
if not job:
|
||||
raise RuntimeError("Can't continue without valid deadline "
|
||||
"submission prior to this plug-in.")
|
||||
self.log.warning("Can't continue without valid deadline "
|
||||
"submission prior to this plug-in.")
|
||||
self.log.info("Skipping Publish Job")
|
||||
return
|
||||
|
||||
data = instance.data.copy()
|
||||
subset = data["subset"]
|
||||
|
|
@ -155,15 +159,17 @@ class SubmitDependentImageSequenceJobDeadline(pyblish.api.InstancePlugin):
|
|||
# This assumes the output files start with subset name and ends with
|
||||
# a file extension.
|
||||
if "ext" in instance.data:
|
||||
ext = re.escape(instance.data["ext"])
|
||||
ext = instance.data["ext"].strip(".")
|
||||
else:
|
||||
ext = "\.\D+"
|
||||
|
||||
regex = "^{subset}.*\d+{ext}$".format(subset=re.escape(subset),
|
||||
ext=ext)
|
||||
regex = "^{subset}.*\d+\.{ext}$".format(subset=re.escape(subset),
|
||||
ext=re.escape(ext))
|
||||
|
||||
# Remove deadline submission job, not needed in metadata
|
||||
data.pop("deadlineSubmissionJob")
|
||||
|
||||
# Write metadata for publish job
|
||||
render_job = data.pop("deadlineSubmissionJob")
|
||||
metadata = {
|
||||
"regex": regex,
|
||||
"startFrame": start,
|
||||
|
|
@ -189,7 +195,7 @@ class SubmitDependentImageSequenceJobDeadline(pyblish.api.InstancePlugin):
|
|||
override = data["overrideExistingFrame"]
|
||||
|
||||
# override = data.get("overrideExistingFrame", False)
|
||||
out_file = render_job.get("OutFile")
|
||||
out_file = job.get("OutFile")
|
||||
if not out_file:
|
||||
raise RuntimeError("OutFile not found in render job!")
|
||||
|
||||
|
|
|
|||
34
colorbleed/plugins/maya/create/colorbleed_vrayscene.py
Normal file
34
colorbleed/plugins/maya/create/colorbleed_vrayscene.py
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
from collections import OrderedDict
|
||||
|
||||
import avalon.maya
|
||||
|
||||
|
||||
class CreateVRayScene(avalon.maya.Creator):
|
||||
|
||||
label = "VRay Scene"
|
||||
family = "colorbleed.vrayscene"
|
||||
# icon = "blocks"
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(CreateVRayScene, self).__init__(*args, **kwargs)
|
||||
|
||||
# We won't be publishing this one
|
||||
self.data["id"] = "avalon.vrayscene"
|
||||
|
||||
# We don't need subset or asset attributes
|
||||
self.data.pop("subset", None)
|
||||
self.data.pop("asset", None)
|
||||
self.data.pop("active", None)
|
||||
|
||||
data = OrderedDict(**self.data)
|
||||
|
||||
data["camera"] = "persp"
|
||||
data["suspendRenderJob"] = False
|
||||
data["suspendPublishJob"] = False
|
||||
data["includeDefaultRenderLayer"] = False
|
||||
data["extendFrames"] = False
|
||||
data["pools"] = ""
|
||||
|
||||
self.data = data
|
||||
|
||||
self.options = {"useSelection": False} # Force no content
|
||||
111
colorbleed/plugins/maya/publish/collect_vray_scene.py
Normal file
111
colorbleed/plugins/maya/publish/collect_vray_scene.py
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
import os
|
||||
|
||||
import pyblish.api
|
||||
|
||||
from avalon import api, maya
|
||||
|
||||
from maya import cmds
|
||||
|
||||
|
||||
class CollectVRayScene(pyblish.api.ContextPlugin):
|
||||
"""Collect all information prior for exporting vrscenes
|
||||
"""
|
||||
|
||||
order = pyblish.api.CollectorOrder
|
||||
label = "Collect VRay Scene"
|
||||
hosts = ["maya"]
|
||||
|
||||
def process(self, context):
|
||||
|
||||
# Sort by displayOrder
|
||||
def sort_by_display_order(layer):
|
||||
return cmds.getAttr("%s.displayOrder" % layer)
|
||||
|
||||
asset = api.Session["AVALON_ASSET"]
|
||||
work_dir = context.data["workspaceDir"]
|
||||
|
||||
# Get VRay Scene instance
|
||||
vray_scenes = maya.lsattr("family", "colorbleed.vrayscene")
|
||||
if not vray_scenes:
|
||||
self.log.info("No instance found of family: `colorbleed.vrayscene`")
|
||||
return
|
||||
|
||||
assert len(vray_scenes) == 1, "Multiple vrayscene instances found!"
|
||||
vray_scene = vray_scenes[0]
|
||||
|
||||
vrscene_data = {k: cmds.getAttr("%s.%s" % (vray_scene, k)) for
|
||||
k in cmds.listAttr(vray_scene, userDefined=True)}
|
||||
|
||||
# Output data
|
||||
start_frame = int(cmds.getAttr("defaultRenderGlobals.startFrame"))
|
||||
end_frame = int(cmds.getAttr("defaultRenderGlobals.endFrame"))
|
||||
|
||||
# Create output file path with template
|
||||
file_name = context.data["currentFile"].replace("\\", "/")
|
||||
vrscene = ("vrayscene", "<Scene>", "<Scene>_<Layer>", "<Layer>")
|
||||
vrscene_output = os.path.join(work_dir, *vrscene)
|
||||
|
||||
vrscene_data["startFrame"] = start_frame
|
||||
vrscene_data["endFrame"] = end_frame
|
||||
vrscene_data["vrsceneOutput"] = vrscene_output
|
||||
|
||||
context.data["startFrame"] = start_frame
|
||||
context.data["endFrame"] = end_frame
|
||||
|
||||
# Check and create render output template for render job
|
||||
# outputDir is required for submit_publish_job
|
||||
if not vrscene_data.get("suspendRenderJob", False):
|
||||
renders = ("renders", "<Scene>", "<Scene>_<Layer>", "<Layer>")
|
||||
output_renderpath = os.path.join(work_dir, *renders)
|
||||
vrscene_data["outputDir"] = output_renderpath
|
||||
|
||||
# Get resolution
|
||||
resolution = (cmds.getAttr("defaultResolution.width"),
|
||||
cmds.getAttr("defaultResolution.height"))
|
||||
|
||||
# Get format extension
|
||||
extension = cmds.getAttr("vraySettings.imageFormatStr")
|
||||
|
||||
# Get render layers
|
||||
render_layers = [i for i in cmds.ls(type="renderLayer") if
|
||||
cmds.getAttr("{}.renderable".format(i)) and not
|
||||
cmds.referenceQuery(i, isNodeReferenced=True)]
|
||||
|
||||
# Check if we need to filter out the default render layer
|
||||
if vrscene_data.get("includeDefaultRenderLayer", True):
|
||||
render_layers = [r for r in render_layers
|
||||
if r != "defaultRenderLayer"]
|
||||
|
||||
render_layers = sorted(render_layers, key=sort_by_display_order)
|
||||
for layer in render_layers:
|
||||
|
||||
if layer.endswith("defaultRenderLayer"):
|
||||
layer = "masterLayer"
|
||||
|
||||
data = {
|
||||
"subset": layer,
|
||||
"setMembers": layer,
|
||||
|
||||
"startFrame": start_frame,
|
||||
"endFrame": end_frame,
|
||||
"renderer": "vray",
|
||||
"resolution": resolution,
|
||||
"ext": extension,
|
||||
|
||||
# instance subset
|
||||
"family": "VRay Scene",
|
||||
"families": ["colorbleed.vrayscene"],
|
||||
"asset": asset,
|
||||
"time": api.time(),
|
||||
"author": context.data["user"],
|
||||
|
||||
# Add source to allow tracing back to the scene from
|
||||
# which was submitted originally
|
||||
"source": file_name
|
||||
}
|
||||
|
||||
data.update(vrscene_data)
|
||||
|
||||
instance = context.create_instance(layer)
|
||||
self.log.info("Created: %s" % instance.name)
|
||||
instance.data.update(data)
|
||||
249
colorbleed/plugins/maya/publish/submit_vray_deadline.py
Normal file
249
colorbleed/plugins/maya/publish/submit_vray_deadline.py
Normal file
|
|
@ -0,0 +1,249 @@
|
|||
import getpass
|
||||
import json
|
||||
import os
|
||||
from copy import deepcopy
|
||||
|
||||
import pyblish.api
|
||||
|
||||
from avalon import api
|
||||
from avalon.vendor import requests
|
||||
|
||||
from maya import cmds
|
||||
|
||||
|
||||
class VraySubmitDeadline(pyblish.api.InstancePlugin):
|
||||
"""Export the scene to `.vrscene` files per frame per render layer
|
||||
|
||||
vrscene files will be written out based on the following template:
|
||||
<project>/vrayscene/<Scene>/<Scene>_<Layer>/<Layer>
|
||||
|
||||
A dependency job will be added for each layer to render the framer
|
||||
through VRay Standalone
|
||||
|
||||
"""
|
||||
label = "Submit to Deadline ( vrscene )"
|
||||
order = pyblish.api.IntegratorOrder
|
||||
hosts = ["maya"]
|
||||
families = ["colorbleed.vrayscene"]
|
||||
|
||||
def process(self, instance):
|
||||
|
||||
AVALON_DEADLINE = api.Session.get("AVALON_DEADLINE",
|
||||
"http://localhost:8082")
|
||||
assert AVALON_DEADLINE, "Requires AVALON_DEADLINE"
|
||||
|
||||
context = instance.context
|
||||
|
||||
deadline_url = "{}/api/jobs".format(AVALON_DEADLINE)
|
||||
deadline_user = context.data.get("deadlineUser", getpass.getuser())
|
||||
|
||||
filepath = context.data["currentFile"]
|
||||
filename = os.path.basename(filepath)
|
||||
task_name = "{} - {}".format(filename, instance.name)
|
||||
|
||||
batch_name = "VRay Scene Export - {}".format(filename)
|
||||
|
||||
# Get the output template for vrscenes
|
||||
vrscene_output = instance.data["vrsceneOutput"]
|
||||
|
||||
# This is also the input file for the render job
|
||||
first_file = self.format_output_filename(instance,
|
||||
filename,
|
||||
vrscene_output)
|
||||
|
||||
# Primary job
|
||||
self.log.info("Submitting export job ..")
|
||||
|
||||
payload = {
|
||||
"JobInfo": {
|
||||
# Top-level group name
|
||||
"BatchName": batch_name,
|
||||
|
||||
# Job name, as seen in Monitor
|
||||
"Name": task_name,
|
||||
|
||||
# Arbitrary username, for visualisation in Monitor
|
||||
"UserName": deadline_user,
|
||||
|
||||
"Plugin": "MayaCmd",
|
||||
"Frames": "1",
|
||||
|
||||
"Comment": context.data.get("comment", ""),
|
||||
},
|
||||
"PluginInfo": {
|
||||
|
||||
# Mandatory for Deadline
|
||||
"Version": cmds.about(version=True),
|
||||
|
||||
# Input
|
||||
"SceneFile": filepath,
|
||||
# Output directory and filename
|
||||
"OutputFilePath": vrscene_output.replace("\\", "/"),
|
||||
|
||||
"CommandLineOptions": self.build_command(instance),
|
||||
|
||||
"UseOnlyCommandLineOptions": True,
|
||||
|
||||
"SkipExistingFrames": True,
|
||||
},
|
||||
|
||||
# Mandatory for Deadline, may be empty
|
||||
"AuxFiles": []
|
||||
}
|
||||
|
||||
environment = dict(AVALON_TOOLS="global;python36;maya2018")
|
||||
environment.update(api.Session.copy())
|
||||
|
||||
jobinfo_environment = self.build_jobinfo_environment(environment)
|
||||
|
||||
payload["JobInfo"].update(jobinfo_environment)
|
||||
|
||||
self.log.info("Job Data:\n{}".format(json.dumps(payload)))
|
||||
|
||||
response = requests.post(url=deadline_url, json=payload)
|
||||
if not response.ok:
|
||||
raise RuntimeError(response.text)
|
||||
|
||||
# Secondary job
|
||||
# Store job to create dependency chain
|
||||
dependency = response.json()
|
||||
|
||||
if instance.data["suspendRenderJob"]:
|
||||
self.log.info("Skipping render job and publish job")
|
||||
return
|
||||
|
||||
self.log.info("Submitting render job ..")
|
||||
|
||||
start_frame = int(instance.data["startFrame"])
|
||||
end_frame = int(instance.data["endFrame"])
|
||||
ext = instance.data.get("ext", "exr")
|
||||
|
||||
# Create output directory for renders
|
||||
render_ouput = self.format_output_filename(instance,
|
||||
filename,
|
||||
instance.data["outputDir"],
|
||||
dir=True)
|
||||
|
||||
self.log.info("Render output: %s" % render_ouput)
|
||||
|
||||
# Update output dir
|
||||
instance.data["outputDir"] = render_ouput
|
||||
|
||||
# Format output file name
|
||||
sequence_filename = ".".join([instance.name, "%04d", ext])
|
||||
output_filename = os.path.join(render_ouput, sequence_filename)
|
||||
|
||||
payload_b = {
|
||||
"JobInfo": {
|
||||
|
||||
"JobDependency0": dependency["_id"],
|
||||
"BatchName": batch_name,
|
||||
"Name": "Render {}".format(task_name),
|
||||
"UserName": deadline_user,
|
||||
|
||||
"Frames": "{}-{}".format(start_frame, end_frame),
|
||||
|
||||
"Plugin": "Vray",
|
||||
"OverrideTaskExtraInfoNames": False,
|
||||
"Whitelist": "cb7"
|
||||
},
|
||||
"PluginInfo": {
|
||||
|
||||
"InputFilename": first_file,
|
||||
"OutputFilename": output_filename,
|
||||
"SeparateFilesPerFrame": True,
|
||||
"VRayEngine": "V-Ray",
|
||||
|
||||
"Width": instance.data["resolution"][0],
|
||||
"Height": instance.data["resolution"][1],
|
||||
|
||||
},
|
||||
"AuxFiles": [],
|
||||
}
|
||||
|
||||
# Add vray renderslave to environment
|
||||
tools = environment["AVALON_TOOLS"] + ";vrayrenderslave"
|
||||
environment_b = deepcopy(environment)
|
||||
environment_b["AVALON_TOOLS"] = tools
|
||||
|
||||
jobinfo_environment_b = self.build_jobinfo_environment(environment_b)
|
||||
payload_b["JobInfo"].update(jobinfo_environment_b)
|
||||
|
||||
self.log.info(json.dumps(payload_b))
|
||||
|
||||
# Post job to deadline
|
||||
response_b = requests.post(url=deadline_url, json=payload_b)
|
||||
if not response_b.ok:
|
||||
raise RuntimeError(response_b.text)
|
||||
|
||||
# Add job for publish job
|
||||
if not instance.data.get("suspendPublishJob", False):
|
||||
instance.data["deadlineSubmissionJob"] = response_b.json()
|
||||
|
||||
def build_command(self, instance):
|
||||
"""Create command for Render.exe to export vray scene
|
||||
|
||||
Returns:
|
||||
str
|
||||
|
||||
"""
|
||||
|
||||
cmd = ('-r vray -proj {project} -cam {cam} -noRender -s {startFrame} '
|
||||
'-e {endFrame} -rl {layer} -exportFramesSeparate')
|
||||
|
||||
return cmd.format(project=instance.context.data["workspaceDir"],
|
||||
cam=instance.data.get("cam", "persp"),
|
||||
startFrame=instance.data["startFrame"],
|
||||
endFrame=instance.data["endFrame"],
|
||||
layer=instance.name)
|
||||
|
||||
def build_jobinfo_environment(self, env):
|
||||
"""Format environment keys and values to match Deadline rquirements
|
||||
|
||||
Returns:
|
||||
dict
|
||||
|
||||
"""
|
||||
return {"EnvironmentKeyValue%d" % index: "%s=%s" % (k, env[k])
|
||||
for index, k in enumerate(env)}
|
||||
|
||||
def format_output_filename(self, instance, filename, template, dir=False):
|
||||
"""Format the expected output file of the Export job
|
||||
|
||||
Example:
|
||||
<Scene>/<Scene>_<Layer>/<Layer>
|
||||
"shot010_v006/shot010_v006_CHARS/CHARS"
|
||||
|
||||
Args:
|
||||
instance:
|
||||
filename(str):
|
||||
dir(bool):
|
||||
|
||||
Returns:
|
||||
str
|
||||
|
||||
"""
|
||||
|
||||
def smart_replace(string, key_values):
|
||||
new_string = string
|
||||
for key, value in key_values.items():
|
||||
new_string = new_string.replace(key, value)
|
||||
return new_string
|
||||
|
||||
# Ensure filename has no extension
|
||||
file_name, _ = os.path.splitext(filename)
|
||||
|
||||
# Reformat without tokens
|
||||
output_path = smart_replace(template,
|
||||
{"<Scene>": file_name,
|
||||
"<Layer>": instance.name})
|
||||
|
||||
if dir:
|
||||
return output_path.replace("\\", "/")
|
||||
|
||||
start_frame = int(instance.data["startFrame"])
|
||||
filename_zero = "{}_{:04d}.vrscene".format(output_path, start_frame)
|
||||
|
||||
result = filename_zero.replace("\\", "/")
|
||||
|
||||
return result
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
import pyblish.api
|
||||
import colorbleed.api
|
||||
|
||||
from maya import cmds
|
||||
|
||||
|
||||
class ValidateTranslatorEnabled(pyblish.api.ContextPlugin):
|
||||
|
||||
order = colorbleed.api.ValidateContentsOrder
|
||||
label = "VRay Translator Settings"
|
||||
families = ["colorbleed.vrayscene"]
|
||||
actions = [colorbleed.api.RepairContextAction]
|
||||
|
||||
def process(self, context):
|
||||
|
||||
# Get vraySettings node
|
||||
vray_settings = cmds.ls(type="VRaySettingsNode")
|
||||
assert vray_settings, "Please ensure a VRay Settings Node is present"
|
||||
|
||||
node = vray_settings[0]
|
||||
|
||||
if not cmds.getAttr("{}.vrscene_on".format(node)):
|
||||
self.info.error("Export vrscene not enabled")
|
||||
|
||||
if not cmds.getAttr("{}.misc_eachFrameInFile".format(node)):
|
||||
self.info.error("Each Frame in File not enabled")
|
||||
|
||||
vrscene_filename = cmds.getAttr("{}.vrscene_filename".format(node))
|
||||
if vrscene_filename != "vrayscene/<Scene>/<Scene>_<Layer>/<Layer>":
|
||||
self.info.error("Template for file name is wrong")
|
||||
|
||||
@classmethod
|
||||
def repair(cls, context):
|
||||
|
||||
vray_settings = cmds.ls(type="VRaySettingsNode")
|
||||
if not vray_settings:
|
||||
node = cmds.createNode("VRaySettingsNode")
|
||||
else:
|
||||
node = vray_settings[0]
|
||||
|
||||
cmds.setAttr("{}.vrscene_on".format(node), True)
|
||||
cmds.setAttr("{}.misc_eachFrameInFile".format(node), True)
|
||||
cmds.setAttr("{}.vrscene_filename".format(node),
|
||||
"vrayscene/<Scene>/<Scene>_<Layer>/<Layer>",
|
||||
type="string")
|
||||
Loading…
Add table
Add a link
Reference in a new issue