You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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()

使用说明

  1. 在Maya中选中单个网格组件(顶点/边/面)
  2. 运行上述脚本,会自动创建一个定位器并对齐到组件的位置与方向
  3. 若选中多个组件,脚本会自动取第一个组件进行计算

内容的提问来源于stack exchange,提问作者AndrewB

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 22:55:12