VTK 获取画布异常
无论使用 Vtk.js 还是将 VTK 编译成 WebAssembly 添加到 web 上,两种方式都要更新页面上 canvas 画布达到显示 3D 场景的效果。
但根据实测,这个 canvas 元素的获取方法并不是随意的:
首先是正确的方式:1
<canvas id="canvas"></canvas>;
document.getElementById("canvas");
(错误示例)但是对于 Vue 2/3
<template>
<canvas ref="_canvas"></canvas>
</template>
<script setup>
import { ref } from 'vue'
const _canvas = ref()
</script>
这种方式以及各种获取方式 (总之 canvas 没有 id) 会产生如下报错:
registerOrRemoveHandler: the target element for event handler registration does not exist, when processing the following event handler registration:……
此时页面只渲染一帧,同时画面会上跳一部分并且显示很虚。
为什么说这个问题很坑呢,因为官方文档没有任何提示,示例代码仅仅提供了代码,并没有提到 canvas id 除了获取元素之外的作用。在 Vue 框架下获取 canvas 的语法直觉上就会用 ref 获取,所以用这个语法代替后报错并不能轻易想到是 id 的副作用。
WASM 编译 ES6
vue/webassembly/opengl https://www.philxu.cn/vue/webassembly-vue-opengl.html#emscripten-编译-es6-模块
-s WASM=1 \
-s ASSERTIONS=1 \
-s EXPORT_ES6=1 \
-s MODULARIZE=1 \
-s USE_ES6_IMPORT_META=0 \
-s TOTAL_MEMORY=134217728 \
-s EXTRA_EXPORTED_RUNTIME_METHODS='["ccall", "cwrap"]'
WASM给JS传送字符串
有两种方式:wasm直接发送字符串给js,或转换成Uint8发送指针给js去访问共享内存。
下面的官方文档中的形式:
示例:
C++端:
std::string test(std::string buffer,std::string name){
std::cout << buffer.length() << std::endl;
return "helo world";
}
EMSCRIPTEN_BINDINGS(module){
emscripten::function(name:"test", fn: &test)
}
JS端:
module.test() // "helo world"
类型化数组方式2: Wasm By Example
Unit8方式: javascript - Passing a JS ArrayBuffer or TypedArray to Emscripten w/o Copying - Stack Overflow
JS向wasm发送字符串
axios("***url",{
responseType:"arraybuffer"
}).then(({data})=>{
const uint8Array = new Uint8Array(data);
// 调用c malloc方法分配内存
const ptr = malloc(uint8Array.length,"xxxx")
Module.HEAPU8.set(uint8Array,ptr)
})
int malloc(int length){
void* ptr = malloc(length)
return int(ptr);
}
这种方式下ptr指向的一块内存地址被C和js共用,C开数组JS写地址就完成了通信。
其他参考资料:
注意上面两篇文章中
Pointer_stringify
方法已经改名为UTF8ToString
:出处
- WebAssembly-函数调用 | This_Wei
- WebAssembly技术_JS调用C函数示例_传递参数、方法导出-云社区-华为云
- WebAssembly cwrap无法传递大字符串问题
- 如何将WebAssembly的C++对象传递给JavaScript回调函数,使用Emscripten?
- 彻底弄懂Js和Wasm间各种数据类型的传递-逐梦个人博客
- 关于 WebAssembly 的一些工程化总结 - 掘金