尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

OpenUSD 中的 WasmFetchResolver 示例:用 Emscripten Fetch API 在浏览器中加载 USD 舞台

OpenUSD 中的 WasmFetchResolver 示例:用 Emscripten Fetch API 在浏览器中加载 USD 舞台 OpenUSD 中的 WasmFetchResolver 示例用 Emscripten Fetch API 在浏览器中加载 USD 舞台【免费下载链接】OpenUSDUniversal Scene Description项目地址: https://gitcode.com/GitHub_Trending/ope/OpenUSD本篇技术指南围绕 OpenUSD 仓库内extras/usd/examples/wasmFetchResolver/示例展开讲解如何借助 Emscripten Fetch API 编写一个自定义 Ar 资产解析器Asset Resolver让浏览器端的 Wasm 版 OpenUSD 通过 HTTP 从 Web 服务器加载 USD 舞台及其引用层并配有一个基于 Express.js 的零配置演示服务器。读完本文你将掌握该示例的构建前提、配置与运行方法、如何接入自己的 USD 资产以及解析器各核心虚函数与浏览器线程模型的源码级实现原理。示例要解决的问题常规 OpenUSD 程序通过文件系统读取.usd/.usda/.usdc资产但在 Wasm 环境浏览器中没有本地文件系统概念只能访问 Emscripten 提供的虚拟文件系统Virtual Filesystem。因此若想让浏览器中的 USD 加载远程服务器上的舞台就必须把按路径读取文件这个环节替换为按 URL 发起 HTTP 请求。WasmFetchResolver 正是为此设计的一个最小演示它实现了一个基于 Emscripten Fetch API 的ArResolver子类用同步 Fetch 请求把 Web 服务器上的文件下载进 Emscripten 虚拟文件系统再交给 OpenUSD 的标准文件系统资产类读取server.js则是一个 Express.js 静态文件服务器用于承载示例页面与被下载的资产。需要特别说明的是示例代码仅用于演示 Fetch 解析器的工作原理README 明确声明其不适用于生产环境not meant for production use在生产场景中需要考虑缓存策略、错误处理、鉴权等问题。目录与文件组成示例位于 extras/usd/examples/wasmFetchResolver核心文件如下文件作用fetchResolver.h / fetchResolver.cppFetchResolver类声明与实现即自定义 Ar 解析器主体main.cpp暴露给浏览器的 JS APIShowTree、ComputeAllDependencies、CreateNewUsdzPackage及异步工作线程server.jsExpress.js 演示服务器静态文件服务 /stages接口 线程所需响应头package.jsonNode.js 依赖与npm run server脚本定义wasmFetchResolver.html手写的最小 Web UI含舞台下拉框与三个操作按钮plugInfo.json声明FetchResolver插件类型编译时被嵌入 Wasm 包stages.json舞台下拉框的数据源示例预置了 teapots 模型CMakeLists.txt编译、链接与安装规则stages/teapots/示例模型stage.usda舞台与meshes/teapot.usdc网格其中stage.usda是一个带引用与实例化的典型场景teapot类通过references [meshes/teapot.usdc]引用网格资产再通过inheritsinstanceable true派生Teapot1、Teapot2两个平移实例正好可以验证解析器在下载主层之后还能继续按相对路径把引用的子层一并抓取下来。构建前提Wasm 构建需开启 Examples该示例随 OpenUSD 的 Wasm 构建一起编译产出。构建时需确保 Examples 处于开启状态在 build_scripts/build_usd.py 中--examples参数默认即为开启defaultTrue对应 CMake 侧的-DPXR_BUILD_EXAMPLESON见 build_usd.py构建目标通过--build-target wasm或wasm64指定脚本内部据此走 Emscripten 工具链emcmake/emmake见 build_usd.py并自动启用 OneTBB 等 Wasm 所需依赖Wasm 构建会默认禁用 Python、工具、测试等组件见 build_usd.py 附近对targetWasm的各组件裁剪逻辑。完成主构建后示例产物与演示服务器会被安装到安装目录下的share/usd/examples/bin/wasmFetchResolver/对应 CMakeLists.txt 中的install规则顶层目录package.json、server.js、stages.jsonpublic/子目录wasmFetchResolver.html、编译产物wasmFetchResolver.js与wasmFetchResolver.wasm以及示例舞台目录stages/。配置示例进入示例安装目录并安装 Node.js 依赖cd $INST_DIR/share/usd/examples/bin/wasmFetchResolver npm install依赖来自 package.json 的dependencies字段express^5.2.1、cors^2.8.5与commander^14.0.2。启动服务器并打开演示页面依赖安装完成后启动服务器npm run server该命令等价于node server.js --port 8080 --directory public。启动成功后控制台会输出Server is running on http://localhost:8080 Serving files from: 安装目录/public随后用浏览器打开http://localhost:8080/wasmFetchResolver.html。页面上的Root layer path下拉菜单已由/stages接口预置了stages.json中的示例模型teapots点击下方三个按钮即可观察解析器工作Show Tree调用UsdStage::Open(url)打开舞台递归打印伪根之下所有 prim 及其 authored 属性验证主层与引用层均已被正确拉取Compute All Dependencies调用UsdUtilsComputeAllDependencies输出该资产的全部 Layers、Assets 与 UnresolvedPaths 清单直观展示解析器实际下载了哪些文件Create USDZ Package调用UsdUtilsCreateNewUsdzPackage在虚拟文件系统/tmp下生成.usdz包并通过浏览器 Blob 触发下载演示远程层 本地打包的完整链路。接入自己的 USD 资产如需测试其他资产操作步骤如下将资产主层及其引用文件拷贝到示例根目录下的public目录中保持相对引用结构不变在 stages.json 中新增一条记录例如[ { name: teapots, path: stages/teapots/stage.usda }, { name: myModel, path: stages/myModel/stage.usda } ]其中name是下拉框显示名path是相对public目录的资产路径刷新页面或点击Refresh按钮下拉菜单即会更新。需要留意的是README 中提到的stages.js实为 stages.json服务器的/stages接口见 server.js直接返回该 JSON 文件。源码深度解析1. 插件注册与解析器骨架fetchResolver.cpp 通过宏AR_DEFINE_RESOLVER(FetchResolver, ArResolver)把FetchResolver注册为ArResolver的派生插件plugInfo.json 声明了插件元数据bases: [ArResolver]并在 CMakeLists.txt 中通过--embed-file将其嵌入 Wasm 包安装路径刻意放在 plug 的搜索路径上SHELL:--embed-file plugInfo.json/usd/wasmFetchResolver/resources/plugInfo.json运行时在 main.cpp 调用ArSetPreferredResolver(FetchResolver)将解析器切换为刚注册的FetchResolver。FetchResolver覆写了 ArResolver 的五个关键虚函数见 fetchResolver.h虚函数行为_CreateIdentifier/_CreateIdentifierForNewAsset基于锚定资产路径拼接标识符相对路径锚定_Resolve绝对路径查虚拟文件系统相对路径向服务器发 HEAD 请求探测存在性_ResolveForNewAsset恒返回空路径当前只读_OpenAsset虚拟文件系统命中则直接打开否则从服务器下载后写入虚拟文件系统再打开_OpenAssetForWrite恒返回nullptr当前只读2. 同步 Fetch 封装_FetchRequest 是底层封装初始化emscripten_fetch_attr_t写入 HTTP 动词GET/HEAD并设置EMSCRIPTEN_FETCH_LOAD_TO_MEMORY | EMSCRIPTEN_FETCH_SYNCHRONOUS两个属性——前者要求把响应加载到内存缓冲区后者要求同步阻塞等待请求完成配合std::unique_ptremscripten_fetch_t管理生命周期析构时调用emscripten_fetch_close。3. 路径解析策略_Resolve见 fetchResolver.cpp先对资产路径做TfNormPath规范化若是绝对路径直接检查虚拟文件系统TfPathExists——这使解析器能命中打包进 Wasm 的资产例如 schema 定义等内置文件若是相对路径则向服务器发起HEAD请求返回200即视为存在解析为该路径否则返回空ArResolvedPath。4. 按需下载与并发去重_OpenAsset_OpenAsset 是下载核心实现缓存 按需抓取 并发去重在互斥锁保护下检查_downloads集合若路径已在下载中isDownloading说明有其他线程正在抓取同一文件调用线程进入条件变量_condition.wait等待该下载结束若虚拟文件系统中已存在该文件此前下载成功直接ArFilesystemAsset::Open(resolvedPath)返回避免重复网络请求否则把路径插入_downloads调用_FetchFile执行 GET 下载下载完成后从_downloads移除并notify_all()成功则ArFilesystemAsset::Open失败返回nullptr控制台打印Fetch Success/Failed: path。_FetchFile 检查响应status 200后先确保目录存在TfMakeDirs再把fetch-data以二进制方式写入虚拟文件系统路径std::ofstream从而把远程文件落地为本地可读文件。5. 浏览器线程模型不阻塞 UI 的异步请求Wasm 环境中 Emscripten Fetch 的同步调用不能发生在浏览器 UI 线程上否则页面会卡死。因此 main.cpp 采用工作线程 任务队列模式pthread创建常驻_WorkerThreadFunc从队列取出Request并执行回调真正的UsdStage::Open、依赖计算等在此时发生UI 线程的_ProcessRequest把请求压入队列后循环调用emscripten_sleep(16)——每次约 16ms 的休眠把控制权交还浏览器事件循环使页面保持响应请求完成后写回结果字符串。四个导出函数通过EMSCRIPTEN_BINDINGSmain.cpp暴露给 JSInitWorkerThread、ShowTree、ComputeAllDependencies、CreateNewUsdzPackage页面在onRuntimeInitialized回调中首先调用InitWorkerThread完成解析器切换与线程启动。6. CMake 链接选项与整库链接CMakeLists.txt 的链接选项揭示了 Wasm 构建的几个关键点-sFETCH1启用 Emscripten Fetch API-sASYNCIFY1允许同步风格的 fetch 代码在异步环境工作--no-entry --bind无独立入口仅导出绑定函数特意使用_pxr_target_link_libraries(wasmFetchResolver usdUtils usd ar tf arch)这种带整库归档语义的链接方式——注释指出若用普通链接编译器会激进地剥离死代码导致解析器注册函数不执行、插件无法被发现因此必须以 whole-archive 方式保住符号。7. 服务器端的关键响应头server.js 为每个响应追加两个自定义头Cross-Origin-Embedder-Policy: require-corp Cross-Origin-Opener-Policy: same-origin这是 Emscripten 多线程-pthread模式的硬性要求缺失这些头时浏览器会因跨源隔离COOP/COEP策略拒绝创建共享内存与 Worker页面将无法正常工作。此外服务器还提供 CORS 中间件、请求日志中间件、/stages接口并用express.static托管public目录。已知限制只读解析器_ResolveForNewAsset恒返回空路径、_OpenAssetForWrite恒返回nullptr本示例不支持写回服务器所有新资产如 USDZ 包只落在 Emscripten 虚拟文件系统的/tmp中同步下载的取舍示例以同步方式阻塞式下载逻辑简单直观但依赖 ASYNCIFY 与工作线程配合不适合大规模资产的并发场景无缓存失效机制_OpenAsset对已下载文件直接复用注释中亦留有 TODOTrack and check previously tried, but failed downloads即失败请求不会重试记录生产环境需要自行补全。延伸阅读解析器基类与资产抽象ar 目录 下的resolver.h、asset.h、resolvedPath.hUSDZ 打包与依赖计算工具usdUtils 目录Wasm 构建参数与工具链处理build_scripts/build_usd.py同仓库其他可参考的解析器示例usdResolverExample。【免费下载链接】OpenUSDUniversal Scene Description项目地址: https://gitcode.com/GitHub_Trending/ope/OpenUSD创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表