mirror of
https://github.com/ynput/ayon-core.git
synced 2025-12-24 21:04:40 +01:00
Merge remote-tracking branch 'upstream/develop' into maya_new_publisher
# Conflicts: # openpype/hosts/maya/plugins/create/create_look.py # openpype/hosts/maya/plugins/create/create_review.py # openpype/hosts/maya/plugins/publish/collect_instances.py # openpype/hosts/maya/plugins/publish/validate_attributes.py # openpype/hosts/maya/plugins/publish/validate_frame_range.py # openpype/hosts/maya/plugins/publish/validate_maya_units.py # openpype/hosts/maya/plugins/publish/validate_mesh_overlapping_uvs.py # openpype/modules/deadline/plugins/publish/collect_pools.py
This commit is contained in:
commit
fd6285399e
8 changed files with 110 additions and 135 deletions
|
|
@ -17,6 +17,7 @@ class CreateLook(plugin.MayaCreator):
|
|||
icon = "paint-brush"
|
||||
|
||||
make_tx = True
|
||||
rs_tex = False
|
||||
|
||||
def get_instance_attr_defs(self):
|
||||
|
||||
|
|
@ -32,6 +33,11 @@ class CreateLook(plugin.MayaCreator):
|
|||
label="MakeTX",
|
||||
tooltip="Whether to generate .tx files for your textures",
|
||||
default=self.make_tx),
|
||||
BoolDef("rstex",
|
||||
label="Convert textures to .rstex",
|
||||
tooltip="Whether to generate Redshift .rstex files for "
|
||||
"your textures",
|
||||
default=self.make_tx),
|
||||
BoolDef("forceCopy",
|
||||
label="Force Copy",
|
||||
tooltip="Enable users to force a copy instead of hardlink."
|
||||
|
|
|
|||
|
|
@ -26,14 +26,15 @@ class CreateReview(plugin.MayaCreator):
|
|||
family = "review"
|
||||
icon = "video-camera"
|
||||
|
||||
use_maya_timeline = True
|
||||
useMayaTimeline = True
|
||||
panZoom = False
|
||||
|
||||
def get_instance_attr_defs(self):
|
||||
|
||||
defs = lib.collect_animation_defs()
|
||||
|
||||
# Option for using Maya or asset frame range in settings.
|
||||
if not self.use_maya_timeline:
|
||||
if not self.useMayaTimeline:
|
||||
# Update the defaults to be the asset frame range
|
||||
frame_range = lib.get_frame_range()
|
||||
defs_by_key = {attr_def.key: attr_def for attr_def in defs}
|
||||
|
|
@ -72,7 +73,10 @@ class CreateReview(plugin.MayaCreator):
|
|||
default=True),
|
||||
EnumDef("transparency",
|
||||
label="Transparency",
|
||||
items=TRANSPARENCIES)
|
||||
items=TRANSPARENCIES),
|
||||
BoolDef("panZoom",
|
||||
label="Enable camera pan/zoom",
|
||||
default=True),
|
||||
])
|
||||
|
||||
return defs
|
||||
|
|
|
|||
|
|
@ -1,47 +1,7 @@
|
|||
from maya import cmds
|
||||
import maya.api.OpenMaya as om
|
||||
|
||||
import pyblish.api
|
||||
|
||||
|
||||
def get_all_children(nodes):
|
||||
"""Return all children of `nodes` including each instanced child.
|
||||
Using maya.cmds.listRelatives(allDescendents=True) includes only the first
|
||||
instance. As such, this function acts as an optimal replacement with a
|
||||
focus on a fast query.
|
||||
|
||||
"""
|
||||
|
||||
sel = om.MSelectionList()
|
||||
traversed = set()
|
||||
iterator = om.MItDag(om.MItDag.kDepthFirst)
|
||||
for node in nodes:
|
||||
|
||||
if node in traversed:
|
||||
# Ignore if already processed as a child
|
||||
# before
|
||||
continue
|
||||
|
||||
sel.clear()
|
||||
sel.add(node)
|
||||
dag = sel.getDagPath(0)
|
||||
|
||||
iterator.reset(dag)
|
||||
# ignore self
|
||||
iterator.next() # noqa: B305
|
||||
while not iterator.isDone():
|
||||
|
||||
path = iterator.fullPathName()
|
||||
|
||||
if path in traversed:
|
||||
iterator.prune()
|
||||
iterator.next() # noqa: B305
|
||||
continue
|
||||
|
||||
traversed.add(path)
|
||||
iterator.next() # noqa: B305
|
||||
|
||||
return list(traversed)
|
||||
from openpype.hosts.maya.api.lib import get_all_children
|
||||
|
||||
|
||||
class CollectNewInstances(pyblish.api.InstancePlugin):
|
||||
|
|
|
|||
|
|
@ -1,6 +1,10 @@
|
|||
import pymel.core as pm
|
||||
from collections import defaultdict
|
||||
|
||||
from maya import cmds
|
||||
|
||||
import pyblish.api
|
||||
|
||||
from openpype.hosts.maya.api.lib import set_attribute
|
||||
from openpype.pipeline.publish import (
|
||||
RepairContextAction,
|
||||
ValidateContentsOrder,
|
||||
|
|
@ -8,7 +12,7 @@ from openpype.pipeline.publish import (
|
|||
)
|
||||
|
||||
|
||||
class ValidateAttributes(pyblish.api.ContextPlugin,
|
||||
class ValidateAttributes(pyblish.api.InstancePlugin,
|
||||
OptionalPyblishPluginMixin):
|
||||
"""Ensure attributes are consistent.
|
||||
|
||||
|
|
@ -29,88 +33,83 @@ class ValidateAttributes(pyblish.api.ContextPlugin,
|
|||
|
||||
attributes = None
|
||||
|
||||
def process(self, context):
|
||||
# Check for preset existence.
|
||||
if not self.is_active(context.data):
|
||||
def process(self, instance):
|
||||
if not self.is_active(instance.data):
|
||||
return
|
||||
|
||||
# Check for preset existence.
|
||||
if not self.attributes:
|
||||
return
|
||||
|
||||
invalid = self.get_invalid(context, compute=True)
|
||||
invalid = self.get_invalid(instance, compute=True)
|
||||
if invalid:
|
||||
raise RuntimeError(
|
||||
"Found attributes with invalid values: {}".format(invalid)
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def get_invalid(cls, context, compute=False):
|
||||
invalid = context.data.get("invalid_attributes", [])
|
||||
def get_invalid(cls, instance, compute=False):
|
||||
if compute:
|
||||
invalid = cls.get_invalid_attributes(context)
|
||||
|
||||
return invalid
|
||||
return cls.get_invalid_attributes(instance)
|
||||
else:
|
||||
return instance.data.get("invalid_attributes", [])
|
||||
|
||||
@classmethod
|
||||
def get_invalid_attributes(cls, context):
|
||||
def get_invalid_attributes(cls, instance):
|
||||
invalid_attributes = []
|
||||
for instance in context:
|
||||
# Filter publisable instances.
|
||||
if not instance.data["publish"]:
|
||||
|
||||
# Filter families.
|
||||
families = [instance.data["family"]]
|
||||
families += instance.data.get("families", [])
|
||||
families = set(families) & set(cls.attributes.keys())
|
||||
if not families:
|
||||
return []
|
||||
|
||||
# Get all attributes to validate.
|
||||
attributes = defaultdict(dict)
|
||||
for family in families:
|
||||
if family not in cls.attributes:
|
||||
# No attributes to validate for family
|
||||
continue
|
||||
|
||||
# Filter families.
|
||||
families = [instance.data["family"]]
|
||||
families += instance.data.get("families", [])
|
||||
families = list(set(families) & set(cls.attributes.keys()))
|
||||
if not families:
|
||||
for preset_attr, preset_value in cls.attributes[family].items():
|
||||
node_name, attribute_name = preset_attr.split(".", 1)
|
||||
attributes[node_name][attribute_name] = preset_value
|
||||
|
||||
if not attributes:
|
||||
return []
|
||||
|
||||
# Get invalid attributes.
|
||||
nodes = cmds.ls(long=True)
|
||||
for node in nodes:
|
||||
node_name = node.rsplit("|", 1)[-1].rsplit(":", 1)[-1]
|
||||
if node_name not in attributes:
|
||||
continue
|
||||
|
||||
# Get all attributes to validate.
|
||||
attributes = {}
|
||||
for family in families:
|
||||
for preset in cls.attributes[family]:
|
||||
[node_name, attribute_name] = preset.split(".")
|
||||
try:
|
||||
attributes[node_name].update(
|
||||
{attribute_name: cls.attributes[family][preset]}
|
||||
)
|
||||
except KeyError:
|
||||
attributes.update({
|
||||
node_name: {
|
||||
attribute_name: cls.attributes[family][preset]
|
||||
}
|
||||
})
|
||||
for attr_name, expected in attributes.items():
|
||||
|
||||
# Get invalid attributes.
|
||||
nodes = pm.ls()
|
||||
for node in nodes:
|
||||
name = node.name(stripNamespace=True)
|
||||
if name not in attributes.keys():
|
||||
# Skip if attribute does not exist
|
||||
if not cmds.attributeQuery(attr_name, node=node, exists=True):
|
||||
continue
|
||||
|
||||
presets_to_validate = attributes[name]
|
||||
for attribute in node.listAttr():
|
||||
names = [attribute.shortName(), attribute.longName()]
|
||||
attribute_name = list(
|
||||
set(names) & set(presets_to_validate.keys())
|
||||
plug = "{}.{}".format(node, attr_name)
|
||||
value = cmds.getAttr(plug)
|
||||
if value != expected:
|
||||
invalid_attributes.append(
|
||||
{
|
||||
"attribute": plug,
|
||||
"expected": expected,
|
||||
"current": value
|
||||
}
|
||||
)
|
||||
if attribute_name:
|
||||
expected = presets_to_validate[attribute_name[0]]
|
||||
if attribute.get() != expected:
|
||||
invalid_attributes.append(
|
||||
{
|
||||
"attribute": attribute,
|
||||
"expected": expected,
|
||||
"current": attribute.get()
|
||||
}
|
||||
)
|
||||
|
||||
context.data["invalid_attributes"] = invalid_attributes
|
||||
instance.data["invalid_attributes"] = invalid_attributes
|
||||
return invalid_attributes
|
||||
|
||||
@classmethod
|
||||
def repair(cls, instance):
|
||||
invalid = cls.get_invalid(instance)
|
||||
for data in invalid:
|
||||
data["attribute"].set(data["expected"])
|
||||
node, attr = data["attribute"].split(".", 1)
|
||||
value = data["expected"]
|
||||
set_attribute(node=node, attribute=attr, value=value)
|
||||
|
|
|
|||
|
|
@ -54,7 +54,6 @@ class ValidateFrameRange(pyblish.api.InstancePlugin,
|
|||
|
||||
frame_start_handle = int(context.data.get("frameStartHandle"))
|
||||
frame_end_handle = int(context.data.get("frameEndHandle"))
|
||||
handles = int(context.data.get("handles"))
|
||||
handle_start = int(context.data.get("handleStart"))
|
||||
handle_end = int(context.data.get("handleEnd"))
|
||||
frame_start = int(context.data.get("frameStart"))
|
||||
|
|
@ -71,8 +70,6 @@ class ValidateFrameRange(pyblish.api.InstancePlugin,
|
|||
assert frame_start_handle <= frame_end_handle, (
|
||||
"start frame is lower then end frame")
|
||||
|
||||
assert handles >= 0, ("handles cannot have negative values")
|
||||
|
||||
# compare with data on instance
|
||||
errors = []
|
||||
if [ef for ef in self.exclude_families
|
||||
|
|
|
|||
|
|
@ -127,7 +127,7 @@ class ValidateMayaUnits(pyblish.api.ContextPlugin):
|
|||
cls.log.debug(current_linear)
|
||||
|
||||
cls.log.info("Setting time unit to match project")
|
||||
# TODO repace query with using 'context.data["assetEntity"]'
|
||||
# TODO replace query with using 'context.data["assetEntity"]'
|
||||
asset_doc = get_current_project_asset()
|
||||
asset_fps = asset_doc["data"]["fps"]
|
||||
mayalib.set_scene_fps(asset_fps)
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
import pyblish.api
|
||||
import openpype.hosts.maya.api.action
|
||||
import math
|
||||
import maya.api.OpenMaya as om
|
||||
import pymel.core as pm
|
||||
|
||||
from six.moves import xrange
|
||||
|
||||
from maya import cmds
|
||||
import maya.api.OpenMaya as om
|
||||
import pyblish.api
|
||||
|
||||
import openpype.hosts.maya.api.action
|
||||
from openpype.pipeline.publish import (
|
||||
ValidateMeshOrder,
|
||||
OptionalPyblishPluginMixin
|
||||
|
|
@ -188,8 +189,7 @@ class GetOverlappingUVs(object):
|
|||
|
||||
center, radius = self._createBoundingCircle(meshfn)
|
||||
for i in xrange(meshfn.numPolygons): # noqa: F821
|
||||
rayb1, face1Orig, face1Vec = self._createRayGivenFace(
|
||||
meshfn, i)
|
||||
rayb1, face1Orig, face1Vec = self._createRayGivenFace(meshfn, i)
|
||||
if not rayb1:
|
||||
continue
|
||||
cui = center[2*i]
|
||||
|
|
@ -209,8 +209,8 @@ class GetOverlappingUVs(object):
|
|||
if (dsqr >= (ri + rj) * (ri + rj)):
|
||||
continue
|
||||
|
||||
rayb2, face2Orig, face2Vec = self._createRayGivenFace(
|
||||
meshfn, j)
|
||||
rayb2, face2Orig, face2Vec = self._createRayGivenFace(meshfn,
|
||||
j)
|
||||
if not rayb2:
|
||||
continue
|
||||
# Exclude the degenerate face
|
||||
|
|
@ -244,37 +244,45 @@ class ValidateMeshHasOverlappingUVs(pyblish.api.InstancePlugin,
|
|||
optional = True
|
||||
|
||||
@classmethod
|
||||
def _get_overlapping_uvs(cls, node):
|
||||
""" Check if mesh has overlapping UVs.
|
||||
def _get_overlapping_uvs(cls, mesh):
|
||||
"""Return overlapping UVs of mesh.
|
||||
|
||||
Args:
|
||||
mesh (str): Mesh node name
|
||||
|
||||
Returns:
|
||||
list: Overlapping uvs for the input mesh in all uv sets.
|
||||
|
||||
:param node: node to check
|
||||
:type node: str
|
||||
:returns: True is has overlapping UVs, False otherwise
|
||||
:rtype: bool
|
||||
"""
|
||||
ovl = GetOverlappingUVs()
|
||||
|
||||
# Store original uv set
|
||||
original_current_uv_set = cmds.polyUVSet(mesh,
|
||||
query=True,
|
||||
currentUVSet=True)
|
||||
|
||||
overlapping_faces = []
|
||||
for i, uv in enumerate(pm.polyUVSet(node, q=1, auv=1)):
|
||||
pm.polyUVSet(node, cuv=1, uvSet=uv)
|
||||
overlapping_faces.extend(ovl._getOverlapUVFaces(str(node)))
|
||||
for uv_set in cmds.polyUVSet(mesh, query=True, allUVSets=True):
|
||||
cmds.polyUVSet(mesh, currentUVSet=True, uvSet=uv_set)
|
||||
overlapping_faces.extend(ovl._getOverlapUVFaces(mesh))
|
||||
|
||||
# Restore original uv set
|
||||
cmds.polyUVSet(mesh, currentUVSet=True, uvSet=original_current_uv_set)
|
||||
|
||||
return overlapping_faces
|
||||
|
||||
@classmethod
|
||||
def get_invalid(cls, instance, compute=False):
|
||||
invalid = []
|
||||
|
||||
if compute:
|
||||
instance.data["overlapping_faces"] = []
|
||||
for node in pm.ls(instance, type="mesh"):
|
||||
invalid = []
|
||||
for node in cmds.ls(instance, type="mesh"):
|
||||
faces = cls._get_overlapping_uvs(node)
|
||||
invalid.extend(faces)
|
||||
# Store values for later.
|
||||
instance.data["overlapping_faces"].extend(faces)
|
||||
else:
|
||||
invalid.extend(instance.data["overlapping_faces"])
|
||||
|
||||
return invalid
|
||||
instance.data["overlapping_faces"] = invalid
|
||||
|
||||
return instance.data.get("overlapping_faces", [])
|
||||
|
||||
def process(self, instance):
|
||||
if not self.is_active(instance.data):
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@
|
|||
|
||||
"""
|
||||
import pyblish.api
|
||||
|
||||
from openpype.lib import TextDef
|
||||
from openpype.pipeline.publish import OpenPypePyblishPluginMixin
|
||||
|
||||
|
|
@ -14,7 +13,11 @@ class CollectDeadlinePools(pyblish.api.InstancePlugin,
|
|||
|
||||
order = pyblish.api.CollectorOrder + 0.420
|
||||
label = "Collect Deadline Pools"
|
||||
families = ["rendering", "render.farm", "renderFarm", "renderlayer"]
|
||||
families = ["rendering",
|
||||
"render.farm",
|
||||
"renderFarm",
|
||||
"renderlayer",
|
||||
"maxrender"]
|
||||
|
||||
primary_pool = None
|
||||
secondary_pool = None
|
||||
|
|
@ -29,7 +32,6 @@ class CollectDeadlinePools(pyblish.api.InstancePlugin,
|
|||
def process(self, instance):
|
||||
|
||||
attr_values = self.get_attr_values_from_data(instance.data)
|
||||
|
||||
if not instance.data.get("primaryPool"):
|
||||
instance.data["primaryPool"] = (
|
||||
attr_values.get("primaryPool") or self.primary_pool or "none"
|
||||
|
|
@ -42,7 +44,6 @@ class CollectDeadlinePools(pyblish.api.InstancePlugin,
|
|||
|
||||
@classmethod
|
||||
def get_attribute_defs(cls):
|
||||
|
||||
# TODO: Preferably this would be an enum for the user
|
||||
# but the Deadline server URL can be dynamic and
|
||||
# can be set per render instance. Since get_attribute_defs
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue