This repository has been archived by the owner on Sep 20, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 129
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Maya: Yeti Validate Rig Input - OP-3454 (#4554)
* Collect input_SET children in instance. * Fix docs. * Only validate yeti if there are nodes in the scene. * Revert code * Remove connection logic from loader * Connection inventory action * Hound * Revert "Collect input_SET children in instance." This reverts commit 052e65c. * Update docs * Update openpype/hosts/maya/plugins/inventory/connect_yeti_rig.py Co-authored-by: Roy Nieterau <roy_nieterau@hotmail.com> * Update openpype/hosts/maya/plugins/inventory/connect_yeti_rig.py Co-authored-by: Roy Nieterau <roy_nieterau@hotmail.com> * Update openpype/hosts/maya/plugins/inventory/connect_yeti_rig.py Co-authored-by: Roy Nieterau <roy_nieterau@hotmail.com> * Update website/docs/artist_hosts_maya_yeti.md Co-authored-by: Roy Nieterau <roy_nieterau@hotmail.com> * BigRoy feedback * Hound * Fix typo * Update openpype/hosts/maya/plugins/inventory/connect_yeti_rig.py Co-authored-by: Roy Nieterau <roy_nieterau@hotmail.com> * Update openpype/hosts/maya/plugins/publish/validate_yeti_renderscript_callbacks.py Co-authored-by: Roy Nieterau <roy_nieterau@hotmail.com> * Update openpype/hosts/maya/plugins/inventory/connect_yeti_rig.py Co-authored-by: Roy Nieterau <roy_nieterau@hotmail.com> * Dont use AVALON_PROJECT * Hound * Update openpype/hosts/maya/plugins/publish/validate_yeti_renderscript_callbacks.py Co-authored-by: Roy Nieterau <roy_nieterau@hotmail.com> --------- Co-authored-by: Roy Nieterau <roy_nieterau@hotmail.com>
- Loading branch information
1 parent
8d828f4
commit a13f80e
Showing
10 changed files
with
260 additions
and
107 deletions.
There are no files selected for viewing
178 changes: 178 additions & 0 deletions
178
openpype/hosts/maya/plugins/inventory/connect_yeti_rig.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,178 @@ | ||
import os | ||
import json | ||
from collections import defaultdict | ||
|
||
from maya import cmds | ||
|
||
from openpype.pipeline import ( | ||
InventoryAction, get_representation_context, get_representation_path | ||
) | ||
from openpype.hosts.maya.api.lib import get_container_members, get_id | ||
|
||
|
||
class ConnectYetiRig(InventoryAction): | ||
"""Connect Yeti Rig with an animation or pointcache.""" | ||
|
||
label = "Connect Yeti Rig" | ||
icon = "link" | ||
color = "white" | ||
|
||
def process(self, containers): | ||
# Validate selection is more than 1. | ||
message = ( | ||
"Only 1 container selected. 2+ containers needed for this action." | ||
) | ||
if len(containers) == 1: | ||
self.display_warning(message) | ||
return | ||
|
||
# Categorize containers by family. | ||
containers_by_family = defaultdict(list) | ||
for container in containers: | ||
family = get_representation_context( | ||
container["representation"] | ||
)["subset"]["data"]["family"] | ||
containers_by_family[family].append(container) | ||
|
||
# Validate to only 1 source container. | ||
source_containers = containers_by_family.get("animation", []) | ||
source_containers += containers_by_family.get("pointcache", []) | ||
source_container_namespaces = [ | ||
x["namespace"] for x in source_containers | ||
] | ||
message = ( | ||
"{} animation containers selected:\n\n{}\n\nOnly select 1 of type " | ||
"\"animation\" or \"pointcache\".".format( | ||
len(source_containers), source_container_namespaces | ||
) | ||
) | ||
if len(source_containers) != 1: | ||
self.display_warning(message) | ||
return | ||
|
||
source_container = source_containers[0] | ||
source_ids = self.nodes_by_id(source_container) | ||
|
||
# Target containers. | ||
target_ids = {} | ||
inputs = [] | ||
|
||
yeti_rig_containers = containers_by_family.get("yetiRig") | ||
if not yeti_rig_containers: | ||
self.display_warning( | ||
"Select at least one yetiRig container" | ||
) | ||
return | ||
|
||
for container in yeti_rig_containers: | ||
target_ids.update(self.nodes_by_id(container)) | ||
|
||
maya_file = get_representation_path( | ||
get_representation_context( | ||
container["representation"] | ||
)["representation"] | ||
) | ||
_, ext = os.path.splitext(maya_file) | ||
settings_file = maya_file.replace(ext, ".rigsettings") | ||
if not os.path.exists(settings_file): | ||
continue | ||
|
||
with open(settings_file) as f: | ||
inputs.extend(json.load(f)["inputs"]) | ||
|
||
# Compare loaded connections to scene. | ||
for input in inputs: | ||
source_node = source_ids.get(input["sourceID"]) | ||
target_node = target_ids.get(input["destinationID"]) | ||
|
||
if not source_node or not target_node: | ||
self.log.debug( | ||
"Could not find nodes for input:\n" + | ||
json.dumps(input, indent=4, sort_keys=True) | ||
) | ||
continue | ||
source_attr, target_attr = input["connections"] | ||
|
||
if not cmds.attributeQuery( | ||
source_attr, node=source_node, exists=True | ||
): | ||
self.log.debug( | ||
"Could not find attribute {} on node {} for " | ||
"input:\n{}".format( | ||
source_attr, | ||
source_node, | ||
json.dumps(input, indent=4, sort_keys=True) | ||
) | ||
) | ||
continue | ||
|
||
if not cmds.attributeQuery( | ||
target_attr, node=target_node, exists=True | ||
): | ||
self.log.debug( | ||
"Could not find attribute {} on node {} for " | ||
"input:\n{}".format( | ||
target_attr, | ||
target_node, | ||
json.dumps(input, indent=4, sort_keys=True) | ||
) | ||
) | ||
continue | ||
|
||
source_plug = "{}.{}".format( | ||
source_node, source_attr | ||
) | ||
target_plug = "{}.{}".format( | ||
target_node, target_attr | ||
) | ||
if cmds.isConnected( | ||
source_plug, target_plug, ignoreUnitConversion=True | ||
): | ||
self.log.debug( | ||
"Connection already exists: {} -> {}".format( | ||
source_plug, target_plug | ||
) | ||
) | ||
continue | ||
|
||
cmds.connectAttr(source_plug, target_plug, force=True) | ||
self.log.debug( | ||
"Connected attributes: {} -> {}".format( | ||
source_plug, target_plug | ||
) | ||
) | ||
|
||
def nodes_by_id(self, container): | ||
ids = {} | ||
for member in get_container_members(container): | ||
id = get_id(member) | ||
if not id: | ||
continue | ||
ids[id] = member | ||
|
||
return ids | ||
|
||
def display_warning(self, message, show_cancel=False): | ||
"""Show feedback to user. | ||
Returns: | ||
bool | ||
""" | ||
|
||
from qtpy import QtWidgets | ||
|
||
accept = QtWidgets.QMessageBox.Ok | ||
if show_cancel: | ||
buttons = accept | QtWidgets.QMessageBox.Cancel | ||
else: | ||
buttons = accept | ||
|
||
state = QtWidgets.QMessageBox.warning( | ||
None, | ||
"", | ||
message, | ||
buttons=buttons, | ||
defaultButton=accept | ||
) | ||
|
||
return state == accept |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.