Fragment Shader — какво е, задачи и принцип на работа

Автор: IT Sectr Публикувано: 2026-06-11 Време за четене: 10 мин

Fragment Shader — е програмируем етап от графичния конвейер, който определя крайния цвят на всеки фрагмент (пиксел) от изображението. Според данни на Khronos Group, 2025, фрагментният шейдър получава интерполирани данни от Vertex Shader и извършва изчисления на осветление, текстуриране и цветови ефекти. Fragment Shader се извиква за всеки пиксел, което го прави най-ресурсоемкият етап от графичния конвейер.

Основни моменти

  • Fragment Shader — програмируем етап на GPU, определящ цвета на всеки пиксел на екрана.
  • Броят на извикванията е равен на разделителната способност на екрана, което го прави основното изчислително натоварване на рендирането.
  • Текстуриране и осветление по Фонг — типични задачи, реализирани във фрагментния шейдър.
  • GLSL и Metal Shading Language предоставят стандартни средства за писане на Fragment Shader.
  • Производителността на Fragment Shader е критична за постигане на 60 FPS в мобилните приложения.

Какво е Fragment Shader?

Fragment Shader (фрагментен или пикселен шейдър) — е програмируем етап от графичния конвейер, който изчислява крайния цвят на всеки фрагмент от изображението. Фрагментът е потенциален пиксел, който след преминаване на тестовете за дълбочина и шаблон става видим пиксел на екрана.

Fragment Shader се изпълнява след растеризация, когато триизмерните примитиви (триъгълници) вече са преобразувани в набор от фрагменти. Шейдърът на входа получава интерполирани атрибути — текстурни координати, нормали, цветове, които са изчислени във Vertex Shader за върховете на триъгълника и линейно интерполирани за всеки пиксел вътре в него.

История на еволюцията на Fragment Shader

Преди появата на програмируеми шейдъри (преди DirectX 8 / OpenGL 2.0) изчисляването на цвета на пиксела се извършваше от фиксиран конвейер с ограничен набор от операции. Програмируемият Fragment Shader се появи през 2001 г. и радикално разшири графичните възможности: разработчиците получиха пълен контрол над цвета на всеки пиксел, което позволи реализирането на фотореалистично осветление, сложни материали и пост-ефекти.

Как работи Fragment Shader?

Fragment Shader се стартира от GPU за всеки фрагмент, генериран от растеризатора. Всяко извикване на шейдъра обработва един фрагмент, чете входните му данни, изпълнява потребителския код и записва изходната стойност — цвета на фрагмента във формат RGBA.

Входни и изходни данни

Входните данни на Fragment Shader включват интерполирани атрибути от Vertex Shader (текстурни координати, нормали, цветове), uniform променливи (източници на светлина, матрици) и текстурни семплери. Изходните данни — вектор на цвета (gl_FragColor в OpenGL ES 2.0 или потребителска променлива в ES 3.0), който се записва в цветовия буфер.

glsl
#version 300 es
precision mediump float;

in vec2 vTexCoord;
uniform sampler2D uTexture;
out vec4 fragColor;

void main() {
    fragColor = texture(uTexture, vTexCoord);
}

Основни задачи на Fragment Shader

Fragment Shader отговаря за визуалното качество на изображението. Всички ефекти, които потребителят вижда на екрана — цвят, сенки, отражения, прозрачност — се изчисляват точно в този етап на графичния конвейер.

Текстуриране

Най-честата операция — вземане на цвят от текстура по интерполирани UV координати. Sampler2D и функцията texture() позволяват получаване на цвета на пиксела от текстурен атлас. Филтрацията (билинейна, трилинейна, анизотропна) се контролира чрез параметри на семплера и влияе върху рязкостта на изображението при различни ъгли на гледане.

Осветление по Фонг

Моделът на осветление по Фонг (Phong shading) се изчислява във Fragment Shader за всеки пиксел, което дава по-гладки отблясъци от върховото осветление (Gouraud shading). Phong lighting включва три компонента: ambient (фоново), diffuse (разсеяно) и specular (огледално отражение).

glsl
// Фрагментен шейдър с осветление по Фонг
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);
}

Пост-ефекти и blending

Fragment Shader позволява прилагане на пост-обработка: цветокорекция чрез LUT таблици, размазване (blur), ефект на сияние (bloom) и tonemapping за HDR рендиране. Всички тези ефекти работят на ниво пиксели и се изпълняват в реално време.

Производителност на Fragment Shader и оптимизация

Производителността на Fragment Shader — основният фактор, ограничаващ FPS в съвременните мобилни игри. Тъй като шейдърът се извиква за всеки пиксел, дори малко увеличение на сложността на кода може да доведе до забележим спад на честотата на кадрите.

Основни проблеми с производителността

  • Overdraw — повторно рисуване на един и същ пиксел поради припокриване на обекти. Особено критично за полупрозрачни обекти.
  • Условни преходи — разклонения във Fragment Shader намаляват ефективността на SIMD изпълнението, тъй като GPU трябва да изпълни и двата клона.
  • Извличания от текстури — всяко извличане на текстура (texture lookup) има закъснение от десетки цикъла на GPU. Минимизирането на броя на семплерите ускорява шейдъра.

Методи за оптимизация на Fragment Shader

За мобилни GPU (Qualcomm Adreno, ARM Mali) се препоръчва: използване на mediump precision за float променливи, комбиниране на извличания от текстури, прилагане на early-z тестове за отхвърляне на невидими фрагменти преди изпълнението на шейдъра.

МетодОписаниеПечалба
Mediump precision16-битова точност вместо 32-битоваДо 2x скорост
Early-ZТест за дълбочина преди шейдъраНамаляване на извикванията
Texture atlasingЕдна текстура вместо няколкоПо-малко превключвания

Fragment Shader vs Vertex Shader: сравнение

И двата типа шейдъри се програмират от разработчика, но работят на различни етапи на конвейера и решават различни задачи. Fragment Shader е значително по-ресурсоемък поради броя на извикванията.

ПараметърFragment ShaderVertex Shader
Брой извикванияМилиони (разделителна способност на екрана)Хиляди (брой върхове)
Входни данниИнтерполирани атрибутиАтрибути на върхове
Основна функцияИзчисляване на цвета на фрагментаТрансформация на геометрията
Достъп до текстуриПълен (множество семплери)Ограничен
Влияние върху производителносттаВисоко (зависи от разделителната способност)Умерено (зависи от геометрията)

Примери за код на Fragment Shader

Fragment Shader може да бъде прост (извличане от текстура) или сложен (многослойно осветление). Нека разгледаме два практически примера: базово текстуриране и ефект на градиент с използване на време.

Базово текстуриране на GLSL

glsl
#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);
}

Пример на Metal Shading Language

cpp
#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 с прости думи?

Fragment Shader — е мини-програма на GPU, която определя какъв цвят ще бъде всеки пиксел на екрана. Ако Vertex Shader определя формата на обекта, то Fragment Shader определя как този обект изглежда — текстура, осветление, цвят.

Защо Fragment Shader е толкова ресурсоемък?

Fragment Shader се извиква за всеки пиксел на екрана. На устройство с разделителна способност 2532x1170 (iPhone) това са почти 3 милиона извиквания на кадър. При 60 FPS шейдърът се изпълнява 180 милиона пъти в секунда, което изисква огромна изчислителна мощност.

Какви ефекти могат да се направят във Fragment Shader?

Във Fragment Shader се реализират: текстуриране, осветление (Phong, PBR), сенки, отражения, пречупвания, bloom, дълбочина на рязкост, цветокорекция, LUT филтри и процедурно генериране на текстури.

Как да оптимизираме Fragment Shader на мобилни устройства?

Използвайте mediump precision за float, намалете броя на извличанията от текстури, прилагайте early-z отхвърляне, комбинирайте шейдърни операции и избягвайте условни преходи вътре в шейдъра.

Каква е разликата между Fragment Shader и Pixel Shader?

Това е едно и също нещо. Терминът Fragment Shader се използва в OpenGL / Vulkan, а Pixel Shader — в терминологията на Direct3D (Microsoft). Функционално са идентични: и двата изчисляват цвета на всеки фрагмент/пиксел.

Резюме

  • Fragment Shader — програмируем етап на GPU, изчисляващ цвета на всеки пиксел от изображението.
  • Броят на извикванията е равен на разделителната способност на екрана, което го прави най-ресурсоемкия етап на рендиране.
  • Текстуриране, осветление по Фонг и пост-ефекти — основните задачи на фрагментния шейдър.
  • Производителността пряко зависи от броя на извличанията от текстури и използването на highp precision.
  • Mediump precision и early-z тестове — ключови техники за оптимизация за мобилни GPU.
  • OpenGL ES използва термина Fragment Shader, Direct3D — Pixel Shader, същността е една и съща.
  • GLSL и Metal Shading Language — основните езици за писане на Fragment Shader в мобилната разработка.

Ще разработим мобилно приложение под ключ

IT Sectr създава iOS и Android приложения за стартъпи и бизнеси от 2017 г. Ще ви консултираме и ще предложим най-доброто решение.

Обсъдете проекта

Прочетете също