You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

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)、plyfilelaspy这些库,你需要:

  • 下载对应Linux x86_64版本的库(因为Lambda用的是Amazon Linux 2环境)
  • 把这些库打包成Lambda层,或者和你的代码一起压缩成zip包上传
  • 注意OpenUSD的库体积可能不小,要控制在Lambda的部署包大小限制内(当前是250MB)

备注:内容来源于stack exchange,提问作者Foncho

火山引擎 最新活动