Система материалов в Babylon.js построена вокруг абстракции Material, которая определяет способ взаимодействия объекта сцены с источниками света, текстурами и шейдерными программами GPU. Материал связывает геометрию меша с графическим конвейером WebGL, обеспечивая передачу параметров и вычислений, необходимых для визуализации.
Шейдеры представляют собой программы, исполняемые непосредственно на графическом процессоре. Babylon.js автоматически генерирует значительную часть шейдерного кода в зависимости от конфигурации материала. Это позволяет объединять различные функции рендеринга — освещение, тени, текстурирование, отражения, прозрачность — в единую шейдерную программу.
Совместимость материалов и шейдеров определяется несколькими факторами:
Внутри движка система компиляции шейдеров динамически создаёт подходящую программу GPU на основе набора defines, определяющих активные функции.
Babylon.js предоставляет несколько стандартных материалов, каждый из которых использует собственный набор шейдеров.
StandardMaterial
Классический материал с моделью освещения Blinn–Phong. Поддерживает:
Шейдер StandardMaterial формируется динамически в зависимости от включённых текстур и источников света.
const material = new BABYLON.StandardMaterial("mat", scene);
material.diffuseTexture = new BABYLON.Texture("diffuse.jpg", scene);
material.specularColor = new BABYLON.Color3(0.5, 0.5, 0.5);
mesh.material = material;
PBRMaterial
Физически корректный материал, реализующий модель Physically Based Rendering (PBR). Предназначен для реалистичного освещения и взаимодействия с окружающей средой.
Поддерживаемые параметры:
Шейдеры PBRMaterial значительно сложнее и используют большое количество условных компиляций.
const pbr = new BABYLON.PBRMaterial("pbr", scene);
pbr.albedoTexture = new BABYLON.Texture("albedo.png", scene);
pbr.metallic = 0.8;
pbr.roughness = 0.2;
mesh.material = pbr;
NodeMaterial
NodeMaterial позволяет конструировать шейдеры через граф узлов. Каждый узел представляет математическую операцию, текстуру или параметр.
Особенности:
В результате компиляции NodeMaterial формируется полноценный шейдер WebGL.
Babylon.js использует систему ShaderMaterial, Effect и MaterialDefines для генерации и компиляции шейдеров.
Процесс включает несколько этапов:
#define.Пример условной директивы:
#ifdef DIFFUSE
vec4 diffuseColor = texture2D(diffuseSampler, vUV);
#endif
Если текстура диффузии присутствует, движок добавляет define
DIFFUSE, активируя соответствующий код.
Это позволяет одной базе шейдера обслуживать множество конфигураций материалов.
Для полного контроля над шейдерами используется ShaderMaterial. Этот тип материала напрямую связывает меш с пользовательскими GLSL-программами.
const shaderMaterial = new BABYLON.ShaderMaterial(
"shader",
scene,
{
vertex: "custom",
fragment: "custom",
},
{
attributes: ["position", "normal", "uv"],
uniforms: ["worldViewProjection"]
}
);
Шейдерные файлы:
// vertex shader
attribute vec3 position;
uniform mat4 worldViewProjection;
void main() {
gl_Position = worldViewProjection * vec4(position, 1.0);
}
// fragment shader
void main() {
gl_FragColor = vec4(1.0,0.0,0.0,1.0);
}
Совместимость ShaderMaterial определяется:
Материал должен соответствовать набору вершинных атрибутов, содержащихся в меше.
Наиболее распространённые атрибуты:
| Атрибут | Назначение |
|---|---|
| position | координаты вершины |
| normal | нормаль поверхности |
| uv | координаты текстуры |
| color | цвет вершины |
| tangent | касательный вектор для нормалей |
Если шейдер ожидает атрибут normal, но геометрия его не
содержит, компиляция может завершиться ошибкой или материал будет
работать некорректно.
Пример добавления нормалей:
BABYLON.VertexData.ComputeNormals(positions, indices, normals);
Defines играют ключевую роль в совместимости материалов и шейдеров.
Они определяют:
Пример набора defines:
#define DIFFUSE
#define NORMAL
#define SPECULAR
#define LIGHT0
#define SHADOW0
Каждая директива активирует определённый блок GLSL-кода.
Если параметры материала изменяются (например добавляется текстура), Babylon.js пересобирает шейдер.
Чрезмерное число вариантов шейдеров приводит к:
Babylon.js использует кэширование эффектов. Если комбинация defines уже была скомпилирована, движок повторно использует существующий shader program.
Кэш основан на строке defines:
DIFFUSE;NORMAL;LIGHT0
Идентичная строка означает возможность повторного использования программы.
Материалы поддерживают различные типы освещения:
Каждый источник света добавляет дополнительные вычисления в шейдере.
Пример:
const light = new BABYLON.PointLight(
"light",
new BABYLON.Vector3(0, 10, 0),
scene
);
При добавлении света активируется define:
#define LIGHT0
Если источников света больше, добавляются дополнительные директивы:
LIGHT1
LIGHT2
Некоторые материалы имеют ограничение на количество источников света.
Тени реализуются через shadow map и требуют дополнительных параметров.
При использовании теней шейдер получает:
Активируется define:
#define SHADOWS
Внутри фрагментного шейдера выполняется проверка видимости:
float shadow = computeShadow();
color *= shadow;
Не все материалы поддерживают тени. Например, некоторые упрощённые материалы или пользовательские ShaderMaterial требуют ручной реализации.
Наличие текстур влияет на структуру шейдера.
Основные типы текстур:
| Тип | Назначение |
|---|---|
| diffuse | базовый цвет |
| normal | рельеф поверхности |
| specular | зеркальный блеск |
| emissive | собственное свечение |
| opacity | прозрачность |
| reflection | отражения |
Каждая текстура добавляет соответствующий sampler:
uniform sampler2D diffuseSampler;
Если текстура отсутствует, соответствующий код исключается из шейдера.
При использовании skinning шейдер должен учитывать трансформации костей.
Включаются дополнительные атрибуты:
И define:
#define NUM_BONE_INFLUENCERS 4
Вершинный шейдер применяет матрицы костей:
vec4 skinnedPosition = boneMatrix * vec4(position, 1.0);
Материал, не поддерживающий skinning, не сможет корректно отображать анимированную модель.
Babylon.js поддерживает hardware instancing, позволяющий рендерить тысячи объектов одним вызовом.
Для этого шейдер должен поддерживать дополнительные матрицы трансформации.
Активируется define:
#define INSTANCES
Вершинный шейдер использует instanceMatrix:
mat4 finalWorld = world * instanceMatrix;
Материал, не учитывающий этот параметр, не будет совместим с инстансингом.
Совместимость шейдеров зависит от версии WebGL.
WebGL 1
ограничения:
WebGL 2
добавляет:
Babylon.js автоматически адаптирует шейдеры под доступную версию WebGL.
При проблемах компиляции шейдера Babylon.js выводит сообщения в консоль браузера.
Типичные причины ошибок:
Инструменты диагностики:
Получить код шейдера:
material.getEffect().getVertexShaderSource();
material.getEffect().getFragmentShaderSource();
Это позволяет анализировать окончательный GLSL, сгенерированный движком.
Babylon.js допускает расширение существующих материалов через MaterialPlugin.
Плагин позволяет:
Пример регистрации:
class CustomPlugin extends BABYLON.MaterialPluginBase {
constructor(material) {
super(material, "CustomPlugin", 200);
}
}
Такой механизм обеспечивает совместимость пользовательских функций с системой стандартных материалов.
Совместимость материалов и шейдеров формируется через комбинацию нескольких слоёв:
Каждый уровень влияет на итоговую структуру шейдера. Гибкость архитектуры Babylon.js позволяет динамически адаптировать шейдеры под параметры сцены, сохраняя совместимость между материалами, геометрией и графическим оборудованием.