Shader (shader) — egy program, amely a GPU-n fut grafikus adatok feldolgozására: csúcsok, fragmentumok vagy számítási feladatok. Ellentétben a CPU-n futó hagyományos kóddal, a shader párhuzamosan működik több száz magon, minden elemet függetlenül feldolgozva. A Khronos Group (2025) adatai szerint a shadereket a modern 3D alkalmazások 100%-ában használják — a mobilos játékoktól a rendszeralkalmazások UI effektusaiig. A fejlesztők speciális nyelveken írják a shadereket: GLSL, HLSL, Metal Shading Language vagy SPIR-V.
Főbb pontok
Shader — egy kicsi program, amely speciális nyelven íródott és a GPU-n fut. Minden shader egy adatelemet — egy csúcsot, fragmentumot (pixelt) vagy munkaelemet — dolgoz fel függetlenül a többitől. A GPU párhuzamossága lehetővé teszi több ezer shader példány egyidejű futtatását.
A kifejezést a Pixar vezette be az 1980-as években a RenderMan felületek megjelenését vezérlő programok leírására. Valós időben a shaderek az NVIDIA GeForce 3-mal (2001) jelentek meg — az első programozható pipeline-nal rendelkező videokártyával. A shaderek előtt a grafikát rögzített paraméterekkel konfigurálták: szín, textúra, keverési mód.
A Unity Technologies (2025) adatai szerint egy átlagos mobiljáték 50–200 shadert használ. Minden shader variánsokkal (variants) rendelkezik különböző platformokhoz, minőségi szintekhez és megvilágítási konfigurációkhoz. A variánsok száma elérheti a 10 000-et projektenként.
A shader architektúrája bemeneti adatokra (attribútumok, uniform változók, textúrák), programkódra és kimeneti adatokra (szín, pozíció) oszlik. Az uniform változók a CPU-ról kerülnek beállításra a shader indítása előtt, és változatlanok maradnak a képkocka összes elemére. Az attribútumok elemenkénti adatok (csúcskoordináták, normális, UV koordináták).
SIMT (Single Instruction, Multiple Threads) — a shaderek végrehajtási modellje GPU-n. Egy utasítás egyszer kerül betöltésre, de több száz szál hajtja végre különböző adatokon. Például a Fragment Shader 1000 pixelhez 1000 szálat indít ugyanazzal a kóddal, de minden szál megkapja a saját UV koordinátáit és interpolált attribútumait.
A SIMT fontos következménye: az elágazások a shaderekben költségesek. Ha egy if blokkon belül a szálak fele az egyik ágra, fele a másikra megy, a GPU mindkét ágat szekvenciálisan hajtja végre az összes szálra. A teljesítmény 50%-ra csökken. Kerülje a dinamikus elágazásokat a shaderekben, vagy minimalizálja őket előzetes CPU-számításokkal.
A modern GPU-k több shader típust támogatnak, mindegyik a grafikus vagy számítási pipeline saját szakaszához. Tekintsük át a fő típusokat: vertex, fragment, compute és a modern mesh-shaderek.
| Shader típus | Pipeline szakasz | Feldolgoz | Nyelv |
|---|---|---|---|
| Vertex Shader | Csúcs | Minden csúcsot | GLSL, HLSL |
| Fragment Shader | Fragment | Minden pixelt | GLSL, HLSL |
| Compute Shader | Számítási | Tetszőleges adat | GLSL, HLSL |
| Geometry Shader | Geometriai | Prímítívek | GLSL, HLSL |
| Tessellation Shader | Tesszelláció | Patch-ek | GLSL, HLSL |
| Mesh Shader | Mesh pipeline | Task + Mesh | HLSL, MSL |
Vertex Shader feldolgozza a geometria minden csúcsát: transzformálja a koordinátákat, kiszámítja a megvilágítást, továbbítja az adatokat a fragment shadernek. Ez a grafikus pipeline kötelező szakasza — nélküle a csúcsok nem kerülnek a képernyőre. A Vertex Shader minden képkocka minden csúcsához meghívásra kerül.
Fragment Shader (vagy Pixel Shader) — a leginkább erőforrás-igényes szakasz. Kiszámítja minden fragmentum végső színét textúrák, megvilágítás és anyag segítségével. A Fragment Shader a geometria által lefedett minden pixelre végrehajtódik, figyelembe véve az összes alkalmazott textúrát és effektust. Ennek a shadernek az optimalizálása adja a legnagyobb teljesítménynövekedést.
Compute Shader — univerzális shader tetszőleges GPU-számításokhoz. Ellentétben a grafikus shaderekkel, nem kötődik geometriához vagy pixelekhez. A Compute Shader tetszőleges adatpufferokkal dolgozik munkacsoportokon keresztül. Fizikához, részecske-szimulációhoz, utóeffektusokhoz és neurális hálózatok inferenciájához használják.
Mesh Shader — a legújabb shader típus, amely az NVIDIA Turing (2018) és a Metal 3 megjelenésével jelent meg. A Mesh Shader egyetlen mesh pipeline-lal helyettesíti a vertex, geometriai és tesszellációs shadereket. A Task Shader-rel együtt működik: a Task Shader dönti el, mely mesh csoportok jelenjenek meg, a Mesh Shader menet közben generálja a geometriát.
A shadereket speciális nyelveken írják, amelyek GPU gépi kódra fordulnak. A nyelv kiválasztása a platformtól és API-tól függ. Tekintsük át a fő nyelveket: GLSL, HLSL, Metal Shading Language és a köztes SPIR-V formátum.
GLSL — a shader nyelve OpenGL, OpenGL ES és WebGL számára. Szintaxis a C-n alapul, vektor típusokkal (vec2, vec4, mat4) és beépített függvényekkel (texture, normalize, reflect) kiegészítve. GLSL ES — a mobil eszközökhöz készült verzió korlátozott pontossággal (lowp, mediump, highp). A Khronos (2025) adatai szerint a GLSL a cross-platform képességének köszönhetően a legelterjedtebb shader nyelv marad.
#version 300 es
precision mediump float;
in vec2 v_texCoord;
uniform sampler2D u_texture;
out vec4 fragColor;
void main() {
fragColor = texture(u_texture, v_texCoord);
}
Egy egyszerű fragment shader a textúrából olvassa ki a színt UV koordináták alapján. A precision mediump utasítja a GPU-t, hogy fele pontosságot használjon float-ra — 25–40%-kal gyorsítja a végrehajtást mobil eszközökön.
HLSL — a Microsoft shader nyelve DirectX-hez. Szintaxisa közelebb áll a C++-hoz osztályok, struktúrák és sablonok támogatásával. A HLSL Windows-alkalmazásokban használatos, és a Shader Model 6.7+ segítségével támogatja a Ray Tracing-et, Mesh Shader-eket és Sampler Feedback-et. Mobil fejlesztéshez a HLSL-t nem közvetlenül használják, de SPIR-V-re fordítva Vulkan-hoz alkalmazzák.
MSL (Metal Shading Language) — az Apple shader nyelve, C++14 alapokon. Ellentétben a GLSL-lel és HLSL-lel, az MSL az alkalmazással együtt fordul le, ami kiküszöböli a JIT-fordítást az eszközön. Az MSL támogatja a mutatókat, sablonokat és a C++ szabványkönyvtárat. Minden Apple eszközön használatos: iPhone, iPad, Mac, Apple TV.
#include <metal_stdlib>
using namespace metal;
struct VertexOut {
float4 position [[position]];
float2 texCoord;
};
fragment float4
myFragment(VertexOut in [[stage_in]],
texture2d<float> tex [[texture(0)]]) {
constexpr sampler s = sampler(filter::linear);
return tex.sample(s, in.texCoord);
}
Az MSL a [[position]], [[stage_in]] és [[texture(N)]] attribútumokat használja az erőforrások kötéséhez. Az Apple fordító optimalizált kódot generál az aktuális GPU-hoz, figyelembe véve a regiszterek és gyorsítótár számát.
SPIR-V — köztes bináris shader formátum, a Vulkan szabványa. A shadereket GLSL vagy HLSL nyelven írják, SPIR-V-re fordítják és betöltik a Vulkan alkalmazásba. A SPIR-V nem kötődik egy adott nyelvhez — léteznek fordítók Rust, Python, OpenCL C nyelvekből SPIR-V-re.
A shaderek mobil platformokon korlátozásokkal rendelkeznek asztali gépekhez képest: kevesebb regiszter, korlátozott pontosság és egyes utasítások támogatásának hiánya. Tekintsük a shaderek specifikumait Android (Vulkan/OpenGL ES) és iOS (Metal) rendszereken.
Android GLSL ES-t használ OpenGL-hez és SPIR-V-t Vulkan-hoz. Az OpenGL ES 3.2 alapértelmezett mediump pontossággal támogatja a shadereket. A Vulkan a GLSL explicit SPIR-V-re fordítását igényli a glslangValidator segítségével. Androidon a shaderek szöveges erőforrásokból vagy lefordított SPIR-V fájlokból töltődnek be.
Qualcomm Adreno GPU illesztőprogram szinten optimalizálja a shadereket. Javaslatok: használjon mediump-t színhez és UV-hez, highp-t csak pozíciókhoz; kerülje a textúra mintavételezést vertex shaderekben; csoportosítsa a számításokat vektorokba (vec4 a 4x float helyett). A Qualcomm (2025) adatai szerint ezek az optimalizálások 30–50%-os javulást eredményeznek.
iOS kizárólag a Metal Shading Language-t használja. A shaderek az Xcode-on keresztül az alkalmazással együtt gépi kódra fordulnak. A Metal Shader Debugger-t és GPU Capture-t biztosít a shaderek profilozásához. Az Apple GPU (TBDR) specifikus optimalizálásokkal rendelkezik: early fragment test, memoryless render targets és programozható keverés.
Az Apple WWDC 2024 adatai szerint iOS shaderekhez kritikus a half használata float helyett, a regiszterterhelés korlátozása (max 64 regiszter) és a függő textúra mintavételezés elkerülése. Az iOS shadereknek kompaktnak kell lenniük — optimális méret 50–100 ALU utasítás.
A Unity és Unreal Engine játékmotorok vizuális shader szerkesztőket (Shader Graph, Material Editor) és absztrakt nyelveket (ShaderLab, USF) biztosítanak. A fejlesztő magas szintű nyelven írja a shadert, a motor pedig lefordítja a célplatformra. A Unity HLSL-t használ köztes nyelvként, az Unreal pedig USF-t (Unreal Shader Format).
Shader optimalizálás — kulcsfontosságú szakasz a mobil eszközök grafikai fejlesztésében. Egy rosszul megírt shader 60-ról 20-ra csökkentheti az FPS-t. Tekintsük át a fő szabályokat és technikákat.
Használja a minimálisan szükséges pontosságot: lowp színhez és UV-hez, mediump normálokhoz és megvilágításhoz, highp csak pozíciókhoz és mátrixokhoz. Az ARM (2025) adatai szerint a mediump műveletek 2-szer gyorsabbak, mint a highp a Mali GPU-n. GLSL ES-ben ezt precision minősítők segítségével állítják be.
Textúra mintavételezés — a legköltségesebb művelet egy shaderben (10–30 ciklus szemben az ALU utasítás 1–2 ciklusával). Csökkentse a mintavételek számát: egyesítse a textúrákat atlaszokba, használjon uniform tömbökben tárolást textúrák helyett, gyorsítótárazza a szomszédos pixelek eredményeit derivatív utasítások segítségével.
Dinamikus elágazások (if uniform változóval) csökkentik a SIMT pipeline teljesítményét. Helyettesítse az elágazásokat matematikai függvényekkel: mix(), step(), smoothstep() és clamp(). Ezek a függvények 1–2 utasításban végrehajtódnak, míg egy elágazás akár 8–16 utasításba is kerülhet a szálak divergenciája miatt.
// Rossz: dinamikus elágazás a shaderben
if (u_enableLight) {
color *= computeLighting(normal);
}
// Jó: az elágazás matematikai helyettesítése
color *= mix(1.0, computeLighting(normal),
float(u_enableLight));
A mix() lineáris interpolációt végez két érték között. Amikor u_enableLight=0, 1.0 kerül visszaadásra — a szín nem változik. Amikor u_enableLight=1, a megvilágítás eredménye kerül visszaadásra. Nincs elágazás — minden szál ugyanazt a kódot hajtja végre.
Tekintsük át a gyakorlati shader példákat mobil fejlesztéshez — az egyszerű árnyalástól a procedurális textúragenerálásig. Minden példa egy adott technikát mutat be.
Phong modell — klasszikus megvilágítási modell diffúz és spekuláris komponensekkel. A Vertex Shader kiszámítja a megvilágítást minden csúcshoz, a Fragment Shader csak interpolálja az eredményt (Gouraud shading). Alacsony költsége miatt alkalmas mobil eszközökhöz.
#version 300 es
layout(location = 0) in vec4 a_position;
layout(location = 1) in vec3 a_normal;
uniform mat4 u_mvp;
uniform mat4 u_modelView;
out vec3 v_color;
void main() {
vec3 normal = normalize(mat3(u_modelView) * a_normal);
vec3 lightDir = normalize(vec3(0.0, 1.0, 1.0));
float diff = max(dot(normal, lightDir), 0.0);
v_color = vec3(0.8, 0.2, 0.2) * (0.3 + diff * 0.7);
gl_Position = u_mvp * a_position;
}
A shader kiszámítja a diffúz megvilágítást: a normális és a fényirány skaláris szorzatát. Az eredmény elkeveredik az ambient (0.3) és diffúz (0.7) komponensekkel. Csúcsonként 10–15 ALU utasítást hajt végre — elfogadható 100 000 poligonhoz 60 FPS mellett mobil GPU-n.
Procedurális textúrák a Fragment Shader-ben jönnek létre fájlból való betöltés nélkül. Video memóriát takarítanak meg és egyszerűsítik az animációt. Példa — sakktábla változó cellamérettel. Csupán néhány ALU utasítás — minimális terhelés a GPU-n.
#version 300 es
precision mediump float;
in vec2 v_uv;
uniform float u_cells;
out vec4 fragColor;
void main() {
vec2 cell = floor(v_uv * u_cells);
float isWhite = mod(cell.x + cell.y, 2.0);
fragColor = mix(vec4(0.1, 0.1, 0.1, 1.0),
vec4(0.9, 0.9, 0.9, 1.0),
isWhite);
}
8 ALU utasítás — ideális shader mobil eszközökhöz. Az u_cells határozza meg a cellák számát tengelyenként. A floor és mod — olcsó műveletek, 1 ciklus alatt végrehajtódnak minden mobil GPU-n.
Gyakran Ismételt Kérdések
Shader a GPU-n fut SIMT módban — egy utasítás több száz szál számára. Hagyományos C++ program — a CPU-n MIMD módban. A shader nem fér hozzá a fájlrendszerhez, bemenethez/kimenethez és dinamikus memóriához. Adatokat puffereken és textúrákon keresztül kap, és pozíciót vagy színt ad vissza.
GLSL — OpenGL ES és WebGL számára, cross-platform. Metal Shading Language — iOS számára. HLSL — a Unity és Unreal Engine alapja. Kezdje a GLSL-lel — az alapok megértése bármely shader nyelvre átvihető.
Fő okok: magas pontosság (highp mediump helyett), túlzott textúra mintavételezés, dinamikus elágazások és a regiszterlimit túllépése. Használja a RenderDoc-ot vagy Xcode GPU Frame Debugger-t a shaderek elemzéséhez.
Compute Shader — shader tetszőleges GPU-számításokhoz: részecskefizika, képfeldolgozás, szövet-szimuláció. Ellentétben a Fragment Shader-rel, nem kötődik pixelekhez és tetszőleges pufferekbe írhat.
Igen, vizuális szerkesztők segítségével: Shader Graph Unity-ben, Material Editor Unreal Engine-ben vagy Metal Shader Converter. Ezek csomóponti diagram alapján generálnak shader kódot. Mély optimalizáláshoz a shader nyelv megértése szükséges.
Összegzés
Kulcsrakész mobilalkalmazást fejlesztünk
Az IT Sectr 2017 óta készít iOS és Android alkalmazásokat induló vállalkozásoknak és vállalkozásoknak. Tanácsot adunk, és a legjobb megoldást javasoljuk.
Olvassa el is