Fragment Shader — е програмируем етап от графичния конвейер, който определя крайния цвят на всеки фрагмент (пиксел) от изображението. Според данни на Khronos Group, 2025, фрагментният шейдър получава интерполирани данни от Vertex Shader и извършва изчисления на осветление, текстуриране и цветови ефекти. Fragment Shader се извиква за всеки пиксел, което го прави най-ресурсоемкият етап от графичния конвейер.
Основни моменти
Fragment Shader (фрагментен или пикселен шейдър) — е програмируем етап от графичния конвейер, който изчислява крайния цвят на всеки фрагмент от изображението. Фрагментът е потенциален пиксел, който след преминаване на тестовете за дълбочина и шаблон става видим пиксел на екрана.
Fragment Shader се изпълнява след растеризация, когато триизмерните примитиви (триъгълници) вече са преобразувани в набор от фрагменти. Шейдърът на входа получава интерполирани атрибути — текстурни координати, нормали, цветове, които са изчислени във Vertex Shader за върховете на триъгълника и линейно интерполирани за всеки пиксел вътре в него.
Преди появата на програмируеми шейдъри (преди DirectX 8 / OpenGL 2.0) изчисляването на цвета на пиксела се извършваше от фиксиран конвейер с ограничен набор от операции. Програмируемият Fragment Shader се появи през 2001 г. и радикално разшири графичните възможности: разработчиците получиха пълен контрол над цвета на всеки пиксел, което позволи реализирането на фотореалистично осветление, сложни материали и пост-ефекти.
Fragment Shader се стартира от GPU за всеки фрагмент, генериран от растеризатора. Всяко извикване на шейдъра обработва един фрагмент, чете входните му данни, изпълнява потребителския код и записва изходната стойност — цвета на фрагмента във формат RGBA.
Входните данни на Fragment Shader включват интерполирани атрибути от Vertex Shader (текстурни координати, нормали, цветове), uniform променливи (източници на светлина, матрици) и текстурни семплери. Изходните данни — вектор на цвета (gl_FragColor в OpenGL ES 2.0 или потребителска променлива в ES 3.0), който се записва в цветовия буфер.
#version 300 es
precision mediump float;
in vec2 vTexCoord;
uniform sampler2D uTexture;
out vec4 fragColor;
void main() {
fragColor = texture(uTexture, vTexCoord);
}
Fragment Shader отговаря за визуалното качество на изображението. Всички ефекти, които потребителят вижда на екрана — цвят, сенки, отражения, прозрачност — се изчисляват точно в този етап на графичния конвейер.
Най-честата операция — вземане на цвят от текстура по интерполирани UV координати. Sampler2D и функцията texture() позволяват получаване на цвета на пиксела от текстурен атлас. Филтрацията (билинейна, трилинейна, анизотропна) се контролира чрез параметри на семплера и влияе върху рязкостта на изображението при различни ъгли на гледане.
Моделът на осветление по Фонг (Phong shading) се изчислява във Fragment Shader за всеки пиксел, което дава по-гладки отблясъци от върховото осветление (Gouraud shading). Phong lighting включва три компонента: ambient (фоново), diffuse (разсеяно) и specular (огледално отражение).
// Фрагментен шейдър с осветление по Фонг
in vec3 vNormal;
in vec3 vPosition;
uniform vec3 uLightDir;
uniform vec3 uLightColor;
void main() {
vec3 norm = normalize(vNormal);
float diff = max(dot(norm, uLightDir), 0.0);
fragColor = vec4(uLightColor * diff, 1.0);
}
Fragment Shader позволява прилагане на пост-обработка: цветокорекция чрез LUT таблици, размазване (blur), ефект на сияние (bloom) и tonemapping за HDR рендиране. Всички тези ефекти работят на ниво пиксели и се изпълняват в реално време.
Производителността на Fragment Shader — основният фактор, ограничаващ FPS в съвременните мобилни игри. Тъй като шейдърът се извиква за всеки пиксел, дори малко увеличение на сложността на кода може да доведе до забележим спад на честотата на кадрите.
За мобилни GPU (Qualcomm Adreno, ARM Mali) се препоръчва: използване на mediump precision за float променливи, комбиниране на извличания от текстури, прилагане на early-z тестове за отхвърляне на невидими фрагменти преди изпълнението на шейдъра.
| Метод | Описание | Печалба |
|---|---|---|
| Mediump precision | 16-битова точност вместо 32-битова | До 2x скорост |
| Early-Z | Тест за дълбочина преди шейдъра | Намаляване на извикванията |
| Texture atlasing | Една текстура вместо няколко | По-малко превключвания |
И двата типа шейдъри се програмират от разработчика, но работят на различни етапи на конвейера и решават различни задачи. Fragment Shader е значително по-ресурсоемък поради броя на извикванията.
| Параметър | Fragment Shader | Vertex Shader |
|---|---|---|
| Брой извиквания | Милиони (разделителна способност на екрана) | Хиляди (брой върхове) |
| Входни данни | Интерполирани атрибути | Атрибути на върхове |
| Основна функция | Изчисляване на цвета на фрагмента | Трансформация на геометрията |
| Достъп до текстури | Пълен (множество семплери) | Ограничен |
| Влияние върху производителността | Високо (зависи от разделителната способност) | Умерено (зависи от геометрията) |
Fragment Shader може да бъде прост (извличане от текстура) или сложен (многослойно осветление). Нека разгледаме два практически примера: базово текстуриране и ефект на градиент с използване на време.
#version 300 es
precision mediump float;
in vec2 vTexCoord;
in vec3 vColor;
uniform sampler2D uDiffuseMap;
out vec4 fragColor;
void main() {
vec4 texColor = texture(uDiffuseMap, vTexCoord);
fragColor = texColor * vec4(vColor, 1.0);
}
#include <metal_stdlib>
using namespace metal;
struct FragmentIn {
float2 texCoord;
float3 normal;
};
fragment float4
fragmentMain(FragmentIn in [[stage_in]],
texture2d<float> tex [[texture(0)]]) {
constexpr sampler s(filter = linear);
float4 color = tex.sample(s, in.texCoord);
return color;
}
Често задавани въпроси
Fragment Shader — е мини-програма на GPU, която определя какъв цвят ще бъде всеки пиксел на екрана. Ако Vertex Shader определя формата на обекта, то Fragment Shader определя как този обект изглежда — текстура, осветление, цвят.
Fragment Shader се извиква за всеки пиксел на екрана. На устройство с разделителна способност 2532x1170 (iPhone) това са почти 3 милиона извиквания на кадър. При 60 FPS шейдърът се изпълнява 180 милиона пъти в секунда, което изисква огромна изчислителна мощност.
Във Fragment Shader се реализират: текстуриране, осветление (Phong, PBR), сенки, отражения, пречупвания, bloom, дълбочина на рязкост, цветокорекция, LUT филтри и процедурно генериране на текстури.
Използвайте mediump precision за float, намалете броя на извличанията от текстури, прилагайте early-z отхвърляне, комбинирайте шейдърни операции и избягвайте условни преходи вътре в шейдъра.
Това е едно и също нещо. Терминът Fragment Shader се използва в OpenGL / Vulkan, а Pixel Shader — в терминологията на Direct3D (Microsoft). Функционално са идентични: и двата изчисляват цвета на всеки фрагмент/пиксел.
Резюме
Ще разработим мобилно приложение под ключ
IT Sectr създава iOS и Android приложения за стартъпи и бизнеси от 2017 г. Ще ви консултираме и ще предложим най-доброто решение.
Прочетете също