1) (data (i32.const 8) '1e000100010001e000~0l0i0b0/0r0t0/0t0l0s0f0.0t0s0') ... ;; Our global constants (not yet exported) (global $nBodyForces/FLOAT64ARRAY_ID i32 (i32.const 3)) (global $nBodyForces/G f64 (f64.const 6.674e-11)) (global $nBodyForces/bodySize i32 (i32.const 4)) (global $nBodyForces/forceSize i32 (i32.const 3)) ... ;; Memory management functions we’ll use in a minute (export 'memory' (memory

WebVR 3. osa: WebAssembly ja AssemblyScripti potentsiaali avamine

Veebikoosseis on kindlasti mitte JavaScripti kui veebi ja maailma lingua franca asendaja.

WebAssembly (lühend Wasm) on binaarne käsuvorming virnapõhisele virtuaalsele masinale. Wasm on loodud kaasaskantavaks sihtmärgiks selliste kõrgetasemeliste keelte nagu C / C ++ / Rust koostamiseks, mis võimaldab veebis juurutamist klientide ja serverite rakenduste jaoks. ' - WebAssembly.org



Oluline on eristada, et WebAssembly pole keel. WebAssembly on nagu '.exe' - või veelgi parem - Java '.class' fail. Selle koostab veebiarendaja teisest keelest, laadib seejärel alla ja töötab teie brauseris.



Veebiassamblee annab JavaScripti jaoks kõik funktsioonid, mida me aeg-ajalt tahtsime laenata, kuid mitte kunagi tõesti tahtis omada. Sarnaselt paadi või hobuse rentimisega võimaldab WebAssembly meil reisida teistesse keeltesse, ilma et peaksime tegema ekstravagantseid „keelelaadi“ valikuid. See on lasknud veebil keskenduda olulistele asjadele, näiteks funktsioonide edastamisele ja kasutuskogemuse parandamisele.

Veebiassamblee kompileerib üle 20 keele: Rust, C / C ++, C # /. Net, Java, Python, Elixir, Go ja muidugi JavaScript.



Kui mäletate meie simulatsiooni arhitektuuriskeemi, delegeerisime kogu simulatsiooni domeenile nBodySimulator, nii et see haldab veebitöötajat.

Simulatsiooni arhitektuuriskeem

Joonis 1: Üldine arhitektuur.

Kui mäletate sissejuhatav postitus , nBodySimulator on step() funktsiooni nimetatakse iga 33 ms järel. step() funktsioon teeb neid asju - nummerdatud ülaltoodud diagrammil:



  1. nBodySimulator's calculateForces() kõned this.worker.postMessage() arvutamise alustamiseks.
  2. töötajaWasm.js this.onmessage() saab teate.
  3. workerWasm.js käivitab sünkroonselt nBodyForces.wasm’s nBodyForces() funktsioon.
  4. workerWasm.js vastab, kasutades this.postMessage() uute jõududega peaniidini.
  5. Peamine lõime this.worker.onMessage() marssalid tagastatud andmed ja kõned.
  6. nBodySimulator's applyForces() laibade asendite ajakohastamiseks.
  7. Lõpuks värvib visualiseerija uuesti.

Kasutajaliidese lõim, veebitöötaja lõim

Joonis 2: simulaatori sammu () funktsioon

Sisse eelmine postitus , ehitasime veebitöötaja, kes mähib meie WASM-i arvutusi. Täna ehitame pisikest kasti sildiga “WASM” ning liigutame andmeid sisse ja välja.

Valisin lihtsuse huvides AssemblyScript lähtekoodikeelena meie arvutuste kirjutamiseks. AssemblyScript on TypeScripti alamhulk - mis on sisestatud JavaScripti - nii et te juba teate seda.

Näiteks arvutab see AssemblyScripti funktsioon kahe keha vahelise gravitatsiooni: :f64 aastal someVar:f64 tähistab muutuja someVar kompilaatori ujukina. Pidage meeles, et see kood on kompileeritud ja töötab täiesti erineva käitamisajaga kui JavaScript.

// AssemblyScript - a TypeScript-like language that compiles to WebAssembly // src/assembly/nBodyForces.ts /** * Given two bodies, calculate the Force of Gravity, * then return as a 3-force vector (x, y, z) * * Sometimes, the force of gravity is: * * Fg = G * mA * mB / r^2 * * Given: * - Fg = Force of gravity * - r = sqrt ( dx + dy + dz) = straight line distance between 3d objects * - G = gravitational constant * - mA, mB = mass of objects * * Today, we're using better-gravity because better-gravity can calculate * force vectors without polar math (sin, cos, tan) * * Fbg = G * mA * mB * dr / r^3 // using dr as a 3-distance vector lets * // us project Fbg as a 3-force vector * * Given: * - Fbg = Force of better gravity * - dr = (dx, dy, dz) // a 3-distance vector * - dx = bodyB.x - bodyA.x * * Force of Better-Gravity: * * - Fbg = (Fx, Fy, Fz) = the change in force applied by gravity each * body's (x,y,z) over this time period * - Fbg = G * mA * mB * dr / r^3 * - dr = (dx, dy, dz) * - Fx = Gmm * dx / r3 * - Fy = Gmm * dy / r3 * - Fz = Gmm * dz / r3 * * From the parameters, return an array [fx, fy, fz] */ function twoBodyForces(xA: f64, yA: f64, zA: f64, mA: f64, xB: f64, yB: f64, zB: f64, mB: f64): f64[]

See AssemblyScripti funktsioon võtab kahe keha jaoks (x, y, z, mass) ja tagastab kolme ujuki massiivi, mis kirjeldab (x, y, z) jõuvektorit, mida kehad üksteisele rakendavad. Me ei saa seda funktsiooni JavaScripti kaudu kutsuda, kuna JavaScriptil pole aimugi, kust seda leida. Me peame selle JavaScripti 'eksportima'. See viib meid esimese tehnilise väljakutseni.

Veebikoostu import ja eksport

ES6-s mõtleme JavaScripti koodi impordile ja ekspordile ning kasutame vanades brauserites töötava koodi loomiseks tööriistu nagu Rollup või Webpack import ja require(). See loob ülalt alla sõltuvuspuu ja võimaldab lahedaid tehnoloogiaid nagu puu raputamine ”Ja koodi jagamine .

Veebikoosseisus täidavad import ja eksport erinevaid ülesandeid kui ES6 import. Veebikoosseisu import / eksport:

Allolevas koodis env.abort ja env.trace on osa keskkonnast, mille peame WebAssembly moodulile pakkuma. nBodyForces.logI ja sõprade funktsioonid pakuvad konsoolile silumissõnumeid. Pange tähele, et stringide edastamine WebAssembleemis sisse / välja ei ole triviaalne, kuna WebAss Assembly ainsad tüübid on i32, i64, f32, f64 numbrid, i32 viited abstraktsele lineaarsele mälule.

Märge: Need koodinäited on JavaScripti koodi (veebitöötaja) ja AssemblyScripti (WASM-koodi) vahel ümberlülitamine.

// Web Worker JavaScript in workerWasm.js /** * When we instantiate the Wasm module, give it a context to work in: * nBodyForces: {} is a table of functions we can import into AssemblyScript. See top of nBodyForces.ts * env: {} describes the environment sent to the Wasm module as it's instantiated */ const importObj = { nBodyForces: { logI(data) { console.log('Log() - ' + data); }, logF(data) { console.log('Log() - ' + data); }, }, env: { abort(msg, file, line, column) { // wasm.__getString() is added by assemblyscript's loader: // https://github.com/AssemblyScript/assemblyscript/tree/master/lib/loader console.error('abort: (' + wasm.__getString(msg) + ') at ' + wasm.__getString(file) + ':' + line + ':' + column); }, trace(msg, n) { console.log('trace: ' + wasm.__getString(msg) + (n ? ' ' : '') + Array.prototype.slice.call(arguments, 2, 2 + n).join(', ')); } } }

Meie AssemblyScripti koodis saame nende funktsioonide importimise lõpule viia nii:

// nBodyForces.ts declare function logI(data: i32): void declare function logF(data: f64): void

Märge : Katkestamine ja jälgimine imporditakse automaatselt .

AssemblyScriptist saame oma liidese eksportida. Siin on mõned eksporditud konstandid:

// src/assembly/nBodyForces.ts // Gravitational constant. Any G could be used in a game. // This value is best for a scientific simulation. export const G: f64 = 6.674e-11; // for sizing and indexing arrays export const bodySize: i32 = 4 export const forceSize: i32 = 3

Ja siin on nBodyForces() eksport millele helistame JavaScripti kaudu. Ekspordime tüübi Float64Array faili ülaosas, et saaksime andmete hankimiseks kasutada veebitöötajal asetsevat AssemblyScripti laadijat (vt allpool):

// src/assembly/nBodyForces.ts export const FLOAT64ARRAY_ID = idof(); ... /** * Given N bodies with mass, in a 3d space, calculate the forces of gravity to be applied to each body. * * This function is exported to JavaScript, so only takes/returns numbers and arrays. * For N bodies, pass and array of 4N values (x,y,z,mass) and expect a 3N array of forces (x,y,z) * Those forces can be applied to the bodies mass to update its position in the simulation. * Calculate the 3-vector each unique pair of bodies applies to each other. * * 0 1 2 3 4 5 * 0 x x x x x * 1 x x x x * 2 x x x * 3 x x * 4 x * 5 * * Sum those forces together into an array of 3-vector x,y,z forces * * Return 0 on success */ export function nBodyForces(arrBodies: Float64Array): Float64Array { // Check inputs const numBodies: i32 = arrBodies.length / bodySize if (arrBodies.length % bodySize !== 0) trace('INVALID nBodyForces parameter. Chaos ensues...') // Create result array. This should be garbage collected later. let arrForces: Float64Array = new Float64Array(numBodies * forceSize) // For all bodies: for (let i: i32 = 0; i i for (let j: i32 = i + 1; j

Veebikoosseisu artefaktid: .wasm ja .wat

Kui meie AssemblyScript nBodyForces.ts on kokku pandud veebikoosseisuks nBodyForces.wasm binaarne , on võimalus luua ka “tekst” versioon, mis kirjeldab binaarseid juhiseid.

Veebikoosseisu artefaktid

Joonis 3: Pidage meeles, et AssemblyScript on keel. WebAssembly on kompilaator ja käitusaeg.

nBodyForces.wat Sees faili näeme järgmist importi ja eksporti:

;; This is a comment in nBodyForces.wat (module ;; compiler defined types (type $FUNCSIG$iii (func (param i32 i32) (result i32))) … ;; Expected imports from JavaScript (import 'env' 'abort' (func $~lib/builtins/abort (param i32 i32 i32 i32))) (import 'env' 'trace' (func $~lib/builtins/trace (param i32 i32 f64 f64 f64 f64 f64))) ;; Memory section defining data constants like strings (memory $0 1) (data (i32.const 8) '1e000100010001e000~0l0i0b0/0r0t0/0t0l0s0f0.0t0s0') ... ;; Our global constants (not yet exported) (global $nBodyForces/FLOAT64ARRAY_ID i32 (i32.const 3)) (global $nBodyForces/G f64 (f64.const 6.674e-11)) (global $nBodyForces/bodySize i32 (i32.const 4)) (global $nBodyForces/forceSize i32 (i32.const 3)) ... ;; Memory management functions we’ll use in a minute (export 'memory' (memory $0)) (export '__alloc' (func $~lib/rt/tlsf/__alloc)) (export '__retain' (func $~lib/rt/pure/__retain)) (export '__release' (func $~lib/rt/pure/__release)) (export '__collect' (func $~lib/rt/pure/__collect)) (export '__rtti_base' (global $~lib/rt/__rtti_base)) ;; Finally our exported constants and function (export 'FLOAT64ARRAY_ID' (global $nBodyForces/FLOAT64ARRAY_ID)) (export 'G' (global $nBodyForces/G)) (export 'bodySize' (global $nBodyForces/bodySize)) (export 'forceSize' (global $nBodyForces/forceSize)) (export 'nBodyForces' (func $nBodyForces/nBodyForces)) ;; Implementation details ...

Nüüd on meil oma nBodyForces.wasm binaarne ja veebitöötaja selle käivitamiseks. Ole valmis blastoffiks! Ja natuke mäluhaldust!

Integreerimise lõpuleviimiseks peame WebAssembleerimisele edastama muutuva hulga ujukeid ja tagastama JavaScripti muutuva hulga ujukid.

Naiivse JavaScripti kodanlusega kavatsesin need räpased muutuva suurusega massiivid tahtmatult edastada platvormidevahelise suure jõudlusega tööajast välja ja välja. Andmete edastamine veebiaadressilt / veebiaadressilt oli selles projektis ülekaalukalt kõige ootamatum raskus.

Kuid suure tänu eest rasket tõstmist tegi AssemblyScripti meeskond , saame nende 'laaduri' abil aidata:

// workerWasm.js - our web worker /** * AssemblyScript loader adds helpers for moving data to/from AssemblyScript. * Highly recommended */ const loader = require('assemblyscript/lib/loader')

require() tähendab, et peame kasutama moodulite kogumit nagu Rollup või Webpack. Selle projekti jaoks valisin Rollupi selle lihtsuse ja paindlikkuse tõttu ega vaadanud enam kunagi tagasi.

Pidage meeles, et meie veebitöötaja töötab eraldi lõimes ja on sisuliselt onmessage() funktsioon funktsiooniga switch() avaldus.

loader loob meie WASM-mooduli koos mõne eriti mugava mäluhalduse funktsiooniga. __retain() ja __release() hallata prügivedu viiteid töötajate käitamise ajal __allocArray() kopeerib meie parameetrite massiivi wasm-mooduli mällu __getFloat64Array() kopeerib tulemuste massiivi wasmi moodulist töötaja tööajale

Nüüd saame marssal hõljuda massiive sisse ja välja nBodyForces() ja viige meie simulatsioon lõpule:

// workerWasm.js /** * Web workers listen for messages from the main thread. */ this.onmessage = function (evt) { // message from UI thread var msg = evt.data switch (msg.purpose) { // Message: Load new wasm module case 'wasmModule': // Instantiate the compiled module we were passed. wasm = loader.instantiate(msg.wasmModule, importObj) // Throws // Tell nBodySimulation.js we are ready this.postMessage({ purpose: 'wasmReady' }) return // Message: Given array of floats describing a system of bodies (x,y,x,mass), // calculate the Grav forces to be applied to each body case 'nBodyForces': if (!wasm) throw new Error('wasm not initialized') // Copy msg.arrBodies array into the wasm instance, increase GC count const dataRef = wasm.__retain(wasm.__allocArray(wasm.FLOAT64ARRAY_ID, msg.arrBodies)); // Do the calculations in this thread synchronously const resultRef = wasm.nBodyForces(dataRef); // Copy result array from the wasm instance to our javascript runtime const arrForces = wasm.__getFloat64Array(resultRef); // Decrease the GC count on dataRef from __retain() here, // and GC count from new Float64Array in wasm module wasm.__release(dataRef); wasm.__release(resultRef); // Message results back to main thread. // see nBodySimulation.js this.worker.onmessage return this.postMessage({ purpose: 'nBodyForces', arrForces }) } }

Kõigega, mida oleme õppinud, vaatame üle oma veebitöötaja ja WebAssembleeni teekonna. Tere tulemast veebi uue brauseri taustaprogrammi juurde. Need on lingid GitHubi koodile:

  1. Hangi indeks.html
  2. main.js
  3. nBodySimulator.js - edastab sõnumi oma veebitöötajale
  4. workerWasm.js - kutsub funktsiooni WebAssembly
  5. nBodyForces.ts - arvutab ja tagastab jõudude massiivi
  6. workerWasm.js - edastab tulemused tagasi peaniidile
  7. nBodySimulator.js - lahendab lubaduse vägede kohta
  8. nBodySimulator.js - siis rakendab jõud kehadele ja käsib visualiseerijatel maalida

Alustame siis saadet nBodyVisualizer.js loomisega! Meie järgmine postitus loob visualiseerija, kasutades Canvas API-d, ja viimane postitus hõlmab WebVR-i ja Aframe-i.

Seotud: Veebikoosseis / roosteõpetus: täiuslik helitöötlus

Põhitõdede mõistmine

Kas WebAssembly saab JavaScripti asendada?

WebAssembly ei ole keel, seega ei saa see JavaScripti asendada. Samuti on funktsioonide ja kasutajakogemuse arendamine WebAssembly'is vähem efektiivne.

Miks on WebAssembly kiirem?

Veebikoosseis on kiirem, kuna see teeb vähem ja oli mõeldud arendaja kasutatavuse asemel jõudluseks.

Kas JavaScripti saab koostada WebAssembly-sse?

Jah, AssemblyScript kompileerib WebAssembly'i ja tunneb end nagu Typescript.

)) (export '__alloc' (func $~lib/rt/tlsf/__alloc)) (export '__retain' (func $~lib/rt/pure/__retain)) (export '__release' (func $~lib/rt/pure/__release)) (export '__collect' (func $~lib/rt/pure/__collect)) (export '__rtti_base' (global $~lib/rt/__rtti_base)) ;; Finally our exported constants and function (export 'FLOAT64ARRAY_ID' (global $nBodyForces/FLOAT64ARRAY_ID)) (export 'G' (global $nBodyForces/G)) (export 'bodySize' (global $nBodyForces/bodySize)) (export 'forceSize' (global $nBodyForces/forceSize)) (export 'nBodyForces' (func $nBodyForces/nBodyForces)) ;; Implementation details ...

Nüüd on meil oma nBodyForces.wasm binaarne ja veebitöötaja selle käivitamiseks. Ole valmis blastoffiks! Ja natuke mäluhaldust!

Integreerimise lõpuleviimiseks peame WebAssembleerimisele edastama muutuva hulga ujukeid ja tagastama JavaScripti muutuva hulga ujukid.

Naiivse JavaScripti kodanlusega kavatsesin need räpased muutuva suurusega massiivid tahtmatult edastada platvormidevahelise suure jõudlusega tööajast välja ja välja. Andmete edastamine veebiaadressilt / veebiaadressilt oli selles projektis ülekaalukalt kõige ootamatum raskus.

Kuid suure tänu eest rasket tõstmist tegi AssemblyScripti meeskond , saame nende 'laaduri' abil aidata:

on llc s või c ettevõte
// workerWasm.js - our web worker /** * AssemblyScript loader adds helpers for moving data to/from AssemblyScript. * Highly recommended */ const loader = require('assemblyscript/lib/loader')

require() tähendab, et peame kasutama moodulite kogumit nagu Rollup või Webpack. Selle projekti jaoks valisin Rollupi selle lihtsuse ja paindlikkuse tõttu ega vaadanud enam kunagi tagasi.

Pidage meeles, et meie veebitöötaja töötab eraldi lõimes ja on sisuliselt onmessage() funktsioon funktsiooniga switch() avaldus.

loader loob meie WASM-mooduli koos mõne eriti mugava mäluhalduse funktsiooniga. __retain() ja __release() hallata prügivedu viiteid töötajate käitamise ajal __allocArray() kopeerib meie parameetrite massiivi wasm-mooduli mällu __getFloat64Array() kopeerib tulemuste massiivi wasmi moodulist töötaja tööajale

mis on c keele kasutamine

Nüüd saame marssal hõljuda massiive sisse ja välja nBodyForces() ja viige meie simulatsioon lõpule:

// workerWasm.js /** * Web workers listen for messages from the main thread. */ this.onmessage = function (evt) { // message from UI thread var msg = evt.data switch (msg.purpose) { // Message: Load new wasm module case 'wasmModule': // Instantiate the compiled module we were passed. wasm = loader.instantiate(msg.wasmModule, importObj) // Throws // Tell nBodySimulation.js we are ready this.postMessage({ purpose: 'wasmReady' }) return // Message: Given array of floats describing a system of bodies (x,y,x,mass), // calculate the Grav forces to be applied to each body case 'nBodyForces': if (!wasm) throw new Error('wasm not initialized') // Copy msg.arrBodies array into the wasm instance, increase GC count const dataRef = wasm.__retain(wasm.__allocArray(wasm.FLOAT64ARRAY_ID, msg.arrBodies)); // Do the calculations in this thread synchronously const resultRef = wasm.nBodyForces(dataRef); // Copy result array from the wasm instance to our javascript runtime const arrForces = wasm.__getFloat64Array(resultRef); // Decrease the GC count on dataRef from __retain() here, // and GC count from new Float64Array in wasm module wasm.__release(dataRef); wasm.__release(resultRef); // Message results back to main thread. // see nBodySimulation.js this.worker.onmessage return this.postMessage({ purpose: 'nBodyForces', arrForces }) } }

Kõigega, mida oleme õppinud, vaatame üle oma veebitöötaja ja WebAssembleeni teekonna. Tere tulemast veebi uue brauseri taustaprogrammi juurde. Need on lingid GitHubi koodile:

  1. Hangi indeks.html
  2. main.js
  3. nBodySimulator.js - edastab sõnumi oma veebitöötajale
  4. workerWasm.js - kutsub funktsiooni WebAssembly
  5. nBodyForces.ts - arvutab ja tagastab jõudude massiivi
  6. workerWasm.js - edastab tulemused tagasi peaniidile
  7. nBodySimulator.js - lahendab lubaduse vägede kohta
  8. nBodySimulator.js - siis rakendab jõud kehadele ja käsib visualiseerijatel maalida

Alustame siis saadet nBodyVisualizer.js loomisega! Meie järgmine postitus loob visualiseerija, kasutades Canvas API-d, ja viimane postitus hõlmab WebVR-i ja Aframe-i.

Seotud: Veebikoosseis / roosteõpetus: täiuslik helitöötlus

Põhitõdede mõistmine

Kas WebAssembly saab JavaScripti asendada?

WebAssembly ei ole keel, seega ei saa see JavaScripti asendada. Samuti on funktsioonide ja kasutajakogemuse arendamine WebAssembly'is vähem efektiivne.

Miks on WebAssembly kiirem?

Veebikoosseis on kiirem, kuna see teeb vähem ja oli mõeldud arendaja kasutatavuse asemel jõudluseks.

Kas JavaScripti saab koostada WebAssembly-sse?

Jah, AssemblyScript kompileerib WebAssembly'i ja tunneb end nagu Typescript.