В WebGL и, соответственно, в
Three.js, для передачи данных между JavaScript и
шейдерами используются три ключевых концепта: uniform,
attribute и varying. Каждый из них имеет свою
область применения и особенности взаимодействия с графическим
конвейером. Понимание этих терминов критически важно для работы с
кастомными материалами, шейдерами и эффектами.
Uniform — это глобальная переменная, доступная и в
вершинном, и в фрагментном шейдере. Она не изменяется для
отдельных вершин или фрагментов в рамках одного рендера, а
задаётся извне через JavaScript. Основное назначение
uniform — передача данных, которые одинаковы для всей
геометрии объекта в конкретный момент времени.
Примеры использования:
modelViewMatrix, projectionMatrix.Синтаксис в GLSL:
uniform mat4 modelViewMatrix;
uniform vec3 lightDirection;
uniform sampler2D diffuseMap;
В Three.js передача данных осуществляется через объект
uniforms в ShaderMaterial:
const material = new THREE.ShaderMaterial({
uniforms: {
uTime: { value: 0.0 },
uColor: { value: new THREE.Color(0xff0000) }
},
vertexShader: vertexShaderCode,
fragmentShader: fragmentShaderCode
});
Изменение uniform в процессе анимации:
material.uniforms.uTime.value += 0.01;
Attribute — это переменная, специфичная для каждой вершины. Она изменяется для каждой отдельной вершины и позволяет передавать в шейдер уникальные данные о геометрии. Attributes являются основным способом передачи информации о позиции, нормалях, цвете, текстурных координатах и любых других пользовательских данных.
GLSL синтаксис:
attribute vec3 position;
attribute vec3 normal;
attribute vec2 uv;
Three.js автоматически связывает стандартные атрибуты
(position, normal, uv) с данными
геометрии. Для кастомных атрибутов используется
BufferAttribute:
const geometry = new THREE.BufferGeometry();
const vertices = new Float32Array([
0, 0, 0,
1, 0, 0,
0, 1, 0
]);
geometry.setAttribute('position', new THREE.BufferAttribute(vertices, 3));
const colors = new Float32Array([
1, 0, 0,
0, 1, 0,
0, 0, 1
]);
geometry.setAttribute('color', new THREE.BufferAttribute(colors, 3));
В шейдере эти атрибуты можно использовать для расчёта позиции или
передачи данных во фрагментный шейдер через varying.
Varying — это переменная, используемая для передачи данных из вершинного шейдера во фрагментный. Она интерполируется автоматически по поверхности примитивов, обеспечивая плавное изменение значений между вершинами треугольника.
Примеры применения:
Синтаксис в GLSL:
// В вершинном шейдере
varying vec3 vColor;
void main() {
vColor = color; // attribute color
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
// Во фрагментном шейдере
varying vec3 vColor;
void main() {
gl_FragColor = vec4(vColor, 1.0);
}
Ключевой момент: varying не задаётся извне, оно
вычисляется в вершинном шейдере и доступно во фрагментном уже как
интерполированное значение.
Attribute → Varying → Fragment Shader Атрибуты
определяют индивидуальные свойства вершин. Эти свойства можно
интерполировать с помощью varying для корректного
отображения на поверхности примитива.
Uniform → Vertex/Fragment Shader Глобальные константы задаются через uniform и могут использоваться на любом этапе шейдера, например, для управления временем, цветом освещения, коэффициентами деформации.
Пример совместного использования:
// Вершинный шейдер
uniform float uTime;
attribute vec3 position;
attribute vec3 color;
varying vec3 vColor;
void main() {
vec3 pos = position + sin(uTime) * 0.5;
vColor = color;
gl_Position = projectionMatrix * modelViewMatrix * vec4(pos, 1.0);
}
// Фрагментный шейдер
varying vec3 vColor;
void main() {
gl_FragColor = vec4(vColor, 1.0);
}
Эффективное понимание и сочетание uniform, attribute и varying позволяет создавать сложные визуальные эффекты в Three.js, управлять геометрией и материалами на уровне шейдеров, а также реализовывать динамические и интерактивные сцены с точным контролем над визуальными параметрами.