Maya中如何获取组件模式下移动工具的轴方向?
获取Maya组件模式下移动工具的轴方向值并对齐定位器
问题原因
你用cmds.xform(q=True, ws=True, ro=True)查询到[0,0,0]是因为组件本身没有旋转属性,移动工具的轴是基于组件的几何特征(法线、边方向等)动态计算的局部坐标系,需要通过组件的几何数据推导才能得到对应旋转值。
解决方案
通过Maya的OpenMaya API获取选中组件的几何信息,构建其局部坐标系的三个轴,再将轴向量转换为旋转矩阵,最终得到欧拉角旋转值。以下是针对不同组件类型(顶点/边/面)的实现代码:
完整脚本
import maya.cmds as cmds import maya.api.OpenMaya as om def get_component_local_axes(): sel = cmds.ls(selection=True, flatten=True) if not sel: cmds.warning("请选中一个网格组件(顶点/边/面)") return None # 转换为OpenMaya选择列表 sel_list = om.MSelectionList() for item in sel: sel_list.add(item) dag_path, component = sel_list.getComponent(0) # 处理顶点组件 if component.apiType() == om.MFn.kMeshVertComponent: fn_mesh = om.MFnMesh(dag_path) # 获取顶点的平均法线 normals = fn_mesh.getVertexNormals(True, component) avg_normal = om.MVector() for n in normals: avg_normal += n avg_normal.normalize() # 构建切线与副切线 tangent = om.MVector(1, 0, 0).cross(avg_normal) if tangent.length() < 0.0001: tangent = om.MVector(0, 1, 0).cross(avg_normal) tangent.normalize() bitangent = avg_normal.cross(tangent) bitangent.normalize() axes = [tangent, bitangent, avg_normal] # 处理边组件 elif component.apiType() == om.MFn.kMeshEdgeComponent: fn_mesh = om.MFnMesh(dag_path) edge_indices = om.MIntArray() component.getElements(edge_indices) edge_idx = edge_indices[0] # 获取边的方向向量 p1_idx, p2_idx = fn_mesh.getEdgeVertices(edge_idx) p1_pos = fn_mesh.getPoint(p1_idx, om.MSpace.kWorld) p2_pos = fn_mesh.getPoint(p2_idx, om.MSpace.kWorld) edge_dir = (p2_pos - p1_pos).normalize() # 获取相邻面的平均法线 connected_faces = fn_mesh.getConnectedFaces(edge_idx) avg_normal = om.MVector() for face_idx in connected_faces: face_normal = fn_mesh.getFaceNormal(face_idx, om.MSpace.kWorld) avg_normal += face_normal avg_normal.normalize() # 构建副切线 bitangent = edge_dir.cross(avg_normal).normalize() axes = [edge_dir, bitangent, avg_normal] # 处理面组件 elif component.apiType() == om.MFn.kMeshFaceComponent: fn_mesh = om.MFnMesh(dag_path) face_indices = om.MIntArray() component.getElements(face_indices) face_idx = face_indices[0] # 获取面法线 face_normal = fn_mesh.getFaceNormal(face_idx, om.MSpace.kWorld).normalize() # 获取面的第一条边方向作为X轴(若与法线平行则换一条边) edge_list = fn_mesh.getEdges(face_idx) p1_idx, p2_idx = fn_mesh.getEdgeVertices(edge_list[0]) p1_pos = fn_mesh.getPoint(p1_idx, om.MSpace.kWorld) p2_pos = fn_mesh.getPoint(p2_idx, om.MSpace.kWorld) face_x = (p2_pos - p1_pos).normalize() if abs(face_x * face_normal) > 0.999: p1_idx, p2_idx = fn_mesh.getEdgeVertices(edge_list[1]) p1_pos = fn_mesh.getPoint(p1_idx, om.MSpace.kWorld) p2_pos = fn_mesh.getPoint(p2_idx, om.MSpace.kWorld) face_x = (p2_pos - p1_pos).normalize() face_y = face_normal.cross(face_x).normalize() axes = [face_x, face_y, face_normal] else: cmds.warning("仅支持网格的顶点、边、面组件") return None # 将轴向量转换为旋转矩阵,再转为欧拉角 rot_matrix = om.MMatrix() for i in range(3): for j in range(3): rot_matrix[i][j] = axes[i][j] euler_rot = om.MEulerRotation(rot_matrix) return [euler_rot.x, euler_rot.y, euler_rot.z] # 示例:创建定位器并对齐到选中组件 def align_locator_to_selected_component(): # 创建定位器 locator = cmds.spaceLocator()[0] # 获取组件世界位置 comp_pos = cmds.xform(q=True, ws=True, t=True) cmds.xform(locator, ws=True, t=comp_pos) # 获取组件局部轴对应的旋转值 comp_rot = get_component_local_axes() if comp_rot: cmds.xform(locator, ws=True, ro=comp_rot) # 执行对齐 align_locator_to_selected_component()
使用说明
- 在Maya中选中单个网格组件(顶点/边/面)
- 运行上述脚本,会自动创建一个定位器并对齐到组件的位置与方向
- 若选中多个组件,脚本会自动取第一个组件进行计算
内容的提问来源于stack exchange,提问作者AndrewB
相关产品推荐
相关产品推荐

