Metahuman_DNA_Calibration/dna_viewer/util/mesh_skin.py
2022-11-29 14:25:24 +01:00

136 lines
4.3 KiB
Python

import logging
from typing import List, Tuple
from maya import cmds
from ..const.naming import SKIN_CLUSTER_AFFIX
from ..const.printing import SKIN_WEIGHT_PRINT_RANGE
from ..model.dna import DNA
class MeshSkin:
"""
A utility class used for interacting and adding skin clusters to a mesh
"""
@staticmethod
def prepare_joints(dna: DNA, mesh_index: int) -> Tuple[List[int], List[str]]:
"""
Gets the joint indices and names needed for the given mesh.
@type dna: DNA
@param dna: Instance of DNA.
@type mesh_index: int
@param mesh_index: The index of the mesh.
@type joints: List[Joint]
@param joints: List of all joints from which some of them are selected as a result.
@rtype: Tuple[List[int], List[str]]
@returns: The tuple containing the list of joint indices and the list of joint names.
"""
joints = dna.read_all_neutral_joints()
joints_temp: List[int] = []
joint_indices = dna.get_all_skin_weights_joint_indices_for_mesh(mesh_index)
joint_ids = []
if any(joint_indices):
for row in joint_indices:
for column in row:
joints_temp.append(column)
joint_ids = list(set(joints_temp))
joint_ids.sort()
else:
lod = dna.get_lowest_lod_containing_meshes([mesh_index])
if lod:
joint_ids = dna.get_joint_indices_for_lod(lod)
joint_names = []
for joint_id in joint_ids:
joint_names.append(joints[joint_id].name)
return joint_ids, joint_names
@staticmethod
def add_skin_cluster(
dna: DNA, mesh_index: int, mesh_name: str, joint_names: List[str]
) -> None:
"""
Creates a skin cluster object.
@type dna: DNA
@param dna: Instance of DNA.
@type mesh_index: int
@param mesh_index: The index of the mesh.
@type mesh_name: str
@param mesh_name: The mesh name that is used for skin cluster naming.
@type joints: List[Joint]
@param joints: List of joints used for adding the skin cluster.
"""
logging.info("adding skin cluster...")
maximum_influences = dna.get_maximum_influence_per_vertex(mesh_index)
cmds.select(joint_names[0], replace=True)
cmds.select(mesh_name, add=True)
skin_cluster = cmds.skinCluster(
toSelectedBones=True,
name=f"{mesh_name}_{SKIN_CLUSTER_AFFIX}",
maximumInfluences=maximum_influences,
skinMethod=0,
obeyMaxInfluences=True,
)
if joint_names:
cmds.skinCluster(
skin_cluster, edit=True, addInfluence=joint_names[1:], weight=0
)
@staticmethod
def set_skin_weights(
dna: DNA, mesh_index: int, mesh_name: str, joint_ids: List[int]
) -> None:
"""
Sets the skin weights attributes.
@type dna: DNA
@param dna: Instance of DNA.
@type mesh_index: int
@param mesh_index: The index of the mesh.
@type mesh_name: str
@param mesh_name: The mesh name that is used for getting the skin cluster name.
@type joint_ids: List[int]
@param joint_ids: List of joint indices used for setting the skin weight attribute.
"""
logging.info("setting skin weights...")
skin_weights = dna.get_skin_weight_matrix_for_mesh(mesh_index)
# import skin weights
temp_str = f"{mesh_name}_{SKIN_CLUSTER_AFFIX}.wl["
for vertex_id, skin_weight in enumerate(skin_weights):
if not (vertex_id + 1) % SKIN_WEIGHT_PRINT_RANGE:
logging.info(f"\t{vertex_id + 1} / {len(skin_weights)}")
vertex_infos = skin_weight
# set all skin weights to zero
vertex_string = f"{temp_str}{str(vertex_id)}].w["
cmds.setAttr(f"{vertex_string}0]", 0.0)
# import skin weights
for vertex_info in vertex_infos:
cmds.setAttr(
f"{vertex_string}{str(joint_ids.index(vertex_info[0]))}]",
float(vertex_info[1]),
)
if len(skin_weights) % SKIN_WEIGHT_PRINT_RANGE != 0:
logging.info(f"\t{len(skin_weights)} / {len(skin_weights)}")