В A-Frame шейдеры позволяют управлять визуальной обработкой
материалов объектов на низком уровне, предоставляя полный контроль над
цветом, освещением, текстурами и эффектами постобработки. Компонент
shader выступает интерфейсом для интеграции
пользовательских шейдеров, работающих поверх системы материалов
A-Frame.
Для использования собственного шейдера необходимо создать компонент, который укажет на GLSL-код вершинного и фрагментного шейдера. Структура подключения выглядит следующим образом:
AFRAME.registerShader('custom-shader', {
schema: {
color: { type: 'color', default: '#FFF' },
time: { type: 'time', default: 0 }
},
vertexShader: `
varying vec3 vPosition;
void main() {
vPosition = position;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`,
fragmentShader: `
uniform vec3 color;
uniform float time;
varying vec3 vPosition;
void main() {
gl_FragColor = vec4(abs(sin(time + vPosition.x)), color.g, color.b, 1.0);
}
`
});
Ключевые моменты:
schema задаёт параметры шейдера, доступные для
изменения через HTML-атрибуты.vertexShader отвечает за преобразование вершин и
передачу данных в фрагментный шейдер.fragmentShader определяет окончательный цвет
пикселя.После регистрации шейдера его можно применять к объектам через
атрибут material:
<a-box material="shader: custom-shader; color: #FF0000"></a-box>
Uniform-переменные обеспечивают передачу динамических данных из JavaScript в GLSL. Их можно обновлять через компонент или через анимации A-Frame:
AFRAME.registerComponent('animate-shader', {
tick: function (time) {
this.el.getObject3D('mesh').material.uniforms.time.value = time / 1000;
}
});
Применение:
<a-box material="shader: custom-shader" animate-shader></a-box>
Особенности:
uniforms автоматически создаются для каждого свойства,
указанного в schema.uniforms возможен через объект материала
Three.js
(this.el.getObject3D('mesh').material.uniforms).A-Frame позволяет подключать текстуры к пользовательским шейдерам
через тип map в schema:
AFRAME.registerShader('texture-shader', {
schema: {
map: { type: 'map' }
},
vertexShader: `
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`,
fragmentShader: `
uniform sampler2D map;
varying vec2 vUv;
void main() {
gl_FragColor = texture2D(map, vUv);
}
`
});
HTML:
<a-plane material="shader: texture-shader; map: url(texture.png)"></a-plane>
Примечания:
map автоматически загружает изображение через
менеджер ресурсов A-Frame.varying.Для взаимодействия с освещением сцены используется встроенная
поддержка lights в Three.js. В шейдере можно добавлять
uniform-переменные для передачи нормалей и вычисления освещённости:
vertexShader: `
varying vec3 vNormal;
varying vec3 vPosition;
void main() {
vNormal = normalize(normalMatrix * normal);
vPosition = (modelViewMatrix * vec4(position, 1.0)).xyz;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`,
fragmentShader: `
uniform vec3 color;
varying vec3 vNormal;
varying vec3 vPosition;
void main() {
vec3 lightDir = normalize(vec3(1.0, 1.0, 1.0));
float diff = max(dot(vNormal, lightDir), 0.0);
gl_FragColor = vec4(color * diff, 1.0);
}
`
Особенности:
normalMatrix автоматически корректирует нормали при
трансформации объекта.С помощью параметров времени, координат и пользовательских uniform-переменных можно создавать эффекты анимации, такие как пульсация, деформация поверхности или цветовые градиенты. Например, волновая анимация поверхности:
vertexShader: `
uniform float time;
varying vec3 vNormal;
void main() {
vec3 pos = position;
pos.y += sin(pos.x * 2.0 + time) * 0.2;
vNormal = normal;
gl_Position = projectionMatrix * modelViewMatrix * vec4(pos, 1.0);
}
`
Особенности:
sin и time обеспечивает
циклические колебания.varying: Передача данных
между шейдерами через varying обеспечивает гибкость и
минимизирует повторения.AFRAME.registerShader('complex-shader', {
schema: {
time: { type: 'time' },
color1: { type: 'color', default: '#FF0000' },
color2: { type: 'color', default: '#0000FF' },
map: { type: 'map' }
},
vertexShader: `
uniform float time;
varying vec2 vUv;
varying float vWave;
void main() {
vUv = uv;
vec3 pos = position;
vWave = sin(pos.x * 5.0 + time) * 0.5;
pos.y += vWave;
gl_Position = projectionMatrix * modelViewMatrix * vec4(pos, 1.0);
}
`,
fragmentShader: `
uniform sampler2D map;
uniform vec3 color1;
uniform vec3 color2;
varying vec2 vUv;
varying float vWave;
void main() {
vec4 tex = texture2D(map, vUv);
vec3 mixColor = mix(color1, color2, abs(vWave));
gl_FragColor = vec4(tex.rgb * mixColor, 1.0);
}
`
});
Этот шейдер сочетает деформацию вершин, градиентное смешение цветов и текстурное наложение, демонстрируя возможности A-Frame по созданию интерактивных и динамических материалов.