Fragment Shader — co to jest, zadania i zasada działania

Autor: IT Sectr Opublikowano: 2026-06-11 Czas czytania: 10 min

Fragment Shader — to programowalny etap potoku graficznego, który określa końcowy kolor każdego fragmentu (piksela) obrazu. Według danych Khronos Group, 2025, shader fragmentów otrzymuje interpolowane dane z Vertex Shader i wykonuje obliczenia oświetlenia, teksturowania i efektów kolorystycznych. Fragment Shader jest wywoływany dla każdego piksela, co czyni go najbardziej zasobożernym etapem potoku graficznego.

Najważniejsze

  • Fragment Shader — programowalny etap GPU, określający kolor każdego piksela na ekranie.
  • Liczba wywołań jest równa rozdzielczości ekranu, co czyni go głównym obciążeniem obliczeniowym renderowania.
  • Teksturowanie i oświetlenie Phonga — typowe zadania realizowane w shaderze fragmentów.
  • GLSL i Metal Shading Language zapewniają standardowe narzędzia do pisania Fragment Shader.
  • Wydajność Fragment Shader jest krytyczna dla osiągnięcia 60 FPS w aplikacjach mobilnych.

Co to jest Fragment Shader?

Fragment Shader (shader fragmentów lub pikseli) — to programowalny etap potoku graficznego, który oblicza końcowy kolor każdego fragmentu obrazu. Fragment to potencjalny piksel, który po przejściu testów głębi i szablonu staje się widocznym pikselem na ekranie.

Fragment Shader jest wykonywany po rasteryzacji, gdy trójwymiarowe prymitywy (trójkąty) zostały już przekształcone w zestaw fragmentów. Na wejściu shader otrzymuje interpolowane atrybuty — współrzędne tekstury, normalne, kolory, które zostały obliczone w Vertex Shader dla wierzchołków trójkąta i liniowo interpolowane dla każdego piksela wewnątrz niego.

Historia ewolucji Fragment Shader

Przed pojawieniem się programowalnych shaderów (przed DirectX 8 / OpenGL 2.0) obliczanie koloru piksela było wykonywane przez stały potok z ograniczonym zestawem operacji. Programowalny Fragment Shader pojawił się w 2001 roku i radykalnie rozszerzył możliwości grafiki: programiści otrzymali pełną kontrolę nad kolorem każdego piksela, co pozwoliło na realizację fotorealistycznego oświetlenia, złożonych materiałów i efektów końcowych.

Jak działa Fragment Shader?

Fragment Shader jest uruchamiany przez GPU dla każdego fragmentu wygenerowanego przez rasteryzator. Każde wywołanie shadera przetwarza jeden fragment, odczytuje jego dane wejściowe, wykonuje kod użytkownika i zapisuje wartość wyjściową — kolor fragmentu w formacie RGBA.

Dane wejściowe i wyjściowe

Dane wejściowe Fragment Shader obejmują interpolowane atrybuty z Vertex Shader (współrzędne tekstury, normalne, kolory), zmienne uniform (źródła światła, macierze) i samplery tekstur. Dane wyjściowe — wektor koloru (gl_FragColor w OpenGL ES 2.0 lub zmienna użytkownika w ES 3.0), który jest zapisywany do bufora koloru.

glsl
#version 300 es
precision mediump float;

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

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

Główne zadania Fragment Shader

Fragment Shader odpowiada za wizualną jakość obrazu. Wszystkie efekty, które użytkownik widzi na ekranie — kolor, cienie, odbicia, przezroczystość — są obliczane właśnie na tym etapie potoku graficznego.

Teksturowanie

Najczęstsza operacja — pobieranie koloru z tekstury według interpolowanych współrzędnych UV. Sampler2D i funkcja texture() pozwalają uzyskać kolor piksela z atlasu tekstur. Filtracja (bilinearna, trójliniowa, anizotropowa) jest kontrolowana przez parametry samplera i wpływa na ostrość obrazu przy różnych kątach widzenia.

Oświetlenie Phonga

Model oświetlenia Phonga (Phong shading) jest obliczany we Fragment Shader dla każdego piksela, co daje gładsze refleksy niż oświetlenie wierzchołkowe (Gouraud shading). Phong lighting obejmuje trzy składowe: ambient (otoczenia), diffuse (rozproszona) i specular (lustrzana).

glsl
// Shader fragmentów z oświetleniem Phonga
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);
}

Efekty końcowe i blending

Fragment Shader pozwala nakładać obróbkę końcową: korekcję kolorów przez tabele LUT, rozmycie (blur), efekt poświaty (bloom) i tonemapping dla renderowania HDR. Wszystkie te efekty działają na poziomie pikseli i są wykonywane w czasie rzeczywistym.

Wydajność Fragment Shader i optymalizacja

