mirror of
https://github.com/ynput/ayon-core.git
synced 2025-12-24 21:04:40 +01:00
Merge branch 'develop' into bugfix/new_publisher_minor_fixes
This commit is contained in:
commit
6ea413ccfe
28 changed files with 802 additions and 154 deletions
37
CHANGELOG.md
37
CHANGELOG.md
|
|
@ -1,8 +1,8 @@
|
|||
# Changelog
|
||||
|
||||
## [3.12.1-nightly.4](https://github.com/pypeclub/OpenPype/tree/HEAD)
|
||||
## [3.12.1](https://github.com/pypeclub/OpenPype/tree/3.12.1) (2022-07-13)
|
||||
|
||||
[Full Changelog](https://github.com/pypeclub/OpenPype/compare/3.12.0...HEAD)
|
||||
[Full Changelog](https://github.com/pypeclub/OpenPype/compare/3.12.0...3.12.1)
|
||||
|
||||
### 📖 Documentation
|
||||
|
||||
|
|
@ -14,6 +14,9 @@
|
|||
|
||||
**🚀 Enhancements**
|
||||
|
||||
- TrayPublisher: Added more options for grouping of instances [\#3494](https://github.com/pypeclub/OpenPype/pull/3494)
|
||||
- NewPublisher: Align creator attributes from top to bottom [\#3487](https://github.com/pypeclub/OpenPype/pull/3487)
|
||||
- NewPublisher: Added ability to use label of instance [\#3484](https://github.com/pypeclub/OpenPype/pull/3484)
|
||||
- General: Creator Plugins have access to project [\#3476](https://github.com/pypeclub/OpenPype/pull/3476)
|
||||
- General: Better arguments order in creator init [\#3475](https://github.com/pypeclub/OpenPype/pull/3475)
|
||||
- Ftrack: Trigger custom ftrack events on project creation and preparation [\#3465](https://github.com/pypeclub/OpenPype/pull/3465)
|
||||
|
|
@ -21,10 +24,15 @@
|
|||
- Blender: Bugfix - Set fps properly on open [\#3426](https://github.com/pypeclub/OpenPype/pull/3426)
|
||||
- Hiero: Add custom scripts menu [\#3425](https://github.com/pypeclub/OpenPype/pull/3425)
|
||||
- Blender: pre pyside install for all platforms [\#3400](https://github.com/pypeclub/OpenPype/pull/3400)
|
||||
- Maya: Ability to set resolution for playblasts from asset, and override through review instance. [\#3360](https://github.com/pypeclub/OpenPype/pull/3360)
|
||||
- Maya: Add additional playblast options to review Extractor. [\#3384](https://github.com/pypeclub/OpenPype/pull/3384)
|
||||
|
||||
**🐛 Bug fixes**
|
||||
|
||||
- TrayPublisher: Keep use instance label in list view [\#3493](https://github.com/pypeclub/OpenPype/pull/3493)
|
||||
- General: Extract review use first frame of input sequence [\#3491](https://github.com/pypeclub/OpenPype/pull/3491)
|
||||
- General: Fix Plist loading for application launch [\#3485](https://github.com/pypeclub/OpenPype/pull/3485)
|
||||
- Nuke: Workfile tools open on start [\#3479](https://github.com/pypeclub/OpenPype/pull/3479)
|
||||
- New Publisher: Disabled context change allows creation [\#3478](https://github.com/pypeclub/OpenPype/pull/3478)
|
||||
- General: thumbnail extractor fix [\#3474](https://github.com/pypeclub/OpenPype/pull/3474)
|
||||
- Kitsu: bugfix with sync-service ans publish plugins [\#3473](https://github.com/pypeclub/OpenPype/pull/3473)
|
||||
- Flame: solved problem with multi-selected loading [\#3470](https://github.com/pypeclub/OpenPype/pull/3470)
|
||||
|
|
@ -38,6 +46,7 @@
|
|||
- Nuke: Slate frame is integrated [\#3427](https://github.com/pypeclub/OpenPype/pull/3427)
|
||||
- Maya: Camera extra data - additional fix for \#3304 [\#3386](https://github.com/pypeclub/OpenPype/pull/3386)
|
||||
- Maya: Handle excluding `model` family from frame range validator. [\#3370](https://github.com/pypeclub/OpenPype/pull/3370)
|
||||
- Harmony: audio validator has wrong logic [\#3364](https://github.com/pypeclub/OpenPype/pull/3364)
|
||||
|
||||
**🔀 Refactored code**
|
||||
|
||||
|
|
@ -46,7 +55,9 @@
|
|||
- General: Use query functions in global plugins [\#3459](https://github.com/pypeclub/OpenPype/pull/3459)
|
||||
- Clockify: Use query functions in clockify actions [\#3458](https://github.com/pypeclub/OpenPype/pull/3458)
|
||||
- General: Use query functions in rest api calls [\#3457](https://github.com/pypeclub/OpenPype/pull/3457)
|
||||
- General: Use query functions in openpype lib functions [\#3454](https://github.com/pypeclub/OpenPype/pull/3454)
|
||||
- General: Use query functions in load utils [\#3446](https://github.com/pypeclub/OpenPype/pull/3446)
|
||||
- General: Move publish plugin and publish render abstractions [\#3442](https://github.com/pypeclub/OpenPype/pull/3442)
|
||||
- General: Use Anatomy after move to pipeline [\#3436](https://github.com/pypeclub/OpenPype/pull/3436)
|
||||
- General: Anatomy moved to pipeline [\#3435](https://github.com/pypeclub/OpenPype/pull/3435)
|
||||
- Fusion: Use client query functions [\#3380](https://github.com/pypeclub/OpenPype/pull/3380)
|
||||
|
|
@ -66,8 +77,6 @@
|
|||
- Webserver: Added CORS middleware [\#3422](https://github.com/pypeclub/OpenPype/pull/3422)
|
||||
- Attribute Defs UI: Files widget show what is allowed to drop in [\#3411](https://github.com/pypeclub/OpenPype/pull/3411)
|
||||
- General: Add ability to change user value for templates [\#3366](https://github.com/pypeclub/OpenPype/pull/3366)
|
||||
- Hosts: More options for in-host callbacks [\#3357](https://github.com/pypeclub/OpenPype/pull/3357)
|
||||
- Multiverse: expose some settings to GUI [\#3350](https://github.com/pypeclub/OpenPype/pull/3350)
|
||||
|
||||
**🐛 Bug fixes**
|
||||
|
||||
|
|
@ -82,7 +91,6 @@
|
|||
- Maya: vray device aspect ratio fix [\#3381](https://github.com/pypeclub/OpenPype/pull/3381)
|
||||
- Flame: bunch of publishing issues [\#3377](https://github.com/pypeclub/OpenPype/pull/3377)
|
||||
- Harmony: added unc path to zifile command in Harmony [\#3372](https://github.com/pypeclub/OpenPype/pull/3372)
|
||||
- Standalone: settings improvements [\#3355](https://github.com/pypeclub/OpenPype/pull/3355)
|
||||
|
||||
**🔀 Refactored code**
|
||||
|
||||
|
|
@ -107,37 +115,20 @@
|
|||
|
||||
[Full Changelog](https://github.com/pypeclub/OpenPype/compare/CI/3.11.1-nightly.1...3.11.1)
|
||||
|
||||
**🆕 New features**
|
||||
|
||||
- Flame: custom export temp folder [\#3346](https://github.com/pypeclub/OpenPype/pull/3346)
|
||||
- Nuke: removing third-party plugins [\#3344](https://github.com/pypeclub/OpenPype/pull/3344)
|
||||
|
||||
**🚀 Enhancements**
|
||||
|
||||
- Pyblish Pype: Hiding/Close issues [\#3367](https://github.com/pypeclub/OpenPype/pull/3367)
|
||||
- Ftrack: Removed requirement of pypeclub role from default settings [\#3354](https://github.com/pypeclub/OpenPype/pull/3354)
|
||||
- Kitsu: Prevent crash on missing frames information [\#3352](https://github.com/pypeclub/OpenPype/pull/3352)
|
||||
|
||||
**🐛 Bug fixes**
|
||||
|
||||
- Nuke: bake streams with slate on farm [\#3368](https://github.com/pypeclub/OpenPype/pull/3368)
|
||||
- Harmony: audio validator has wrong logic [\#3364](https://github.com/pypeclub/OpenPype/pull/3364)
|
||||
- Nuke: Fix missing variable in extract thumbnail [\#3363](https://github.com/pypeclub/OpenPype/pull/3363)
|
||||
- Nuke: Fix precollect writes [\#3361](https://github.com/pypeclub/OpenPype/pull/3361)
|
||||
- AE- fix validate\_scene\_settings and renderLocal [\#3358](https://github.com/pypeclub/OpenPype/pull/3358)
|
||||
- deadline: fixing misidentification of revieables [\#3356](https://github.com/pypeclub/OpenPype/pull/3356)
|
||||
- General: Create only one thumbnail per instance [\#3351](https://github.com/pypeclub/OpenPype/pull/3351)
|
||||
- nuke: adding extract thumbnail settings 3.10 [\#3347](https://github.com/pypeclub/OpenPype/pull/3347)
|
||||
- General: Fix last version function [\#3345](https://github.com/pypeclub/OpenPype/pull/3345)
|
||||
|
||||
## [3.11.0](https://github.com/pypeclub/OpenPype/tree/3.11.0) (2022-06-17)
|
||||
|
||||
[Full Changelog](https://github.com/pypeclub/OpenPype/compare/CI/3.11.0-nightly.4...3.11.0)
|
||||
|
||||
**🐛 Bug fixes**
|
||||
|
||||
- General: Handle empty source key on instance [\#3342](https://github.com/pypeclub/OpenPype/pull/3342)
|
||||
|
||||
## [3.10.0](https://github.com/pypeclub/OpenPype/tree/3.10.0) (2022-05-26)
|
||||
|
||||
[Full Changelog](https://github.com/pypeclub/OpenPype/compare/CI/3.10.0-nightly.6...3.10.0)
|
||||
|
|
|
|||
|
|
@ -2522,12 +2522,30 @@ def load_capture_preset(data=None):
|
|||
temp_options2['multiSampleEnable'] = False
|
||||
temp_options2['multiSampleCount'] = preset[id][key]
|
||||
|
||||
if key == 'renderDepthOfField':
|
||||
temp_options2['renderDepthOfField'] = preset[id][key]
|
||||
|
||||
if key == 'ssaoEnable':
|
||||
if preset[id][key] is True:
|
||||
temp_options2['ssaoEnable'] = True
|
||||
else:
|
||||
temp_options2['ssaoEnable'] = False
|
||||
|
||||
if key == 'ssaoSamples':
|
||||
temp_options2['ssaoSamples'] = preset[id][key]
|
||||
|
||||
if key == 'ssaoAmount':
|
||||
temp_options2['ssaoAmount'] = preset[id][key]
|
||||
|
||||
if key == 'ssaoRadius':
|
||||
temp_options2['ssaoRadius'] = preset[id][key]
|
||||
|
||||
if key == 'hwFogDensity':
|
||||
temp_options2['hwFogDensity'] = preset[id][key]
|
||||
|
||||
if key == 'ssaoFilterRadius':
|
||||
temp_options2['ssaoFilterRadius'] = preset[id][key]
|
||||
|
||||
if key == 'alphaCut':
|
||||
temp_options2['transparencyAlgorithm'] = 5
|
||||
temp_options2['transparencyQuality'] = 1
|
||||
|
|
@ -2535,6 +2553,48 @@ def load_capture_preset(data=None):
|
|||
if key == 'headsUpDisplay':
|
||||
temp_options['headsUpDisplay'] = True
|
||||
|
||||
if key == 'fogging':
|
||||
temp_options['fogging'] = preset[id][key] or False
|
||||
|
||||
if key == 'hwFogStart':
|
||||
temp_options2['hwFogStart'] = preset[id][key]
|
||||
|
||||
if key == 'hwFogEnd':
|
||||
temp_options2['hwFogEnd'] = preset[id][key]
|
||||
|
||||
if key == 'hwFogAlpha':
|
||||
temp_options2['hwFogAlpha'] = preset[id][key]
|
||||
|
||||
if key == 'hwFogFalloff':
|
||||
temp_options2['hwFogFalloff'] = int(preset[id][key])
|
||||
|
||||
if key == 'hwFogColorR':
|
||||
temp_options2['hwFogColorR'] = preset[id][key]
|
||||
|
||||
if key == 'hwFogColorG':
|
||||
temp_options2['hwFogColorG'] = preset[id][key]
|
||||
|
||||
if key == 'hwFogColorB':
|
||||
temp_options2['hwFogColorB'] = preset[id][key]
|
||||
|
||||
if key == 'motionBlurEnable':
|
||||
if preset[id][key] is True:
|
||||
temp_options2['motionBlurEnable'] = True
|
||||
else:
|
||||
temp_options2['motionBlurEnable'] = False
|
||||
|
||||
if key == 'motionBlurSampleCount':
|
||||
temp_options2['motionBlurSampleCount'] = preset[id][key]
|
||||
|
||||
if key == 'motionBlurShutterOpenFraction':
|
||||
temp_options2['motionBlurShutterOpenFraction'] = preset[id][key]
|
||||
|
||||
if key == 'lineAAEnable':
|
||||
if preset[id][key] is True:
|
||||
temp_options2['lineAAEnable'] = True
|
||||
else:
|
||||
temp_options2['lineAAEnable'] = False
|
||||
|
||||
else:
|
||||
temp_options[str(key)] = preset[id][key]
|
||||
|
||||
|
|
@ -2544,7 +2604,24 @@ def load_capture_preset(data=None):
|
|||
'gpuCacheDisplayFilter',
|
||||
'multiSample',
|
||||
'ssaoEnable',
|
||||
'textureMaxResolution'
|
||||
'ssaoSamples',
|
||||
'ssaoAmount',
|
||||
'ssaoFilterRadius',
|
||||
'ssaoRadius',
|
||||
'hwFogStart',
|
||||
'hwFogEnd',
|
||||
'hwFogAlpha',
|
||||
'hwFogFalloff',
|
||||
'hwFogColorR',
|
||||
'hwFogColorG',
|
||||
'hwFogColorB',
|
||||
'hwFogDensity',
|
||||
'textureMaxResolution',
|
||||
'motionBlurEnable',
|
||||
'motionBlurSampleCount',
|
||||
'motionBlurShutterOpenFraction',
|
||||
'lineAAEnable',
|
||||
'renderDepthOfField'
|
||||
]:
|
||||
temp_options.pop(key, None)
|
||||
|
||||
|
|
|
|||
|
|
@ -54,20 +54,28 @@ class LoadClip(plugin.NukeLoader):
|
|||
script_start = int(nuke.root()["first_frame"].value())
|
||||
|
||||
# option gui
|
||||
defaults = {
|
||||
"start_at_workfile": True
|
||||
options_defaults = {
|
||||
"start_at_workfile": True,
|
||||
"add_retime": True
|
||||
}
|
||||
|
||||
options = [
|
||||
qargparse.Boolean(
|
||||
"start_at_workfile",
|
||||
help="Load at workfile start frame",
|
||||
default=True
|
||||
)
|
||||
]
|
||||
|
||||
node_name_template = "{class_name}_{ext}"
|
||||
|
||||
@classmethod
|
||||
def get_options(cls, *args):
|
||||
return [
|
||||
qargparse.Boolean(
|
||||
"start_at_workfile",
|
||||
help="Load at workfile start frame",
|
||||
default=cls.options_defaults["start_at_workfile"]
|
||||
),
|
||||
qargparse.Boolean(
|
||||
"add_retime",
|
||||
help="Load with retime",
|
||||
default=cls.options_defaults["add_retime"]
|
||||
)
|
||||
]
|
||||
|
||||
@classmethod
|
||||
def get_representations(cls):
|
||||
return (
|
||||
|
|
@ -86,7 +94,10 @@ class LoadClip(plugin.NukeLoader):
|
|||
file = self.fname.replace("\\", "/")
|
||||
|
||||
start_at_workfile = options.get(
|
||||
"start_at_workfile", self.defaults["start_at_workfile"])
|
||||
"start_at_workfile", self.options_defaults["start_at_workfile"])
|
||||
|
||||
add_retime = options.get(
|
||||
"add_retime", self.options_defaults["add_retime"])
|
||||
|
||||
version = context['version']
|
||||
version_data = version.get("data", {})
|
||||
|
|
@ -151,7 +162,7 @@ class LoadClip(plugin.NukeLoader):
|
|||
data_imprint = {}
|
||||
for k in add_keys:
|
||||
if k == 'version':
|
||||
data_imprint.update({k: context["version"]['name']})
|
||||
data_imprint[k] = context["version"]['name']
|
||||
elif k == 'colorspace':
|
||||
colorspace = repre["data"].get(k)
|
||||
colorspace = colorspace or version_data.get(k)
|
||||
|
|
@ -159,10 +170,13 @@ class LoadClip(plugin.NukeLoader):
|
|||
if used_colorspace:
|
||||
data_imprint["used_colorspace"] = used_colorspace
|
||||
else:
|
||||
data_imprint.update(
|
||||
{k: context["version"]['data'].get(k, str(None))})
|
||||
data_imprint[k] = context["version"]['data'].get(
|
||||
k, str(None))
|
||||
|
||||
data_imprint.update({"objectName": read_name})
|
||||
data_imprint["objectName"] = read_name
|
||||
|
||||
if add_retime and version_data.get("retime", None):
|
||||
data_imprint["addRetime"] = True
|
||||
|
||||
read_node["tile_color"].setValue(int("0x4ecd25ff", 16))
|
||||
|
||||
|
|
@ -174,7 +188,7 @@ class LoadClip(plugin.NukeLoader):
|
|||
loader=self.__class__.__name__,
|
||||
data=data_imprint)
|
||||
|
||||
if version_data.get("retime", None):
|
||||
if add_retime and version_data.get("retime", None):
|
||||
self._make_retimes(read_node, version_data)
|
||||
|
||||
self.set_as_member(read_node)
|
||||
|
|
@ -198,7 +212,12 @@ class LoadClip(plugin.NukeLoader):
|
|||
read_node = nuke.toNode(container['objectName'])
|
||||
file = get_representation_path(representation).replace("\\", "/")
|
||||
|
||||
start_at_workfile = bool("start at" in read_node['frame_mode'].value())
|
||||
start_at_workfile = "start at" in read_node['frame_mode'].value()
|
||||
|
||||
add_retime = [
|
||||
key for key in read_node.knobs().keys()
|
||||
if "addRetime" in key
|
||||
]
|
||||
|
||||
project_name = legacy_io.active_project()
|
||||
version_doc = get_version_by_id(project_name, representation["parent"])
|
||||
|
|
@ -286,7 +305,7 @@ class LoadClip(plugin.NukeLoader):
|
|||
"updated to version: {}".format(version_doc.get("name"))
|
||||
)
|
||||
|
||||
if version_data.get("retime", None):
|
||||
if add_retime and version_data.get("retime", None):
|
||||
self._make_retimes(read_node, version_data)
|
||||
else:
|
||||
self.clear_members(read_node)
|
||||
|
|
|
|||
|
|
@ -1,20 +1,8 @@
|
|||
from .pipeline import (
|
||||
install,
|
||||
ls,
|
||||
|
||||
set_project_name,
|
||||
get_context_title,
|
||||
get_context_data,
|
||||
update_context_data,
|
||||
TrayPublisherHost,
|
||||
)
|
||||
|
||||
|
||||
__all__ = (
|
||||
"install",
|
||||
"ls",
|
||||
|
||||
"set_project_name",
|
||||
"get_context_title",
|
||||
"get_context_data",
|
||||
"update_context_data",
|
||||
"TrayPublisherHost",
|
||||
)
|
||||
|
|
|
|||
|
|
@ -9,6 +9,8 @@ from openpype.pipeline import (
|
|||
register_creator_plugin_path,
|
||||
legacy_io,
|
||||
)
|
||||
from openpype.host import HostBase, INewPublisher
|
||||
|
||||
|
||||
ROOT_DIR = os.path.dirname(os.path.dirname(
|
||||
os.path.abspath(__file__)
|
||||
|
|
@ -17,6 +19,35 @@ PUBLISH_PATH = os.path.join(ROOT_DIR, "plugins", "publish")
|
|||
CREATE_PATH = os.path.join(ROOT_DIR, "plugins", "create")
|
||||
|
||||
|
||||
class TrayPublisherHost(HostBase, INewPublisher):
|
||||
name = "traypublisher"
|
||||
|
||||
def install(self):
|
||||
os.environ["AVALON_APP"] = self.name
|
||||
legacy_io.Session["AVALON_APP"] = self.name
|
||||
|
||||
pyblish.api.register_host("traypublisher")
|
||||
pyblish.api.register_plugin_path(PUBLISH_PATH)
|
||||
register_creator_plugin_path(CREATE_PATH)
|
||||
|
||||
def get_context_title(self):
|
||||
return HostContext.get_project_name()
|
||||
|
||||
def get_context_data(self):
|
||||
return HostContext.get_context_data()
|
||||
|
||||
def update_context_data(self, data, changes):
|
||||
HostContext.save_context_data(data, changes)
|
||||
|
||||
def set_project_name(self, project_name):
|
||||
# TODO Deregister project specific plugins and register new project
|
||||
# plugins
|
||||
os.environ["AVALON_PROJECT"] = project_name
|
||||
legacy_io.Session["AVALON_PROJECT"] = project_name
|
||||
legacy_io.install()
|
||||
HostContext.set_project_name(project_name)
|
||||
|
||||
|
||||
class HostContext:
|
||||
_context_json_path = None
|
||||
|
||||
|
|
@ -150,32 +181,3 @@ def get_context_data():
|
|||
|
||||
def update_context_data(data, changes):
|
||||
HostContext.save_context_data(data)
|
||||
|
||||
|
||||
def get_context_title():
|
||||
return HostContext.get_project_name()
|
||||
|
||||
|
||||
def ls():
|
||||
"""Probably will never return loaded containers."""
|
||||
return []
|
||||
|
||||
|
||||
def install():
|
||||
"""This is called before a project is known.
|
||||
|
||||
Project is defined with 'set_project_name'.
|
||||
"""
|
||||
os.environ["AVALON_APP"] = "traypublisher"
|
||||
|
||||
pyblish.api.register_host("traypublisher")
|
||||
pyblish.api.register_plugin_path(PUBLISH_PATH)
|
||||
register_creator_plugin_path(CREATE_PATH)
|
||||
|
||||
|
||||
def set_project_name(project_name):
|
||||
# TODO Deregister project specific plugins and register new project plugins
|
||||
os.environ["AVALON_PROJECT"] = project_name
|
||||
legacy_io.Session["AVALON_PROJECT"] = project_name
|
||||
legacy_io.install()
|
||||
HostContext.set_project_name(project_name)
|
||||
|
|
|
|||
|
|
@ -37,6 +37,21 @@ class TrayPublishCreator(Creator):
|
|||
# Use same attributes as for instance attrobites
|
||||
return self.get_instance_attr_defs()
|
||||
|
||||
def _store_new_instance(self, new_instance):
|
||||
"""Tray publisher specific method to store instance.
|
||||
|
||||
Instance is stored into "workfile" of traypublisher and also add it
|
||||
to CreateContext.
|
||||
|
||||
Args:
|
||||
new_instance (CreatedInstance): Instance that should be stored.
|
||||
"""
|
||||
|
||||
# Host implementation of storing metadata about instance
|
||||
HostContext.add_instance(new_instance.data_to_store())
|
||||
# Add instance to current context
|
||||
self._add_instance_to_context(new_instance)
|
||||
|
||||
|
||||
class SettingsCreator(TrayPublishCreator):
|
||||
create_allow_context_change = True
|
||||
|
|
@ -58,10 +73,8 @@ class SettingsCreator(TrayPublishCreator):
|
|||
data["settings_creator"] = True
|
||||
# Create new instance
|
||||
new_instance = CreatedInstance(self.family, subset_name, data, self)
|
||||
# Host implementation of storing metadata about instance
|
||||
HostContext.add_instance(new_instance.data_to_store())
|
||||
# Add instance to current context
|
||||
self._add_instance_to_context(new_instance)
|
||||
|
||||
self._store_new_instance(new_instance)
|
||||
|
||||
def get_instance_attr_defs(self):
|
||||
return [
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
import os
|
||||
|
||||
import clique
|
||||
import pyblish.api
|
||||
|
||||
|
||||
|
|
@ -29,6 +31,14 @@ class CollectSettingsSimpleInstances(pyblish.api.InstancePlugin):
|
|||
for filename in filepath_item["filenames"]
|
||||
]
|
||||
|
||||
cols, rems = clique.assemble(filepaths)
|
||||
source = None
|
||||
if cols:
|
||||
source = cols[0].format("{head}{padding}{tail}")
|
||||
elif rems:
|
||||
source = rems[0]
|
||||
|
||||
instance.data["source"] = source
|
||||
instance.data["sourceFilepaths"] = filepaths
|
||||
instance.data["stagingDir"] = filepath_item["directory"]
|
||||
|
||||
|
|
@ -45,6 +55,8 @@ class CollectSettingsSimpleInstances(pyblish.api.InstancePlugin):
|
|||
"files": filenames
|
||||
})
|
||||
|
||||
instance.data["source"] = "\n".join(filepaths)
|
||||
|
||||
self.log.debug("Created Simple Settings instance {}".format(
|
||||
instance.data
|
||||
))
|
||||
|
|
|
|||
|
|
@ -11,6 +11,10 @@ except Exception:
|
|||
from openpype.lib.python_2_comp import WeakMethod
|
||||
|
||||
|
||||
class MissingEventSystem(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class EventCallback(object):
|
||||
"""Callback registered to a topic.
|
||||
|
||||
|
|
@ -176,16 +180,20 @@ class Event(object):
|
|||
topic (str): Identifier of event.
|
||||
data (Any): Data specific for event. Dictionary is recommended.
|
||||
source (str): Identifier of source.
|
||||
event_system (EventSystem): Event system in which can be event
|
||||
triggered.
|
||||
"""
|
||||
|
||||
_data = {}
|
||||
|
||||
def __init__(self, topic, data=None, source=None):
|
||||
def __init__(self, topic, data=None, source=None, event_system=None):
|
||||
self._id = str(uuid4())
|
||||
self._topic = topic
|
||||
if data is None:
|
||||
data = {}
|
||||
self._data = data
|
||||
self._source = source
|
||||
self._event_system = event_system
|
||||
|
||||
def __getitem__(self, key):
|
||||
return self._data[key]
|
||||
|
|
@ -211,28 +219,118 @@ class Event(object):
|
|||
|
||||
def emit(self):
|
||||
"""Emit event and trigger callbacks."""
|
||||
StoredCallbacks.emit_event(self)
|
||||
if self._event_system is None:
|
||||
raise MissingEventSystem(
|
||||
"Can't emit event {}. Does not have set event system.".format(
|
||||
str(repr(self))
|
||||
)
|
||||
)
|
||||
self._event_system.emit_event(self)
|
||||
|
||||
|
||||
class StoredCallbacks:
|
||||
_registered_callbacks = []
|
||||
class EventSystem(object):
|
||||
"""Encapsulate event handling into an object.
|
||||
|
||||
System wraps registered callbacks and triggered events into single object
|
||||
so it is possible to create mutltiple independent systems that have their
|
||||
topics and callbacks.
|
||||
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self._registered_callbacks = []
|
||||
|
||||
def add_callback(self, topic, callback):
|
||||
"""Register callback in event system.
|
||||
|
||||
Args:
|
||||
topic (str): Topic for EventCallback.
|
||||
callback (Callable): Function or method that will be called
|
||||
when topic is triggered.
|
||||
|
||||
Returns:
|
||||
EventCallback: Created callback object which can be used to
|
||||
stop listening.
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def add_callback(cls, topic, callback):
|
||||
callback = EventCallback(topic, callback)
|
||||
cls._registered_callbacks.append(callback)
|
||||
self._registered_callbacks.append(callback)
|
||||
return callback
|
||||
|
||||
@classmethod
|
||||
def emit_event(cls, event):
|
||||
def create_event(self, topic, data, source):
|
||||
"""Create new event which is bound to event system.
|
||||
|
||||
Args:
|
||||
topic (str): Event topic.
|
||||
data (dict): Data related to event.
|
||||
source (str): Source of event.
|
||||
|
||||
Returns:
|
||||
Event: Object of event.
|
||||
"""
|
||||
|
||||
return Event(topic, data, source, self)
|
||||
|
||||
def emit(self, topic, data, source):
|
||||
"""Create event based on passed data and emit it.
|
||||
|
||||
This is easiest way how to trigger event in an event system.
|
||||
|
||||
Args:
|
||||
topic (str): Event topic.
|
||||
data (dict): Data related to event.
|
||||
source (str): Source of event.
|
||||
|
||||
Returns:
|
||||
Event: Created and emitted event.
|
||||
"""
|
||||
|
||||
event = self.create_event(topic, data, source)
|
||||
event.emit()
|
||||
return event
|
||||
|
||||
def emit_event(self, event):
|
||||
"""Emit event object.
|
||||
|
||||
Args:
|
||||
event (Event): Prepared event with topic and data.
|
||||
"""
|
||||
|
||||
invalid_callbacks = []
|
||||
for callback in cls._registered_callbacks:
|
||||
for callback in self._registered_callbacks:
|
||||
callback.process_event(event)
|
||||
if not callback.is_ref_valid:
|
||||
invalid_callbacks.append(callback)
|
||||
|
||||
for callback in invalid_callbacks:
|
||||
cls._registered_callbacks.remove(callback)
|
||||
self._registered_callbacks.remove(callback)
|
||||
|
||||
|
||||
class GlobalEventSystem:
|
||||
"""Event system living in global scope of process.
|
||||
|
||||
This is primarily used in host implementation to trigger events
|
||||
related to DCC changes or changes of context in the host implementation.
|
||||
"""
|
||||
|
||||
_global_event_system = None
|
||||
|
||||
@classmethod
|
||||
def get_global_event_system(cls):
|
||||
if cls._global_event_system is None:
|
||||
cls._global_event_system = EventSystem()
|
||||
return cls._global_event_system
|
||||
|
||||
@classmethod
|
||||
def add_callback(cls, topic, callback):
|
||||
event_system = cls.get_global_event_system()
|
||||
return event_system.add_callback(topic, callback)
|
||||
|
||||
@classmethod
|
||||
def emit(cls, topic, data, source):
|
||||
event_system = cls.get_global_event_system()
|
||||
return event_system.emit(topic, data, source)
|
||||
|
||||
|
||||
def register_event_callback(topic, callback):
|
||||
|
|
@ -249,7 +347,8 @@ def register_event_callback(topic, callback):
|
|||
enable/disable listening to a topic or remove the callback from
|
||||
the topic completely.
|
||||
"""
|
||||
return StoredCallbacks.add_callback(topic, callback)
|
||||
|
||||
return GlobalEventSystem.add_callback(topic, callback)
|
||||
|
||||
|
||||
def emit_event(topic, data=None, source=None):
|
||||
|
|
@ -263,6 +362,5 @@ def emit_event(topic, data=None, source=None):
|
|||
Returns:
|
||||
Event: Object of event that was emitted.
|
||||
"""
|
||||
event = Event(topic, data, source)
|
||||
event.emit()
|
||||
return event
|
||||
|
||||
return GlobalEventSystem.emit(topic, data, source)
|
||||
|
|
|
|||
|
|
@ -84,6 +84,11 @@ class CreateProjectFolders(BaseAction):
|
|||
create_project_folders(basic_paths, project_name)
|
||||
self.create_ftrack_entities(basic_paths, project_entity)
|
||||
|
||||
self.trigger_event(
|
||||
"openpype.project.structure.created",
|
||||
{"project_name": project_name}
|
||||
)
|
||||
|
||||
except Exception as exc:
|
||||
self.log.warning("Creating of structure crashed.", exc_info=True)
|
||||
session.rollback()
|
||||
|
|
|
|||
|
|
@ -116,6 +116,7 @@ class IntegrateFtrackNote(pyblish.api.InstancePlugin):
|
|||
"app_name": app_name,
|
||||
"app_label": app_label,
|
||||
"published_paths": "<br/>".join(sorted(published_paths)),
|
||||
"source": instance.data.get("source", '')
|
||||
}
|
||||
comment = template.format(**format_data)
|
||||
if not comment:
|
||||
|
|
|
|||
|
|
@ -2,13 +2,13 @@ import os
|
|||
import platform
|
||||
|
||||
|
||||
from openpype.client import get_asset_by_name
|
||||
from openpype.modules import OpenPypeModule
|
||||
from openpype_interfaces import (
|
||||
ITrayService,
|
||||
ILaunchHookPaths
|
||||
)
|
||||
from openpype.lib.events import register_event_callback
|
||||
from openpype.pipeline import AvalonMongoDB
|
||||
|
||||
from .exceptions import InvalidContextError
|
||||
|
||||
|
|
@ -197,22 +197,13 @@ class TimersManager(OpenPypeModule, ITrayService, ILaunchHookPaths):
|
|||
" Project: \"{}\" Asset: \"{}\" Task: \"{}\""
|
||||
).format(str(project_name), str(asset_name), str(task_name)))
|
||||
|
||||
dbconn = AvalonMongoDB()
|
||||
dbconn.install()
|
||||
dbconn.Session["AVALON_PROJECT"] = project_name
|
||||
|
||||
asset_doc = dbconn.find_one(
|
||||
{
|
||||
"type": "asset",
|
||||
"name": asset_name
|
||||
},
|
||||
{
|
||||
"data.tasks": True,
|
||||
"data.parents": True
|
||||
}
|
||||
asset_doc = get_asset_by_name(
|
||||
project_name,
|
||||
asset_name,
|
||||
fields=["_id", "name", "data.tasks", "data.parents"]
|
||||
)
|
||||
|
||||
if not asset_doc:
|
||||
dbconn.uninstall()
|
||||
raise InvalidContextError((
|
||||
"Asset \"{}\" not found in project \"{}\""
|
||||
).format(asset_name, project_name))
|
||||
|
|
@ -220,7 +211,6 @@ class TimersManager(OpenPypeModule, ITrayService, ILaunchHookPaths):
|
|||
asset_data = asset_doc.get("data") or {}
|
||||
asset_tasks = asset_data.get("tasks") or {}
|
||||
if task_name not in asset_tasks:
|
||||
dbconn.uninstall()
|
||||
raise InvalidContextError((
|
||||
"Task \"{}\" not found on asset \"{}\" in project \"{}\""
|
||||
).format(task_name, asset_name, project_name))
|
||||
|
|
@ -238,9 +228,10 @@ class TimersManager(OpenPypeModule, ITrayService, ILaunchHookPaths):
|
|||
hierarchy_items = asset_data.get("parents") or []
|
||||
hierarchy_items.append(asset_name)
|
||||
|
||||
dbconn.uninstall()
|
||||
return {
|
||||
"project_name": project_name,
|
||||
"asset_id": str(asset_doc["_id"]),
|
||||
"asset_name": asset_doc["name"],
|
||||
"task_name": task_name,
|
||||
"task_type": task_type,
|
||||
"hierarchy": hierarchy_items
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ UpdateData = collections.namedtuple("UpdateData", ["instance", "changes"])
|
|||
|
||||
class ImmutableKeyError(TypeError):
|
||||
"""Accessed key is immutable so does not allow changes or removements."""
|
||||
|
||||
def __init__(self, key, msg=None):
|
||||
self.immutable_key = key
|
||||
if not msg:
|
||||
|
|
@ -40,6 +41,7 @@ class ImmutableKeyError(TypeError):
|
|||
|
||||
class HostMissRequiredMethod(Exception):
|
||||
"""Host does not have implemented required functions for creation."""
|
||||
|
||||
def __init__(self, host, missing_methods):
|
||||
self.missing_methods = missing_methods
|
||||
self.host = host
|
||||
|
|
@ -66,6 +68,7 @@ class InstanceMember:
|
|||
TODO:
|
||||
Implement and use!
|
||||
"""
|
||||
|
||||
def __init__(self, instance, name):
|
||||
self.instance = instance
|
||||
|
||||
|
|
@ -94,6 +97,7 @@ class AttributeValues:
|
|||
values(dict): Values after possible conversion.
|
||||
origin_data(dict): Values loaded from host before conversion.
|
||||
"""
|
||||
|
||||
def __init__(self, attr_defs, values, origin_data=None):
|
||||
from openpype.lib.attribute_definitions import UnknownDef
|
||||
|
||||
|
|
@ -174,6 +178,10 @@ class AttributeValues:
|
|||
output = {}
|
||||
for key in self._data:
|
||||
output[key] = self[key]
|
||||
|
||||
for key, attr_def in self._attr_defs_by_key.items():
|
||||
if key not in output:
|
||||
output[key] = attr_def.default
|
||||
return output
|
||||
|
||||
@staticmethod
|
||||
|
|
@ -196,6 +204,7 @@ class CreatorAttributeValues(AttributeValues):
|
|||
Args:
|
||||
instance (CreatedInstance): Instance for which are values hold.
|
||||
"""
|
||||
|
||||
def __init__(self, instance, *args, **kwargs):
|
||||
self.instance = instance
|
||||
super(CreatorAttributeValues, self).__init__(*args, **kwargs)
|
||||
|
|
@ -211,6 +220,7 @@ class PublishAttributeValues(AttributeValues):
|
|||
publish_attributes(PublishAttributes): Wrapper for multiple publish
|
||||
attributes is used as parent object.
|
||||
"""
|
||||
|
||||
def __init__(self, publish_attributes, *args, **kwargs):
|
||||
self.publish_attributes = publish_attributes
|
||||
super(PublishAttributeValues, self).__init__(*args, **kwargs)
|
||||
|
|
@ -232,6 +242,7 @@ class PublishAttributes:
|
|||
attr_plugins(list): List of publish plugins that may have defined
|
||||
attribute definitions.
|
||||
"""
|
||||
|
||||
def __init__(self, parent, origin_data, attr_plugins=None):
|
||||
self.parent = parent
|
||||
self._origin_data = copy.deepcopy(origin_data)
|
||||
|
|
@ -270,6 +281,7 @@ class PublishAttributes:
|
|||
key(str): Plugin name.
|
||||
default: Default value if plugin was not found.
|
||||
"""
|
||||
|
||||
if key not in self._data:
|
||||
return default
|
||||
|
||||
|
|
@ -287,11 +299,13 @@ class PublishAttributes:
|
|||
|
||||
def plugin_names_order(self):
|
||||
"""Plugin names order by their 'order' attribute."""
|
||||
|
||||
for name in self._plugin_names_order:
|
||||
yield name
|
||||
|
||||
def data_to_store(self):
|
||||
"""Convert attribute values to "data to store"."""
|
||||
|
||||
output = {}
|
||||
for key, attr_value in self._data.items():
|
||||
output[key] = attr_value.data_to_store()
|
||||
|
|
@ -299,6 +313,7 @@ class PublishAttributes:
|
|||
|
||||
def changes(self):
|
||||
"""Return changes per each key."""
|
||||
|
||||
changes = {}
|
||||
for key, attr_val in self._data.items():
|
||||
attr_changes = attr_val.changes()
|
||||
|
|
@ -314,6 +329,7 @@ class PublishAttributes:
|
|||
|
||||
def set_publish_plugins(self, attr_plugins):
|
||||
"""Set publish plugins attribute definitions."""
|
||||
|
||||
self._plugin_names_order = []
|
||||
self._missing_plugins = []
|
||||
self.attr_plugins = attr_plugins or []
|
||||
|
|
@ -365,6 +381,7 @@ class CreatedInstance:
|
|||
`openpype.pipeline.registered_host`.
|
||||
new(bool): Is instance new.
|
||||
"""
|
||||
|
||||
# Keys that can't be changed or removed from data after loading using
|
||||
# creator.
|
||||
# - 'creator_attributes' and 'publish_attributes' can change values of
|
||||
|
|
@ -566,6 +583,7 @@ class CreatedInstance:
|
|||
@property
|
||||
def id(self):
|
||||
"""Instance identifier."""
|
||||
|
||||
return self._data["instance_id"]
|
||||
|
||||
@property
|
||||
|
|
@ -574,10 +592,12 @@ class CreatedInstance:
|
|||
|
||||
Access to data is needed to modify values.
|
||||
"""
|
||||
|
||||
return self
|
||||
|
||||
def changes(self):
|
||||
"""Calculate and return changes."""
|
||||
|
||||
changes = {}
|
||||
new_keys = set()
|
||||
for key, new_value in self._data.items():
|
||||
|
|
@ -716,6 +736,7 @@ class CreateContext:
|
|||
self.manual_creators = {}
|
||||
|
||||
self.publish_discover_result = None
|
||||
self.publish_plugins_mismatch_targets = []
|
||||
self.publish_plugins = []
|
||||
self.plugins_with_defs = []
|
||||
self._attr_plugins_by_family = {}
|
||||
|
|
@ -838,6 +859,7 @@ class CreateContext:
|
|||
discover_result = DiscoverResult()
|
||||
plugins_with_defs = []
|
||||
plugins_by_targets = []
|
||||
plugins_mismatch_targets = []
|
||||
if discover_publish_plugins:
|
||||
discover_result = publish_plugins_discover()
|
||||
publish_plugins = discover_result.plugins
|
||||
|
|
@ -847,11 +869,19 @@ class CreateContext:
|
|||
plugins_by_targets = pyblish.logic.plugins_by_targets(
|
||||
publish_plugins, list(targets)
|
||||
)
|
||||
|
||||
# Collect plugins that can have attribute definitions
|
||||
for plugin in publish_plugins:
|
||||
if OpenPypePyblishPluginMixin in inspect.getmro(plugin):
|
||||
plugins_with_defs.append(plugin)
|
||||
|
||||
plugins_mismatch_targets = [
|
||||
plugin
|
||||
for plugin in publish_plugins
|
||||
if plugin not in plugins_by_targets
|
||||
]
|
||||
|
||||
self.publish_plugins_mismatch_targets = plugins_mismatch_targets
|
||||
self.publish_discover_result = discover_result
|
||||
self.publish_plugins = plugins_by_targets
|
||||
self.plugins_with_defs = plugins_with_defs
|
||||
|
|
|
|||
|
|
@ -102,6 +102,10 @@ class BaseCreator:
|
|||
|
||||
return self.create_context.project_name
|
||||
|
||||
@property
|
||||
def host(self):
|
||||
return self.create_context.host
|
||||
|
||||
def get_group_label(self):
|
||||
"""Group label under which are instances grouped in UI.
|
||||
|
||||
|
|
|
|||
|
|
@ -47,12 +47,11 @@ class CollectFromCreateContext(pyblish.api.ContextPlugin):
|
|||
"label": subset,
|
||||
"name": subset,
|
||||
"family": in_data["family"],
|
||||
"families": instance_families
|
||||
"families": instance_families,
|
||||
"representations": []
|
||||
})
|
||||
for key, value in in_data.items():
|
||||
if key not in instance.data:
|
||||
instance.data[key] = value
|
||||
self.log.info("collected instance: {}".format(instance.data))
|
||||
self.log.info("parsing data: {}".format(in_data))
|
||||
|
||||
instance.data["representations"] = list()
|
||||
|
|
|
|||
|
|
@ -497,11 +497,29 @@
|
|||
"override_viewport_options": true,
|
||||
"displayLights": "default",
|
||||
"textureMaxResolution": 1024,
|
||||
"multiSample": 4,
|
||||
"renderDepthOfField": true,
|
||||
"shadows": true,
|
||||
"textures": true,
|
||||
"twoSidedLighting": true,
|
||||
"ssaoEnable": true,
|
||||
"lineAAEnable": true,
|
||||
"multiSample": 8,
|
||||
"ssaoEnable": false,
|
||||
"ssaoAmount": 1,
|
||||
"ssaoRadius": 16,
|
||||
"ssaoFilterRadius": 16,
|
||||
"ssaoSamples": 16,
|
||||
"fogging": false,
|
||||
"hwFogFalloff": "0",
|
||||
"hwFogDensity": 0.0,
|
||||
"hwFogStart": 0,
|
||||
"hwFogEnd": 100,
|
||||
"hwFogAlpha": 0,
|
||||
"hwFogColorR": 1.0,
|
||||
"hwFogColorG": 1.0,
|
||||
"hwFogColorB": 1.0,
|
||||
"motionBlurEnable": false,
|
||||
"motionBlurSampleCount": 8,
|
||||
"motionBlurShutterOpenFraction": 0.2,
|
||||
"cameras": false,
|
||||
"clipGhosts": false,
|
||||
"controlVertices": false,
|
||||
|
|
|
|||
|
|
@ -287,7 +287,11 @@
|
|||
"LoadClip": {
|
||||
"enabled": true,
|
||||
"_representations": [],
|
||||
"node_name_template": "{class_name}_{ext}"
|
||||
"node_name_template": "{class_name}_{ext}",
|
||||
"options_defaults": {
|
||||
"start_at_workfile": true,
|
||||
"add_retime": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"workfile_builder": {
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@
|
|||
"default_variants": [
|
||||
"Main"
|
||||
],
|
||||
"description": "Publish workfile backup",
|
||||
"detailed_description": "",
|
||||
"description": "Backup of a working scene",
|
||||
"detailed_description": "Workfiles are full scenes from any application that are directly edited by artists. They represent a state of work on a task at a given point and are usually not directly referenced into other scenes.",
|
||||
"allow_sequences": true,
|
||||
"extensions": [
|
||||
".ma",
|
||||
|
|
@ -30,6 +30,201 @@
|
|||
".psb",
|
||||
".aep"
|
||||
]
|
||||
},
|
||||
{
|
||||
"family": "model",
|
||||
"identifier": "",
|
||||
"label": "Model",
|
||||
"icon": "fa.cubes",
|
||||
"default_variants": [
|
||||
"Main",
|
||||
"Proxy",
|
||||
"Sculpt"
|
||||
],
|
||||
"description": "Clean models",
|
||||
"detailed_description": "Models should only contain geometry data, without any extras like cameras, locators or bones.\n\nKeep in mind that models published from tray publisher are not validated for correctness. ",
|
||||
"allow_sequences": false,
|
||||
"extensions": [
|
||||
".ma",
|
||||
".mb",
|
||||
".obj",
|
||||
".abc",
|
||||
".fbx",
|
||||
".bgeo",
|
||||
".bgeogz",
|
||||
".bgeosc",
|
||||
".usd",
|
||||
".blend"
|
||||
]
|
||||
},
|
||||
{
|
||||
"family": "pointcache",
|
||||
"identifier": "",
|
||||
"label": "Pointcache",
|
||||
"icon": "fa.gears",
|
||||
"default_variants": [
|
||||
"Main"
|
||||
],
|
||||
"description": "Geometry Caches",
|
||||
"detailed_description": "Alembic or bgeo cache of animated data",
|
||||
"allow_sequences": true,
|
||||
"extensions": [
|
||||
".abc",
|
||||
".bgeo",
|
||||
".bgeogz",
|
||||
".bgeosc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"family": "plate",
|
||||
"identifier": "",
|
||||
"label": "Plate",
|
||||
"icon": "mdi.camera-image",
|
||||
"default_variants": [
|
||||
"Main",
|
||||
"BG",
|
||||
"Animatic",
|
||||
"Reference",
|
||||
"Offline"
|
||||
],
|
||||
"description": "Footage Plates",
|
||||
"detailed_description": "Any type of image seqeuence coming from outside of the studio. Usually camera footage, but could also be animatics used for reference.",
|
||||
"allow_sequences": true,
|
||||
"extensions": [
|
||||
".exr",
|
||||
".png",
|
||||
".dpx",
|
||||
".jpg",
|
||||
".tiff",
|
||||
".tif",
|
||||
".mov",
|
||||
".mp4",
|
||||
".avi"
|
||||
]
|
||||
},
|
||||
{
|
||||
"family": "render",
|
||||
"identifier": "",
|
||||
"label": "Render",
|
||||
"icon": "mdi.folder-multiple-image",
|
||||
"default_variants": [],
|
||||
"description": "Rendered images or video",
|
||||
"detailed_description": "Sequence or single file renders",
|
||||
"allow_sequences": true,
|
||||
"extensions": [
|
||||
".exr",
|
||||
".png",
|
||||
".dpx",
|
||||
".jpg",
|
||||
".jpeg",
|
||||
".tiff",
|
||||
".tif",
|
||||
".mov",
|
||||
".mp4",
|
||||
".avi"
|
||||
]
|
||||
},
|
||||
{
|
||||
"family": "camera",
|
||||
"identifier": "",
|
||||
"label": "Camera",
|
||||
"icon": "fa.video-camera",
|
||||
"default_variants": [],
|
||||
"description": "3d Camera",
|
||||
"detailed_description": "Ideally this should be only camera itself with baked animation, however, it can technically also include helper geometry.",
|
||||
"allow_sequences": false,
|
||||
"extensions": [
|
||||
".abc",
|
||||
".ma",
|
||||
".hip",
|
||||
".blend",
|
||||
".fbx",
|
||||
".usd"
|
||||
]
|
||||
},
|
||||
{
|
||||
"family": "image",
|
||||
"identifier": "",
|
||||
"label": "Image",
|
||||
"icon": "fa.image",
|
||||
"default_variants": [
|
||||
"Reference",
|
||||
"Texture",
|
||||
"Concept",
|
||||
"Background"
|
||||
],
|
||||
"description": "Single image",
|
||||
"detailed_description": "Any image data can be published as image family. References, textures, concept art, matte paints. This is a fallback 2d family for everything that doesn't fit more specific family.",
|
||||
"allow_sequences": false,
|
||||
"extensions": [
|
||||
".exr",
|
||||
".jpg",
|
||||
".jpeg",
|
||||
".dpx",
|
||||
".bmp",
|
||||
".tif",
|
||||
".tiff",
|
||||
".png",
|
||||
".psb",
|
||||
".psd"
|
||||
]
|
||||
},
|
||||
{
|
||||
"family": "vdb",
|
||||
"identifier": "",
|
||||
"label": "VDB Volumes",
|
||||
"icon": "fa.cloud",
|
||||
"default_variants": [],
|
||||
"description": "Sparse volumetric data",
|
||||
"detailed_description": "Hierarchical data structure for the efficient storage and manipulation of sparse volumetric data discretized on three-dimensional grids",
|
||||
"allow_sequences": true,
|
||||
"extensions": [
|
||||
".vdb"
|
||||
]
|
||||
},
|
||||
{
|
||||
"family": "matchmove",
|
||||
"identifier": "",
|
||||
"label": "Matchmove",
|
||||
"icon": "fa.empire",
|
||||
"default_variants": [
|
||||
"Camera",
|
||||
"Object",
|
||||
"Mocap"
|
||||
],
|
||||
"description": "Matchmoving script",
|
||||
"detailed_description": "Script exported from matchmoving application to be later processed into a tracked camera with additional data",
|
||||
"allow_sequences": false,
|
||||
"extensions": []
|
||||
},
|
||||
{
|
||||
"family": "rig",
|
||||
"identifier": "",
|
||||
"label": "Rig",
|
||||
"icon": "fa.wheelchair",
|
||||
"default_variants": [],
|
||||
"description": "CG rig file",
|
||||
"detailed_description": "CG rigged character or prop. Rig should be clean of any extra data and directly loadable into it's respective application\t",
|
||||
"allow_sequences": false,
|
||||
"extensions": [
|
||||
".ma",
|
||||
".blend",
|
||||
".hip",
|
||||
".hda"
|
||||
]
|
||||
},
|
||||
{
|
||||
"family": "simpleUnrealTexture",
|
||||
"identifier": "",
|
||||
"label": "Simple UE texture",
|
||||
"icon": "fa.image",
|
||||
"default_variants": [
|
||||
""
|
||||
],
|
||||
"description": "Simple Unreal Engine texture",
|
||||
"detailed_description": "Texture files with Unreal Engine naming conventions",
|
||||
"allow_sequences": false,
|
||||
"extensions": []
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -822,7 +822,7 @@
|
|||
},
|
||||
{
|
||||
"type": "label",
|
||||
"label": "Template may contain formatting keys <b>intent</b>, <b>comment</b>, <b>host_name</b>, <b>app_name</b>, <b>app_label</b> and <b>published_paths</b>."
|
||||
"label": "Template may contain formatting keys <b>intent</b>, <b>comment</b>, <b>host_name</b>, <b>app_name</b>, <b>app_label</b>, <b>published_paths</b> and <b>source</b>."
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
|
|
|
|||
|
|
@ -202,12 +202,15 @@
|
|||
"decimal": 0
|
||||
},
|
||||
{
|
||||
"type": "number",
|
||||
"key": "multiSample",
|
||||
"label": "Anti Aliasing Samples",
|
||||
"decimal": 0,
|
||||
"minimum": 0,
|
||||
"maximum": 32
|
||||
"type": "splitter"
|
||||
},
|
||||
{
|
||||
"type":"boolean",
|
||||
"key": "renderDepthOfField",
|
||||
"label": "Depth of Field"
|
||||
},
|
||||
{
|
||||
"type": "splitter"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
|
|
@ -224,11 +227,145 @@
|
|||
"key": "twoSidedLighting",
|
||||
"label": "Two Sided Lighting"
|
||||
},
|
||||
{
|
||||
"type": "splitter"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "lineAAEnable",
|
||||
"label": "Enable Anti-Aliasing"
|
||||
},
|
||||
{
|
||||
"type": "number",
|
||||
"key": "multiSample",
|
||||
"label": "Anti Aliasing Samples",
|
||||
"decimal": 0,
|
||||
"minimum": 0,
|
||||
"maximum": 32
|
||||
},
|
||||
{
|
||||
"type": "splitter"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "ssaoEnable",
|
||||
"label": "Screen Space Ambient Occlusion"
|
||||
},
|
||||
{
|
||||
"type": "number",
|
||||
"key": "ssaoAmount",
|
||||
"label": "SSAO Amount"
|
||||
},
|
||||
{
|
||||
"type": "number",
|
||||
"key": "ssaoRadius",
|
||||
"label": "SSAO Radius"
|
||||
},
|
||||
{
|
||||
"type": "number",
|
||||
"key": "ssaoFilterRadius",
|
||||
"label": "SSAO Filter Radius",
|
||||
"decimal": 0,
|
||||
"minimum": 1,
|
||||
"maximum": 32
|
||||
},
|
||||
{
|
||||
"type": "number",
|
||||
"key": "ssaoSamples",
|
||||
"label": "SSAO Samples",
|
||||
"decimal": 0,
|
||||
"minimum": 8,
|
||||
"maximum": 32
|
||||
},
|
||||
{
|
||||
"type": "splitter"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "fogging",
|
||||
"label": "Enable Hardware Fog"
|
||||
},
|
||||
{
|
||||
"type": "enum",
|
||||
"key": "hwFogFalloff",
|
||||
"label": "Hardware Falloff",
|
||||
"enum_items": [
|
||||
{ "0": "Linear"},
|
||||
{ "1": "Exponential"},
|
||||
{ "2": "Exponential Squared"}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "number",
|
||||
"key": "hwFogDensity",
|
||||
"label": "Fog Density",
|
||||
"decimal": 2,
|
||||
"minimum": 0,
|
||||
"maximum": 1
|
||||
},
|
||||
{
|
||||
"type": "number",
|
||||
"key": "hwFogStart",
|
||||
"label": "Fog Start"
|
||||
},
|
||||
{
|
||||
"type": "number",
|
||||
"key": "hwFogEnd",
|
||||
"label": "Fog End"
|
||||
},
|
||||
{
|
||||
"type": "number",
|
||||
"key": "hwFogAlpha",
|
||||
"label": "Fog Alpha"
|
||||
},
|
||||
{
|
||||
"type": "number",
|
||||
"key": "hwFogColorR",
|
||||
"label": "Fog Color R",
|
||||
"decimal": 2,
|
||||
"minimum": 0,
|
||||
"maximum": 1
|
||||
},
|
||||
{
|
||||
"type": "number",
|
||||
"key": "hwFogColorG",
|
||||
"label": "Fog Color G",
|
||||
"decimal": 2,
|
||||
"minimum": 0,
|
||||
"maximum": 1
|
||||
},
|
||||
{
|
||||
"type": "number",
|
||||
"key": "hwFogColorB",
|
||||
"label": "Fog Color B",
|
||||
"decimal": 2,
|
||||
"minimum": 0,
|
||||
"maximum": 1
|
||||
},
|
||||
{
|
||||
"type": "splitter"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "motionBlurEnable",
|
||||
"label": "Enable Motion Blur"
|
||||
},
|
||||
{
|
||||
"type": "number",
|
||||
"key": "motionBlurSampleCount",
|
||||
"label": "Motion Blur Sample Count",
|
||||
"decimal": 0,
|
||||
"minimum": 8,
|
||||
"maximum": 32
|
||||
},
|
||||
{
|
||||
"type": "number",
|
||||
"key": "motionBlurShutterOpenFraction",
|
||||
"label": "Shutter Open Fraction",
|
||||
"decimal": 3,
|
||||
"minimum": 0.01,
|
||||
"maximum": 32
|
||||
},
|
||||
{
|
||||
"type": "splitter"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -11,10 +11,52 @@
|
|||
{
|
||||
"key": "LoadImage",
|
||||
"label": "Image Loader"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "dict",
|
||||
"collapsible": true,
|
||||
"key": "LoadClip",
|
||||
"label": "Clip Loader",
|
||||
"checkbox_key": "enabled",
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "enabled",
|
||||
"label": "Enabled"
|
||||
},
|
||||
{
|
||||
"key": "LoadClip",
|
||||
"label": "Clip Loader"
|
||||
"type": "list",
|
||||
"key": "_representations",
|
||||
"label": "Representations",
|
||||
"object_type": "text"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "node_name_template",
|
||||
"label": "Node name template"
|
||||
},
|
||||
{
|
||||
"type": "splitter"
|
||||
},
|
||||
{
|
||||
"type": "dict",
|
||||
"collapsible": false,
|
||||
"key": "options_defaults",
|
||||
"label": "Loader option defaults",
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "start_at_workfile",
|
||||
"label": "Start at worfile beggining"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "add_retime",
|
||||
"label": "Add retime"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -154,15 +154,20 @@ class PublishReport:
|
|||
self._all_instances_by_id = {}
|
||||
self._current_context = None
|
||||
|
||||
def reset(self, context, publish_discover_result=None):
|
||||
def reset(self, context, create_context):
|
||||
"""Reset report and clear all data."""
|
||||
self._publish_discover_result = publish_discover_result
|
||||
|
||||
self._publish_discover_result = create_context.publish_discover_result
|
||||
self._plugin_data = []
|
||||
self._plugin_data_with_plugin = []
|
||||
self._current_plugin_data = {}
|
||||
self._all_instances_by_id = {}
|
||||
self._current_context = context
|
||||
|
||||
for plugin in create_context.publish_plugins_mismatch_targets:
|
||||
plugin_data = self._add_plugin_data_item(plugin)
|
||||
plugin_data["skipped"] = True
|
||||
|
||||
def add_plugin_iter(self, plugin, context):
|
||||
"""Add report about single iteration of plugin."""
|
||||
for instance in context:
|
||||
|
|
@ -205,6 +210,7 @@ class PublishReport:
|
|||
"name": plugin.__name__,
|
||||
"label": label,
|
||||
"order": plugin.order,
|
||||
"targets": list(plugin.targets),
|
||||
"instances_data": [],
|
||||
"actions_data": [],
|
||||
"skipped": False,
|
||||
|
|
@ -777,10 +783,7 @@ class PublisherController:
|
|||
# - pop the key after first collector using it would be safest option?
|
||||
self._publish_context.data["create_context"] = self.create_context
|
||||
|
||||
self._publish_report.reset(
|
||||
self._publish_context,
|
||||
self.create_context.publish_discover_result
|
||||
)
|
||||
self._publish_report.reset(self._publish_context, self.create_context)
|
||||
self._publish_validation_errors = []
|
||||
self._publish_current_plugin_validation_errors = None
|
||||
self._publish_error = None
|
||||
|
|
|
|||
|
|
@ -83,10 +83,8 @@ class PublishReport:
|
|||
|
||||
logs = []
|
||||
plugins_items_by_id = {}
|
||||
plugins_id_order = []
|
||||
for plugin_data in data["plugins_data"]:
|
||||
item = PluginItem(plugin_data)
|
||||
plugins_id_order.append(item.id)
|
||||
plugins_items_by_id[item.id] = item
|
||||
for instance_data_item in plugin_data["instances_data"]:
|
||||
instance_id = instance_data_item["id"]
|
||||
|
|
@ -95,6 +93,14 @@ class PublishReport:
|
|||
copy.deepcopy(log_item_data), item.id, instance_id
|
||||
)
|
||||
logs.append(log_item)
|
||||
sorted_plugins = sorted(
|
||||
plugins_items_by_id.values(),
|
||||
key=lambda item: item.order
|
||||
)
|
||||
plugins_id_order = [
|
||||
plugin_item.id
|
||||
for plugin_item in sorted_plugins
|
||||
]
|
||||
|
||||
logs_by_instance_id = collections.defaultdict(list)
|
||||
for log_item in logs:
|
||||
|
|
|
|||
|
|
@ -854,6 +854,9 @@ class ProjectWidget(SettingsCategoryWidget):
|
|||
project_list_widget.version_change_requested.connect(
|
||||
self._on_source_version_change
|
||||
)
|
||||
project_list_widget.extract_to_file_requested.connect(
|
||||
self._on_extract_to_file
|
||||
)
|
||||
|
||||
self.project_list_widget = project_list_widget
|
||||
|
||||
|
|
|
|||
|
|
@ -1008,6 +1008,7 @@ class ProjectSortFilterProxy(QtCore.QSortFilterProxyModel):
|
|||
class ProjectListWidget(QtWidgets.QWidget):
|
||||
project_changed = QtCore.Signal()
|
||||
version_change_requested = QtCore.Signal(str)
|
||||
extract_to_file_requested = QtCore.Signal()
|
||||
|
||||
def __init__(self, parent, only_active=False):
|
||||
self._parent = parent
|
||||
|
|
@ -1099,7 +1100,12 @@ class ProjectListWidget(QtWidgets.QWidget):
|
|||
self.version_change_requested
|
||||
)
|
||||
submenu.addAction(action)
|
||||
|
||||
extract_action = QtWidgets.QAction("Extract to file", menu)
|
||||
extract_action.triggered.connect(self.extract_to_file_requested)
|
||||
|
||||
menu.addMenu(submenu)
|
||||
menu.addAction(extract_action)
|
||||
menu.exec_(QtGui.QCursor.pos())
|
||||
|
||||
def on_item_clicked(self, new_index):
|
||||
|
|
|
|||
|
|
@ -12,9 +12,7 @@ from openpype.pipeline import (
|
|||
install_host,
|
||||
AvalonMongoDB,
|
||||
)
|
||||
from openpype.hosts.traypublisher import (
|
||||
api as traypublisher
|
||||
)
|
||||
from openpype.hosts.traypublisher.api import TrayPublisherHost
|
||||
from openpype.tools.publisher import PublisherWindow
|
||||
from openpype.tools.utils.constants import PROJECT_NAME_ROLE
|
||||
from openpype.tools.utils.models import (
|
||||
|
|
@ -111,9 +109,13 @@ class StandaloneOverlayWidget(QtWidgets.QFrame):
|
|||
if project_name:
|
||||
self._set_project(project_name)
|
||||
|
||||
@property
|
||||
def host(self):
|
||||
return self._publisher_window.controller.host
|
||||
|
||||
def _set_project(self, project_name):
|
||||
self._project_name = project_name
|
||||
traypublisher.set_project_name(project_name)
|
||||
self.host.set_project_name(project_name)
|
||||
self.setVisible(False)
|
||||
self.project_selected.emit(project_name)
|
||||
|
||||
|
|
@ -190,7 +192,8 @@ class TrayPublishWindow(PublisherWindow):
|
|||
|
||||
|
||||
def main():
|
||||
install_host(traypublisher)
|
||||
host = TrayPublisherHost()
|
||||
install_host(host)
|
||||
app = QtWidgets.QApplication([])
|
||||
window = TrayPublishWindow()
|
||||
window.show()
|
||||
|
|
|
|||
3
openpype/vendor/python/common/capture.py
vendored
3
openpype/vendor/python/common/capture.py
vendored
|
|
@ -380,7 +380,8 @@ Viewport2Options = {
|
|||
"transparencyAlgorithm": 1,
|
||||
"transparencyQuality": 0.33,
|
||||
"useMaximumHardwareLights": True,
|
||||
"vertexAnimationCache": 0
|
||||
"vertexAnimationCache": 0,
|
||||
"renderDepthOfField": 0
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""Package declaring Pype version."""
|
||||
__version__ = "3.12.1-nightly.4"
|
||||
__version__ = "3.12.1"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
[tool.poetry]
|
||||
name = "OpenPype"
|
||||
version = "3.12.1-nightly.4" # OpenPype
|
||||
version = "3.12.1" # OpenPype
|
||||
description = "Open VFX and Animation pipeline with support."
|
||||
authors = ["OpenPype Team <info@openpype.io>"]
|
||||
license = "MIT License"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue