Ammo.js — это порт физического движка Bullet Physics на язык JavaScript, полученный с использованием инструмента Emscripten. Исходный код Bullet, написанный на C++, транслируется в код, исполняемый в браузере. В зависимости от конфигурации компиляции Emscripten формирует две основные версии библиотеки:
Обе версии предоставляют одинаковый API с точки зрения JavaScript, но существенно различаются по внутреннему устройству, производительности и механике загрузки.
asm.js — это строго ограниченное подмножество JavaScript, предназначенное для выполнения низкоуровневых вычислений с производительностью, близкой к нативной. Код asm.js генерируется Emscripten из C++-исходников.
Скомпилированная версия Ammo.js в формате asm.js представляет собой:
.js-файлВ asm.js используется большая типизированная область памяти:
var buffer = new ArrayBuffer(TOTAL_MEMORY);
var HEAPF32 = new Float32Array(buffer);
var HEAP32 = new Int32Array(buffer);
Память выделяется заранее и имеет фиксированный размер. Расширение памяти невозможно без полной перезагрузки модуля. Управление памятью осуществляется вручную через экспортируемые функции:
_malloc_freeЭто означает, что создание и удаление объектов физики требует контроля жизненного цикла, аналогично C++.
Преимущества:
Недостатки:
.js-файлаВ сложных сценах с большим количеством тел, ограничений и столкновений asm.js начинает уступать по производительности WebAssembly-версии.
WebAssembly — это бинарный формат для выполнения кода в браузере. В
отличие от asm.js, WASM представляет собой компактный бинарный модуль
(.wasm), загружаемый и компилируемый браузером
напрямую.
Сборка Ammo.js в формате WASM состоит из:
ammo.js)ammo.wasm)JavaScript-файл выполняет роль загрузчика и интерфейса к WebAssembly-модулю.
Загрузка происходит асинхронно:
Ammo().then(function(AmmoLib) {
const Ammo = AmmoLib;
});
Модуль WebAssembly компилируется браузером в машинный код во время загрузки. Современные браузеры используют потоковую компиляцию (streaming compilation), что сокращает время старта.
WASM использует линейную память, аналогичную asm.js, но реализованную на уровне виртуальной машины браузера. Ключевые особенности:
Память также управляется вручную через экспортируемые функции
_malloc и _free.
Преимущества:
В задачах интенсивной физической симуляции WASM-версия показывает ощутимое преимущество, особенно при:
| Характеристика | asm.js | WebAssembly |
|---|---|---|
| Формат | JavaScript | Бинарный |
| Размер | Больше | Меньше |
| Скорость | Высокая | Очень высокая |
| Время старта | Дольше | Быстрее |
| Поддержка потоков | Нет | Возможна |
| Совместимость | Старые браузеры | Современные браузеры |
Основные различия касаются не API, а внутренней реализации и производительности. Код, написанный для Ammo.js, в большинстве случаев не требует изменений при переходе между версиями.
При компиляции C++-версии Bullet в asm.js или WASM используются различные флаги:
Для asm.js:
emcc -O3 -s WASM=0
Для WebAssembly:
emcc -O3 -s WASM=1
Дополнительные параметры позволяют:
-s USE_PTHREADS=1)-s INITIAL_MEMORY)-s ALLOW_MEMORY_GROWTH=1)Выбор флагов напрямую влияет на поведение итоговой сборки Ammo.js.
С точки зрения JavaScript-разработчика различия минимальны:
var Ammo = Ammo();
Ammo().then(function(Ammo) {
// работа с библиотекой
});
WASM-версия требует асинхронной инициализации из-за загрузки бинарного модуля. Это влияет на архитектуру приложения: создание физического мира должно происходить после полной загрузки библиотеки.
asm.js оправдана в случаях:
WebAssembly предпочтительна при:
При использовании Ammo.js совместно с графическими библиотеками различия проявляются в частоте обновления сцены. В связке с интенсивным рендерингом через WebGL WebAssembly снижает нагрузку на главный поток за счёт более быстрой обработки физического шага:
dynamicsWorld.stepSimulation(deltaTime, 10);
При высокой частоте кадров (60+ FPS) WASM позволяет уменьшить число субшагов и стабилизировать симуляцию.
Современные браузеры полностью поддерживают WebAssembly. Поддержка asm.js сохраняется, но его развитие фактически прекращено в пользу WASM. Новые оптимизации в движках JavaScript ориентированы преимущественно на WebAssembly.
Переход на WASM стал естественным этапом эволюции портов C++-движков в веб-среду. Ammo.js в формате WebAssembly обеспечивает наиболее близкое соответствие производительности оригинальному движку Bullet на нативной платформе.
Таким образом, различие между версиями не в функциональности, а в уровне эффективности исполнения, механике загрузки и архитектурной модели памяти.