Вершинный шейдер (vertex shader) выполняется для каждой
вершины объекта и отвечает за преобразование её позиции, нормалей и
других атрибутов перед передачей на этап растеризации. Основная задача
вершинного шейдера — определить координаты вершин в пространстве
экрана, а также подготовить данные для последующей работы
фрагментного шейдера.
Преобразование координат Для каждой вершины используется матрица модели, вида и проекции:
gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(position, 1.0);
Здесь position — локальные координаты вершины, а
итоговая gl_Position определяет её положение на
экране.
Передача атрибутов Вершинный шейдер может
передавать фрагментному шейдеру любые данные через varying
(GLSL 1.0) или out (GLSL 3.0), например цвета, нормали или
UV-координаты:
varying vec3 vNormal;
void main() {
vNormal = normalMatrix * normal;
gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(position, 1.0);
}
Здесь vNormal используется для расчёта освещения в
фрагментном шейдере.
Динамические эффекты Вершинный шейдер позволяет реализовывать эффекты деформации: колебания вершин, волны, анимацию скелета, морфинг. Например, простая волна по оси Y:
vec3 pos = position;
pos.y += sin(time + position.x) * 0.5;
gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(pos, 1.0);Фрагментный шейдер (fragment shader) отвечает за
определение окрашивания каждого пикселя, который
попадает в область, образованную треугольниками. Здесь вычисляется цвет,
прозрачность, освещённость и любые визуальные эффекты поверхности.
Расчёт цвета Цвет пикселя может определяться как текстурой, так и результатом освещения:
varying vec3 vNormal;
uniform vec3 lightDir;
void main() {
float intensity = max(dot(normalize(vNormal), normalize(lightDir)), 0.0);
vec3 color = vec3(1.0, 0.5, 0.2) * intensity;
gl_FragColor = vec4(color, 1.0);
}
Здесь vNormal — нормаль, полученная из вершинного
шейдера, а lightDir — направление источника света.
Работа с текстурами Использование
sampler2D позволяет накладывать текстуры:
uniform sampler2D map;
varying vec2 vUv;
void main() {
vec4 texColor = texture2D(map, vUv);
gl_FragColor = texColor;
}Постобработка и эффекты Фрагментный шейдер используется для эффектов, таких как размытие, свечения, fog, ambient occlusion. Например, простое затемнение по глубине:
varying float vDepth;
void main() {
float fog = smoothstep(5.0, 50.0, vDepth);
vec3 baseColor = vec3(0.8, 0.3, 0.1);
gl_FragColor = vec4(baseColor * (1.0 - fog), 1.0);
}Вершинный и фрагментный шейдеры тесно связаны через передаваемые данные. Основные принципы:
Varying-переменные Данные, рассчитанные в вершинном шейдере, интерполируются по поверхности треугольника и передаются во фрагментный шейдер:
varying vec3 vNormal;
void main() {
vNormal = normalMatrix * normal;
gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(position, 1.0);
}
Фрагментный шейдер получает интерполированные значения для каждого пикселя.
Единая логика освещения Вершинный шейдер отвечает за нормали и позиции вершин, фрагментный — за финальный цвет с учётом этих данных. Это позволяет реализовать Phong, Blinn-Phong или PBR освещение.
Оптимизация Часть вычислений можно делать в вершинном шейдере для уменьшения нагрузки на фрагментный, но слишком грубые приближения могут привести к заметной дискретизации на поверхности.
В Three.js вершинный и фрагментный шейдеры задаются через
ShaderMaterial:
const material = new THREE.ShaderMaterial({
vertexShader: vertexShaderSource,
fragmentShader: fragmentShaderSource,
uniforms: {
time: { value: 0.0 },
lightDir: { value: new THREE.Vector3(1, 1, 1) }
}
});
vertexShaderSource — строка с GLSL
кодом вершинного шейдера.fragmentShaderSource — строка с GLSL
кодом фрагментного шейдера.uniforms — глобальные переменные,
доступные в обоих шейдерах.Использование ShaderMaterial позволяет полностью
контролировать рендеринг, создавая уникальные визуальные эффекты и
динамику геометрии.
В совокупности, вершинные и фрагментные шейдеры дают полный контроль над визуальной составляющей 3D-сцены, позволяя создавать как реалистичные, так и стилизованные эффекты.