WASM 集成指南
本文档讲述将以RVO2 (https://github.com/snape/RVO2) 库为例,通过 Emscripten 编译为 WebAssembly (WASM) 模块,并在 Cocos Creator 项目中使用这个模块。Cocos用C++库可以参考。
1. 编译 WASM 模块
需要使用 emcc
命令,该命令是 Emscripten 编译器的一部分。下面的命令将生成 .js
和 .wasm
文件,其中 binds.cpp
是自己编写的,用于定义 Emscripten 导出的函数和类。
使用以下命令编译 C++ 代码:
emcc Agent.cpp KdTree.cpp Obstacle.cpp RVOSimulator.cpp binds.cpp -I. -o rvo2.js -s WASM=1 -s ALLOW_MEMORY_GROWTH=1 -s DYNAMIC_EXECUTION=0 --bind -s MODULARIZE=1 -s EXPORT_NAME='createRvo2Module'
为了进一步提升性能,可以在编译命令中加上 -O3
选项,启用最高级别的优化:
emcc Agent.cpp KdTree.cpp Obstacle.cpp RVOSimulator.cpp binds.cpp -I. -o rvo2.js -O3 -s WASM=1 -s ALLOW_MEMORY_GROWTH=1 -s DYNAMIC_EXECUTION=0 --bind -s MODULARIZE=1 -s EXPORT_NAME='createRvo2Module'
2. 文件部署
将生成的 rvo2.js
和 rvo2.wasm
文件拷贝到项目的 assets/scripts/3rd/rvo2
目录下。
3. 代码修改
为了兼容旧版本的 Node.js,修改 rvo2.js
文件中的以下代码,第1步如果加了-O3选项,此步忽略:
if (numericVersion < 160000)
改为:
if (numericVersion < 140000)
这样可以避免在 Node.js v14.16.0 环境下运行时出现版本兼容性错误。
4. 更改文件扩展名
将 rvo2.wasm
文件重命名为 rvo2.bin
,以便 Cocos 引擎将其作为 buffer 类型导入,确保按照 BufferAsset
类型正确加载。
5. 类型定义文件
创建 rvo2.d.ts
文件,以提供 TypeScript 支持:
export interface ModuleConfigOptions {
wasmBinary?: Uint8Array;
}
export default function createRvo2Module(options?: ModuleConfigOptions): Promise<RVO2Module>;
export interface RVO2Module {
}
6. 加载 WASM 模块
编写加载代码,其中’788394bd-56d9-41e4-8d30-cbbd992b13a9’是rvo2.bin
的uuid,确保遵循 Cocos Creator 文档中关于 ESM 与 CJS 交互规则的指导(https://docs.cocos.com/creator/3.8/manual/zh/scripting/modules/spec.html):
// assets/scripts/3rd/rvo2/rvo2wasm.ts
import { default as createRvo2Module, RVO2Module } from './rvo2.js';
import { assetManager, BufferAsset } from 'cc';
export async function loadWasm(): Promise<RVO2Module> {
try {
const wasmBinaryData = await new Promise<Uint8Array>((resolve, reject) => {
assetManager.loadAny<BufferAsset>('788394bd-56d9-41e4-8d30-cbbd992b13a9', (error, asset) => {
if (error) {
reject(error);
} else {
resolve(new Uint8Array(asset.buffer()));
}
});
});
try {
const module = await createRvo2Module({ wasmBinary: wasmBinaryData });
return module;
} catch (error) {
console.error('模块加载失败', error);
throw error;
}
} catch (error) {
console.error('Failed to load or initialize the wasm module:', error);
throw error;
}
}