# 干扰示例
¥Interference example
Colin Eberhardt 和 Ben Smith 的 WebAssembly 干扰效果 (opens new window)(如果它是用 AssemblyScript 编写的)。
¥Colin Eberhardt's and Ben Smith's WebAssembly interference effect (opens new window), if it was written in AssemblyScript.
# 内容
¥Contents
从 WebAssembly 模块导出函数和变量。
¥Exporting functions and variables from a WebAssembly module.
调用函数并读取从 WebAssembly 导出的变量。
¥Calling functions and reading variables exported from WebAssembly.
利用
Mathf
,利用 32 位浮点数学来加速计算。¥Utilizing 32-bit floating point math to speed up calculations by utilizing
Mathf
.将图片缓冲区保留在模块的内存中并将其复制到画布。
¥Keeping an image buffer within the module's memory and copying it to a canvas.
根据浏览器端视口的大小手动增加内存。
¥Manually growing memory depending on the size of the viewport on the browser side.
最后:不断更新和渲染图片缓冲区。
¥And finally: Continuously updating and rendering the image buffer.
# 示例
¥Example
癫痫警告
当暴露于某些光模式或闪烁的灯光时,极少数人可能会出现癫痫发作。接触电脑屏幕上的某些图案或背景可能会诱发这些人癫痫发作。某些情况可能会诱发以前未检测到的癫痫症状,即使对于既往没有癫痫发作或癫痫病史的人也是如此。
¥A very small percentage of individuals may experience epileptic seizures when exposed to certain light patterns or flashing lights. Exposure to certain patterns or backgrounds on a computer screen may induce an epileptic seizure in these individuals. Certain conditions may induce previously undetected epileptic symptoms even in persons who have no history of prior seizures or epilepsy.
如果你在观看时遇到以下任何症状 - 头晕、视力改变、眼睛或肌肉抽搐、意识丧失、迷失方向、任何不自主的运动或抽搐 - 立即停止使用并咨询你的医生。
¥If you experience any of the following symptoms while viewing - dizziness, altered vision, eye or muscle twitches, loss of awareness, disorientation, any involuntary movement, or convulsions - IMMEDIATELY discontinue use and consult your physician.
#!optimize=speed&runtime=stub
var width = 320;
var height = 200;
// Let's utilize the entire heap as our image buffer
export const offset = __heap_base;
/** Sets a single pixel's color. */
function set(x: i32, y: i32, v: f32): void {
var vi = <i32>v;
store<i32>(offset + ((width * y + x) << 2), ~vi << 24 | vi << 8);
}
/** Computes the distance between two pixels. */
function distance(x1: i32, y1: i32, x2: f32, y2: f32): f32 {
var dx = <f32>x1 - x2;
var dy = <f32>y1 - y2;
return Mathf.sqrt(dx * dx + dy * dy);
}
/** Performs one tick. */
export function update(tick: f32): void {
var w = <f32>width;
var h = <f32>height;
var hw = w * 0.5,
hh = h * 0.5;
var cx1 = (Mathf.sin(tick * 2) + Mathf.sin(tick )) * hw * 0.3 + hw,
cy1 = (Mathf.cos(tick) ) * hh * 0.3 + hh,
cx2 = (Mathf.sin(tick * 4) + Mathf.sin(tick + 1.2)) * hw * 0.3 + hw,
cy2 = (Mathf.sin(tick * 3) + Mathf.cos(tick + 0.1)) * hh * 0.3 + hh;
var res = <f32>48 / Mathf.max(w, h);
var y = 0;
do {
let x = 0;
do {
set(x, y, Mathf.abs(
Mathf.sin(distance(x, y, cx1, cy1) * res) +
Mathf.sin(distance(x, y, cx2, cy2) * res)
) * 120);
} while (++x != width)
} while (++y != height)
}
/** Recomputes and potentially grows memory on resize of the viewport. */
export function resize(w: i32, h: i32): void {
width = w; height = h;
// Pages are 64kb. Rounds up using mask 0xffff before shifting to pages.
var needed = <i32>((offset + (w * h * sizeof<i32>() + 0xffff)) & ~0xffff) >>> 16;
var actual = memory.size();
if (needed > actual) memory.grow(needed - actual);
}
#!html
<canvas id="canvas" style="width: 100%; height: 100%; background: #aff"></canvas>
<script type="module">
const exports = await instantiate(await compile());
const canvas = document.getElementById("canvas");
const context = canvas.getContext("2d");
const step = 0.012;
// Upscale the image to speed up calculations
const upscaleFactor = 4;
var width, height, image;
// Inform the module about the viewport's size, incl. on resize
function onresize() {
width = (canvas.offsetWidth / upscaleFactor) | 0;
height = (canvas.offsetHeight / upscaleFactor) | 0;
canvas.width = width;
canvas.height = height;
image = context.createImageData(width, height);
exports.resize(width, height);
}
onresize();
new ResizeObserver(onresize).observe(canvas);
// Keep updating the image
var tick = 0.0;
(function update() {
requestAnimationFrame(update);
exports.update(tick += step);
new Uint32Array(image.data.buffer).set(new Uint32Array(exports.memory.buffer, exports.offset.value, width * height));
context.putImageData(image, 0, 0);
})();
</script>
注意
该示例做出了一个重要假设:由于我们没有使用复杂的运行时,因此我们可以从 __heap_base
开始重新调整整个堆的用途,作为我们的图片缓冲区。
¥The example makes one important assumption: Since we are not using a sophisticated runtime, we can instead repurpose the entire heap, starting at __heap_base
, as our image buffer.
一旦不再满足此条件,人们就会通过指定合适的 --memoryBase
来保留一些空间,或者导出动态实例化的内存块(例如 Uint32Array
),并将其用作 WebAssembly 和 JavaScript 中的图片缓冲区。
¥As soon as this condition is no longer met, one would instead either reserve some space by specifying a suitable --memoryBase
or export a dynamically instantiated chunk of memory, like an Uint32Array
, and utilize it as the image buffer both in WebAssembly and in JavaScript.
# 本地运行
¥Running locally
按照 入门 中所述设置一个新的 AssemblyScript 项目,并将 module.ts
复制到 assembly/index.ts
,将 index.html
复制到项目的顶层目录。编辑 package.json
中的构建命令以包括
¥Set up a new AssemblyScript project as described in Getting started and copy module.ts
to assembly/index.ts
and index.html
to the project's top-level directory. Edit the build commands in package.json
to include
--runtime stub
现在可以使用以下命令编译该示例
¥The example can now be compiled with
npm run asbuild
要查看该示例,可以将 index.html
中的实例化修改为
¥To view the example, one can modify the instantiation in index.html
from
loader.instantiate(module_wasm).then(({ exports }) => {
到
¥to
WebAssembly.instantiateStreaming(fetch('./build/optimized.wasm'), {
JSMath: Math
}).then(({ exports }) => {
因为这里最终不需要使用 loader(不交换托管对象)。如果使用加载程序,它将自动提供 JSMath
。
¥because using the loader is not ultimately necessary here (no managed objects are exchanged). If the loader is used instead, it will automatically provide JSMath
.
有些浏览器在现在打开 index.html
时可能会限制 fetch
ing 本地资源,但可以设置本地服务器作为解决方法:
¥Some browsers may restrict fetch
ing local resources when just opening index.html
now, but one can set up a local server as a workaround:
npm install --save-dev http-server
http-server . -o -c-1