将 15000 行代码从 C++ 编译为 WebAssembly,是种怎样的体验?
总体的规划
 
-  
  
为使用 Emscripten 编译代码做好准备;  -  
  
修改代码,解决编译到 WebAssembly 遇到的问题。  
第一步:准备代码
 
-  
  
尽可能减少依赖项的数量。  -  
  
修改代码。  -  
  
为导出函数和/或枚举做准备。  
依赖关系
-  
  
Emscripten 内置 OpenGL 的支持,但严格来说,只能支持 OpenGL 的子集 WebGL2。  -  
  
glad 是一个 OpenGL 加载库,Emscripten 可以处理这部分,因此不需要在意。  -  
  
glm 是一个只有头文件的数学库。我们可以使用 -I 选项将其包含到构建中。  
修改头文件并排除有问题的函数
  
    
    
  
   
     
     
   #ifdef __EMSCRIPTEN__
   
     
     
   
   
     
     
   #include <GL/gl.h>
   
     
     
   
   
     
     
   #include <GLES3/gl3.h>
   
     
     
   
   
     
     
   #else
   
     
     
   
   
     
     
   #include <glad/glad.h>
   
     
     
   
   
     
     
   #endif
  
    
    
    
-  
  
一些无法用 Emscripten 编译到 WebGL2 的 OpenGL 函数。对于这一类函数,我只能暂时注释掉,然后等到第二步再解决。  -  
  
一些需要读写磁盘的函数,例如加载字体。由于编译好的代码会放到 Web 上运行,因此 Emscripten 禁止访问磁盘。如果你需要从磁盘读取文件,则可以在链接时将其预加载到 Emscripten 提供的虚拟文件系统。我使用了这个虚拟文件系统来预加载所有的着色器。  
准备导出函数和/或枚举
  
    
    
  
   
     
     
   -sEXPORTED_FUNCTIONS=’[$(shell cat functions_to_export.txt)]’
  
    
    
    
-  
  
包含WebAssembly 代码的 .wasm 文件。  -  
  
一个 .js 文件,这是一个“胶水”文件,能够在WebAssembly 和你希望与之交互的其他 JavaScript 或 HTML 文件之间建立链接。  -  
  
一个 .data 文件,其中包含我在 Emscripten 的虚拟文件系统中预加载的文件。  
第二步:修改代码
 
-  
  
选择一个类,比如说球体类。  -  
  
修改代码,使其能够通过新编译的渲染引擎。  -  
  
遇到一些由于从C++ 到 WebAssembly 的转换而引发的错误。  -  
  
修复错误。  -  
  
重复第一步。  
问题
 
-  
  
指针问题。  -  
  
OpenGL 的问题。  
指针
例子
-  
  
我有一个 C 函数,经过了 WebAssembly 的编译,可更改背景颜色。这个函数需要一个参数:constfloat* color。  -  
  
在JavaScript 中,颜色存储在一个简单的 JavaScript 数组中。  -  
  
我直接将这个数组传给了 C 函数。  
  
    
    
  
   
     
     
   -s ‘EXPORTED_RUNTIME_METHODS=[“ccall”, “cwrap”]’
  
    
    
    
  
    
    
  
   
     
     
   Module.ccall('wr_post_processing_effect_pass_set_name', null,['number', 'string'], [colorPassTrough, "colorPassThrough"]);
  
    
    
    
  
    
    
  
   
     
     
   var buf =Module._malloc(myTypedArray.length*myTypedArray.BYTES_PER_ELEMENT);
   
     
     
   
   
     
     
   Module.HEAPU8.set(myTypedArray, buf);
   
     
     
   
   
     
     
   Module.ccall('my_function', 'number', ['number'], [buf]);
   
     
     
   
   
     
     
   Module._free(buf);
  
    
    
    
  
    
    
  
   
     
     
   float *wrjs_array3(float element0, float element1, floatelement2) {
   
     
     
   
   
     
     
   static float array[3];
   
     
     
   
   
     
     
   array[0] = element0;
   
     
     
   
   
     
     
   array[1] = element1;
   
     
     
   
   
     
     
   array[2] = element2;
   
     
     
   
   
     
     
   return array;
   
     
     
   
   
     
     
   }
  
    
    
    
OpenGL
-  
  
修改 C++ 代码,用不同的方式来实现相同的功能,同时能与 gcc(必须保证渲染引擎的桌面版能够正常运行)和 WebAssembly 兼容。  -  
  
使用 EM_ASM,这是一种很方便的方法,我们可以直接用 C 编写 WebGL 代码。如果遇到某个 WebGL 2 的函数,而 OpenGL ES 3 没有,就可以使用这种方法。  -  
  
发挥创造力。我直接重新实现了一些着色器或代码中不可用的函数,并利用 ifdef 为编译器 Emscripten 或 gcc 编写了不同的处理。  
建议
-  
  
尽量采用纯 C 语言编写的 API,C 版的 API 比 C++ 更容易导出。  -  
  
见机行事,没有某个神奇的解决方案能够解决编译成 WebAssembly引入的所有问题。  -  
  
小心没有任何错误和警告的问题,导出的函数会经常发生这种情况。  -  
  
仔细管理指针,并仔细检查你提供给 WebAssembly 的数据是否得到了正确的解释。  -  
  
减少代码依赖项的数量。  
结果
☞
 
        CSDN  
        
         
         
        
      
 
       
     
         成就一亿技术人 
       
 
       
     Official Account 
   
 
  