OpenGL Shading Language
OpenGL Shading Language (zkráceně GLSL nebo také GLslang) je vyšší programovací jazyk pro psaní shaderů, který vychází ze syntaxe jazyka C pro všeobecné použití. Jazyk GLSL byl vytvořen konsorciem OpenGL ARB.
Popis
Jazyk vznikl v rámci procesu postupné transformace fixního vykreslovacího řetězce na řetězec programovatelný a stal se jednou z vyspělejších alternativ k tehdy používaným nižším programovacím jazykům pro psaní shaderů.
Nová funkcionalita (nebo funkcionalita specifická pro určitého výrobce či hardware) je do GLSL často doplňována nejprve v podobě tzv. rozšíření (např. podpora geometry shaderu), které je třeba v kódu explicitně aktivovat a v pozdějších verzích se významná rozšíření stávají součástí funkcionality základní.
Verze
Tabulka shrnující jednotlivé verze OpenGL a příslušné verze GLSL, které byly v rámci dané specifikace představeny:[1]
Verze GLSL | Verze OpenGL |
---|---|
1.10.59 | 2.0 |
1.20.8 | 2.1 |
1.30.10 | 3.0 |
1.40.08 | 3.1 |
1.50.11 | 3.2 |
3.30.6 | 3.3 |
4.00.9 | 4.0 |
4.10.6 | 4.1 |
4.20.6 | 4.2 |
Operátory
Jazyk GLSL poskytuje operátory známé z jazyka C. Výjimku tvoří operátory související s ukazateli, které nejsou v jazyce GLSL podporovány. V prvních verzích rovněž nebylo možné používat bitové operátory — jejich podpora byla zavedena ve verzi 1.30.[2] Oproti jazyku C je navíc k dispozici speciální operátor swizzle.
Datové typy
GLSL podporuje skalární datové typy jazyka C. Lze použít i datový typ void ovšem pouze jako typ návratové hodnoty funkcí. Podpora struktur a polí umožňuje tvorbu uživatelských datových typů.
Skalární typy
bool
— pravdivostní datový typ (true/false)int
— 32bit, celé číslo se znaménkemuint
— 32bit, celé číslo bez znaménkafloat
— 32bit, číslo s plovoucí desetinnou čárkoudouble
— 64bit, číslo s plovoucí desetinnou čárkou a dvojnásobnou přesností
Vektorové typy
Vektor je homogenní datový typ. GLSL má vestavěnou podporu pro jedno- až čtyř-složkové vektory. Název vektorového datového typu (např. dvec4
) se skládá z prefixu části "vec" a sufixu. Prefix určuje datový typ složek vektoru[p 1] a sufix určuje jejich počet. Příklad použití (včetně inicializace):
vec4 color0 = vec4(1.0, 0.0, 0.0, 0.0);
K jednotlivým složkám vektoru lze pak přistupovat pomocí definovaných složek x, y, z a w (např. color0.x = 0.5;
).[3]
Matice
GLSL poskytuje podporu pro práci s maticemi o rozměrech 2x2 až 4x4, přičemž matice nemusí být pouze čtvercová (k dispozici jsou všechny kombinace uvedených rozměrů). Názvy maticových datových typů jsou tvořeny obdobně jako u vektorů — název začíná prefixem následuje část "mat" a je ukončen sufixem. Prefix určuje datový typ prvků matice[p 1] a sufix určuje rozměr matice (např. mat3x4; u čtvercových matic je použit zkrácený zápis např. mat3 pro matici o rozměrech 3x3). Příklad použití (včetně inicializace):
K jednotlivým prvkům matice přistupujeme obdobně jako k prvkům pole v jazyce C:[3]
mat3 matrix;
matrix[1] = vec3(3.0, 3.0, 3.0);
matrix[2][0] = 16.0;
Další datové typy
GLSL nabízí i tzv. opaque (česky někdy též "transparentní") datové typy. Opaque datový typ je ve skutečnosti pouze handler (handle) na nějaký jiný objekt. Přístup k takovému objektu probíhá přes sadu vestavěných funkcí (přímé čtení či zápis hodnoty proměnné takového typu není možné). Při deklaraci jednoho opaque datového typu jsou ve skutečnosti deklarovány objekty dva, handler samotný i vnitřní objekt ke kterému handler přistupuje. Deklarace těchto typů je možná pouze na některých místech kódu — typicky bývají deklarovány např. jako parametry funkcí. [4]
Do kategorie opaque datových typů spadají v GLSL tzv. Samplery (např. sampler2D) a jedná se o handler k jedno-, dvou- či tří-rozměrné textuře, hloubkové textuře, cube-mapě apod.
Image je další třídou opaque datových typů (např. image1D, image2D, image2DMS a další). jedná se o handler k jedno-, dvou- či tří-rozměrnému obrázku (image), které se používají pro načítání či ukládání souborů obsahujících statický obraz (případně pro další atomické operace).
Řídící struktury a funkce
Jazyk GLSL využívá stejnou konstrukci řídících struktur (větvení, cyklů, skoků) a funkcí jako jazyk C. Kromě podpory uživatelských funkcí disponuje GLSL i sadou funkcí vestavěných. Některé z nich jsou podobné funkcím jazyka C (zejména matematickým) — např. funkce exp() nebo abs(), zatímco jiné jsou určeny speciálně pro práci s grafikou — např. smoothstep() nebo texture2D().
Direktivy preprocesoru
Pro řízení předzpracování zdrojového kódu, je k dispozici sada preprocesorových direktiv známých z jazyka C. Navíc jsou k dispozici speciální direktivy #version
a #extension
.[4]
Direktiva version
Direktiva #version
se musí nacházet na začátku každého zdrojového souboru a určuje verzi GLSL, která bude při překladu použita.
#version 150
Direktiva extension
Chování GLSL lze dále ovlivnit pomocí tzv. rozšíření OpenGL (OpenGL extensions). Tato rozšíření lze řídit právě pomocí direktivy #extension
:
#extension jmeno_rozsireni: chovani
Kde položka "jmeno_rozsireni" definuje název konkrétního rozšíření nebo nabývá hodnoty "all" chceme-li pracovat se všemi rozšířeními. Dané rozšíření lze v části "chovani" povolit nebo zakázat a dále pak definovat chování v případě, kdy rozšíření není dostupné.
Komentáře
Komentáře lze zapisovat ve stejném formátu jako v jazycích C, C++.
/* krátká verze */
// celořádková verze
Proces překladu
Kód shaderu může být umístěn v samostatném souboru nebo jako textový řetězec v rámci hlavního programu. Vlastní překlad probíhá až za běhu aplikace. Nejprve je třeba vytvořit shader objekt a definovat jeho typ (např. GL_VERTEX_SHADER) voláním OpenGL funkce glCreateShader(). Vlastní překlad je vyvolán funkcí glCompileShader() (jako parametr je předán řetězec s kódem shaderu). Dalším krokem je sestavení přeložených shaderů ve výsledný program. Opět je nejprve nutné vytvořit speciální objekt program funkcí glCreateProgram(). Následuje připojení přeložených shader objektů — glAttachShader() a potom již vlastní proces linkování — glLinkProgram(), v rámci kterého dochází rovněž k mapování proměnných hlavního programu a proměnných GLSL shaderů.[5]
Ukázka vertex shaderu
Uvedený vertex shader realizuje stejnou transformaci vstupu jako fixní vykreslovací řetězec.
#version 120
void main(void)
{
gl_Position = ftransform();
}
Použitá funkce ftransform()
není od verze GLSL 1.40 dostupná. Při použití novější specifikace GLSL musí programátor místo použití této funkce explicitně vykonat násobení vertexu projekční a modelview maticí.
#version 140
uniform Transformation
{
mat4 projection_matrix;
mat4 modelview_matrix;
};
in vec3 vertex;
void main()
{
gl_Position = projection_matrix * modelview_matrix * vec4(vertex, 1.0);
}
Ukázka geometry shaderu
Následující kód realizuje jednoduchý průchozí geometry shader pro barvu a pozici vertexu.
#version 120
#extension GL_EXT_geometry_shader4 : enable
void main()
{
for (int i = 0; i < gl_VerticesIn; ++i)
{
gl_FrontColor = gl_FrontColorIn[i];
gl_Position = gl_PositionIn[i];
EmitVertex();
}
}
Od verze GLSL 1.50 nejsou již geometry shadery rozšířením, ale staly se součástí základní funkcionality GLSL. V souvislosti s tím došlo i k mírné změně syntaxe.
#version 150
layout(triangles) in;
layout(triangle_strip, max_vertices = 3) out;
void main()
{
for (int i = 0; i < gl_in.length(); i++)
{
gl_Position = gl_in[i].gl_Position;
EmitVertex();
}
EndPrimitive();
}
Ukázka fragment shaderu
Jednoduchý shader, jehož výstupem bude fragment červené barvy.
#version 120
void main(void)
{
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
Při použití specifikace GLSL 1.30 nebo pozdější je třeba shader upravit.
#version 150
out vec4 MyFragColor;
void main(void)
{
MyFragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
V hlavním programu je potřeba provést navázání proměnné:
glBindFragDataLocation(Program, 0, "FragColor");
kde:
Program
— handler použitého shader programu0
— index barvového bufferu"MyFragColor"
— uživatelsky definovaný název barvového bufferu
Ukázka Tessellation control shaderu
Příklad tessellation control shaderu pracujícího s trojúhelníky.[6]
#version 400
layout(vertices = 3) out;
in vec3 vPosition[];
out vec3 tcPosition[];
uniform float TessLevelInner;
uniform float TessLevelOuter;
void main()
{
tcPosition[gl_InvocationID] = vPosition[gl_InvocationID];
if (gl_InvocationID == 0)
{
gl_TessLevelInner[0] = TessLevelInner;
gl_TessLevelOuter[0] = TessLevelOuter;
gl_TessLevelOuter[1] = TessLevelOuter;
gl_TessLevelOuter[2] = TessLevelOuter;
}
}
Ukázka Tessellation evaluation shaderu
Příklad tessellation evaluation shaderu pracujícího s trojúhelníky.[6]
#version 400
layout(triangles, equal_spacing, cw) in;
in vec3 tcPosition[];
out vec3 tePosition;
out vec3 tePatchDistance;
uniform mat4 Projection;
uniform mat4 Modelview;
void main()
{
vec3 p0 = gl_TessCoord.x * tcPosition[0];
vec3 p1 = gl_TessCoord.y * tcPosition[1];
vec3 p2 = gl_TessCoord.z * tcPosition[2];
tePatchDistance = gl_TessCoord;
tePosition = normalize(p0 + p1 + p2);
gl_Position = Projection * Modelview * vec4(tePosition, 1);
}
Odkazy
Poznámky
- U názvů datových typů (vektorů a matic) jejichž složky jsou typu float, se prefix v neuvádí.
Reference
V tomto článku byl použit překlad textu z článku GLSL na anglické Wikipedii.
- History of OpenGL (Historie OpenGL)
- GLSL Language Specification, Version 1.30
- Datové typy GLSL. www.opengl.org [online]. [cit. 2011-12-04]. Dostupné v archivu pořízeném dne 2012-01-17.
- GLSL Language Specification, Version 4.20
- An intro to modern OpenGL
- Triangle Tessellation with OpenGL 4.0
Související články
- Ostatní jazyky pro psaní shaderů
Externí odkazy
- Oficiální stránka OpenGL Archivováno 26. 2. 2011 na Wayback Machine
- GLSL Language Specification, Version 4.20.6
- GLSL Language Specification, Version 4.10.6
- GLSL Language Specification, Version 4.00.8
- GLSL Language Specification, Version 3.30.6
- GLSL Language Specification, Version 1.50
- GLSL Language Specification, Version 1.40
- GLSL Language Specification, Version 1.30
- GLSL Language Specification, Version 1.20
- OpenGL Fragment Shader Specification
- OpenGL Vertex Shader Specification
- OpenGL Shader Objects Specification
- IDE
- Příklady a ukázky