В Babylon.js организация и переиспользование шейдерного кода осуществляется с помощью механизма Shader Include. Он позволяет отделять повторяющиеся части шейдеров в отдельные файлы или строки, а затем подключать их в основные шейдерные программы. Такой подход делает код более читаемым, поддерживаемым и модульным.
В Babylon.js шейдерные включения работают через объект
Effect.ShadersStore. В него можно добавить собственный блок
кода, который впоследствии будет включён в любой шейдер через директиву
#include.
Пример создания шейдерного блока:
BABYLON.Effect.ShadersStore["myCustomFunctions"] = `
float saturate(float value) {
return clamp(value, 0.0, 1.0);
}
vec3 adjustBrightness(vec3 color, float factor) {
return color * factor;
}
`;
После этого в основном шейдере подключение происходит через
стандартную директиву #include:
#include<myCustomFunctions>
void main() {
vec3 color = vec3(1.0, 0.5, 0.2);
color = adjustBrightness(color, 1.2);
gl_FragColor = vec4(color, 1.0);
}
Ключевые моменты:
ShadersStore должно совпадать с именем в
#include.vertex)
так и в фрагментных (fragment) шейдерах.В крупных проектах часто требуется использовать одни и те же функции
или константы в нескольких шейдерах. Shader Include идеально подходит
для этой задачи. Можно создать библиотеку функций, которая будет
храниться в ShadersStore и подключаться по мере
необходимости.
Пример организации библиотеки:
// Определение блока для работы с освещением
BABYLON.Effect.ShadersStore["lightingFunctions"] = `
vec3 applyDirectionalLight(vec3 normal, vec3 lightDir, vec3 lightColor) {
float diff = max(dot(normal, lightDir), 0.0);
return diff * lightColor;
}
vec3 applyAmbientLight(vec3 color, vec3 ambient) {
return color + ambient;
}
`;
// Определение блока для работы с текстурами
BABYLON.Effect.ShadersStore["textureFunctions"] = `
vec4 sampleTexture(sampler2D tex, vec2 uv) {
return texture2D(tex, uv);
}
`;
В фрагментном шейдере их можно комбинировать:
#include<lightingFunctions>
#include<textureFunctions>
void main() {
vec3 normal = normalize(vNormal);
vec3 lightDir = normalize(vec3(0.5, 1.0, 0.3));
vec3 lightColor = vec3(1.0, 1.0, 1.0);
vec3 color = applyDirectionalLight(normal, lightDir, lightColor);
color = applyAmbientLight(color, vec3(0.1, 0.1, 0.1));
vec4 texColor = sampleTexture(uSampler, vUV);
gl_FragColor = vec4(color * texColor.rgb, texColor.a);
}
Babylon.js поддерживает добавление шейдерных блоков динамически на уровне приложения. Это удобно, если нужно менять или расширять функциональность шейдера без полной его перекомпиляции.
function addShaderBlock(name, code) {
BABYLON.Effect.ShadersStore[name] = code;
}
// Пример динамического добавления функции для размытия
addShaderBlock("blurFunctions", `
vec3 blur(vec3 color, float intensity) {
return color * intensity;
}
`);
Подключение в шейдере работает аналогично статическим блокам:
#include<blurFunctions>
void main() {
vec3 color = vec3(1.0, 0.5, 0.2);
color = blur(color, 0.8);
gl_FragColor = vec4(color, 1.0);
}
#include, поэтому ошибки
компиляции могут возникнуть при неправильном порядке.lighting_applyDirectionalLight).uniform или
varying. Важно следить за областью видимости этих
переменных, чтобы избежать конфликтов.Для стандартных материалов, создаваемых через
NodeMaterial, Shader Include также доступен. Можно
создавать собственные блоки нод и подключать их как повторно
используемые фрагменты кода. Это особенно полезно при разработке сложных
PBR-материалов, где одна и та же логика освещения, обработки текстур или
эффектов повторяется во многих материалах.
const nodeMaterial = new BABYLON.NodeMaterial("myNodeMaterial", scene);
nodeMaterial.loadFromSnippetAsync("customSnippetId").then(() => {
nodeMaterial.build();
sphere.material = nodeMaterial;
});
Внутри таких сниппетов также можно подключать шейдерные блоки через
#include, что обеспечивает единый и централизованный подход
к повторному использованию функций.
Использование Shader Include позволяет:
Благодаря этому подходу Babylon.js становится удобным инструментом для разработки как простых эффектов, так и сложных визуальных систем с большим количеством материалов и шейдеров.