mirror of
https://github.com/ynput/ayon-core.git
synced 2026-01-01 16:34:53 +01:00
add some comment
This commit is contained in:
parent
22251f4958
commit
7075d5c445
21 changed files with 573 additions and 45 deletions
|
|
@ -0,0 +1,55 @@
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from openpype.lib import PreLaunchHook
|
||||||
|
|
||||||
|
|
||||||
|
class AddPythonScriptToLaunchArgs(PreLaunchHook):
|
||||||
|
"""Add python script to be executed before Blender launch."""
|
||||||
|
|
||||||
|
# Append after file argument
|
||||||
|
order = 15
|
||||||
|
app_groups = [
|
||||||
|
"blender",
|
||||||
|
]
|
||||||
|
|
||||||
|
def execute(self):
|
||||||
|
if not self.launch_context.data.get("python_scripts"):
|
||||||
|
return
|
||||||
|
|
||||||
|
# Add path to workfile to arguments
|
||||||
|
for python_script_path in self.launch_context.data["python_scripts"]:
|
||||||
|
self.log.info(
|
||||||
|
f"Adding python script {python_script_path} to launch"
|
||||||
|
)
|
||||||
|
# Test script path exists
|
||||||
|
python_script_path = Path(python_script_path)
|
||||||
|
if not python_script_path.exists():
|
||||||
|
self.log.warning(
|
||||||
|
f"Python script {python_script_path} doesn't exist. "
|
||||||
|
"Skipped..."
|
||||||
|
)
|
||||||
|
continue
|
||||||
|
|
||||||
|
if "--" in self.launch_context.launch_args:
|
||||||
|
# Insert before separator
|
||||||
|
separator_index = self.launch_context.launch_args.index("--")
|
||||||
|
self.launch_context.launch_args.insert(
|
||||||
|
separator_index,
|
||||||
|
"-P",
|
||||||
|
)
|
||||||
|
self.launch_context.launch_args.insert(
|
||||||
|
separator_index + 1,
|
||||||
|
python_script_path.as_posix(),
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
self.launch_context.launch_args.extend(
|
||||||
|
["-P", python_script_path.as_posix()]
|
||||||
|
)
|
||||||
|
|
||||||
|
# Ensure separator
|
||||||
|
if "--" not in self.launch_context.launch_args:
|
||||||
|
self.launch_context.launch_args.append("--")
|
||||||
|
|
||||||
|
self.launch_context.launch_args.extend(
|
||||||
|
[*self.launch_context.data.get("script_args", [])]
|
||||||
|
)
|
||||||
|
|
@ -128,7 +128,14 @@ def get_all_children(parent, node_type=None):
|
||||||
|
|
||||||
|
|
||||||
def get_current_renderer():
|
def get_current_renderer():
|
||||||
"""get current renderer"""
|
"""
|
||||||
|
Notes:
|
||||||
|
Get current renderer for Max
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
"{Current Renderer}:{Current Renderer}"
|
||||||
|
e.g. "Redshift_Renderer:Redshift_Renderer"
|
||||||
|
"""
|
||||||
return rt.renderers.production
|
return rt.renderers.production
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
18
openpype/hosts/max/plugins/create/create_redshift_proxy.py
Normal file
18
openpype/hosts/max/plugins/create/create_redshift_proxy.py
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""Creator plugin for creating camera."""
|
||||||
|
from openpype.hosts.max.api import plugin
|
||||||
|
from openpype.pipeline import CreatedInstance
|
||||||
|
|
||||||
|
|
||||||
|
class CreateRedshiftProxy(plugin.MaxCreator):
|
||||||
|
identifier = "io.openpype.creators.max.redshiftproxy"
|
||||||
|
label = "Redshift Proxy"
|
||||||
|
family = "redshiftproxy"
|
||||||
|
icon = "gear"
|
||||||
|
|
||||||
|
def create(self, subset_name, instance_data, pre_create_data):
|
||||||
|
|
||||||
|
_ = super(CreateRedshiftProxy, self).create(
|
||||||
|
subset_name,
|
||||||
|
instance_data,
|
||||||
|
pre_create_data) # type: CreatedInstance
|
||||||
63
openpype/hosts/max/plugins/load/load_redshift_proxy.py
Normal file
63
openpype/hosts/max/plugins/load/load_redshift_proxy.py
Normal file
|
|
@ -0,0 +1,63 @@
|
||||||
|
import os
|
||||||
|
import clique
|
||||||
|
|
||||||
|
from openpype.pipeline import (
|
||||||
|
load,
|
||||||
|
get_representation_path
|
||||||
|
)
|
||||||
|
from openpype.hosts.max.api.pipeline import containerise
|
||||||
|
from openpype.hosts.max.api import lib
|
||||||
|
|
||||||
|
|
||||||
|
class RedshiftProxyLoader(load.LoaderPlugin):
|
||||||
|
"""Load rs files with Redshift Proxy"""
|
||||||
|
|
||||||
|
label = "Load Redshift Proxy"
|
||||||
|
families = ["redshiftproxy"]
|
||||||
|
representations = ["rs"]
|
||||||
|
order = -9
|
||||||
|
icon = "code-fork"
|
||||||
|
color = "white"
|
||||||
|
|
||||||
|
def load(self, context, name=None, namespace=None, data=None):
|
||||||
|
from pymxs import runtime as rt
|
||||||
|
|
||||||
|
filepath = self.filepath_from_context(context)
|
||||||
|
rs_proxy = rt.RedshiftProxy()
|
||||||
|
rs_proxy.file = filepath
|
||||||
|
files_in_folder = os.listdir(os.path.dirname(filepath))
|
||||||
|
collections, remainder = clique.assemble(files_in_folder)
|
||||||
|
if collections:
|
||||||
|
rs_proxy.is_sequence = True
|
||||||
|
|
||||||
|
container = rt.container()
|
||||||
|
container.name = name
|
||||||
|
rs_proxy.Parent = container
|
||||||
|
|
||||||
|
asset = rt.getNodeByName(name)
|
||||||
|
|
||||||
|
return containerise(
|
||||||
|
name, [asset], context, loader=self.__class__.__name__)
|
||||||
|
|
||||||
|
def update(self, container, representation):
|
||||||
|
from pymxs import runtime as rt
|
||||||
|
|
||||||
|
path = get_representation_path(representation)
|
||||||
|
node = rt.getNodeByName(container["instance_node"])
|
||||||
|
for children in node.Children:
|
||||||
|
children_node = rt.getNodeByName(children.name)
|
||||||
|
for proxy in children_node.Children:
|
||||||
|
proxy.file = path
|
||||||
|
|
||||||
|
lib.imprint(container["instance_node"], {
|
||||||
|
"representation": str(representation["_id"])
|
||||||
|
})
|
||||||
|
|
||||||
|
def switch(self, container, representation):
|
||||||
|
self.update(container, representation)
|
||||||
|
|
||||||
|
def remove(self, container):
|
||||||
|
from pymxs import runtime as rt
|
||||||
|
|
||||||
|
node = rt.getNodeByName(container["instance_node"])
|
||||||
|
rt.delete(node)
|
||||||
62
openpype/hosts/max/plugins/publish/extract_redshift_proxy.py
Normal file
62
openpype/hosts/max/plugins/publish/extract_redshift_proxy.py
Normal file
|
|
@ -0,0 +1,62 @@
|
||||||
|
import os
|
||||||
|
import pyblish.api
|
||||||
|
from openpype.pipeline import publish
|
||||||
|
from pymxs import runtime as rt
|
||||||
|
from openpype.hosts.max.api import maintained_selection
|
||||||
|
|
||||||
|
|
||||||
|
class ExtractRedshiftProxy(publish.Extractor):
|
||||||
|
"""
|
||||||
|
Extract Redshift Proxy with rsProxy
|
||||||
|
"""
|
||||||
|
|
||||||
|
order = pyblish.api.ExtractorOrder - 0.1
|
||||||
|
label = "Extract RedShift Proxy"
|
||||||
|
hosts = ["max"]
|
||||||
|
families = ["redshiftproxy"]
|
||||||
|
|
||||||
|
def process(self, instance):
|
||||||
|
container = instance.data["instance_node"]
|
||||||
|
start = int(instance.context.data.get("frameStart"))
|
||||||
|
end = int(instance.context.data.get("frameEnd"))
|
||||||
|
|
||||||
|
self.log.info("Extracting Redshift Proxy...")
|
||||||
|
stagingdir = self.staging_dir(instance)
|
||||||
|
rs_filename = "{name}.rs".format(**instance.data)
|
||||||
|
rs_filepath = os.path.join(stagingdir, rs_filename)
|
||||||
|
rs_filepath = rs_filepath.replace("\\", "/")
|
||||||
|
|
||||||
|
rs_filenames = self.get_rsfiles(instance, start, end)
|
||||||
|
|
||||||
|
with maintained_selection():
|
||||||
|
# select and export
|
||||||
|
con = rt.getNodeByName(container)
|
||||||
|
rt.select(con.Children)
|
||||||
|
# Redshift rsProxy command
|
||||||
|
# rsProxy fp selected compress connectivity startFrame endFrame
|
||||||
|
# camera warnExisting transformPivotToOrigin
|
||||||
|
rt.rsProxy(rs_filepath, 1, 0, 0, start, end, 0, 1, 1)
|
||||||
|
|
||||||
|
self.log.info("Performing Extraction ...")
|
||||||
|
|
||||||
|
if "representations" not in instance.data:
|
||||||
|
instance.data["representations"] = []
|
||||||
|
|
||||||
|
representation = {
|
||||||
|
'name': 'rs',
|
||||||
|
'ext': 'rs',
|
||||||
|
'files': rs_filenames if len(rs_filenames) > 1 else rs_filenames[0], # noqa
|
||||||
|
"stagingDir": stagingdir,
|
||||||
|
}
|
||||||
|
instance.data["representations"].append(representation)
|
||||||
|
self.log.info("Extracted instance '%s' to: %s" % (instance.name,
|
||||||
|
stagingdir))
|
||||||
|
|
||||||
|
def get_rsfiles(self, instance, startFrame, endFrame):
|
||||||
|
rs_filenames = []
|
||||||
|
rs_name = instance.data["name"]
|
||||||
|
for frame in range(startFrame, endFrame + 1):
|
||||||
|
rs_filename = "%s.%04d.rs" % (rs_name, frame)
|
||||||
|
rs_filenames.append(rs_filename)
|
||||||
|
|
||||||
|
return rs_filenames
|
||||||
|
|
@ -0,0 +1,54 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
import pyblish.api
|
||||||
|
from openpype.pipeline import PublishValidationError
|
||||||
|
from pymxs import runtime as rt
|
||||||
|
from openpype.pipeline.publish import RepairAction
|
||||||
|
from openpype.hosts.max.api.lib import get_current_renderer
|
||||||
|
|
||||||
|
|
||||||
|
class ValidateRendererRedshiftProxy(pyblish.api.InstancePlugin):
|
||||||
|
"""
|
||||||
|
Validates Redshift as the current renderer for creating
|
||||||
|
Redshift Proxy
|
||||||
|
"""
|
||||||
|
|
||||||
|
order = pyblish.api.ValidatorOrder
|
||||||
|
families = ["redshiftproxy"]
|
||||||
|
hosts = ["max"]
|
||||||
|
label = "Redshift Renderer"
|
||||||
|
actions = [RepairAction]
|
||||||
|
|
||||||
|
def process(self, instance):
|
||||||
|
invalid = self.get_redshift_renderer(instance)
|
||||||
|
if invalid:
|
||||||
|
raise PublishValidationError("Please install Redshift for 3dsMax"
|
||||||
|
" before using the Redshift proxy instance") # noqa
|
||||||
|
invalid = self.get_current_renderer(instance)
|
||||||
|
if invalid:
|
||||||
|
raise PublishValidationError("The Redshift proxy extraction"
|
||||||
|
"discontinued since the current renderer is not Redshift") # noqa
|
||||||
|
|
||||||
|
def get_redshift_renderer(self, instance):
|
||||||
|
invalid = list()
|
||||||
|
max_renderers_list = str(rt.RendererClass.classes)
|
||||||
|
if "Redshift_Renderer" not in max_renderers_list:
|
||||||
|
invalid.append(max_renderers_list)
|
||||||
|
|
||||||
|
return invalid
|
||||||
|
|
||||||
|
def get_current_renderer(self, instance):
|
||||||
|
invalid = list()
|
||||||
|
renderer_class = get_current_renderer()
|
||||||
|
current_renderer = str(renderer_class).split(":")[0]
|
||||||
|
if current_renderer != "Redshift_Renderer":
|
||||||
|
invalid.append(current_renderer)
|
||||||
|
|
||||||
|
return invalid
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def repair(cls, instance):
|
||||||
|
for Renderer in rt.RendererClass.classes:
|
||||||
|
renderer = Renderer()
|
||||||
|
if "Redshift_Renderer" in str(renderer):
|
||||||
|
rt.renderers.production = renderer
|
||||||
|
break
|
||||||
0
openpype/hosts/nuke/startup/__init__.py
Normal file
0
openpype/hosts/nuke/startup/__init__.py
Normal file
|
|
@ -68,6 +68,7 @@ def main():
|
||||||
if knob["name"] == "file_type":
|
if knob["name"] == "file_type":
|
||||||
ext = knob["value"]
|
ext = knob["value"]
|
||||||
for w in write_selected_nodes:
|
for w in write_selected_nodes:
|
||||||
|
# data for mapping the path
|
||||||
data = {
|
data = {
|
||||||
"work": os.getenv("AVALON_WORKDIR"),
|
"work": os.getenv("AVALON_WORKDIR"),
|
||||||
"subset": w["name"].value(),
|
"subset": w["name"].value(),
|
||||||
|
|
|
||||||
47
openpype/hosts/nuke/startup/frame_setting_for_read_nodes.py
Normal file
47
openpype/hosts/nuke/startup/frame_setting_for_read_nodes.py
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
""" OpenPype custom script for resetting read nodes start frame values """
|
||||||
|
|
||||||
|
import nuke
|
||||||
|
import nukescripts
|
||||||
|
|
||||||
|
|
||||||
|
class FrameSettingsPanel(nukescripts.PythonPanel):
|
||||||
|
""" Frame Settings Panel """
|
||||||
|
def __init__(self):
|
||||||
|
nukescripts.PythonPanel.__init__(self, "Set Frame Start (Read Node)")
|
||||||
|
|
||||||
|
# create knobs
|
||||||
|
self.frame = nuke.Int_Knob(
|
||||||
|
'frame', 'Frame Number')
|
||||||
|
self.selected = nuke.Boolean_Knob("selection")
|
||||||
|
# add knobs to panel
|
||||||
|
self.addKnob(self.selected)
|
||||||
|
self.addKnob(self.frame)
|
||||||
|
|
||||||
|
# set values
|
||||||
|
self.selected.setValue(False)
|
||||||
|
self.frame.setValue(nuke.root().firstFrame())
|
||||||
|
|
||||||
|
def process(self):
|
||||||
|
""" Process the panel values. """
|
||||||
|
# get values
|
||||||
|
frame = self.frame.value()
|
||||||
|
if self.selected.value():
|
||||||
|
# selected nodes processing
|
||||||
|
if not nuke.selectedNodes():
|
||||||
|
return
|
||||||
|
for rn_ in nuke.selectedNodes():
|
||||||
|
if rn_.Class() != "Read":
|
||||||
|
continue
|
||||||
|
rn_["frame_mode"].setValue("start_at")
|
||||||
|
rn_["frame"].setValue(str(frame))
|
||||||
|
else:
|
||||||
|
# all nodes processing
|
||||||
|
for rn_ in nuke.allNodes(filter="Read"):
|
||||||
|
rn_["frame_mode"].setValue("start_at")
|
||||||
|
rn_["frame"].setValue(str(frame))
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
p_ = FrameSettingsPanel()
|
||||||
|
if p_.showModalDialog():
|
||||||
|
print(p_.process())
|
||||||
|
|
@ -43,18 +43,22 @@ def open_file(filepath):
|
||||||
"""
|
"""
|
||||||
Loading project
|
Loading project
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
from . import bmdvr
|
||||||
|
|
||||||
pm = get_project_manager()
|
pm = get_project_manager()
|
||||||
|
page = bmdvr.GetCurrentPage()
|
||||||
|
if page is not None:
|
||||||
|
# Save current project only if Resolve has an active page, otherwise
|
||||||
|
# we consider Resolve being in a pre-launch state (no open UI yet)
|
||||||
|
project = pm.GetCurrentProject()
|
||||||
|
print(f"Saving current project: {project}")
|
||||||
|
pm.SaveProject()
|
||||||
|
|
||||||
file = os.path.basename(filepath)
|
file = os.path.basename(filepath)
|
||||||
fname, _ = os.path.splitext(file)
|
fname, _ = os.path.splitext(file)
|
||||||
dname, _ = fname.split("_v")
|
dname, _ = fname.split("_v")
|
||||||
|
|
||||||
# deal with current project
|
|
||||||
project = pm.GetCurrentProject()
|
|
||||||
log.info(f"Test `pm`: {pm}")
|
|
||||||
pm.SaveProject()
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
log.info(f"Test `dname`: {dname}")
|
|
||||||
if not set_project_manager_to_folder_name(dname):
|
if not set_project_manager_to_folder_name(dname):
|
||||||
raise
|
raise
|
||||||
# load project from input path
|
# load project from input path
|
||||||
|
|
@ -72,6 +76,7 @@ def open_file(filepath):
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def current_file():
|
def current_file():
|
||||||
pm = get_project_manager()
|
pm = get_project_manager()
|
||||||
current_dir = os.getenv("AVALON_WORKDIR")
|
current_dir = os.getenv("AVALON_WORKDIR")
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,45 @@
|
||||||
|
import os
|
||||||
|
|
||||||
|
from openpype.lib import PreLaunchHook
|
||||||
|
import openpype.hosts.resolve
|
||||||
|
|
||||||
|
|
||||||
|
class ResolveLaunchLastWorkfile(PreLaunchHook):
|
||||||
|
"""Special hook to open last workfile for Resolve.
|
||||||
|
|
||||||
|
Checks 'start_last_workfile', if set to False, it will not open last
|
||||||
|
workfile. This property is set explicitly in Launcher.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Execute after workfile template copy
|
||||||
|
order = 10
|
||||||
|
app_groups = ["resolve"]
|
||||||
|
|
||||||
|
def execute(self):
|
||||||
|
if not self.data.get("start_last_workfile"):
|
||||||
|
self.log.info("It is set to not start last workfile on start.")
|
||||||
|
return
|
||||||
|
|
||||||
|
last_workfile = self.data.get("last_workfile_path")
|
||||||
|
if not last_workfile:
|
||||||
|
self.log.warning("Last workfile was not collected.")
|
||||||
|
return
|
||||||
|
|
||||||
|
if not os.path.exists(last_workfile):
|
||||||
|
self.log.info("Current context does not have any workfile yet.")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Add path to launch environment for the startup script to pick up
|
||||||
|
self.log.info(f"Setting OPENPYPE_RESOLVE_OPEN_ON_LAUNCH to launch "
|
||||||
|
f"last workfile: {last_workfile}")
|
||||||
|
key = "OPENPYPE_RESOLVE_OPEN_ON_LAUNCH"
|
||||||
|
self.launch_context.env[key] = last_workfile
|
||||||
|
|
||||||
|
# Set the openpype prelaunch startup script path for easy access
|
||||||
|
# in the LUA .scriptlib code
|
||||||
|
op_resolve_root = os.path.dirname(openpype.hosts.resolve.__file__)
|
||||||
|
script_path = os.path.join(op_resolve_root, "startup.py")
|
||||||
|
key = "OPENPYPE_RESOLVE_STARTUP_SCRIPT"
|
||||||
|
self.launch_context.env[key] = script_path
|
||||||
|
self.log.info("Setting OPENPYPE_RESOLVE_STARTUP_SCRIPT to: "
|
||||||
|
f"{script_path}")
|
||||||
62
openpype/hosts/resolve/startup.py
Normal file
62
openpype/hosts/resolve/startup.py
Normal file
|
|
@ -0,0 +1,62 @@
|
||||||
|
"""This script is used as a startup script in Resolve through a .scriptlib file
|
||||||
|
|
||||||
|
It triggers directly after the launch of Resolve and it's recommended to keep
|
||||||
|
it optimized for fast performance since the Resolve UI is actually interactive
|
||||||
|
while this is running. As such, there's nothing ensuring the user isn't
|
||||||
|
continuing manually before any of the logic here runs. As such we also try
|
||||||
|
to delay any imports as much as possible.
|
||||||
|
|
||||||
|
This code runs in a separate process to the main Resolve process.
|
||||||
|
|
||||||
|
"""
|
||||||
|
import os
|
||||||
|
|
||||||
|
import openpype.hosts.resolve.api
|
||||||
|
|
||||||
|
|
||||||
|
def ensure_installed_host():
|
||||||
|
"""Install resolve host with openpype and return the registered host.
|
||||||
|
|
||||||
|
This function can be called multiple times without triggering an
|
||||||
|
additional install.
|
||||||
|
"""
|
||||||
|
from openpype.pipeline import install_host, registered_host
|
||||||
|
host = registered_host()
|
||||||
|
if host:
|
||||||
|
return host
|
||||||
|
|
||||||
|
install_host(openpype.hosts.resolve.api)
|
||||||
|
return registered_host()
|
||||||
|
|
||||||
|
|
||||||
|
def launch_menu():
|
||||||
|
print("Launching Resolve OpenPype menu..")
|
||||||
|
ensure_installed_host()
|
||||||
|
openpype.hosts.resolve.api.launch_pype_menu()
|
||||||
|
|
||||||
|
|
||||||
|
def open_file(path):
|
||||||
|
# Avoid the need to "install" the host
|
||||||
|
host = ensure_installed_host()
|
||||||
|
host.open_file(path)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
# Open last workfile
|
||||||
|
workfile_path = os.environ.get("OPENPYPE_RESOLVE_OPEN_ON_LAUNCH")
|
||||||
|
if workfile_path:
|
||||||
|
open_file(workfile_path)
|
||||||
|
else:
|
||||||
|
print("No last workfile set to open. Skipping..")
|
||||||
|
|
||||||
|
# Launch OpenPype menu
|
||||||
|
from openpype.settings import get_project_settings
|
||||||
|
from openpype.pipeline.context_tools import get_current_project_name
|
||||||
|
project_name = get_current_project_name()
|
||||||
|
settings = get_project_settings(project_name)
|
||||||
|
if settings.get("resolve", {}).get("launch_openpype_menu_on_start", True):
|
||||||
|
launch_menu()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
-- Run OpenPype's Python launch script for resolve
|
||||||
|
function file_exists(name)
|
||||||
|
local f = io.open(name, "r")
|
||||||
|
return f ~= nil and io.close(f)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
openpype_startup_script = os.getenv("OPENPYPE_RESOLVE_STARTUP_SCRIPT")
|
||||||
|
if openpype_startup_script ~= nil then
|
||||||
|
script = fusion:MapPath(openpype_startup_script)
|
||||||
|
|
||||||
|
if file_exists(script) then
|
||||||
|
-- We must use RunScript to ensure it runs in a separate
|
||||||
|
-- process to Resolve itself to avoid a deadlock for
|
||||||
|
-- certain imports of OpenPype libraries or Qt
|
||||||
|
print("Running launch script: " .. script)
|
||||||
|
fusion:RunScript(script)
|
||||||
|
else
|
||||||
|
print("Launch script not found at: " .. script)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -29,6 +29,9 @@ def setup(env):
|
||||||
log.info("Utility Scripts Dir: `{}`".format(util_scripts_paths))
|
log.info("Utility Scripts Dir: `{}`".format(util_scripts_paths))
|
||||||
log.info("Utility Scripts: `{}`".format(scripts))
|
log.info("Utility Scripts: `{}`".format(scripts))
|
||||||
|
|
||||||
|
# Make sure scripts dir exists
|
||||||
|
os.makedirs(util_scripts_dir, exist_ok=True)
|
||||||
|
|
||||||
# make sure no script file is in folder
|
# make sure no script file is in folder
|
||||||
for script in os.listdir(util_scripts_dir):
|
for script in os.listdir(util_scripts_dir):
|
||||||
path = os.path.join(util_scripts_dir, script)
|
path = os.path.join(util_scripts_dir, script)
|
||||||
|
|
@ -50,6 +53,14 @@ def setup(env):
|
||||||
|
|
||||||
src = os.path.join(directory, script)
|
src = os.path.join(directory, script)
|
||||||
dst = os.path.join(util_scripts_dir, script)
|
dst = os.path.join(util_scripts_dir, script)
|
||||||
|
|
||||||
|
# TODO: Make this a less hacky workaround
|
||||||
|
if script == "openpype_startup.scriptlib":
|
||||||
|
# Handle special case for scriptlib that needs to be a folder
|
||||||
|
# up from the Comp folder in the Fusion scripts
|
||||||
|
dst = os.path.join(os.path.dirname(util_scripts_dir),
|
||||||
|
script)
|
||||||
|
|
||||||
log.info("Copying `{}` to `{}`...".format(src, dst))
|
log.info("Copying `{}` to `{}`...".format(src, dst))
|
||||||
if os.path.isdir(src):
|
if os.path.isdir(src):
|
||||||
shutil.copytree(
|
shutil.copytree(
|
||||||
|
|
|
||||||
|
|
@ -35,41 +35,47 @@ class CollectFramesFixDef(
|
||||||
|
|
||||||
rewrite_version = attribute_values.get("rewrite_version")
|
rewrite_version = attribute_values.get("rewrite_version")
|
||||||
|
|
||||||
if frames_to_fix:
|
if not frames_to_fix:
|
||||||
instance.data["frames_to_fix"] = frames_to_fix
|
return
|
||||||
|
|
||||||
subset_name = instance.data["subset"]
|
instance.data["frames_to_fix"] = frames_to_fix
|
||||||
asset_name = instance.data["asset"]
|
|
||||||
|
|
||||||
project_entity = instance.data["projectEntity"]
|
subset_name = instance.data["subset"]
|
||||||
project_name = project_entity["name"]
|
asset_name = instance.data["asset"]
|
||||||
|
|
||||||
version = get_last_version_by_subset_name(project_name,
|
project_entity = instance.data["projectEntity"]
|
||||||
subset_name,
|
project_name = project_entity["name"]
|
||||||
asset_name=asset_name)
|
|
||||||
if not version:
|
|
||||||
self.log.warning("No last version found, "
|
|
||||||
"re-render not possible")
|
|
||||||
return
|
|
||||||
|
|
||||||
representations = get_representations(project_name,
|
version = get_last_version_by_subset_name(
|
||||||
version_ids=[version["_id"]])
|
project_name,
|
||||||
published_files = []
|
subset_name,
|
||||||
for repre in representations:
|
asset_name=asset_name
|
||||||
if repre["context"]["family"] not in self.families:
|
)
|
||||||
continue
|
if not version:
|
||||||
|
self.log.warning(
|
||||||
|
"No last version found, re-render not possible"
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
for file_info in repre.get("files"):
|
representations = get_representations(
|
||||||
published_files.append(file_info["path"])
|
project_name, version_ids=[version["_id"]]
|
||||||
|
)
|
||||||
|
published_files = []
|
||||||
|
for repre in representations:
|
||||||
|
if repre["context"]["family"] not in self.families:
|
||||||
|
continue
|
||||||
|
|
||||||
instance.data["last_version_published_files"] = published_files
|
for file_info in repre.get("files"):
|
||||||
self.log.debug("last_version_published_files::{}".format(
|
published_files.append(file_info["path"])
|
||||||
instance.data["last_version_published_files"]))
|
|
||||||
|
|
||||||
if rewrite_version:
|
instance.data["last_version_published_files"] = published_files
|
||||||
instance.data["version"] = version["name"]
|
self.log.debug("last_version_published_files::{}".format(
|
||||||
# limits triggering version validator
|
instance.data["last_version_published_files"]))
|
||||||
instance.data.pop("latestVersion")
|
|
||||||
|
if self.rewrite_version_enable and rewrite_version:
|
||||||
|
instance.data["version"] = version["name"]
|
||||||
|
# limits triggering version validator
|
||||||
|
instance.data.pop("latestVersion")
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_attribute_defs(cls):
|
def get_attribute_defs(cls):
|
||||||
|
|
|
||||||
|
|
@ -223,6 +223,13 @@
|
||||||
"command": "import webbrowser;webbrowser.open(url='https://openpype.io/docs/artist_hosts_nuke_tut')",
|
"command": "import webbrowser;webbrowser.open(url='https://openpype.io/docs/artist_hosts_nuke_tut')",
|
||||||
"tooltip": "Open the OpenPype Nuke user doc page"
|
"tooltip": "Open the OpenPype Nuke user doc page"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "action",
|
||||||
|
"sourcetype": "python",
|
||||||
|
"title": "Set Frame Start (Read Node)",
|
||||||
|
"command": "from openpype.hosts.nuke.startup.frame_setting_for_read_nodes import main;main();",
|
||||||
|
"tooltip": "Set frame start for read node(s)"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "action",
|
"type": "action",
|
||||||
"sourcetype": "python",
|
"sourcetype": "python",
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
{
|
{
|
||||||
|
"launch_openpype_menu_on_start": false,
|
||||||
"imageio": {
|
"imageio": {
|
||||||
"ocio_config": {
|
"ocio_config": {
|
||||||
"enabled": false,
|
"enabled": false,
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,11 @@
|
||||||
"label": "DaVinci Resolve",
|
"label": "DaVinci Resolve",
|
||||||
"is_file": true,
|
"is_file": true,
|
||||||
"children": [
|
"children": [
|
||||||
|
{
|
||||||
|
"type": "boolean",
|
||||||
|
"key": "launch_openpype_menu_on_start",
|
||||||
|
"label": "Launch OpenPype menu on start of Resolve"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"key": "imageio",
|
"key": "imageio",
|
||||||
"type": "dict",
|
"type": "dict",
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ By clicking the icon ```OpenPype Menu``` rolls out.
|
||||||
|
|
||||||
Choose ```OpenPype Menu > Launcher``` to open the ```Launcher``` window.
|
Choose ```OpenPype Menu > Launcher``` to open the ```Launcher``` window.
|
||||||
|
|
||||||
When opened you can **choose** the **project** to work in from the list. Then choose the particular **asset** you want to work on then choose **task**
|
When opened you can **choose** the **project** to work in from the list. Then choose the particular **asset** you want to work on then choose **task**
|
||||||
and finally **run 3dsmax by its icon** in the tools.
|
and finally **run 3dsmax by its icon** in the tools.
|
||||||
|
|
||||||

|

|
||||||
|
|
@ -65,13 +65,13 @@ If not any workfile present simply hit ```Save As``` and keep ```Subversion``` e
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
OpenPype correctly names it and add version to the workfile. This basically happens whenever user trigger ```Save As``` action. Resulting into incremental version numbers like
|
OpenPype correctly names it and add version to the workfile. This basically happens whenever user trigger ```Save As``` action. Resulting into incremental version numbers like
|
||||||
|
|
||||||
```workfileName_v001```
|
```workfileName_v001```
|
||||||
|
|
||||||
```workfileName_v002```
|
```workfileName_v002```
|
||||||
|
|
||||||
etc.
|
etc.
|
||||||
|
|
||||||
Basically meaning user is free of guessing what is the correct naming and other necessities to keep everything in order and managed.
|
Basically meaning user is free of guessing what is the correct naming and other necessities to keep everything in order and managed.
|
||||||
|
|
||||||
|
|
@ -105,13 +105,13 @@ Before proceeding further please check [Glossary](artist_concepts.md) and [What
|
||||||
|
|
||||||
### Intro
|
### Intro
|
||||||
|
|
||||||
Current OpenPype integration (ver 3.15.0) supports only ```PointCache``` and ```Camera``` families now.
|
Current OpenPype integration (ver 3.15.0) supports only ```PointCache```, ```Camera```, ```Geometry``` and ```Redshift Proxy``` families now.
|
||||||
|
|
||||||
**Pointcache** family being basically any geometry outputted as Alembic cache (.abc) format
|
**Pointcache** family being basically any geometry outputted as Alembic cache (.abc) format
|
||||||
|
|
||||||
**Camera** family being 3dsmax Camera object with/without animation outputted as native .max, FBX, Alembic format
|
**Camera** family being 3dsmax Camera object with/without animation outputted as native .max, FBX, Alembic format
|
||||||
|
|
||||||
|
**Redshift Proxy** family being Redshift Proxy object with/without animation outputted as rs format(Redshift Proxy's very own format)
|
||||||
---
|
---
|
||||||
|
|
||||||
:::note Work in progress
|
:::note Work in progress
|
||||||
|
|
@ -119,7 +119,3 @@ This part of documentation is still work in progress.
|
||||||
:::
|
:::
|
||||||
|
|
||||||
## ...to be added
|
## ...to be added
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
61
website/docs/dev_blender.md
Normal file
61
website/docs/dev_blender.md
Normal file
|
|
@ -0,0 +1,61 @@
|
||||||
|
---
|
||||||
|
id: dev_blender
|
||||||
|
title: Blender integration
|
||||||
|
sidebar_label: Blender integration
|
||||||
|
toc_max_heading_level: 4
|
||||||
|
---
|
||||||
|
|
||||||
|
## Run python script at launch
|
||||||
|
In case you need to execute a python script when Blender is started (aka [`-P`](https://docs.blender.org/manual/en/latest/advanced/command_line/arguments.html#python-options)), for example to programmatically modify a blender file for conformation, you can create an OpenPype hook as follows:
|
||||||
|
|
||||||
|
```python
|
||||||
|
from openpype.hosts.blender.hooks import pre_add_run_python_script_arg
|
||||||
|
from openpype.lib import PreLaunchHook
|
||||||
|
|
||||||
|
|
||||||
|
class MyHook(PreLaunchHook):
|
||||||
|
"""Add python script to be executed before Blender launch."""
|
||||||
|
|
||||||
|
order = pre_add_run_python_script_arg.AddPythonScriptToLaunchArgs.order - 1
|
||||||
|
app_groups = [
|
||||||
|
"blender",
|
||||||
|
]
|
||||||
|
|
||||||
|
def execute(self):
|
||||||
|
self.launch_context.data.setdefault("python_scripts", []).append(
|
||||||
|
"/path/to/my_script.py"
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
You can write a bare python script, as you could run into the [Text Editor](https://docs.blender.org/manual/en/latest/editors/text_editor.html).
|
||||||
|
|
||||||
|
### Python script with arguments
|
||||||
|
#### Adding arguments
|
||||||
|
In case you need to pass arguments to your script, you can append them to `self.launch_context.data["script_args"]`:
|
||||||
|
|
||||||
|
```python
|
||||||
|
self.launch_context.data.setdefault("script_args", []).append(
|
||||||
|
"--my-arg",
|
||||||
|
"value",
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Parsing arguments
|
||||||
|
You can parse arguments in your script using [argparse](https://docs.python.org/3/library/argparse.html) as follows:
|
||||||
|
|
||||||
|
```python
|
||||||
|
import argparse
|
||||||
|
|
||||||
|
parser = argparse.ArgumentParser(
|
||||||
|
description="Parsing arguments for my_script.py"
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--my-arg",
|
||||||
|
nargs="?",
|
||||||
|
help="My argument",
|
||||||
|
)
|
||||||
|
args, unknown = arg_parser.parse_known_args(
|
||||||
|
sys.argv[sys.argv.index("--") + 1 :]
|
||||||
|
)
|
||||||
|
print(args.my_arg)
|
||||||
|
```
|
||||||
|
|
@ -180,6 +180,7 @@ module.exports = {
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"dev_deadline",
|
"dev_deadline",
|
||||||
|
"dev_blender",
|
||||||
"dev_colorspace"
|
"dev_colorspace"
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue