Maya 2022 Python实现立方体贴合起伏曲面下落的问题求助
在Maya2022中用Python实现立方体贴合起伏曲面(修复closestIntersection RuntimeError)
错误原因
- 参数顺序错误:
MFnMesh.closestIntersection()的API参数顺序有严格要求,你错误地将空间参数(MSpace.kWorld)提前,导致调用时抛出RuntimeError。 - 射线方向错误:当前射线方向是向上
(0,1,0),无法命中下方的地面模型,应改为向下发射(0,-1,0)。 - 射线起点硬编码:代码中强制将射线起点设为
(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")
使用说明
- 确保场景中存在指定名称的起伏地面模型和立方体模型。
- 如果你的立方体顶点索引与默认pCube不同,需要调整
cube_verts中的顶点编号。 - 运行脚本后,立方体将自动移动并旋转,底部贴合地面曲面。
内容的提问来源于stack exchange,提问作者fishpeek
相关产品推荐
相关产品推荐

