Каждый объект сцены в Babylon.js обладает собственной системой трансформаций. Положение, вращение и масштаб объединяются в локальную матрицу, после чего вычисляется мировая матрица (World Matrix). Она описывает окончательное положение объекта в мировом пространстве сцены.
Мировая матрица формируется на основе нескольких факторов:
position)rotation или
rotationQuaternion)scaling)На каждом кадре движок проверяет, изменились ли параметры трансформации. Если изменения обнаружены, выполняется пересчёт мировой матрицы. Даже если объект не двигается, проверка всё равно происходит. В сценах с большим количеством объектов это становится заметной нагрузкой на CPU.
Для статической геометрии подобные вычисления являются избыточными.
В типичной сцене может находиться множество объектов, которые никогда не изменяют своё положение:
Если сцена содержит тысячи таких объектов, на каждом кадре происходит:
Даже если реального изменения трансформации нет, проверка всё равно выполняется.
Это создаёт:
Для решения этой задачи в Babylon.js используется механизм заморозки мировой матрицы.
Babylon.js предоставляет метод:
mesh.freezeWorldMatrix();
Этот вызов замораживает мировую матрицу объекта, предотвращая её дальнейший пересчёт.
После заморозки:
Это существенно снижает нагрузку на CPU в сценах с большим количеством статических объектов.
При вызове freezeWorldMatrix() происходит следующий
процесс:
_isWorldMatrixFrozen устанавливается в
trueВнутренний механизм проверки выглядит концептуально следующим образом:
if (worldMatrixFrozen) {
return cachedWorldMatrix;
}
Таким образом, при рендере кадра движок просто использует кэшированную матрицу, не выполняя никаких вычислений.
Статический объект сцены:
const rock = BABYLON.MeshBuilder.CreateBox("rock", { size: 2 }, scene);
rock.position = new BABYLON.Vector3(10, 0, -5);
rock.rotation.y = Math.PI / 4;
rock.freezeWorldMatrix();
После заморозки любые попытки изменить трансформацию не приведут к обновлению положения.
Если требуется снова изменить трансформацию, используется метод:
mesh.unfreezeWorldMatrix();
После этого объект снова начинает участвовать в системе пересчёта матриц.
Пример:
rock.unfreezeWorldMatrix();
rock.position.x += 5;
rock.freezeWorldMatrix();
Такая схема применяется, когда объект большую часть времени остаётся статичным, но иногда перемещается.
Заморозка эффективна в следующих ситуациях.
1. Статическая геометрия уровня
2. Декорации
3. Импортированные сцены
Многие модели из 3D-редакторов являются полностью статическими. После загрузки их можно заморозить.
4. Инстансы, которые не двигаются
При использовании большого количества инстансов заморозка помогает дополнительно снизить нагрузку.
Часто применяется автоматическая заморозка всех статических объектов:
scene.meshes.forEach(mesh => {
if (!mesh.skeleton && !mesh.parent) {
mesh.freezeWorldMatrix();
}
});
Подобный подход используется после загрузки уровня.
Заморозка мировой матрицы накладывает ряд ограничений.
После заморозки любые изменения:
mesh.position.x += 1;
mesh.rotation.y += 0.1;
не будут влиять на реальное положение объекта.
Если объект получает родителя после заморозки, трансформации могут работать некорректно.
Корректная последовательность:
назначить родителя
задать трансформации
заморозить матрицу
Анимации, изменяющие:
не будут работать, пока матрица заморожена.
В Babylon.js трансформации могут наследоваться от родителя.
Parent World Matrix
×
Local Matrix
=
Child World Matrix
Если заморозить матрицу дочернего объекта, а затем переместить родителя, дочерний объект не обновит положение.
Поэтому заморозку рекомендуется применять только к объектам:
После загрузки моделей из форматов:
часто создаётся множество мешей. Если модель используется как неподвижная декорация, её геометрию можно оптимизировать.
Пример:
BABYLON.SceneLoader.ImportMesh("", "models/", "house.glb", scene, function(meshes) {
meshes.forEach(mesh => {
mesh.freezeWorldMatrix();
});
});
Это уменьшает количество вычислений при рендере сцены.
Заморозка мировой матрицы особенно эффективна в сочетании с другими методами оптимизации.
1. MergeMeshes
Объединение геометрии снижает количество draw call.
2. Hardware Instancing
Использование GPU для повторяющихся объектов.
3. Freeze Materials
Материалы также можно замораживать:
material.freeze();
4. Freeze Active Meshes
Фиксация набора видимых мешей сцены.
Комплексное применение этих техник значительно повышает производительность сложных сцен.
Babylon.js хранит состояние заморозки в объекте
TransformNode. Основной флаг:
_isWorldMatrixFrozen
При его активации:
computeWorldMatrixЭто особенно важно, потому что computeWorldMatrix()
вызывается очень часто — иногда тысячи раз за кадр в
сложных сценах.
В сценах с большим количеством статических объектов применение
freezeWorldMatrix может дать:
Наиболее заметный эффект наблюдается в сценах с:
Часто используется следующий рабочий процесс:
Пример:
scene.executeWhenReady(() => {
scene.meshes.forEach(mesh => {
if (!mesh.skeleton && !mesh.animations.length) {
mesh.freezeWorldMatrix();
}
});
});
Такой подход позволяет автоматически оптимизировать геометрию уровня.
Некоторые типы объектов не подходят для заморозки мировой матрицы.
Динамические объекты
Анимированные меши
Объекты с физикой
Если позиция управляется физическим движком (например, Ammo.js или Cannon.js), заморозка приведёт к некорректному поведению.
UI-элементы в 3D пространстве
Элементы интерфейса могут часто менять положение.
Метод freezeWorldMatrix является важной оптимизацией
Babylon.js для сцен с большим количеством неподвижной геометрии. Он
позволяет полностью исключить пересчёт мировых матриц для объектов,
трансформация которых не меняется, тем самым уменьшая нагрузку на CPU и
повышая общую производительность рендеринга.