Merge pull request #1358 from pypeclub/feature/redshift-proxy-support

Maya: Support for Redshift proxies
This commit is contained in:
Milan Kolar 2021-04-20 19:28:57 +02:00 committed by GitHub
commit 15e3663a56
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 276 additions and 2 deletions

View file

@ -0,0 +1,23 @@
# -*- coding: utf-8 -*-
"""Creator of Redshift proxy subset types."""
from openpype.hosts.maya.api import plugin, lib
class CreateRedshiftProxy(plugin.Creator):
"""Create instance of Redshift Proxy subset."""
name = "redshiftproxy"
label = "Redshift Proxy"
family = "redshiftproxy"
icon = "gears"
def __init__(self, *args, **kwargs):
super(CreateRedshiftProxy, self).__init__(*args, **kwargs)
animation_data = lib.collect_animation_data()
self.data["animation"] = False
self.data["proxyFrameStart"] = animation_data["frameStart"]
self.data["proxyFrameEnd"] = animation_data["frameEnd"]
self.data["proxyFrameStep"] = animation_data["step"]

View file

@ -0,0 +1,146 @@
# -*- coding: utf-8 -*-
"""Loader for Redshift proxy."""
from avalon.maya import lib
from avalon import api
from openpype.api import get_project_settings
import os
import maya.cmds as cmds
import clique
class RedshiftProxyLoader(api.Loader):
"""Load Redshift proxy"""
families = ["redshiftproxy"]
representations = ["rs"]
label = "Import Redshift Proxy"
order = -10
icon = "code-fork"
color = "orange"
def load(self, context, name=None, namespace=None, options=None):
"""Plugin entry point."""
from avalon.maya.pipeline import containerise
from openpype.hosts.maya.api.lib import namespaced
try:
family = context["representation"]["context"]["family"]
except ValueError:
family = "redshiftproxy"
asset_name = context['asset']["name"]
namespace = namespace or lib.unique_namespace(
asset_name + "_",
prefix="_" if asset_name[0].isdigit() else "",
suffix="_",
)
# Ensure Redshift for Maya is loaded.
cmds.loadPlugin("redshift4maya", quiet=True)
with lib.maintained_selection():
cmds.namespace(addNamespace=namespace)
with namespaced(namespace, new=False):
nodes, group_node = self.create_rs_proxy(
name, self.fname)
self[:] = nodes
if not nodes:
return
# colour the group node
settings = get_project_settings(os.environ['AVALON_PROJECT'])
colors = settings['maya']['load']['colors']
c = colors.get(family)
if c is not None:
cmds.setAttr("{0}.useOutlinerColor".format(group_node), 1)
cmds.setAttr("{0}.outlinerColor".format(group_node),
c[0], c[1], c[2])
return containerise(
name=name,
namespace=namespace,
nodes=nodes,
context=context,
loader=self.__class__.__name__)
def update(self, container, representation):
node = container['objectName']
assert cmds.objExists(node), "Missing container"
members = cmds.sets(node, query=True) or []
rs_meshes = cmds.ls(members, type="RedshiftProxyMesh")
assert rs_meshes, "Cannot find RedshiftProxyMesh in container"
filename = api.get_representation_path(representation)
for rs_mesh in rs_meshes:
cmds.setAttr("{}.fileName".format(rs_mesh),
filename,
type="string")
# Update metadata
cmds.setAttr("{}.representation".format(node),
str(representation["_id"]),
type="string")
def remove(self, container):
# Delete container and its contents
if cmds.objExists(container['objectName']):
members = cmds.sets(container['objectName'], query=True) or []
cmds.delete([container['objectName']] + members)
# Remove the namespace, if empty
namespace = container['namespace']
if cmds.namespace(exists=namespace):
members = cmds.namespaceInfo(namespace, listNamespace=True)
if not members:
cmds.namespace(removeNamespace=namespace)
else:
self.log.warning("Namespace not deleted because it "
"still has members: %s", namespace)
def switch(self, container, representation):
self.update(container, representation)
def create_rs_proxy(self, name, path):
"""Creates Redshift Proxies showing a proxy object.
Args:
name (str): Proxy name.
path (str): Path to proxy file.
Returns:
(str, str): Name of mesh with Redshift proxy and its parent
transform.
"""
rs_mesh = cmds.createNode(
'RedshiftProxyMesh', name="{}_RS".format(name))
mesh_shape = cmds.createNode("mesh", name="{}_GEOShape".format(name))
cmds.setAttr("{}.fileName".format(rs_mesh),
path,
type="string")
cmds.connectAttr("{}.outMesh".format(rs_mesh),
"{}.inMesh".format(mesh_shape))
group_node = cmds.group(empty=True, name="{}_GRP".format(name))
mesh_transform = cmds.listRelatives(mesh_shape,
parent=True, fullPath=True)
cmds.parent(mesh_transform, group_node)
nodes = [rs_mesh, mesh_shape, group_node]
# determine if we need to enable animation support
files_in_folder = os.listdir(os.path.dirname(path))
collections, remainder = clique.assemble(files_in_folder)
if collections:
cmds.setAttr("{}.useFrameExtension".format(rs_mesh), 1)
return nodes, group_node

