### WASM 集成实践(Cocos Creator 3.8.1)

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.jsrvo2.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;
    }
}
7赞

优秀666

菜鸟的我问问,这样做的作用是什么

运行C++,计算密集型的需要,例如物理之类的

有测过性能提升多少吗

ROV2十倍以上。

性能这么夸张么?牛
本人小白想测试一下,请问return的module要如何使用呢?
比如Simulator要如何在代码中实例化?

binds.cpp这个文件里面写的是啥 楼主方便贴一下吗

把各个类的声明,关键字‘emcc’,让gpt生成下bind。

是 Agent.h,KdTree.h,Obstacle.h中类的声明吗?

所有的.h吧,把注释去掉复制一遍所有的类声明,给ai生成下emcc的