Source code for dna_viewer.builder.maya.skin_weights

import logging
from typing import List, Tuple, Union

from maya import cmds, mel
from maya.api.OpenMaya import MFnMesh, MGlobal
from maya.api.OpenMayaAnim import MFnSkinCluster

from ...builder.maya.util import Maya
from ...common import DNAViewerError


[docs]class MayaSkinWeights: """ A class used for reading and storing skin weight related data needed for adding skin clusters """ no_of_influences: int skinning_method: int joints: List[str] vertices_info: List[List[Union[int, float]]] def __init__(self, skin_cluster: MFnSkinCluster, mesh_name: str) -> None: self.no_of_influences = cmds.skinCluster(skin_cluster.name(), q=True, mi=True) self.skinning_method = cmds.skinCluster(skin_cluster.name(), q=True, sm=True) self.joints = self.get_skin_cluster_influence(skin_cluster) self.vertices_info = self.get_skin_weights_for_mesh_name( skin_cluster, mesh_name )
[docs] def get_skin_cluster_influence(self, skin_cluster: MFnSkinCluster) -> List[str]: """ Gets a list of joint names that are influences to the skin cluster. @type skin_cluster: MFnSkinCluster @param skin_cluster: The functionalities of a maya skin cluster object @rtype: List[str] @returns: The list if names of the joints that influence the skin cluster """ influences: List[str] = cmds.skinCluster(skin_cluster.name(), q=True, inf=True) if influences and not isinstance(influences[0], str): influences = [obj.name() for obj in influences] return influences
[docs] def get_skin_weights_for_mesh_name( self, skin_cluster: MFnSkinCluster, mesh_name: str, ) -> List[List[Union[int, float]]]: """ Gets the skin weights concerning the given mesh. @type skin_cluster: MFnSkinCluster @param skin_cluster: The functionalities of a maya skin cluster object @type mesh_name: str @param mesh_name: The name of the mesh @rtype: List[List[Union[int, float]]] @returns: A list of list of weight indices and the weight values """ mesh = Maya.get_element(mesh_name) components = MGlobal.getSelectionListByName(f"{mesh_name}.vtx[*]").getComponent( 0 )[1] weights_data, chunk = skin_cluster.getWeights(mesh, components) iterator = [ weights_data[i : i + chunk] for i in range(0, len(weights_data), chunk) ] vertices_info = [] for weights in iterator: vertex_weights: List[float] = [] vertices_info.append(vertex_weights) for i, weight in enumerate(weights): if weight: vertex_weights.append(i) vertex_weights.append(weight) return vertices_info
[docs]def get_skin_weights_data(mesh_name: str) -> Tuple[MFnMesh, MFnSkinCluster]: """ Gets the maya objects that manipulate the mesh node and the skin cluster for a given mesh name. @type mesh_name: str @param mesh_name: The name of the mesh @rtype: Tuple[MFnMesh, MFnSkinCluster] @returns: The maya object that manipulate the mesh node and the skin cluster for a given mesh name. """ skin_cluster_name = mel.eval(f"findRelatedSkinCluster {mesh_name}") if skin_cluster_name: skin_cluster = MFnSkinCluster(Maya.get_element(skin_cluster_name)) mesh_node = MFnMesh(Maya.get_element(mesh_name)) return mesh_node, skin_cluster raise DNAViewerError(f"Unable to find skin for given mesh: {mesh_name}")
[docs]def get_skin_weights_from_scene(mesh_name: str) -> MayaSkinWeights: """ Gets the instance of this class filled with data from the scene for a given mesh name. @type mesh_name: str @param mesh_name: The mesh name @rtype: MayaSkinWeights @returns: An instance of this class with the data from the scene """ _, skin_cluster = get_skin_weights_data(mesh_name) return MayaSkinWeights(skin_cluster, mesh_name)
[docs]def get_file_joint_mappings( skin_weights: MayaSkinWeights, skin_cluster: MFnSkinCluster ) -> List[int]: """ Returns a list of object indices representing the influences concerning the joint names specified in the skin weight model. @type skin_weights: MayaSkinWeights @param skin_weights: The instance of the model storing data about skin weights @type skin_cluster: MFnSkinCluster @param skin_cluster: An object for working with functions concerning a skin cluster in maya @rtype: List[int] @returns: a list of indices representing the influences concerning the given joints """ file_joint_mapping: List[int] = [] for joint_name in skin_weights.joints: file_joint_mapping.append( skin_cluster.indexForInfluenceObject(Maya.get_element(joint_name)) ) return file_joint_mapping
[docs]def set_skin_weights_to_scene(mesh_name: str, skin_weights: MayaSkinWeights) -> None: """ Sets the skin weights to the scene. @type mesh_name: str @param mesh_name: The mesh name @type skin_weights: MayaSkinWeights @param skin_weights: The object containing data that need to be set to the scene. """ mesh_node, skin_cluster = get_skin_weights_data(mesh_name) file_joint_mapping = get_file_joint_mappings(skin_weights, skin_cluster) import_skin_weights(skin_cluster, mesh_node, skin_weights, file_joint_mapping) logging.info("Set skin weights ended.")
[docs]def import_skin_weights( skin_cluster: MFnSkinCluster, mesh_node: MFnMesh, skin_weights: MayaSkinWeights, file_joint_mapping: List[int], ) -> None: """ Imports the skin weights to the scene using the joint mapping and the data provided in the model containing the weights. @type skin_cluster: MFnSkinCluster @param skin_cluster: An object for working with functions concerning a skin cluster in maya @type mesh_node: MFnMesh @param mesh_node: An object for working with functions concerning meshes in maya @type skin_weights: MayaSkinWeights @param skin_weights: The instance of the model storing data about skin weights @type file_joint_mapping: List[int] @param file_joint_mapping: a list of indices representing the influences concerning joints """ temp_str = f"{skin_cluster.name()}.wl[" for vtx_id in range(cmds.polyEvaluate(mesh_node.name(), vertex=True)): vtx_info = skin_weights.vertices_info[vtx_id] vtx_str = f"{temp_str}{str(vtx_id)}].w[" cmds.setAttr(f"{vtx_str}0]", 0.0) for i in range(0, len(vtx_info), 2): cmds.setAttr( f"{vtx_str}{str(file_joint_mapping[int(vtx_info[i])])}]", vtx_info[i + 1], )