MetaWhiz/scripts/utils/dna_utils.py
2025-04-17 13:00:39 +08:00

1068 lines
36 KiB
Python

#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Tool - DNA Utilities
Provides utilities for working with DNA files and data
"""
import os
import sys
import json
import maya.cmds as cmds
import maya.mel as mel
# Import configuration
import config
class DNAUtils:
"""Utilities for working with DNA files and data"""
def __init__(self):
"""Initialize DNA utilities"""
self.pydna_available = False
self.pydna_error = None
self.dna_calib_available = False
self.dna_calib_error = None
self.current_dna = None
self.current_dna_file = None
self.current_dna_version = None
# Ensure pydna is in the Python path
if config.PYDNA_PATH not in sys.path:
sys.path.append(config.PYDNA_PATH)
# Ensure DNA Calibration tools are in the Python path
if config.DNA_CALIB_PATH not in sys.path:
sys.path.append(config.DNA_CALIB_PATH)
# Try to import pydna modules
try:
# First try to import from the specific version directory
import pydna
self.pydna_available = True
print(f"PyDNA module loaded successfully: {config.PYDNA_PATH}")
except ImportError as e:
self.pydna_error = str(e)
# Try to find pydna in alternative locations
try:
# Try parent directory
parent_dir = os.path.dirname(config.PYDNA_PATH)
if parent_dir not in sys.path:
sys.path.append(parent_dir)
import pydna
self.pydna_available = True
print(f"PyDNA module loaded successfully from alternative location: {parent_dir}")
except ImportError:
self.pydna_available = False
cmds.warning(f"PyDNA module not found, some DNA features may be unavailable: {self.pydna_error}")
# Try to import DNA Calibration modules
try:
# Import DNA Calibration modules
import dna_calibration
self.dna_calib_available = True
print(f"DNA Calibration module loaded successfully: {config.DNA_CALIB_PATH}")
except ImportError as e:
self.dna_calib_error = str(e)
self.dna_calib_available = False
cmds.warning(f"DNA Calibration module not found, calibration features may be unavailable: {self.dna_calib_error}")
def load_dna(self, file_path):
"""
Load a DNA file into the scene
Args:
file_path (str): Path to the DNA file
Returns:
bool: True if successful, False otherwise
"""
if not os.path.exists(file_path):
error_msg = f"DNA file not found: {file_path}"
cmds.warning(error_msg)
cmds.confirmDialog(
title="DNA loading error",
message=error_msg,
button=["OK"],
defaultButton="OK"
)
return False
if not self.pydna_available:
error_msg = "PyDNA module not found, cannot load DNA file"
if self.pydna_error:
error_msg += f"\nError details: {self.pydna_error}"
cmds.warning(error_msg)
cmds.confirmDialog(
title="PyDNA module loading error",
message=error_msg,
button=["OK"],
defaultButton="OK"
)
return False
try:
# Import pydna modules
import pydna
from pydna.dna_reader import DNAReader
# Read DNA file
reader = DNAReader()
dna = reader.read(file_path)
if not dna:
cmds.warning(f"Unable to read DNA file: {file_path}")
return False
# Create mesh from DNA
mesh_name = os.path.splitext(os.path.basename(file_path))[0]
result = self._create_mesh_from_dna(dna, mesh_name)
if not result:
cmds.warning(f"Unable to create mesh from DNA: {file_path}")
return False
# Create skeleton from DNA
result = self._create_skeleton_from_dna(dna, mesh_name)
if not result:
cmds.warning(f"Unable to create skeleton from DNA: {file_path}")
return False
print(f"Successfully loaded DNA file: {file_path}")
return True
except Exception as e:
cmds.warning(f"Error loading DNA file: {str(e)}")
return False
def save_dna(self, file_path):
"""
Save the current scene as a DNA file
Args:
file_path (str): Path to save the DNA file
Returns:
bool: True if successful, False otherwise
"""
if not self.pydna_available:
cmds.warning("PyDNA module not found, cannot save DNA file")
return False
try:
# Import pydna modules
import pydna
from pydna.dna_writer import DNAWriter
# Get selected mesh and skeleton
selection = cmds.ls(selection=True)
if not selection:
cmds.warning("Please select a mesh or skeleton")
return False
# Find mesh and skeleton
mesh = None
skeleton = None
for obj in selection:
if cmds.objectType(obj) == "transform":
shapes = cmds.listRelatives(obj, shapes=True)
if shapes and cmds.objectType(shapes[0]) == "mesh":
mesh = obj
elif cmds.objectType(obj) == "joint":
# Find root joint
root = obj
parent = cmds.listRelatives(root, parent=True)
while parent and cmds.objectType(parent[0]) == "joint":
root = parent[0]
parent = cmds.listRelatives(root, parent=True)
skeleton = root
if not mesh:
cmds.warning("Mesh not found")
return False
if not skeleton:
cmds.warning("Skeleton not found")
return False
# Create DNA from mesh and skeleton
dna = self._create_dna_from_scene(mesh, skeleton)
if not dna:
cmds.warning(f"Unable to create DNA from scene")
return False
# Write DNA file
writer = DNAWriter()
result = writer.write(dna, file_path)
if not result:
cmds.warning(f"Unable to write DNA file: {file_path}")
return False
print(f"Successfully saved DNA file: {file_path}")
return True
except Exception as e:
cmds.warning(f"Error saving DNA file: {str(e)}")
return False
def create_dna(self, mesh, skeleton):
"""
Create a DNA from a mesh and skeleton
Args:
mesh (str): Name of the mesh
skeleton (str): Name of the skeleton
Returns:
bool: True if successful, False otherwise
"""
if not self.pydna_available:
cmds.warning("PyDNA module not found, cannot create DNA")
return False
try:
# Import pydna modules
import pydna
from pydna.dna_creator import DNACreator
# Check if mesh and skeleton exist
if not cmds.objExists(mesh):
cmds.warning(f"Mesh not found: {mesh}")
return False
if not cmds.objExists(skeleton):
cmds.warning(f"Skeleton not found: {skeleton}")
return False
# Create DNA
creator = DNACreator()
dna = creator.create(mesh, skeleton)
if not dna:
cmds.warning(f"Unable to create DNA")
return False
# Store DNA in scene
self._store_dna_in_scene(dna, mesh)
print(f"Successfully created DNA from {mesh} and {skeleton}")
return True
except Exception as e:
cmds.warning(f"Error creating DNA: {str(e)}")
return False
def update_dna(self, mesh, skeleton):
"""
Update a DNA from a mesh and skeleton
Args:
mesh (str): Name of the mesh
skeleton (str): Name of the skeleton
Returns:
bool: True if successful, False otherwise
"""
if not self.pydna_available:
cmds.warning("PyDNA module not found, cannot update DNA")
return False
try:
# Import pydna modules
import pydna
from pydna.dna_updater import DNAUpdater
# Check if mesh and skeleton exist
if not cmds.objExists(mesh):
cmds.warning(f"Mesh not found: {mesh}")
return False
if not cmds.objExists(skeleton):
cmds.warning(f"Skeleton not found: {skeleton}")
return False
# Get DNA from scene
dna = self._get_dna_from_scene(mesh)
if not dna:
cmds.warning(f"Unable to find DNA data, please create DNA first")
return False
# Update DNA
updater = DNAUpdater()
result = updater.update(dna, mesh, skeleton)
if not result:
cmds.warning(f"Unable to update DNA")
return False
# Store updated DNA in scene
self._store_dna_in_scene(dna, mesh)
print(f"Successfully updated DNA")
return True
except Exception as e:
cmds.warning(f"Error updating DNA: {str(e)}")
return False
def export_dna(self, file_path):
"""
Export DNA to a file
Args:
file_path (str): Path to export the DNA file
Returns:
bool: True if successful, False otherwise
"""
if not self.pydna_available:
cmds.warning("PyDNA module not found, cannot export DNA")
return False
try:
# Import pydna modules
import pydna
from pydna.dna_writer import DNAWriter
# Get selected mesh
selection = cmds.ls(selection=True)
if not selection:
cmds.warning("Please select a mesh")
return False
mesh = None
for obj in selection:
if cmds.objectType(obj) == "transform":
shapes = cmds.listRelatives(obj, shapes=True)
if shapes and cmds.objectType(shapes[0]) == "mesh":
mesh = obj
break
if not mesh:
cmds.warning("Mesh not found")
return False
# Get DNA from scene
dna = self._get_dna_from_scene(mesh)
if not dna:
cmds.warning(f"Unable to find DNA data, please create DNA first")
return False
# Write DNA file
writer = DNAWriter()
result = writer.write(dna, file_path)
if not result:
cmds.warning(f"Unable to write DNA file: {file_path}")
return False
print(f"Successfully exported DNA file: {file_path}")
return True
except Exception as e:
cmds.warning(f"Error exporting DNA file: {str(e)}")
return False
def get_dna_attributes(self, dna_file=None):
"""
Get DNA attributes
Args:
dna_file (str, optional): Path to the DNA file. If None, get from scene.
Returns:
dict: Dictionary of DNA attributes
"""
if not self.pydna_available:
cmds.warning("PyDNA module not found, cannot get DNA attributes")
return {}
try:
# Import pydna modules
import pydna
# Get DNA
dna = None
if dna_file and os.path.exists(dna_file):
# Read DNA file
from pydna.dna_reader import DNAReader
reader = DNAReader()
dna = reader.read(dna_file)
else:
# Get from scene
selection = cmds.ls(selection=True)
if not selection:
cmds.warning("Please select a mesh or load a DNA file")
return {}
mesh = None
for obj in selection:
if cmds.objectType(obj) == "transform":
shapes = cmds.listRelatives(obj, shapes=True)
if shapes and cmds.objectType(shapes[0]) == "mesh":
mesh = obj
break
if not mesh:
cmds.warning("Mesh not found")
return {}
dna = self._get_dna_from_scene(mesh)
if not dna:
cmds.warning(f"Unable to find DNA data")
return {}
# Get attributes
attributes = {}
# General attributes
attributes["general.name"] = dna.getName()
attributes["general.version"] = dna.getVersion()
attributes["general.topology"] = dna.getTopology()
# Mesh attributes
mesh_count = dna.getMeshCount()
attributes["mesh.count"] = mesh_count
for i in range(mesh_count):
mesh = dna.getMesh(i)
attributes[f"mesh.{i}.name"] = mesh.getName()
attributes[f"mesh.{i}.vertex_count"] = mesh.getVertexCount()
attributes[f"mesh.{i}.triangle_count"] = mesh.getTriangleCount()
# Joint attributes
joint_count = dna.getJointCount()
attributes["joint.count"] = joint_count
for i in range(joint_count):
joint = dna.getJoint(i)
attributes[f"joint.{i}.name"] = joint.getName()
attributes[f"joint.{i}.parent"] = joint.getParent()
# BlendShape attributes
blendshape_count = dna.getBlendShapeCount()
attributes["blendshape.count"] = blendshape_count
for i in range(blendshape_count):
blendshape = dna.getBlendShape(i)
attributes[f"blendshape.{i}.name"] = blendshape.getName()
attributes[f"blendshape.{i}.target_count"] = blendshape.getTargetCount()
return attributes
except Exception as e:
cmds.warning(f"Error getting DNA attributes: {str(e)}")
return {}
def set_dna_attribute(self, attr_name, value):
"""
Set a DNA attribute
Args:
attr_name (str): Name of the attribute
value (any): Value to set
Returns:
bool: True if successful, False otherwise
"""
if not self.pydna_available:
cmds.warning("PyDNA module not found, cannot set DNA attribute")
return False
try:
# Import pydna modules
import pydna
# Get DNA from scene
selection = cmds.ls(selection=True)
if not selection:
cmds.warning("Please select a mesh")
return False
mesh = None
for obj in selection:
if cmds.objectType(obj) == "transform":
shapes = cmds.listRelatives(obj, shapes=True)
if shapes and cmds.objectType(shapes[0]) == "mesh":
mesh = obj
break
if not mesh:
cmds.warning("Mesh not found")
return False
dna = self._get_dna_from_scene(mesh)
if not dna:
cmds.warning(f"Unable to find DNA data, please create DNA first")
return False
# Set attribute
# Parse attribute name
parts = attr_name.split(".")
if len(parts) < 2:
cmds.warning(f"Invalid attribute name: {attr_name}")
return False
category = parts[0]
if category == "general":
if parts[1] == "name":
dna.setName(value)
elif parts[1] == "version":
dna.setVersion(value)
elif parts[1] == "topology":
dna.setTopology(value)
elif category == "mesh" and len(parts) >= 3:
try:
mesh_index = int(parts[1])
mesh = dna.getMesh(mesh_index)
if parts[2] == "name":
mesh.setName(value)
except (ValueError, IndexError):
cmds.warning(f"Invalid mesh index: {parts[1]}")
return False
elif category == "joint" and len(parts) >= 3:
try:
joint_index = int(parts[1])
joint = dna.getJoint(joint_index)
if parts[2] == "name":
joint.setName(value)
except (ValueError, IndexError):
cmds.warning(f"Invalid joint index: {parts[1]}")
return False
elif category == "blendshape" and len(parts) >= 3:
try:
blendshape_index = int(parts[1])
blendshape = dna.getBlendShape(blendshape_index)
if parts[2] == "name":
blendshape.setName(value)
except (ValueError, IndexError):
cmds.warning(f"Invalid BlendShape index: {parts[1]}")
return False
else:
cmds.warning(f"Unsupported attribute category: {category}")
return False
# Store updated DNA in scene
self._store_dna_in_scene(dna, mesh)
print(f"Successfully set DNA attribute: {attr_name} = {value}")
return True
except Exception as e:
cmds.warning(f"Error setting DNA attribute: {str(e)}")
return False
def _create_mesh_from_dna(self, dna, name):
"""
Create a mesh from DNA
Args:
dna: DNA object
name (str): Name for the mesh
Returns:
bool: True if successful, False otherwise
"""
try:
# Get mesh data from DNA
mesh_count = dna.getMeshCount()
if mesh_count == 0:
cmds.warning("No mesh data in DNA")
return False
# Create mesh for each DNA mesh
for i in range(mesh_count):
dna_mesh = dna.getMesh(i)
mesh_name = f"{name}_mesh_{i}"
# Get vertices
vertex_count = dna_mesh.getVertexCount()
vertices = []
for j in range(vertex_count):
pos = dna_mesh.getVertexPosition(j)
vertices.append((pos.x, pos.y, pos.z))
# Get triangles
triangle_count = dna_mesh.getTriangleCount()
triangles = []
for j in range(triangle_count):
tri = dna_mesh.getTriangle(j)
triangles.append((tri.v1, tri.v2, tri.v3))
# Create mesh
mesh = cmds.polyCreateFacet(
name=mesh_name,
p=vertices,
f=triangles
)[0]
# Get UVs
uv_count = dna_mesh.getUVCount()
if uv_count > 0:
# Create UV set
cmds.polyUVSet(mesh, create=True, uvSet="map1")
# Set UVs
for j in range(uv_count):
uv = dna_mesh.getUV(j)
cmds.polyEditUV(f"{mesh}.map1[{j}]", u=uv.u, v=uv.v)
return True
except Exception as e:
cmds.warning(f"Error creating mesh: {str(e)}")
return False
def _create_skeleton_from_dna(self, dna, name):
"""
Create a skeleton from DNA
Args:
dna: DNA object
name (str): Name for the skeleton
Returns:
bool: True if successful, False otherwise
"""
try:
# Get joint data from DNA
joint_count = dna.getJointCount()
if joint_count == 0:
cmds.warning("No joint data in DNA")
return False
# Create joints
joints = {}
for i in range(joint_count):
dna_joint = dna.getJoint(i)
joint_name = dna_joint.getName()
parent_index = dna_joint.getParent()
# Get joint position
pos = dna_joint.getPosition()
# Create joint
joint = cmds.joint(name=joint_name, p=(pos.x, pos.y, pos.z))
joints[i] = joint
# Set joint orientation
orient = dna_joint.getOrientation()
cmds.setAttr(f"{joint}.rotateX", orient.x)
cmds.setAttr(f"{joint}.rotateY", orient.y)
cmds.setAttr(f"{joint}.rotateZ", orient.z)
# Set parent
if parent_index >= 0:
parent_joint = joints.get(parent_index)
if parent_joint:
cmds.parent(joint, parent_joint)
# Rename root joint
root_joint = joints.get(0)
if root_joint:
cmds.rename(root_joint, f"{name}_root")
return True
except Exception as e:
cmds.warning(f"Error creating skeleton: {str(e)}")
return False
def _create_dna_from_scene(self, mesh, skeleton):
"""
Create a DNA from scene objects
Args:
mesh (str): Name of the mesh
skeleton (str): Name of the skeleton
Returns:
object: DNA object or None if failed
"""
try:
# Import pydna modules
import pydna
from pydna.dna_creator import DNACreator
# Create DNA
creator = DNACreator()
dna = creator.create(mesh, skeleton)
return dna
except Exception as e:
cmds.warning(f"Error creating DNA from scene: {str(e)}")
return None
def _store_dna_in_scene(self, dna, mesh):
"""
Store DNA in the scene as mesh attributes
Args:
dna: DNA object
mesh (str): Name of the mesh
Returns:
bool: True if successful, False otherwise
"""
try:
# Import pydna modules
import pydna
from pydna.dna_writer import DNAWriter
# Serialize DNA to JSON
writer = DNAWriter()
dna_json = writer.toJSON(dna)
# Store as mesh attribute
if not cmds.attributeQuery("dnaData", node=mesh, exists=True):
cmds.addAttr(mesh, longName="dnaData", dataType="string")
cmds.setAttr(f"{mesh}.dnaData", dna_json, type="string")
return True
except Exception as e:
cmds.warning(f"Error storing DNA data: {str(e)}")
return False
def _get_dna_from_scene(self, mesh):
"""
Get DNA from scene
Args:
mesh (str): Name of the mesh
Returns:
object: DNA object or None if not found
"""
try:
# Import pydna modules
import pydna
from pydna.dna_reader import DNAReader
# Check if mesh has DNA data
if not cmds.attributeQuery("dnaData", node=mesh, exists=True):
return None
# Get DNA data
dna_json = cmds.getAttr(f"{mesh}.dnaData")
if not dna_json:
return None
# Deserialize DNA from JSON
reader = DNAReader()
dna = reader.fromJSON(dna_json)
# Store the current DNA
self.current_dna = dna
self.current_dna_version = self._detect_dna_version(dna)
return dna
except Exception as e:
cmds.warning(f"Error getting DNA data: {str(e)}")
return None
def detect_dna_version(self, dna_file):
"""
Detect the version of a DNA file
Args:
dna_file (str): Path to the DNA file
Returns:
str: DNA version (e.g., 'MH.4', 'MH.3', 'Custom')
"""
try:
# Import pydna modules
import pydna
from pydna.dna_reader import DNAReader
# Read DNA file
reader = DNAReader()
dna = reader.read(dna_file)
if not dna:
return "Unknown"
return self._detect_dna_version(dna)
except Exception as e:
cmds.warning(f"Error detecting DNA version: {str(e)}")
return "Unknown"
def _detect_dna_version(self, dna):
"""
Detect the version of a DNA object
Args:
dna: DNA object
Returns:
str: DNA version (e.g., 'MH.4', 'MH.3', 'Custom')
"""
try:
# Get DNA metadata
metadata = dna.getMetaData()
if not metadata:
return "Unknown"
# Check for MetaHuman version
if "metahuman" in metadata.lower():
if "4." in metadata:
return "MH.4"
elif "3." in metadata:
return "MH.3"
else:
return "MetaHuman"
# Check for specific markers
joint_count = dna.getJointCount()
mesh_count = dna.getMeshCount()
# MetaHuman 4 typically has 411 joints
if joint_count >= 400 and joint_count <= 420:
return "MH.4"
# MetaHuman 3 typically has 245 joints
elif joint_count >= 240 and joint_count <= 260:
return "MH.3"
else:
return "Custom"
except Exception as e:
cmds.warning(f"Error detecting DNA version: {str(e)}")
return "Unknown"
def validate_dna(self, dna_file=None):
"""
Validate a DNA file structure
Args:
dna_file (str, optional): Path to the DNA file. If None, validate current DNA.
Returns:
dict: Validation results with issues and warnings
"""
try:
# Import pydna modules
import pydna
from pydna.dna_reader import DNAReader
# Get DNA object
dna = None
if dna_file:
reader = DNAReader()
dna = reader.read(dna_file)
else:
dna = self.current_dna
if not dna:
return {"valid": False, "errors": ["No DNA data available"], "warnings": []}
# Initialize validation results
results = {
"valid": True,
"errors": [],
"warnings": [],
"info": {}
}
# Check basic structure
joint_count = dna.getJointCount()
mesh_count = dna.getMeshCount()
blendshape_count = dna.getBlendShapeCount() if hasattr(dna, "getBlendShapeCount") else 0
results["info"] = {
"version": self._detect_dna_version(dna),
"joint_count": joint_count,
"mesh_count": mesh_count,
"blendshape_count": blendshape_count
}
# Validate joints
if joint_count == 0:
results["errors"].append("No joints found in DNA")
results["valid"] = False
# Validate meshes
if mesh_count == 0:
results["errors"].append("No meshes found in DNA")
results["valid"] = False
# Check for root joint
root_joint = None
try:
root_joint = dna.getJoint(0)
except:
results["errors"].append("No root joint found")
results["valid"] = False
# Check for MetaHuman compatibility
version = results["info"]["version"]
if version in ["MH.4", "MH.3", "MetaHuman"]:
# Check for specific MetaHuman joints
mh_joints = ["head", "neck", "spine", "pelvis"]
found_joints = []
for i in range(joint_count):
joint = dna.getJoint(i)
joint_name = joint.getName().lower()
for mh_joint in mh_joints:
if mh_joint in joint_name and mh_joint not in found_joints:
found_joints.append(mh_joint)
missing_joints = [j for j in mh_joints if j not in found_joints]
if missing_joints:
results["warnings"].append(f"Missing expected MetaHuman joints: {', '.join(missing_joints)}")
# Set final validity
results["valid"] = len(results["errors"]) == 0
return results
except Exception as e:
cmds.warning(f"Error validating DNA: {str(e)}")
return {"valid": False, "errors": [str(e)], "warnings": []}
def extract_blendshapes_from_dna(self, output_dir, dna_file=None):
"""
Extract blendshapes from DNA file
Args:
output_dir (str): Directory to save extracted blendshapes
dna_file (str, optional): Path to the DNA file. If None, use current DNA.
Returns:
list: List of extracted blendshape file paths
"""
try:
# Import pydna modules
import pydna
from pydna.dna_reader import DNAReader
# Get DNA object
dna = None
if dna_file:
reader = DNAReader()
dna = reader.read(dna_file)
else:
dna = self.current_dna
if not dna:
cmds.warning("No DNA data available for extracting blendshapes")
return []
# Check if output directory exists, if not create it
if not os.path.exists(output_dir):
os.makedirs(output_dir)
# Get blendshape count
blendshape_count = dna.getBlendShapeCount() if hasattr(dna, "getBlendShapeCount") else 0
if blendshape_count == 0:
cmds.warning("No blendshapes found in DNA")
return []
# Extract blendshapes
extracted_files = []
base_mesh = None
# Create base mesh
try:
mesh_name = "temp_dna_base_mesh"
base_mesh = self._create_mesh_from_dna(dna, mesh_name)
except Exception as e:
cmds.warning(f"Error creating base mesh: {str(e)}")
return []
# Extract each blendshape
for i in range(blendshape_count):
try:
blendshape = dna.getBlendShape(i)
blendshape_name = blendshape.getName()
# Create blendshape mesh
bs_mesh_name = f"temp_bs_{blendshape_name}"
self._create_blendshape_mesh(dna, i, bs_mesh_name)
# Export blendshape mesh
output_file = os.path.join(output_dir, f"{blendshape_name}.obj")
cmds.select(bs_mesh_name)
cmds.file(output_file, force=True, exportSelected=True, type="OBJexport")
# Delete temporary mesh
cmds.delete(bs_mesh_name)
extracted_files.append(output_file)
except Exception as e:
cmds.warning(f"Error extracting blendshape {i}: {str(e)}")
# Clean up
if base_mesh and cmds.objExists(base_mesh):
cmds.delete(base_mesh)
return extracted_files
except Exception as e:
cmds.warning(f"Error extracting blendshapes: {str(e)}")
return []
def _create_blendshape_mesh(self, dna, blendshape_index, name):
"""
Create a mesh for a specific blendshape
Args:
dna: DNA object
blendshape_index (int): Index of the blendshape
name (str): Name for the blendshape mesh
Returns:
str: Name of the created mesh or None if failed
"""
try:
# Get blendshape
blendshape = dna.getBlendShape(blendshape_index)
# Get base mesh
mesh_index = 0 # Usually the first mesh
dna_mesh = dna.getMesh(mesh_index)
# Get vertices and topology
vertex_count = dna_mesh.getVertexCount()
vertices = []
# Apply blendshape deltas to base vertices
for i in range(vertex_count):
base_pos = dna_mesh.getVertex(i)
delta = blendshape.getVertexDelta(i)
# Apply delta
pos = [base_pos.x + delta.x, base_pos.y + delta.y, base_pos.z + delta.z]
vertices.append(pos)
# Get face topology
face_count = dna_mesh.getFaceCount()
faces = []
for i in range(face_count):
face = dna_mesh.getFace(i)
faces.append([face.v1, face.v2, face.v3])
# Create mesh
mesh = cmds.polyCreateFacet(name=name, point=vertices, face=faces)[0]
return mesh
except Exception as e:
cmds.warning(f"Error creating blendshape mesh: {str(e)}")
return None