В Three.js uniform — это глобальная
переменная шейдера, значение которой задаётся на стороне JavaScript и
может быть использовано в вершинных и фрагментных шейдерах GLSL. В
отличие от атрибутов (attribute), uniform не изменяется для
каждой вершины, а остаётся постоянным на всю отрисовку
примитива. Это делает uniform идеальным инструментом для
передачи данных, таких как матрицы трансформации, цвета, текстуры и
параметры освещения.
Пример базового объявления uniform в GLSL:
uniform float time;
uniform vec3 lightPosition;
uniform sampler2D textureMap;
В JavaScript эти uniform устанавливаются через объект
uniforms материала:
const material = new THREE.ShaderMaterial({
uniforms: {
time: { value: 0.0 },
lightPosition: { value: new THREE.Vector3(10, 10, 10) },
textureMap: { value: myTexture }
},
vertexShader: vertexShaderSource,
fragmentShader: fragmentShaderSource
});
Three.js предоставляет набор встроенных uniform, которые автоматически передаются в шейдер и позволяют ускорить разработку и унифицировать работу с объектами. Основные категории:
Использование в вершинном шейдере:
vec4 mvPosition = modelViewMatrix * vec4(position, 1.0);
gl_Position = projectionMatrix * mvPosition;
Пример для вычисления вектора от фрагмента к камере:
vec3 viewDir = normalize(cameraPosition - worldPosition);
Three.js автоматически поддерживает uniform для всех стандартных
источников света, если используется MeshStandardMaterial
или MeshPhongMaterial с включёнными светильниками:
Использование этих uniform позволяет создавать шейдеры, которые интегрируются с системой освещения Three.js без ручной передачи всех параметров света.
Three.js включает встроенные uniform для стандартных карт материала:
diffuseMap).Пример использования в фрагментном шейдере:
uniform sampler2D map;
varying vec2 vUv;
void main() {
vec4 texColor = texture2D(map, vUv);
gl_FragColor = texColor;
}
Для создания анимаций часто используются:
Пример динамической анимации:
material.uniforms.time.value = clock.getElapsedTime();
В шейдере можно использовать для смещения вершин:
position.y += sin(position.x + time) * 0.5;
Uniform можно обновлять в реальном времени без пересоздания
материала. Доступ к ним через объект uniforms:
material.uniforms.lightPosition.value.set(5, 10, 5);
material.uniforms.time.value += 0.01;
Особенность Three.js — каждый uniform должен быть объектом с
ключом value, даже если передаётся число или
вектор. Это связано с тем, что Three.js отслеживает ссылки на объекты и
автоматически обновляет GPU.
onBeforeCompile.Пример расширения стандартного материала:
material.onBeforeComp ile = (shader) => {
shader.uniforms.time = { value: 0 };
shader.fragmentShader = 'uniform float time;\n' + shader.fragmentShader;
};
Это позволяет интегрировать собственные эффекты в готовые материалы без переписывания шейдера полностью.
THREE.Vector3, THREE.Color) вместо создания
новых при каждом кадре.Встроенные uniform в Three.js позволяют создавать гибкие шейдеры, совместимые с камерой, светом и материалами без лишнего кода. Правильное понимание матриц, позиционирования камеры и типов света обеспечивает эффективное использование GPU и реалистичное отображение 3D-сцены. Uniform остаются ключевым инструментом для динамических эффектов, анимаций и интеграции пользовательских шейдеров в существующую систему Three.js.