Wydajność Fragment Shader — główny czynnik ograniczający FPS w nowoczesnych grach mobilnych. Ponieważ shader jest wywoływany dla każdego piksela, nawet niewielkie zwiększenie złożoności kodu może prowadzić do zauważalnego spadku liczby klatek na sekundę.

Główne problemy wydajnościowe

  • Overdraw — ponowne rysowanie tego samego piksela z powodu nakładania się obiektów. Szczególnie krytyczny dla półprzezroczystych obiektów.
  • Rozgałęzienia warunkowe — gałęzie w Fragment Shader zmniejszają wydajność wykonywania SIMD, ponieważ GPU musi wykonać obie ścieżki.
  • Pobieranie z tekstur — każde pobranie tekstury (texture lookup) ma opóźnienie dziesiątek cykli GPU. Minimalizacja liczby samplerów przyspiesza shader.

Metody optymalizacji Fragment Shader

Dla mobilnych GPU (Qualcomm Adreno, ARM Mali) zaleca się: używanie mediump precision dla zmiennych float, łączenie pobrań tekstur, stosowanie testów early-z do odrzucania niewidocznych fragmentów przed wykonaniem shadera.

MetodaOpisZysk
Mediump precision16-bitowa precyzja zamiast 32-bitowejDo 2x szybkości
Early-ZTest głębi przed shaderemRedukcja wywołań
Texture atlasingJedna tekstura zamiast kilkuMniej przełączeń

Fragment Shader vs Vertex Shader: porównanie

Oba typy shaderów są programowane przez programistę, ale działają na różnych etapach potoku i rozwiązują różne zadania. Fragment Shader jest znacznie bardziej zasobożerny ze względu na liczbę wywołań.

ParametrFragment ShaderVertex Shader
Liczba wywołańMiliony (rozdzielczość ekranu)Tysiące (liczba wierzchołków)
Dane wejścioweInterpolowane atrybutyAtrybuty wierzchołków
Główna funkcjaObliczanie koloru fragmentuTransformacja geometrii
Dostęp do teksturPełny (wiele samplerów)Ograniczony
Wpływ na wydajnośćWysoki (zależy od rozdzielczości)Umiarkowany (zależy od geometrii)

Przykłady kodu Fragment Shader

Fragment Shader może być prosty (pobieranie z tekstury) lub złożony (wielowarstwowe oświetlenie). Rozważmy dwa praktyczne przykłady: podstawowe teksturowanie i efekt gradientu z użyciem czasu.

Podstawowe teksturowanie w 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);
}

Przykład w 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;
}

Często zadawane pytania

Co to jest Fragment Shader prostymi słowami?

Fragment Shader — to mini-program na GPU, który określa, jakiego koloru będzie każdy piksel na ekranie. Jeśli Vertex Shader określa kształt obiektu, to Fragment Shader określa, jak ten obiekt wygląda — tekstura, oświetlenie, kolor.

Dlaczego Fragment Shader jest tak zasobożerny?

Fragment Shader jest wywoływany dla każdego piksela na ekranie. Na urządzeniu z rozdzielczością 2532x1170 (iPhone) to prawie 3 miliony wywołań na klatkę. Przy 60 FPS shader wykonuje się 180 milionów razy na sekundę, co wymaga ogromnej mocy obliczeniowej.

Jakie efekty można zrobić w Fragment Shader?

We Fragment Shader realizuje się: teksturowanie, oświetlenie (Phong, PBR), cienie, odbicia, załamania, bloom, głębię ostrości, korekcję kolorów, filtry LUT i proceduralne generowanie tekstur.

Jak zoptymalizować Fragment Shader na urządzeniach mobilnych?

Używaj mediump precision dla float, zmniejsz liczbę pobrań tekstur, stosuj odrzucanie early-z, łącz operacje shadera i unikaj rozgałęzień warunkowych wewnątrz shadera.

Czym różni się Fragment Shader od Pixel Shader?

To to samo. Termin Fragment Shader jest używany w OpenGL / Vulkan, a Pixel Shader — w terminologii Direct3D (Microsoft). Funkcjonalnie są identyczne: oba obliczają kolor każdego fragmentu/piksela.

Podsumowanie

  • Fragment Shader — programowalny etap GPU, obliczający kolor każdego piksela obrazu.
  • Liczba wywołań jest równa rozdzielczości ekranu, co czyni go najbardziej zasobożernym etapem renderowania.
  • Teksturowanie, oświetlenie Phonga i efekty końcowe — główne zadania shadera fragmentów.
  • Wydajność bezpośrednio zależy od liczby pobrań tekstur i użycia highp precision.
  • Mediump precision i testy early-z — kluczowe techniki optymalizacji dla mobilnych GPU.
  • OpenGL ES używa terminu Fragment Shader, Direct3D — Pixel Shader, istota ta sama.
  • GLSL i Metal Shading Language — główne języki do pisania Fragment Shader w tworzeniu aplikacji mobilnych.

Opracujemy aplikację mobilną pod klucz

IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.

Omów projekt

Przeczytaj również