View file

@ -0,0 +1,80 @@
# -*- coding: utf-8 -*-
"""Redshift Proxy extractor."""
import os
import avalon.maya
import openpype.api
from maya import cmds
class ExtractRedshiftProxy(openpype.api.Extractor):
"""Extract the content of the instance to a redshift proxy file."""
label = "Redshift Proxy (.rs)"
hosts = ["maya"]
families = ["redshiftproxy"]
def process(self, instance):
"""Extractor entry point."""
staging_dir = self.staging_dir(instance)
file_name = "{}.rs".format(instance.name)
file_path = os.path.join(staging_dir, file_name)
anim_on = instance.data["animation"]
rs_options = "exportConnectivity=0;enableCompression=1;keepUnused=0;"
repr_files = file_name
if not anim_on:
# Remove animation information because it is not required for
# non-animated subsets
instance.data.pop("proxyFrameStart", None)
instance.data.pop("proxyFrameEnd", None)
else:
start_frame = instance.data["proxyFrameStart"]
end_frame = instance.data["proxyFrameEnd"]
rs_options = "{}startFrame={};endFrame={};frameStep={};".format(
rs_options, start_frame,
end_frame, instance.data["proxyFrameStep"]
)
root, ext = os.path.splitext(file_path)
# Padding is taken from number of digits of the end_frame.
# Not sure where Redshift is taking it.
repr_files = [
"{}.{}{}".format(root, str(frame).rjust(4, "0"), ext) # noqa: E501
for frame in range(
int(start_frame),
int(end_frame) + 1,
int(instance.data["proxyFrameStep"]),
)]
# vertex_colors = instance.data.get("vertexColors", False)
# Write out rs file
self.log.info("Writing: '%s'" % file_path)
with avalon.maya.maintained_selection():
cmds.select(instance.data["setMembers"], noExpand=True)
cmds.file(file_path,
pr=False,
force=True,
type="Redshift Proxy",
exportSelected=True,
options=rs_options)
if "representations" not in instance.data:
instance.data["representations"] = []
self.log.debug("Files: {}".format(repr_files))
representation = {
'name': 'rs',
'ext': 'rs',
'files': repr_files,
"stagingDir": staging_dir,
}
instance.data["representations"].append(representation)
self.log.info("Extracted instance '%s' to: %s"
% (instance.name, staging_dir))

View file

@ -93,7 +93,8 @@ class IntegrateAssetNew(pyblish.api.InstancePlugin):
"harmony.palette",
"editorial",
"background",
"camerarig"
"camerarig",
"redshiftproxy"
]
exclude_families = ["clip"]
db_representation_context_keys = [

@ -1 +1 @@
Subproject commit 911bd8999ab0030d0f7412dde6fd545c1a73b62d
Subproject commit 807e8577a0268580a2934ba38889911adad26eb1

View file

@ -691,3 +691,27 @@ under selected hierarchies and match them with shapes loaded with rig (published
under `input_SET`). This mechanism uses *cbId* attribute on those shapes.
If match is found shapes are connected using their `outMesh` and `outMesh`. Thus you can easily connect existing animation to loaded rig.
:::
## Using Redshift Proxies
OpenPype supports working with Redshift Proxy files. You can create Redshift Proxy from almost
any hierarchy in Maya and it will be included there. Redshift can export animation
proxy file per frame.
### Creating Redshift Proxy
To mark data to publish as Redshift Proxy, select them in Maya and - **OpenPype → Create ...** and
then select **Redshift Proxy**. You can name your subset and hit **Create** button.
You can enable animation in Attribute Editor:
![Maya - Yeti Rig Setup](assets/maya-create_rs_proxy.jpg)
### Publishing Redshift Proxies
Once data are marked as Redshift Proxy instance, they can be published - **OpenPype → Publish ...**
### Using Redshift Proxies
Published proxy files can be loaded with OpenPype Loader. It will create mesh and attach Redshift Proxy
parameters to it - Redshift will then represent proxy with bounding box.

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB