Библиотека Oimo.js предназначена для высокопроизводительной физической симуляции тел в 3D-пространстве. Одним из ключевых аспектов работы с физикой является эффективная передача данных о трансформациях объектов между движком и визуализацией. Для этого используется TypedArray, который обеспечивает быстрый доступ к массивам чисел в формате, подходящем для WebGL и других графических API.
TypedArray — это типизированный массив в JavaScript,
который хранит элементы строго определённого типа (например,
Float32Array, Uint16Array). В контексте
Oimo.js TypedArray применяется для:
Ключевое преимущество — непосредственный доступ к памяти, что позволяет обновлять трансформации тысяч объектов за один кадр без создания промежуточных объектов.
Каждое тело в Oimo.js содержит позицию и ориентацию, которые можно представить в виде массива чисел:
// Пример структуры трансформации для одного тела
// [posX, posY, posZ, rotX, rotY, rotZ, rotW]
const transform = new Float32Array(7);
posX, posY, posZ — координаты центра масс тела.rotX, rotY, rotZ, rotW — компоненты кватерниона,
определяющие вращение.Для передачи трансформаций сразу для всех тел создаётся большой массив:
const numBodies = world.numRigidBodies;
const transforms = new Float32Array(numBodies * 7);
for (let i = 0; i < numBodies; i++) {
const body = world.rigidBodies[i];
const offset = i * 7;
transforms[offset] = body.position.x;
transforms[offset + 1] = body.position.y;
transforms[offset + 2] = body.position.z;
transforms[offset + 3] = body.rotation.x;
transforms[offset + 4] = body.rotation.y;
transforms[offset + 5] = body.rotation.z;
transforms[offset + 6] = body.rotation.w;
}
При работе с WebGL или Three.js массив трансформаций может быть
передан напрямую в Shader Storage Buffer Object или
использоваться для обновления Matrix4 объектов:
for (let i = 0; i < numBodies; i++) {
const offset = i * 7;
const position = transforms.subarray(offset, offset + 3);
const rotation = transforms.subarray(offset + 3, offset + 7);
mesh[i].position.set(position[0], position[1], position[2]);
mesh[i].quaternion.set(rotation[0], rotation[1], rotation[2], rotation[3]);
}
Использование subarray позволяет избежать копирования
данных и напрямую работать с нужной областью памяти.
Предварительное выделение массива Создание
одного большого Float32Array на весь кадр эффективнее, чем
отдельные массивы для каждого тела.
Использование кватернионов вместо матриц Кватернионы экономят память (4 числа против 16 в матрице) и упрощают интерполяцию вращений.
Обновление только изменённых тел В динамических сценах можно хранить флаги изменения трансформации и обновлять только те тела, которые движутся.
Совмещение массивов Для сложных объектов (позиция, вращение, масштаб) удобно объединять все данные в один TypedArray, чтобы передавать их одним блоком в шейдер.
Oimo.js позволяет задать масштаб тела при создании через
setShape. Для передачи масштаба вместе с позицией и
вращением массив трансформаций расширяется:
// [posX, posY, posZ, rotX, rotY, rotZ, rotW, scaleX, scaleY, scaleZ]
const transformWithScale = new Float32Array(numBodies * 10);
Масштаб передаётся так же, как позиция и кватернион, и позволяет графическому движку корректно отображать объекты без дополнительных вычислений.
TypedArray для трансформаций особенно полезен при:
Эта методика обеспечивает высокую производительность и минимизацию задержек между расчётом физики и визуализацией.
world.step() → обновление TypedArray → рендер.Vector3 и
Quaternion каждый кадр.Использование TypedArray делает систему трансформаций плоской, компактной и совместимой с современными графическими пайплайнами, что критично для сложных 3D-сцен с сотнями и тысячами динамических тел.