Материалы в Babylon.js представляют собой сложные объекты, управляющие рендерингом поверхностей. Они определяют шейдеры, текстуры, параметры освещения, прозрачность, отражения и множество других характеристик. Во время каждого кадра движок проверяет состояние материалов, обновляет параметры шейдеров и пересчитывает связанные данные.
В сценах с большим количеством объектов эти проверки могут становиться существенной нагрузкой для процессора. Для оптимизации в Babylon.js реализован механизм заморозки материалов, позволяющий отключить часть вычислений, если материал больше не изменяется.
Основные методы:
material.freeze()material.unfreeze()Заморозка сообщает движку, что параметры материала остаются постоянными и не требуют пересчёта каждый кадр.
Во время рендеринга Babylon.js выполняет ряд операций для каждого материала:
Даже если материал не меняется, часть этих проверок выполняется регулярно. В сложных сценах с сотнями мешей и материалов подобные операции могут занимать значительное время.
Заморозка отключает:
В результате уменьшается нагрузка на CPU и повышается стабильность кадровой частоты.
Метод freeze() переводит материал в состояние
неизменяемости.
Пример:
const material = new BABYLON.StandardMaterial("mat", scene);
material.diffuseColor = new BABYLON.Color3(1, 0, 0);
material.freeze();
После вызова:
Внутри движка устанавливается флаг:
material.isFrozen === true
Этот флаг используется системой рендеринга для пропуска ряда вычислений.
При стандартном рендеринге Babylon.js выполняет процедуру подготовки материала через метод:
isReadyForSubMesh
В этом методе:
Если материал заморожен, значительная часть этой логики пропускается.
Упрощённая схема:
Обычный материал
каждый кадр
проверка параметров
обновление defines
проверка текстур
обновление шейдера
Замороженный материал
каждый кадр
использование уже подготовленного эффекта
Это особенно эффективно в сценах со статическими объектами.
Метод unfreeze() снимает ограничение и возвращает
материал в обычный режим работы.
material.unfreeze();
После вызова:
Флаг состояния:
material.isFrozen === false
Создание статической сцены с большим количеством объектов.
const material = new BABYLON.StandardMaterial("groundMat", scene);
material.diffuseTexture = new BABYLON.Texture("ground.jpg", scene);
const ground = BABYLON.MeshBuilder.CreateGround("ground", {
width: 100,
height: 100
}, scene);
ground.material = material;
material.freeze();
Если параметры материала не изменяются во время выполнения, заморозка избавляет от повторных вычислений.
Заморозка эффективна в следующих случаях:
Статические окружения
Большие сцены
Материалы без анимации
При наличии сотен мешей, использующих один материал, экономия CPU может быть заметной.
Заморозка недопустима, если материал изменяется во время работы сцены.
Типичные ситуации:
Анимация параметров
material.diffuseColor = new BABYLON.Color3(0,1,0);
Изменение текстур
material.diffuseTexture = new BABYLON.Texture("newTexture.jpg", scene);
Переключение прозрачности
material.alpha = 0.5;
Динамическое освещение
Если шейдер зависит от часто изменяемых параметров.
В подобных случаях материал необходимо сначала разморозить:
material.unfreeze();
material.diffuseColor = new BABYLON.Color3(0,1,0);
material.freeze();
Для диагностики используется свойство:
material.isFrozen
Пример:
if (!material.isFrozen) {
material.freeze();
}
Это полезно при управлении состоянием материалов в сложных сценах.
Заморозка предполагает, что состояние текстур остаётся неизменным.
Если текстура является динамической:
DynamicTextureVideoTextureRenderTargetTextureиспользование freeze() может привести к некорректному
отображению, поскольку движок не будет обновлять связанные данные.
Пример проблемы:
const videoTexture = new BABYLON.VideoTexture("video", "movie.mp4", scene);
material.diffuseTexture = videoTexture;
material.freeze();
Видео перестанет корректно обновляться.
Babylon.js использует систему defines, определяющую конфигурацию шейдера:
При изменении параметров движок может перекомпилировать шейдер.
Заморозка фиксирует текущий набор defines.
Пример:
#define DIFFUSE
#define NORMAL
#define SPECULAR
После freeze эти флаги остаются неизменными.
Babylon.js рендерит геометрию через структуру SubMesh.
Каждый SubMesh хранит ссылку на:
Когда материал заморожен, SubMesh использует уже подготовленный эффект без повторной проверки.
Это уменьшает:
В больших сценах иногда замораживают все статические материалы.
Пример:
scene.materials.forEach(mat => {
mat.freeze();
});
Перед этим необходимо убедиться, что:
Иначе возможны ошибки отображения.
При использовании загрузчиков, например SceneLoader,
материалы часто настраиваются после загрузки модели.
Типичный порядок действий:
Пример:
BABYLON.SceneLoader.Append("models/", "house.glb", scene, function () {
scene.materials.forEach(mat => {
mat.freeze();
});
});
Такой подход оптимизирует статические ассеты.
Материалы физически корректного рендеринга (PBRMaterial)
содержат больше вычислений:
Заморозка особенно полезна именно для них.
Пример:
const pbr = new BABYLON.PBRMaterial("pbr", scene);
pbr.albedoTexture = new BABYLON.Texture("albedo.png", scene);
pbr.metallic = 1;
pbr.roughness = 0.3;
pbr.freeze();
В сложных сценах это существенно снижает CPU-нагрузку.
Упрощённая оценка:
| Сцена | Без freeze | С freeze |
|---|---|---|
| 100 материалов | регулярные проверки | минимальные проверки |
| 500 материалов | высокая CPU нагрузка | значительная экономия |
| 1000+ материалов | возможны просадки FPS | стабильная частота кадров |
Эффект зависит от:
Заморозка материалов часто используется совместно с другими механизмами:
freezeActiveMeshes
scene.freezeActiveMeshes();
instancing
Mesh.createInstance()
thin instances
mesh.thinInstanceAdd()
LOD
mesh.addLODLevel()
Комбинация этих методов позволяет значительно оптимизировать сцены с большим количеством объектов.
freeze()Если требуется изменить параметры:
unfreeze → изменить параметры → freeze
Такая схема позволяет сохранить гибкость и производительность.
Заморозка не влияет на:
Она оптимизирует исключительно CPU-часть подготовки материалов.
В некоторых сценах выигрыш может быть небольшим, если количество материалов невелико.
Состояния материала:
Normal
↓ freeze()
Frozen
↓ unfreeze()
Normal
Frozen-состояние означает:
Это делает freeze() одним из простых и эффективных
способов оптимизации рендеринга в Babylon.js.