AWS Lambda环境下从USD/USDA文件提取顶点或转换为PLY文件的Python实现问题
AWS Lambda环境下从USD/USDA文件提取顶点或转换为PLY文件的Python实现问题
看起来你现在卡在两个关键点上:一是直接读取USD顶点时数据不准,二是在AWS Lambda这种不能用桌面工具的环境下没法转格式。我来帮你逐个解决这些问题。
一、修复顶点提取的准确性问题
你遇到的Z值几乎为0、顶点数量不足的问题,90%的概率是因为没考虑USD节点的空间变换。USD里的Mesh通常会嵌套在带有平移、旋转、缩放的Xform节点下,你当前的代码只读取了Mesh本地空间的原始顶点,完全没考虑父节点的变换,自然会导致坐标混乱,甚至漏掉部分被变换影响的顶点。
我给你修改一下提取函数,加入世界空间变换的计算:
from pxr import Usd, UsdGeom, Sdf import numpy as np def extract_world_points_from_usd(file_path): """提取USD/USDA文件中所有Mesh的世界空间3D顶点""" stage = Usd.Stage.Open(file_path) points = [] # 创建Xform缓存,用于计算世界空间变换 xform_cache = UsdGeom.XformCache() for prim in stage.Traverse(): # 不仅要检查是否是Mesh,还要确保它是可渲染的(排除一些代理或不可见的Mesh) if prim.IsA(UsdGeom.Mesh) and UsdGeom.Imageable(prim).ComputeVisibility() != UsdGeom.Tokens.invisible: mesh = UsdGeom.Mesh(prim) # 获取Mesh本地空间的顶点 local_points = mesh.GetPointsAttr().Get() if not local_points: continue # 计算该Mesh的世界空间变换矩阵 world_xform = xform_cache.GetLocalToWorldTransform(prim) # 将本地顶点转换为世界空间顶点 world_points = [world_xform.Transform(p) for p in local_points] points.extend(world_points) return np.array(points, dtype=np.float64)
这样处理后,顶点的Z值应该就能正常显示了,而且也不会漏掉被变换影响的顶点。另外,我加了可见性检查,避免提取那些不可见的Mesh顶点,这也可能是你之前顶点数量少的原因之一。
二、在AWS Lambda中把USD转成PLY文件
既然你觉得转成PLY再处理更顺手,那咱们用纯Python库来实现这个转换,完全不需要Blender这类工具。这里需要用到plyfile库(用来生成PLY文件),结合上面的世界空间顶点提取代码:
首先,确保在Lambda环境中安装了plyfile(可以打包成层或者和代码一起部署),然后用下面的代码实现转换:
from pxr import Usd, UsdGeom import numpy as np from plyfile import PlyData, PlyElement def usd_to_ply(file_path, output_ply_path): # 先提取世界空间的顶点 stage = Usd.Stage.Open(file_path) xform_cache = UsdGeom.XformCache() all_points = [] for prim in stage.Traverse(): if prim.IsA(UsdGeom.Mesh) and UsdGeom.Imageable(prim).ComputeVisibility() != UsdGeom.Tokens.invisible: mesh = UsdGeom.Mesh(prim) local_points = mesh.GetPointsAttr().Get() if not local_points: continue world_xform = xform_cache.GetLocalToWorldTransform(prim) world_points = [world_xform.Transform(p) for p in local_points] all_points.extend(world_points) # 转换为numpy数组,适配plyfile的格式要求 points_np = np.array(all_points, dtype=[('x', 'f8'), ('y', 'f8'), ('z', 'f8')]) # 创建PLY元素 vertex_element = PlyElement.describe(points_np, 'vertex') # 写入PLY文件 PlyData([vertex_element], text=False).write(output_ply_path)
这个函数会把USD中所有可见Mesh的世界空间顶点导出成PLY文件,完全是纯Python实现,适合在Lambda里运行。
三、从顶点/PLY转成LAS文件
不管你是用修复后的顶点提取函数,还是从PLY文件读取顶点,都可以用laspy库来生成LAS文件。这里给你一个简单的示例:
import laspy import numpy as np def points_to_las(points_np, output_las_path): # LAS文件通常需要设置坐标的缩放和偏移(因为LAS用整数存储坐标,减少文件大小) scale = 0.001 # 根据你的数据精度调整 offset = np.min(points_np, axis=0) # 创建LAS文件 with laspy.open(output_las_path, mode='w', header=laspy.LasHeader(point_format=3, version='1.2')) as writer: writer.header.scales = [scale, scale, scale] writer.header.offsets = offset.tolist() # 写入顶点 writer.write_points(laspy.ScaleAwarePointRecord( x=points_np[:, 0], y=points_np[:, 1], z=points_np[:, 2], header=writer.header ))
如果是从PLY转LAS,先读取PLY的顶点,再传入这个函数即可。
关于AWS Lambda的依赖打包
最后提醒一下,Lambda默认没有pxr(OpenUSD)、plyfile、laspy这些库,你需要:
- 下载对应Linux x86_64版本的库(因为Lambda用的是Amazon Linux 2环境)
- 把这些库打包成Lambda层,或者和你的代码一起压缩成zip包上传
- 注意OpenUSD的库体积可能不小,要控制在Lambda的部署包大小限制内(当前是250MB)
备注:内容来源于stack exchange,提问作者Foncho




