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

Maya 2022 Python实现立方体贴合起伏曲面下落的问题求助

在Maya2022中用Python实现立方体贴合起伏曲面(修复closestIntersection RuntimeError)

错误原因

  1. 参数顺序错误:MFnMesh.closestIntersection()的API参数顺序有严格要求,你错误地将空间参数(MSpace.kWorld)提前,导致调用时抛出RuntimeError。
  2. 射线方向错误:当前射线方向是向上(0,1,0),无法命中下方的地面模型,应改为向下发射(0,-1,0)。
  3. 射线起点硬编码:代码中强制将射线起点设为(0,0,0),没有使用传入的检测起点,导致检测逻辑失效。

修复后的射线检测函数

import maya.cmds as cmds
import maya.api.OpenMaya as OpenMaya

def ray_intersects_object(ray_start, ray_direction, object_name):
    selection_list = OpenMaya.MSelectionList()
    try:
        selection_list.add(object_name)
    except:
        cmds.warning(f"对象 {object_name} 不存在")
        return False, None, None
        
    dag_path = selection_list.getDagPath(0)
    mesh_fn = OpenMaya.MFnMesh(dag_path)
    
    # 使用传入的起点,转换为Maya浮点点
    ray_source = OpenMaya.MFloatPoint(ray_start[0], ray_start[1], ray_start[2])
    # 转换射线方向为Maya浮点向量
    ray_direction = OpenMaya.MFloatVector(ray_direction[0], ray_direction[1], ray_direction[2])
    
    # 调用参数顺序正确的closestIntersection
    hit, hit_param, hit_point, hit_normal, face_id = mesh_fn.closestIntersection(
        ray_source,
        ray_direction,
        None,  # 检测所有面,无需指定面ID
        None,  # 无需指定三角面ID
        False, # 不对ID排序
        OpenMaya.MSpace.kWorld,
        100.0, # 最大检测距离
        False, # 不检测双向射线
        None,  # 使用默认加速参数
        False  # 不对命中结果排序
    )
    
    if hit:
        return True, [hit_point.x, hit_point.y, hit_point.z], [hit_normal.x, hit_normal.y, hit_normal.z]
    else:
        return False, None, None

完整实现立方体贴合曲面的脚本

以下脚本会获取立方体底部的四个顶点,分别向下发射射线检测地面,计算立方体的平移位置和旋转角度,使底部完全贴合曲面:

def fit_cube_to_ground(cube_name, ground_name):
    # 获取立方体底部的四个顶点世界坐标(默认pCube的底部顶点索引为0、1、3、4)
    cube_verts = cmds.xform(
        f"{cube_name}.vtx[0]", f"{cube_name}.vtx[1]", 
        f"{cube_name}.vtx[3]", f"{cube_name}.vtx[4]", 
        q=True, ws=True, t=True
    )
    bottom_points = [tuple(cube_verts[i:i+3]) for i in range(0, len(cube_verts), 3)]
    
    hit_results = []
    # 对每个底部顶点向下发射射线
    for point in bottom_points:
        hit, hit_pos, hit_normal = ray_intersects_object(point, (0, -1, 0), ground_name)
        if hit:
            hit_results.append((hit_pos, hit_normal))
        else:
            cmds.warning(f"顶点 {point} 未检测到地面交点")
            return
    
    # 计算立方体平移距离:取所有交点的平均Y值调整位置
    avg_y = sum(pos[1] for pos, _ in hit_results) / len(hit_results)
    current_cube_pivot_y = cmds.xform(cube_name, q=True, ws=True, rp=True)[1]
    cmds.xform(cube_name, ws=True, t=(0, avg_y - current_cube_pivot_y, 0))
    
    # 计算贴合曲面的旋转角度:使用交点法线的平均方向
    avg_normal = [0,0,0]
    for _, normal in hit_results:
        avg_normal[0] += normal[0]
        avg_normal[1] += normal[1]
        avg_normal[2] += normal[2]
    avg_normal = [n/len(hit_results) for n in avg_normal]
    
    # 计算从世界Y轴到平均法线的旋转
    up_vector = OpenMaya.MVector(0,1,0)
    target_normal = OpenMaya.MVector(*avg_normal)
    rotation = up_vector.rotateTo(target_normal)
    euler_rot = rotation.asEulerRotation()
    cmds.xform(cube_name, ws=True, ro=(
        euler_rot.x * 180/3.14159, 
        euler_rot.y * 180/3.14159, 
        euler_rot.z * 180/3.14159
    ))

# 使用示例:替换为你的立方体和地面名称
fit_cube_to_ground("pCube1", "ground")

使用说明

  1. 确保场景中存在指定名称的起伏地面模型和立方体模型。
  2. 如果你的立方体顶点索引与默认pCube不同,需要调整cube_verts中的顶点编号。
  3. 运行脚本后,立方体将自动移动并旋转,底部贴合地面曲面。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 11:33:13