mirror of
https://github.com/ynput/ayon-core.git
synced 2026-01-01 08:24:53 +01:00
rename config folder
This commit is contained in:
parent
bb17ef7221
commit
7667674317
182 changed files with 272 additions and 272 deletions
48
pype/plugins/maya/load/_load_animation.py
Normal file
48
pype/plugins/maya/load/_load_animation.py
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
import pype.maya.plugin
|
||||
|
||||
|
||||
class AbcLoader(pype.maya.plugin.ReferenceLoader):
|
||||
"""Specific loader of Alembic for the avalon.animation family"""
|
||||
|
||||
families = ["studio.animation",
|
||||
"studio.camera",
|
||||
"studio.pointcache"]
|
||||
representations = ["abc"]
|
||||
|
||||
label = "Reference animation"
|
||||
order = -10
|
||||
icon = "code-fork"
|
||||
color = "orange"
|
||||
|
||||
def process_reference(self, context, name, namespace, data):
|
||||
|
||||
import maya.cmds as cmds
|
||||
from avalon import maya
|
||||
|
||||
cmds.loadPlugin("AbcImport.mll", quiet=True)
|
||||
# Prevent identical alembic nodes from being shared
|
||||
# Create unique namespace for the cameras
|
||||
|
||||
# Get name from asset being loaded
|
||||
# Assuming name is subset name from the animation, we split the number
|
||||
# suffix from the name to ensure the namespace is unique
|
||||
name = name.split("_")[0]
|
||||
namespace = maya.unique_namespace("{}_".format(name),
|
||||
format="%03d",
|
||||
suffix="_abc")
|
||||
|
||||
# hero_001 (abc)
|
||||
# asset_counter{optional}
|
||||
|
||||
nodes = cmds.file(self.fname,
|
||||
namespace=namespace,
|
||||
sharedReferenceFile=False,
|
||||
groupReference=True,
|
||||
groupName="{}:{}".format(namespace, name),
|
||||
reference=True,
|
||||
returnNewNodes=True)
|
||||
|
||||
# load studio ID attribute
|
||||
self[:] = nodes
|
||||
|
||||
return nodes
|
||||
147
pype/plugins/maya/load/actions.py
Normal file
147
pype/plugins/maya/load/actions.py
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
"""A module containing generic loader actions that will display in the Loader.
|
||||
|
||||
"""
|
||||
|
||||
from avalon import api
|
||||
|
||||
|
||||
class SetFrameRangeLoader(api.Loader):
|
||||
"""Specific loader of Alembic for the avalon.animation family"""
|
||||
|
||||
families = ["studio.animation",
|
||||
"studio.camera",
|
||||
"studio.pointcache"]
|
||||
representations = ["abc"]
|
||||
|
||||
label = "Set frame range"
|
||||
order = 11
|
||||
icon = "clock-o"
|
||||
color = "white"
|
||||
|
||||
def load(self, context, name, namespace, data):
|
||||
|
||||
import maya.cmds as cmds
|
||||
|
||||
version = context['version']
|
||||
version_data = version.get("data", {})
|
||||
|
||||
start = version_data.get("startFrame", None)
|
||||
end = version_data.get("endFrame", None)
|
||||
|
||||
if start is None or end is None:
|
||||
print("Skipping setting frame range because start or "
|
||||
"end frame data is missing..")
|
||||
return
|
||||
|
||||
cmds.playbackOptions(minTime=start,
|
||||
maxTime=end,
|
||||
animationStartTime=start,
|
||||
animationEndTime=end)
|
||||
|
||||
|
||||
class SetFrameRangeWithHandlesLoader(api.Loader):
|
||||
"""Specific loader of Alembic for the avalon.animation family"""
|
||||
|
||||
families = ["studio.animation",
|
||||
"studio.camera",
|
||||
"studio.pointcache"]
|
||||
representations = ["abc"]
|
||||
|
||||
label = "Set frame range (with handles)"
|
||||
order = 12
|
||||
icon = "clock-o"
|
||||
color = "white"
|
||||
|
||||
def load(self, context, name, namespace, data):
|
||||
|
||||
import maya.cmds as cmds
|
||||
|
||||
version = context['version']
|
||||
version_data = version.get("data", {})
|
||||
|
||||
start = version_data.get("startFrame", None)
|
||||
end = version_data.get("endFrame", None)
|
||||
|
||||
if start is None or end is None:
|
||||
print("Skipping setting frame range because start or "
|
||||
"end frame data is missing..")
|
||||
return
|
||||
|
||||
# Include handles
|
||||
handles = version_data.get("handles", 0)
|
||||
start -= handles
|
||||
end += handles
|
||||
|
||||
cmds.playbackOptions(minTime=start,
|
||||
maxTime=end,
|
||||
animationStartTime=start,
|
||||
animationEndTime=end)
|
||||
|
||||
|
||||
class ImportMayaLoader(api.Loader):
|
||||
"""Import action for Maya (unmanaged)
|
||||
|
||||
Warning:
|
||||
The loaded content will be unmanaged and is *not* visible in the
|
||||
scene inventory. It's purely intended to merge content into your scene
|
||||
so you could also use it as a new base.
|
||||
|
||||
"""
|
||||
representations = ["ma"]
|
||||
families = ["*"]
|
||||
|
||||
label = "Import"
|
||||
order = 10
|
||||
icon = "arrow-circle-down"
|
||||
color = "#775555"
|
||||
|
||||
def load(self, context, name=None, namespace=None, data=None):
|
||||
import maya.cmds as cmds
|
||||
|
||||
from avalon import maya
|
||||
from avalon.maya import lib
|
||||
|
||||
choice = self.display_warning()
|
||||
if choice is False:
|
||||
return
|
||||
|
||||
asset = context['asset']
|
||||
|
||||
namespace = namespace or lib.unique_namespace(
|
||||
asset["name"] + "_",
|
||||
prefix="_" if asset["name"][0].isdigit() else "",
|
||||
suffix="_",
|
||||
)
|
||||
|
||||
with maya.maintained_selection():
|
||||
cmds.file(self.fname,
|
||||
i=True,
|
||||
namespace=namespace,
|
||||
returnNewNodes=True,
|
||||
groupReference=True,
|
||||
groupName="{}:{}".format(namespace, name))
|
||||
|
||||
# We do not containerize imported content, it remains unmanaged
|
||||
return
|
||||
|
||||
def display_warning(self):
|
||||
"""Show warning to ensure the user can't import models by accident
|
||||
|
||||
Returns:
|
||||
bool
|
||||
|
||||
"""
|
||||
|
||||
from avalon.vendor.Qt import QtWidgets
|
||||
|
||||
accept = QtWidgets.QMessageBox.Ok
|
||||
buttons = accept | QtWidgets.QMessageBox.Cancel
|
||||
|
||||
message = "Are you sure you want import this"
|
||||
state = QtWidgets.QMessageBox.warning(None,
|
||||
"Are you sure?",
|
||||
message,
|
||||
buttons=buttons,
|
||||
defaultButton=accept)
|
||||
|
||||
return state == accept
|
||||
33
pype/plugins/maya/load/load_alembic.py
Normal file
33
pype/plugins/maya/load/load_alembic.py
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
import pype.maya.plugin
|
||||
|
||||
|
||||
class AbcLoader(pype.maya.plugin.ReferenceLoader):
|
||||
"""Specific loader of Alembic for the avalon.animation family"""
|
||||
|
||||
families = ["studio.animation",
|
||||
"studio.pointcache"]
|
||||
label = "Reference animation"
|
||||
representations = ["abc"]
|
||||
order = -10
|
||||
icon = "code-fork"
|
||||
color = "orange"
|
||||
|
||||
def process_reference(self, context, name, namespace, data):
|
||||
|
||||
import maya.cmds as cmds
|
||||
|
||||
cmds.loadPlugin("AbcImport.mll", quiet=True)
|
||||
nodes = cmds.file(self.fname,
|
||||
namespace=namespace,
|
||||
sharedReferenceFile=False,
|
||||
groupReference=True,
|
||||
groupName="{}:{}".format(namespace, name),
|
||||
reference=True,
|
||||
returnNewNodes=True)
|
||||
|
||||
self[:] = nodes
|
||||
|
||||
return nodes
|
||||
|
||||
def switch(self, container, representation):
|
||||
self.update(container, representation)
|
||||
45
pype/plugins/maya/load/load_camera.py
Normal file
45
pype/plugins/maya/load/load_camera.py
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
import pype.maya.plugin
|
||||
|
||||
|
||||
class CameraLoader(pype.maya.plugin.ReferenceLoader):
|
||||
"""Specific loader of Alembic for the avalon.animation family"""
|
||||
|
||||
families = ["studio.camera"]
|
||||
label = "Reference camera"
|
||||
representations = ["abc", "ma"]
|
||||
order = -10
|
||||
icon = "code-fork"
|
||||
color = "orange"
|
||||
|
||||
def process_reference(self, context, name, namespace, data):
|
||||
|
||||
import maya.cmds as cmds
|
||||
# Get family type from the context
|
||||
|
||||
cmds.loadPlugin("AbcImport.mll", quiet=True)
|
||||
nodes = cmds.file(self.fname,
|
||||
namespace=namespace,
|
||||
sharedReferenceFile=False,
|
||||
groupReference=True,
|
||||
groupName="{}:{}".format(namespace, name),
|
||||
reference=True,
|
||||
returnNewNodes=True)
|
||||
|
||||
cameras = cmds.ls(nodes, type="camera")
|
||||
|
||||
# Check the Maya version, lockTransform has been introduced since
|
||||
# Maya 2016.5 Ext 2
|
||||
version = int(cmds.about(version=True))
|
||||
if version >= 2016:
|
||||
for camera in cameras:
|
||||
cmds.camera(camera, edit=True, lockTransform=True)
|
||||
else:
|
||||
self.log.warning("This version of Maya does not support locking of"
|
||||
" transforms of cameras.")
|
||||
|
||||
self[:] = nodes
|
||||
|
||||
return nodes
|
||||
|
||||
def switch(self, container, representation):
|
||||
self.update(container, representation)
|
||||
40
pype/plugins/maya/load/load_look.py
Normal file
40
pype/plugins/maya/load/load_look.py
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
import pype.maya.plugin
|
||||
|
||||
|
||||
class LookLoader(pype.maya.plugin.ReferenceLoader):
|
||||
"""Specific loader for lookdev"""
|
||||
|
||||
families = ["studio.look"]
|
||||
representations = ["ma"]
|
||||
|
||||
label = "Reference look"
|
||||
order = -10
|
||||
icon = "code-fork"
|
||||
color = "orange"
|
||||
|
||||
def process_reference(self, context, name, namespace, data):
|
||||
"""
|
||||
Load and try to ssign Lookdev to nodes based on relationship data
|
||||
Args:
|
||||
name:
|
||||
namespace:
|
||||
context:
|
||||
data:
|
||||
|
||||
Returns:
|
||||
|
||||
"""
|
||||
|
||||
import maya.cmds as cmds
|
||||
from avalon import maya
|
||||
|
||||
with maya.maintained_selection():
|
||||
nodes = cmds.file(self.fname,
|
||||
namespace=namespace,
|
||||
reference=True,
|
||||
returnNewNodes=True)
|
||||
|
||||
self[:] = nodes
|
||||
|
||||
def switch(self, container, representation):
|
||||
self.update(container, representation)
|
||||
33
pype/plugins/maya/load/load_mayaascii.py
Normal file
33
pype/plugins/maya/load/load_mayaascii.py
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
import pype.maya.plugin
|
||||
|
||||
|
||||
class MayaAsciiLoader(pype.maya.plugin.ReferenceLoader):
|
||||
"""Load the model"""
|
||||
|
||||
families = ["pype.mayaAscii"]
|
||||
representations = ["ma"]
|
||||
|
||||
label = "Reference Maya Ascii"
|
||||
order = -10
|
||||
icon = "code-fork"
|
||||
color = "orange"
|
||||
|
||||
def process_reference(self, context, name, namespace, data):
|
||||
|
||||
import maya.cmds as cmds
|
||||
from avalon import maya
|
||||
|
||||
with maya.maintained_selection():
|
||||
nodes = cmds.file(self.fname,
|
||||
namespace=namespace,
|
||||
reference=True,
|
||||
returnNewNodes=True,
|
||||
groupReference=True,
|
||||
groupName="{}:{}".format(namespace, name))
|
||||
|
||||
self[:] = nodes
|
||||
|
||||
return nodes
|
||||
|
||||
def switch(self, container, representation):
|
||||
self.update(container, representation)
|
||||
125
pype/plugins/maya/load/load_model.py
Normal file
125
pype/plugins/maya/load/load_model.py
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
from avalon import api
|
||||
import pype.maya.plugin
|
||||
|
||||
|
||||
class ModelLoader(pype.maya.plugin.ReferenceLoader):
|
||||
"""Load the model"""
|
||||
|
||||
families = ["studio.model"]
|
||||
representations = ["ma"]
|
||||
|
||||
label = "Reference Model"
|
||||
order = -10
|
||||
icon = "code-fork"
|
||||
color = "orange"
|
||||
|
||||
def process_reference(self, context, name, namespace, data):
|
||||
|
||||
import maya.cmds as cmds
|
||||
from avalon import maya
|
||||
|
||||
with maya.maintained_selection():
|
||||
nodes = cmds.file(self.fname,
|
||||
namespace=namespace,
|
||||
reference=True,
|
||||
returnNewNodes=True,
|
||||
groupReference=True,
|
||||
groupName="{}:{}".format(namespace, name))
|
||||
|
||||
self[:] = nodes
|
||||
|
||||
return nodes
|
||||
|
||||
def switch(self, container, representation):
|
||||
self.update(container, representation)
|
||||
|
||||
|
||||
class GpuCacheLoader(api.Loader):
|
||||
"""Load model Alembic as gpuCache"""
|
||||
|
||||
families = ["studio.model"]
|
||||
representations = ["abc"]
|
||||
|
||||
label = "Import Gpu Cache"
|
||||
order = -5
|
||||
icon = "code-fork"
|
||||
color = "orange"
|
||||
|
||||
def load(self, context, name, namespace, data):
|
||||
|
||||
import maya.cmds as cmds
|
||||
import avalon.maya.lib as lib
|
||||
from avalon.maya.pipeline import containerise
|
||||
|
||||
asset = context['asset']['name']
|
||||
namespace = namespace or lib.unique_namespace(
|
||||
asset + "_",
|
||||
prefix="_" if asset[0].isdigit() else "",
|
||||
suffix="_",
|
||||
)
|
||||
|
||||
cmds.loadPlugin("gpuCache", quiet=True)
|
||||
|
||||
# Root group
|
||||
label = "{}:{}".format(namespace, name)
|
||||
root = cmds.group(name=label, empty=True)
|
||||
|
||||
# Create transform with shape
|
||||
transform_name = label + "_GPU"
|
||||
transform = cmds.createNode("transform", name=transform_name,
|
||||
parent=root)
|
||||
cache = cmds.createNode("gpuCache",
|
||||
parent=transform,
|
||||
name="{0}Shape".format(transform_name))
|
||||
|
||||
# Set the cache filepath
|
||||
cmds.setAttr(cache + '.cacheFileName', self.fname, type="string")
|
||||
cmds.setAttr(cache + '.cacheGeomPath', "|", type="string") # root
|
||||
|
||||
# Lock parenting of the transform and cache
|
||||
cmds.lockNode([transform, cache], lock=True)
|
||||
|
||||
nodes = [root, transform, cache]
|
||||
self[:] = nodes
|
||||
|
||||
return containerise(
|
||||
name=name,
|
||||
namespace=namespace,
|
||||
nodes=nodes,
|
||||
context=context,
|
||||
loader=self.__class__.__name__)
|
||||
|
||||
def update(self, container, representation):
|
||||
|
||||
import maya.cmds as cmds
|
||||
|
||||
path = api.get_representation_path(representation)
|
||||
|
||||
# Update the cache
|
||||
members = cmds.sets(container['objectName'], query=True)
|
||||
caches = cmds.ls(members, type="gpuCache", long=True)
|
||||
|
||||
assert len(caches) == 1, "This is a bug"
|
||||
|
||||
for cache in caches:
|
||||
cmds.setAttr(cache + ".cacheFileName", path, type="string")
|
||||
|
||||
cmds.setAttr(container["objectName"] + ".representation",
|
||||
str(representation["_id"]),
|
||||
type="string")
|
||||
|
||||
def switch(self, container, representation):
|
||||
self.update(container, representation)
|
||||
|
||||
def remove(self, container):
|
||||
import maya.cmds as cmds
|
||||
members = cmds.sets(container['objectName'], query=True)
|
||||
cmds.lockNode(members, lock=False)
|
||||
cmds.delete([container['objectName']] + members)
|
||||
|
||||
# Clean up the namespace
|
||||
try:
|
||||
cmds.namespace(removeNamespace=container['namespace'],
|
||||
deleteNamespaceContent=True)
|
||||
except RuntimeError:
|
||||
pass
|
||||
70
pype/plugins/maya/load/load_rig.py
Normal file
70
pype/plugins/maya/load/load_rig.py
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
from maya import cmds
|
||||
|
||||
import pype.maya.plugin
|
||||
from avalon import api, maya
|
||||
|
||||
|
||||
class RigLoader(pype.maya.plugin.ReferenceLoader):
|
||||
"""Specific loader for rigs
|
||||
|
||||
This automatically creates an instance for animators upon load.
|
||||
|
||||
"""
|
||||
|
||||
families = ["studio.rig"]
|
||||
representations = ["ma"]
|
||||
|
||||
label = "Reference rig"
|
||||
order = -10
|
||||
icon = "code-fork"
|
||||
color = "orange"
|
||||
|
||||
def process_reference(self, context, name, namespace, data):
|
||||
|
||||
nodes = cmds.file(self.fname,
|
||||
namespace=namespace,
|
||||
reference=True,
|
||||
returnNewNodes=True,
|
||||
groupReference=True,
|
||||
groupName="{}:{}".format(namespace, name))
|
||||
|
||||
# Store for post-process
|
||||
self[:] = nodes
|
||||
if data.get("post_process", True):
|
||||
self._post_process(name, namespace, context, data)
|
||||
|
||||
return nodes
|
||||
|
||||
def _post_process(self, name, namespace, context, data):
|
||||
|
||||
# TODO(marcus): We are hardcoding the name "out_SET" here.
|
||||
# Better register this keyword, so that it can be used
|
||||
# elsewhere, such as in the Integrator plug-in,
|
||||
# without duplication.
|
||||
|
||||
output = next((node for node in self if
|
||||
node.endswith("out_SET")), None)
|
||||
controls = next((node for node in self if
|
||||
node.endswith("controls_SET")), None)
|
||||
|
||||
assert output, "No out_SET in rig, this is a bug."
|
||||
assert controls, "No controls_SET in rig, this is a bug."
|
||||
|
||||
# Find the roots amongst the loaded nodes
|
||||
roots = cmds.ls(self[:], assemblies=True, long=True)
|
||||
assert roots, "No root nodes in rig, this is a bug."
|
||||
|
||||
asset = api.Session["AVALON_ASSET"]
|
||||
dependency = str(context["representation"]["_id"])
|
||||
|
||||
# Create the animation instance
|
||||
with maya.maintained_selection():
|
||||
cmds.select([output, controls] + roots, noExpand=True)
|
||||
api.create(name=namespace,
|
||||
asset=asset,
|
||||
family="studio.animation",
|
||||
options={"useSelection": True},
|
||||
data={"dependencies": dependency})
|
||||
|
||||
def switch(self, container, representation):
|
||||
self.update(container, representation)
|
||||
80
pype/plugins/maya/load/load_setdress.py
Normal file
80
pype/plugins/maya/load/load_setdress.py
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
from avalon import api
|
||||
|
||||
|
||||
class SetDressLoader(api.Loader):
|
||||
|
||||
families = ["studio.setdress"]
|
||||
representations = ["json"]
|
||||
|
||||
label = "Load Set Dress"
|
||||
order = -9
|
||||
icon = "code-fork"
|
||||
color = "orange"
|
||||
|
||||
def load(self, context, name, namespace, data):
|
||||
|
||||
from avalon.maya.pipeline import containerise
|
||||
from avalon.maya import lib
|
||||
|
||||
asset = context['asset']['name']
|
||||
namespace = namespace or lib.unique_namespace(
|
||||
asset + "_",
|
||||
prefix="_" if asset[0].isdigit() else "",
|
||||
suffix="_",
|
||||
)
|
||||
|
||||
from config import setdress_api
|
||||
|
||||
containers = setdress_api.load_package(filepath=self.fname,
|
||||
name=name,
|
||||
namespace=namespace)
|
||||
|
||||
self[:] = containers
|
||||
|
||||
# Only containerize if any nodes were loaded by the Loader
|
||||
nodes = self[:]
|
||||
if not nodes:
|
||||
return
|
||||
|
||||
return containerise(
|
||||
name=name,
|
||||
namespace=namespace,
|
||||
nodes=nodes,
|
||||
context=context,
|
||||
loader=self.__class__.__name__)
|
||||
|
||||
def update(self, container, representation):
|
||||
|
||||
from config import setdress_api
|
||||
return setdress_api.update_package(container,
|
||||
representation)
|
||||
|
||||
def remove(self, container):
|
||||
"""Remove all sub containers"""
|
||||
|
||||
from avalon import api
|
||||
from config import setdress_api
|
||||
import maya.cmds as cmds
|
||||
|
||||
# Remove all members
|
||||
member_containers = setdress_api.get_contained_containers(container)
|
||||
for member_container in member_containers:
|
||||
self.log.info("Removing container %s",
|
||||
member_container['objectName'])
|
||||
api.remove(member_container)
|
||||
|
||||
# Remove alembic hierarchy reference
|
||||
# TODO: Check whether removing all contained references is safe enough
|
||||
members = cmds.sets(container['objectName'], query=True) or []
|
||||
references = cmds.ls(members, type="reference")
|
||||
for reference in references:
|
||||
self.log.info("Removing %s", reference)
|
||||
fname = cmds.referenceQuery(reference, filename=True)
|
||||
cmds.file(fname, removeReference=True)
|
||||
|
||||
# Delete container and its contents
|
||||
if cmds.objExists(container['objectName']):
|
||||
members = cmds.sets(container['objectName'], query=True) or []
|
||||
cmds.delete([container['objectName']] + members)
|
||||
|
||||
# TODO: Ensure namespace is gone
|
||||
144
pype/plugins/maya/load/load_vrayproxy.py
Normal file
144
pype/plugins/maya/load/load_vrayproxy.py
Normal file
|
|
@ -0,0 +1,144 @@
|
|||
from avalon.maya import lib
|
||||
from avalon import api
|
||||
|
||||
import maya.cmds as cmds
|
||||
|
||||
|
||||
class VRayProxyLoader(api.Loader):
|
||||
"""Load VRayMesh proxy"""
|
||||
|
||||
families = ["studio.vrayproxy"]
|
||||
representations = ["vrmesh"]
|
||||
|
||||
label = "Import VRay Proxy"
|
||||
order = -10
|
||||
icon = "code-fork"
|
||||
color = "orange"
|
||||
|
||||
def load(self, context, name, namespace, data):
|
||||
|
||||
from avalon.maya.pipeline import containerise
|
||||
from pype.maya.lib import namespaced
|
||||
|
||||
asset_name = context['asset']["name"]
|
||||
namespace = namespace or lib.unique_namespace(
|
||||
asset_name + "_",
|
||||
prefix="_" if asset_name[0].isdigit() else "",
|
||||
suffix="_",
|
||||
)
|
||||
|
||||
# Ensure V-Ray for Maya is loaded.
|
||||
cmds.loadPlugin("vrayformaya", quiet=True)
|
||||
|
||||
with lib.maintained_selection():
|
||||
cmds.namespace(addNamespace=namespace)
|
||||
with namespaced(namespace, new=False):
|
||||
nodes = self.create_vray_proxy(name,
|
||||
filename=self.fname)
|
||||
|
||||
self[:] = nodes
|
||||
if not nodes:
|
||||
return
|
||||
|
||||
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 []
|
||||
vraymeshes = cmds.ls(members, type="VRayMesh")
|
||||
assert vraymeshes, "Cannot find VRayMesh in container"
|
||||
|
||||
filename = api.get_representation_path(representation)
|
||||
|
||||
for vray_mesh in vraymeshes:
|
||||
cmds.setAttr("{}.fileName".format(vray_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_vray_proxy(self, name, filename):
|
||||
"""Re-create the structure created by VRay to support vrmeshes
|
||||
|
||||
Args:
|
||||
name(str): name of the asset
|
||||
|
||||
Returns:
|
||||
nodes(list)
|
||||
"""
|
||||
|
||||
# Create nodes
|
||||
vray_mesh = cmds.createNode('VRayMesh', name="{}_VRMS".format(name))
|
||||
mesh_shape = cmds.createNode("mesh", name="{}_GEOShape".format(name))
|
||||
vray_mat = cmds.createNode("VRayMeshMaterial",
|
||||
name="{}_VRMM".format(name))
|
||||
vray_mat_sg = cmds.createNode("shadingEngine",
|
||||
name="{}_VRSG".format(name))
|
||||
|
||||
cmds.setAttr("{}.fileName".format(vray_mesh),
|
||||
filename,
|
||||
type="string")
|
||||
|
||||
# Create important connections
|
||||
cmds.connectAttr("time1.outTime",
|
||||
"{0}.currentFrame".format(vray_mesh))
|
||||
cmds.connectAttr("{}.fileName2".format(vray_mesh),
|
||||
"{}.fileName".format(vray_mat))
|
||||
cmds.connectAttr("{}.instancing".format(vray_mesh),
|
||||
"{}.instancing".format(vray_mat))
|
||||
cmds.connectAttr("{}.output".format(vray_mesh),
|
||||
"{}.inMesh".format(mesh_shape))
|
||||
cmds.connectAttr("{}.overrideFileName".format(vray_mesh),
|
||||
"{}.overrideFileName".format(vray_mat))
|
||||
cmds.connectAttr("{}.currentFrame".format(vray_mesh),
|
||||
"{}.currentFrame".format(vray_mat))
|
||||
|
||||
# Set surface shader input
|
||||
cmds.connectAttr("{}.outColor".format(vray_mat),
|
||||
"{}.surfaceShader".format(vray_mat_sg))
|
||||
|
||||
# Connect mesh to shader
|
||||
cmds.sets([mesh_shape], addElement=vray_mat_sg)
|
||||
|
||||
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 = [vray_mesh, mesh_shape, vray_mat, vray_mat_sg, group_node]
|
||||
|
||||
# Fix: Force refresh so the mesh shows correctly after creation
|
||||
cmds.refresh()
|
||||
cmds.setAttr("{}.geomType".format(vray_mesh), 2)
|
||||
|
||||
return nodes
|
||||
298
pype/plugins/maya/load/load_yeti_cache.py
Normal file
298
pype/plugins/maya/load/load_yeti_cache.py
Normal file
|
|
@ -0,0 +1,298 @@
|
|||
import os
|
||||
import json
|
||||
import re
|
||||
import glob
|
||||
from collections import defaultdict
|
||||
|
||||
from maya import cmds
|
||||
|
||||
from avalon import api
|
||||
from avalon.maya import lib as avalon_lib, pipeline
|
||||
from pype.maya import lib
|
||||
|
||||
|
||||
class YetiCacheLoader(api.Loader):
|
||||
|
||||
families = ["studio.yeticache", "studio.yetiRig"]
|
||||
representations = ["fur"]
|
||||
|
||||
label = "Load Yeti Cache"
|
||||
order = -9
|
||||
icon = "code-fork"
|
||||
color = "orange"
|
||||
|
||||
def load(self, context, name=None, namespace=None, data=None):
|
||||
|
||||
# Build namespace
|
||||
asset = context["asset"]
|
||||
if namespace is None:
|
||||
namespace = self.create_namespace(asset["name"])
|
||||
|
||||
# Ensure Yeti is loaded
|
||||
if not cmds.pluginInfo("pgYetiMaya", query=True, loaded=True):
|
||||
cmds.loadPlugin("pgYetiMaya", quiet=True)
|
||||
|
||||
# Get JSON
|
||||
fname, ext = os.path.splitext(self.fname)
|
||||
settings_fname = "{}.fursettings".format(fname)
|
||||
with open(settings_fname, "r") as fp:
|
||||
fursettings = json.load(fp)
|
||||
|
||||
# Check if resources map exists
|
||||
# Get node name from JSON
|
||||
if "nodes" not in fursettings:
|
||||
raise RuntimeError("Encountered invalid data, expect 'nodes' in "
|
||||
"fursettings.")
|
||||
|
||||
node_data = fursettings["nodes"]
|
||||
nodes = self.create_nodes(namespace, node_data)
|
||||
|
||||
group_name = "{}:{}".format(namespace, name)
|
||||
group_node = cmds.group(nodes, name=group_name)
|
||||
|
||||
nodes.append(group_node)
|
||||
|
||||
self[:] = nodes
|
||||
|
||||
return pipeline.containerise(name=name,
|
||||
namespace=namespace,
|
||||
nodes=nodes,
|
||||
context=context,
|
||||
loader=self.__class__.__name__)
|
||||
|
||||
def remove(self, container):
|
||||
|
||||
from maya import cmds
|
||||
|
||||
namespace = container["namespace"]
|
||||
container_name = container["objectName"]
|
||||
|
||||
self.log.info("Removing '%s' from Maya.." % container["name"])
|
||||
|
||||
container_content = cmds.sets(container_name, query=True)
|
||||
nodes = cmds.ls(container_content, long=True)
|
||||
|
||||
nodes.append(container_name)
|
||||
|
||||
try:
|
||||
cmds.delete(nodes)
|
||||
except ValueError:
|
||||
# Already implicitly deleted by Maya upon removing reference
|
||||
pass
|
||||
|
||||
cmds.namespace(removeNamespace=namespace, deleteNamespaceContent=True)
|
||||
|
||||
def update(self, container, representation):
|
||||
|
||||
namespace = container["namespace"]
|
||||
container_node = container["objectName"]
|
||||
path = api.get_representation_path(representation)
|
||||
|
||||
# Get all node data
|
||||
fname, ext = os.path.splitext(path)
|
||||
settings_fname = "{}.fursettings".format(fname)
|
||||
with open(settings_fname, "r") as fp:
|
||||
settings = json.load(fp)
|
||||
|
||||
# Collect scene information of asset
|
||||
set_members = cmds.sets(container["objectName"], query=True)
|
||||
container_root = lib.get_container_transforms(container,
|
||||
members=set_members,
|
||||
root=True)
|
||||
scene_nodes = cmds.ls(set_members, type="pgYetiMaya", long=True)
|
||||
|
||||
# Build lookup with cbId as keys
|
||||
scene_lookup = defaultdict(list)
|
||||
for node in scene_nodes:
|
||||
cb_id = lib.get_id(node)
|
||||
scene_lookup[cb_id].append(node)
|
||||
|
||||
# Re-assemble metadata with cbId as keys
|
||||
meta_data_lookup = {n["cbId"]: n for n in settings["nodes"]}
|
||||
|
||||
# Compare look ups and get the nodes which ar not relevant any more
|
||||
to_delete_lookup = {cb_id for cb_id in scene_lookup.keys() if
|
||||
cb_id not in meta_data_lookup}
|
||||
if to_delete_lookup:
|
||||
|
||||
# Get nodes and remove entry from lookup
|
||||
to_remove = []
|
||||
for _id in to_delete_lookup:
|
||||
# Get all related nodes
|
||||
shapes = scene_lookup[_id]
|
||||
# Get the parents of all shapes under the ID
|
||||
transforms = cmds.listRelatives(shapes,
|
||||
parent=True,
|
||||
fullPath=True) or []
|
||||
to_remove.extend(shapes + transforms)
|
||||
|
||||
# Remove id from look uop
|
||||
scene_lookup.pop(_id, None)
|
||||
|
||||
cmds.delete(to_remove)
|
||||
|
||||
for cb_id, data in meta_data_lookup.items():
|
||||
|
||||
# Update cache file name
|
||||
file_name = data["name"].replace(":", "_")
|
||||
cache_file_path = "{}.%04d.fur".format(file_name)
|
||||
data["attrs"]["cacheFileName"] = os.path.join(path, cache_file_path)
|
||||
|
||||
if cb_id not in scene_lookup:
|
||||
|
||||
self.log.info("Creating new nodes ..")
|
||||
|
||||
new_nodes = self.create_nodes(namespace, [data])
|
||||
cmds.sets(new_nodes, addElement=container_node)
|
||||
cmds.parent(new_nodes, container_root)
|
||||
|
||||
else:
|
||||
# Update the matching nodes
|
||||
scene_nodes = scene_lookup[cb_id]
|
||||
lookup_result = meta_data_lookup[cb_id]["name"]
|
||||
|
||||
# Remove namespace if any (e.g.: "character_01_:head_YNShape")
|
||||
node_name = lookup_result.rsplit(":", 1)[-1]
|
||||
|
||||
for scene_node in scene_nodes:
|
||||
|
||||
# Get transform node, this makes renaming easier
|
||||
transforms = cmds.listRelatives(scene_node,
|
||||
parent=True,
|
||||
fullPath=True) or []
|
||||
assert len(transforms) == 1, "This is a bug!"
|
||||
|
||||
# Get scene node's namespace and rename the transform node
|
||||
lead = scene_node.rsplit(":", 1)[0]
|
||||
namespace = ":{}".format(lead.rsplit("|")[-1])
|
||||
|
||||
new_shape_name = "{}:{}".format(namespace, node_name)
|
||||
new_trans_name = new_shape_name.rsplit("Shape", 1)[0]
|
||||
|
||||
transform_node = transforms[0]
|
||||
cmds.rename(transform_node,
|
||||
new_trans_name,
|
||||
ignoreShape=False)
|
||||
|
||||
# Get the newly named shape node
|
||||
yeti_nodes = cmds.listRelatives(new_trans_name,
|
||||
children=True)
|
||||
yeti_node = yeti_nodes[0]
|
||||
|
||||
for attr, value in data["attrs"].items():
|
||||
lib.set_attribute(attr, value, yeti_node)
|
||||
|
||||
cmds.setAttr("{}.representation".format(container_node),
|
||||
str(representation["_id"]),
|
||||
typ="string")
|
||||
|
||||
def switch(self, container, representation):
|
||||
self.update(container, representation)
|
||||
|
||||
# helper functions
|
||||
|
||||
def create_namespace(self, asset):
|
||||
"""Create a unique namespace
|
||||
Args:
|
||||
asset (dict): asset information
|
||||
|
||||
"""
|
||||
|
||||
asset_name = "{}_".format(asset)
|
||||
prefix = "_" if asset_name[0].isdigit()else ""
|
||||
namespace = avalon_lib.unique_namespace(asset_name,
|
||||
prefix=prefix,
|
||||
suffix="_")
|
||||
|
||||
return namespace
|
||||
|
||||
def validate_cache(self, filename, pattern="%04d"):
|
||||
"""Check if the cache has more than 1 frame
|
||||
|
||||
All caches with more than 1 frame need to be called with `%04d`
|
||||
If the cache has only one frame we return that file name as we assume
|
||||
it is a snapshot.
|
||||
|
||||
Args:
|
||||
filename(str)
|
||||
pattern(str)
|
||||
|
||||
Returns:
|
||||
str
|
||||
|
||||
"""
|
||||
|
||||
glob_pattern = filename.replace(pattern, "*")
|
||||
|
||||
escaped = re.escape(filename)
|
||||
re_pattern = escaped.replace(pattern, "-?[0-9]+")
|
||||
|
||||
files = glob.glob(glob_pattern)
|
||||
files = [str(f) for f in files if re.match(re_pattern, f)]
|
||||
|
||||
if len(files) == 1:
|
||||
return files[0]
|
||||
elif len(files) == 0:
|
||||
self.log.error("Could not find cache files for '%s'" % filename)
|
||||
|
||||
return filename
|
||||
|
||||
def create_nodes(self, namespace, settings):
|
||||
"""Create nodes with the correct namespace and settings
|
||||
|
||||
Args:
|
||||
namespace(str): namespace
|
||||
settings(list): list of dictionaries
|
||||
|
||||
Returns:
|
||||
list
|
||||
|
||||
"""
|
||||
|
||||
nodes = []
|
||||
for node_settings in settings:
|
||||
|
||||
# Create pgYetiMaya node
|
||||
original_node = node_settings["name"]
|
||||
node_name = "{}:{}".format(namespace, original_node)
|
||||
yeti_node = cmds.createNode("pgYetiMaya", name=node_name)
|
||||
|
||||
# Create transform node
|
||||
transform_node = node_name.rstrip("Shape")
|
||||
|
||||
lib.set_id(transform_node, node_settings["transform"]["cbId"])
|
||||
lib.set_id(yeti_node, node_settings["cbId"])
|
||||
|
||||
nodes.extend([transform_node, yeti_node])
|
||||
|
||||
# Ensure the node has no namespace identifiers
|
||||
attributes = node_settings["attrs"]
|
||||
|
||||
# Check if cache file name is stored
|
||||
if "cacheFileName" not in attributes:
|
||||
file_name = original_node.replace(":", "_")
|
||||
cache_name = "{}.%04d.fur".format(file_name)
|
||||
cache = os.path.join(self.fname, cache_name)
|
||||
|
||||
self.validate_cache(cache)
|
||||
attributes["cacheFileName"] = cache
|
||||
|
||||
# Update attributes with requirements
|
||||
attributes.update({"viewportDensity": 0.1,
|
||||
"verbosity": 2,
|
||||
"fileMode": 1})
|
||||
|
||||
# Apply attributes to pgYetiMaya node
|
||||
for attr, value in attributes.items():
|
||||
lib.set_attribute(attr, value, yeti_node)
|
||||
|
||||
# Fix for : YETI-6
|
||||
# Fixes the render stats (this is literally taken from Perigrene's
|
||||
# ../scripts/pgYetiNode.mel script)
|
||||
cmds.setAttr("{}.visibleInReflections".format(yeti_node), True)
|
||||
cmds.setAttr("{}.visibleInRefractions".format(yeti_node), True)
|
||||
|
||||
# Connect to the time node
|
||||
cmds.connectAttr("time1.outTime", "%s.currentTime" % yeti_node)
|
||||
|
||||
return nodes
|
||||
31
pype/plugins/maya/load/load_yeti_rig.py
Normal file
31
pype/plugins/maya/load/load_yeti_rig.py
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
import pype.maya.plugin
|
||||
|
||||
|
||||
class YetiRigLoader(pype.maya.plugin.ReferenceLoader):
|
||||
|
||||
families = ["studio.yetiRig"]
|
||||
representations = ["ma"]
|
||||
|
||||
label = "Load Yeti Rig"
|
||||
order = -9
|
||||
icon = "code-fork"
|
||||
color = "orange"
|
||||
|
||||
def process_reference(self, context, name=None, namespace=None, data=None):
|
||||
|
||||
import maya.cmds as cmds
|
||||
from avalon import maya
|
||||
|
||||
with maya.maintained_selection():
|
||||
nodes = cmds.file(self.fname,
|
||||
namespace=namespace,
|
||||
reference=True,
|
||||
returnNewNodes=True,
|
||||
groupReference=True,
|
||||
groupName="{}:{}".format(namespace, name))
|
||||
|
||||
self[:] = nodes
|
||||
|
||||
self.log.info("Yeti Rig Connection Manager will be available soon")
|
||||
|
||||
return nodes
|
||||
Loading…
Add table
Add a link
Reference in a new issue