Using Rust and WebAssembly to Optimize 3D Model Vertex Merging in Frontend Development
This article explains how to create, compile, and integrate a Rust‑based WebAssembly component for accelerating 3D model vertex merging in the browser, covering tool installation, code examples, data transfer techniques, performance tuning with hashing, and compatibility adjustments for both webpack and Vite.
WebAssembly (wasm) is a binary format that runs in browsers and other environments with high speed, efficiency, and portability. For frontend engineers, wasm enables heavy computations to be off‑loaded from JavaScript, improving performance.
Rust is chosen to write wasm modules because of its strict memory management, which reduces the risk of memory leaks and makes the generated code safer. The wasm-pack tool packages Rust code as an npm module, allowing seamless consumption in JavaScript projects.
Installation steps :
cargo install rustup # Rust installer and version manager (similar to nvm) cargo install wasm-pack # Install wasm-pack tool cargo generate --git https://github.com/rustwasm/wasm-pack-templateAfter generating the project, the src directory contains lib.rs and utils.rs . Functions intended for JavaScript are marked with #[wasm_bindgen] :
#[wasm_bindgen]
pub fn add_attribute(&mut self, attribute: &Float32Array, item_size: u32) {
self.attributes.push(BufferAttribute {
array: attribute.to_vec(),
item_size,
});
}Data is passed as Float32Array objects, avoiding costly copies. The Rust side can expose pointers and lengths for JavaScript to read directly from wasm memory:
pub fn get_attribute_ptr(&self, index: usize) -> *const f32 {
self.attributes[index].array.as_ptr()
}
pub fn get_attribute_length(&self, index: usize) -> usize {
self.attributes[index].array.len()
}JavaScript retrieves the data:
const ptr = bg.get_attribute_ptr(i);
const length = bg.get_attribute_length(i);
const buffer = new Float32Array(wasm.getMemory().buffer, ptr, length);To improve the hash‑based vertex‑matching algorithm, the Rust implementation switches from building long strings to using std::collections::hash_map::DefaultHasher :
use std::collections::hash_map::DefaultHasher;
let mut hasher = DefaultHasher::new();
// inside the loop
hasher.write_i32(value);
let hash = hasher.finish();After this change, the wasm version runs roughly twice as fast as the original JavaScript implementation.
Packaging for different bundlers :
The default wasm-pack output ( merge_vertice_wasm.js ) works with webpack. To make it compatible with Vite, the module is modified to expose a getMemory function and handle the promise‑based loading strategy:
import * as wasm from './merge_vertice_wasm_bg.wasm';
import * as wasm_bg from './merge_vertice_wasm_bg.js';
let memory;
if (wasm.default) {
wasm.default({ './merge_vertice_wasm_bg.js': wasm_bg }).then(_wasm => {
memory = _wasm.memory;
wasm_bg.__wbg_set_wasm(_wasm);
});
} else {
memory = wasm.memory;
wasm_bg.__wbg_set_wasm(wasm);
}
export * from './merge_vertice_wasm_bg.js';
export function getMemory() { return memory; }With this adjustment, the same wasm component can be imported and used in both webpack and Vite projects.
Calling JavaScript from Rust :
[dependencies]
wasm-bindgen = "0.2.84"
[dependencies.web-sys]
version = "0.3.64"
features = ["console"] extern crate web_sys;
// Log a message
web_sys::console::log_1(&JsValue::from(log_content));
// Measure time
web_sys::console::time_with_label(label);
web_sys::console::time_end_with_label(label);Performance screenshots show the original JavaScript version taking significantly longer than the optimized wasm version.
Conclusion : The guide walks through the entire workflow—from installing Rust and wasm‑pack, writing and optimizing Rust code, handling data transfer, adapting the build output for different frontend bundlers, to invoking JavaScript APIs from Rust—demonstrating how wasm can effectively accelerate compute‑heavy frontend tasks.
JD Retail Technology
Official platform of JD Retail Technology, delivering insightful R&D news and a deep look into the lives and work of technologists.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.