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 (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.
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.
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 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.
#version 300 es
precision mediump float;
in vec2 vTexCoord;
uniform sampler2D uTexture;
out vec4 fragColor;
void main() {
fragColor = texture(uTexture, vTexCoord);
}
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.
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.
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).
// 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);
}
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 — 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ę.
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.
| Metoda | Opis | Zysk |
|---|---|---|
| Mediump precision | 16-bitowa precyzja zamiast 32-bitowej | Do 2x szybkości |
| Early-Z | Test głębi przed shaderem | Redukcja wywołań |
| Texture atlasing | Jedna tekstura zamiast kilku | Mniej przełączeń |
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ń.
| Parametr | Fragment Shader | Vertex Shader |
|---|---|---|
| Liczba wywołań | Miliony (rozdzielczość ekranu) | Tysiące (liczba wierzchołków) |
| Dane wejściowe | Interpolowane atrybuty | Atrybuty wierzchołków |
| Główna funkcja | Obliczanie koloru fragmentu | Transformacja geometrii |
| Dostęp do tekstur | Pełny (wiele samplerów) | Ograniczony |
| Wpływ na wydajność | Wysoki (zależy od rozdzielczości) | Umiarkowany (zależy od geometrii) |
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.
#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;
}
Często zadawane pytania
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.
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.
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.
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.
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
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.
Przeczytaj również