O OpenGL
Po celé té strastiplné cestě jste se zatím naučili jen vypisovat text do konzole, maximálně vykreslit do konzole pár okének. V této a pár dalších kapitolech se konečně dočkáte velkého zlomu. Naučíte se, jak zobrazit grafický výstup. A to hned ve 3D.
Co je OpenGL
OpenGL je API. Ve windows najdete knihovnu opengl32.dll, která vám pomůže dostat se k implementaci tohoto API. Někdy, když se mluví o OpenGL, má se na mysli právě implementace tohoto API.
OpenGL API vám popisuje, jakými prostředky můžete komunikovat s grafickou kartou. Jaké máte k dispozici funkce, co tyto funkce očekávají za vstup, jak se mění kontext aplikace atp. O definici API se stará jakási non-profit skupina Khronos, jejíž členové jsou firmy jako AMD, Google, WARGAMING atp. Prostě velcí hráči, kteří mají na vývoji tohoto API nějaký zájem.
Firma Microsoft má konkurenční API - Microsoft DirectX. DirectX a OpenGL se v podstatě snaží o totéž - poskytnout programátorům přistup ke grafické kartě. Zatímco OpenGL je multiplatformí, takže běží na Windows, Linuxu i OSX, DirectX je jen pro Windows.
O implementaci OpenGL se starají výrobci grafických karet. Pokud už vám někdy někdo řekl, že byste měli čas od času aktualizovat ovladače grafické karty, tak to je (mimo jiné) kvůli OpenGL. Ovladače totiž obsahují implementaci OpenGL. Aktualizace vám může opravit chyby (kdy se nějaké funkce nechovali tak, jak by podle OpenGL standardu měly), nebo přináší novou verzi OpenGL (kterou vaše grafická karta dokáže podporovat).
Kromě oficiálních implementací ještě existuje open-source implementace Mesa 3D. (Používá se hlavně na Linuxu).
Verze a specifikace
OpenGL existuje v několika specifikacích. Každá specifikace se vyvíjí, takže vznikají nové verze. Než ale začnete zjišťovat, jakou verzi máte k dispozici na svém počítači, aktualizujte si ovladače grafické karty.
Aktualizace ovladačů grafické karty
Ovladače grafické karty jsou to, co vám zpřístupňuje funkce grafické karty. Tedy to, co využívá OpenGL. Proto se vyplatí mít nainstalované nejnovější ovladače, které přinášejí nejnovější (OpenGL) funkce.
Ve Windows stiskněte windows klávesu + r (otevře se okno
Run
) a zadejte příkaz dxdiag
. V otevřeném
okně na druhé záložce uvidíte, jakou máte grafickou kartu a jaké verze
ovladačů. Pak už jen stačí zajít na web výrobce vaší grafické karty
(nejspíš AMD, NVIDIA nebo Intel) a najít poslední aktualizace ovladačů.
V Linuxu můžete zjistit grafickou kartu příkazem lspci | egrep VGA
.
S aktualizací je to ale trošku horší. Sice také můžete stáhnout a
nainstalovat ovladače z stránek výrobce, ale nemám s tím moc dobré zkušenosti.
Nejednou se mi stalo, že výsledkem instalace bylo to, že se mi nespustilo
grafické rozhraní a nešlo s tím už nic udělat (musel jsem reinstalovat PC).
A když vše proběhlo v pořádku, tak po nějaké době přišla aktualizace jádra
Linuxu, následkem čehož mi zase nenaběhla grafika a mohl jsem reinstalovat.
Proto raději zůstávám u opensource ovladačů Mesa, ikdyž nepřinášejí maximální
výkon.
OpenGL
Základní specifikace je OpenGL. První verze vznikla v roce 1992. Zatím poslední verze 4.6 vznikla v roce 2017.
Rozdíly mezi verzemi OpenGL 1.x, 2.x a 3.x jsou poměrně zásadní. Já se budu věnovat verzi OpenGL 3.3. Verze OpenGL 4.0 sice vyšla už v roce 2010, ale na trhu je stále spousta grafických karet, která tuto verzi nepodporuje (já mám dokonce v práci počítač, který podporuje jen verzi 2.1).
Nové verze OpenGL odstranili některé staré funkce z OpenGL. Dejte si proto pozor na to, pokud budete hledat na internetu další OpenGL tutoriály (nebo kupovat knížky), abyste nestudovali nic staršího než verzi 3.x.
Nicméně bez zajímavosti není, že OpenGL umožňuje přistupovat i ke starším verzím API. Při inicializaci OpenGL si můžete (vlastně musíte) říct, jakou verzi OpenGL chcete. (Pokud požádáte o novější než vaše grafická karta a ovladače zvládají, skončí inicializace chybou.)
Podporovanou verzi OpenGL zjistíte v Linuxu pomocí příkazu glxinfo. (Program je součástí každé normální distribuce).
> glxinfo | egrep version server glx version string: 1.4 client glx version string: 1.4 GLX version: 1.4 Max core profile version: 4.1 Max compat profile version: 3.0 Max GLES1 profile version: 1.1 Max GLES[23] profile version: 3.0 OpenGL core profile version string: 4.1 (Core Profile) Mesa 17.2.5 OpenGL core profile shading language version string: 4.10 OpenGL version string: 3.0 Mesa 17.2.5 OpenGL shading language version string: 1.30 OpenGL ES profile version string: OpenGL ES 3.0 Mesa 17.2.5 OpenGL ES profile shading language version string: OpenGL ES GLSL ES 3.00
Co je z tohoto výstupu zajímavé, je řádek „OpenGL core profile version string: 4.1 (Core Profile) Mesa 17.2.5“, který říká, že používám ovladače Mesa ve verzi 17.2.5, které mi mohou poskytnout OpenGL ve verzi 4.1, pokud si o řeknu při inicializaci OpenGL kontextu o verzi 4.1 core profile.
Další zajímavý řádek je „OpenGL version string: 3.0 Mesa 17.2.5“, což je verze OpenGL v compatibility režimu. Můžete požádat i o 3.0 Core Profile verzi, nebo nižší. Pokud ale budete chtít vyšší verzi (4.1), musíte požádat o Core Profile.
Inicializace nějaké verze OpenGL v Core profile způsobí, že dostanete jen a právě tuto verzi OpenGL. Naproti tomu Compatibility režim vám umožní používat i starší (deprecated) funkce a různá rozšíření, jež nejsou součástí Core Profilu. Z tohoto důvodu je lepší používat Core profile, právě proto, abyste se deprecated funkcím vyhnuli. Compatibility režim se hodí pro starší software, který už deprecated funkce používá, nebo ve chvílích, kdy chcete použít nějaké funkce, jež nejsou v Core Profile (a nemusí tak být dostupné na každém systému.)
Moje verze Mesa 3D nepodporuje OpenGL 4.1 v kompatibilním režimu.
Pro zajímavost ještě ukáži výstup na mém počítači v práci (který používá levnou grafickou kartu od Intelu):
> glxinfo | egrep version server glx version string: 1.4 client glx version string: 1.4 GLX version: 1.4 Max core profile version: 0.0 Max compat profile version: 2.1 Max GLES1 profile version: 1.1 Max GLES[23] profile version: 2.0 OpenGL version string: 2.1 Mesa 17.0.5 OpenGL shading language version string: 1.20 OpenGL ES profile version string: OpenGL ES 2.0 Mesa 17.0.5 OpenGL ES profile shading language version string: OpenGL ES GLSL ES 1.0.16
Pokud máte taky tak „blbou“ grafiku, nezoufejte, i pro vás existuje řešení.
Můžete zkusit vynutit softwarovou emulaci OpenGL funkcí pomocí nastavení systémové proměnné
LIBGL_ALWAYS_SOFTWARE=1
.
Spusťte program takto:
$ LIBGL_ALWAYS_SOFTWARE=1 ./program
Například:
$ LIBGL_ALWAYS_SOFTWARE=1 glxinfo | egrep version server glx version string: 1.4 client glx version string: 1.4 GLX version: 1.4 Max core profile version: 3.3 Max compat profile version: 3.0 Max GLES1 profile version: 1.1 Max GLES[23] profile version: 3.0 OpenGL core profile version string: 3.3 (Core Profile) Mesa 17.0.5 OpenGL core profile shading language version string: 3.30 OpenGL version string: 3.0 Mesa 17.0.5 OpenGL shading language version string: 1.30 OpenGL ES profile version string: OpenGL ES 3.0 Mesa 17.0.5 OpenGL ES profile shading language version string: OpenGL ES GLSL ES 3.00
Druhou možností je nainstalovat si Linux do Virtual Boxu. Ten bude softwarově emulovat lepší graifku než máte na počítači a OpenGL 3.3 vám tam půjde :-). Bude to samozřejmě pomalé, ale na ty jednoduché příklady z mého tutoriálu to bude bohatě stačit.
Do Windows si můžete stáhnout a nainstalovat program GLview, který vám ukáže jaké verze OpenGL váš počítač podporuje.
Všiměte si, že ovladače na windows (na tom samém počítači ze kterého je první glxinfo výstup) podporují dokonce i verzi OpenGL 4.4.
Můžete si také stáhnout program GPU Caps Viewer, který vám zobrazí informace nejen o OpenGL, ale i o OpenCL a CUDA. (To jsou API pro nějaké distribuované výpočty pomocí grafické karty, nic co by nás v tomto tutoriálu zajímalo.)
OpenGL ES
OpenGL for Embedded Systems (OpenGL ES nebo GLES) je API, které se používá na mobilních telefonech, tabletech a dalších „embedded“ zařízeních. Jedná se o podmnožinu funkcí z „plnohodnotného“ OpenGL.
OpenGL ES se věnovat v tomto tutoriálu nebudu. Ale vězte, že když se naučíte OpenGL, naučit se OpenGL ES je už maličkost (vlastě je to spíš záležitost odnaučování se :-).
WebGL
WebGL (Web Graphics Library) je JavaScriptové API pro přístup k OpenGL ES. V předchozích kapitolách jste mohli vidět zdrojový kód JavaScriptu, který jsem použil pro 3D grafiku v těchto kapitolách. JavaScript je samozřejmě jiný programovací jazyk než C, ale i tak vám to může dát alespoň rámcovou představu o tom, jak se s WebGL (potažmo OpenGL ES) pracuje.
Pokud se tedy zabýváte vývojem webů, bude i pro vás znalost OpenGL přínosem.
Vulkan
Vulkan je nové API vydané skupinou Khronos. Jedná se o low-level API, které umožňuje psát ještě efektivnější programy než OpenGL. To má na druhou stranu tu nevýhodu, že psaní programů je ve Vulkanu také obtížnější.
Když vyšla první verze Vulkanu, mohli jste se dočíst v bulváru titulky jako "Jedna dlouhá éra končí, Vulkan nahradí stárnoucí OpenGL". Což je samozřejmě nesmysl.
Odhadovat budoucí vývoj v IT je těžké, nicméně podle oficiálního vyjádření Khronos Group:
„A key advantage of Vulkan over OpenGL is the ability to generate GPU work in parallel using many CPU cores, making Vulkan particularly useful for CPU-bound developers, eliminating a bottleneck in applications from diverse domains including games, computer-aided design and mobile apps. Vulkan complements the traditional OpenGL and OpenGL ES APIs that provide a higher level of abstraction to access GPU functionality, which may be more convenient for many developers.
Khronos will continue to evolve OpenGL and OpenGL ES in parallel with Vulkan to meet market needs.“
To dává vcelku smysl, protože vývoj aplikací ve Vulkanu je náročnější, tedy i dražší. A dokud budou světu vládnout peníze …
Inicializace kontextu a okna
Kontext OpenGL si můžete představit jako nějakou datovou strukturu kdesi v paměti, kterou můžete přes OpenGL API různě měnit a tím ovlivňovat výsledný grafický výstup.
Při inicializaci kontextu se také vytváří nějaké okno, do kterého se bude grafický výstup zapisovat. Jak se toto okno vytváří už je ale závislé na prostředí, kde aplikace běží (jinak se vytváří ve Windows, jinak v Linuxu atp.).
Aby měli vývojáři jednodušší práci, vznikly knihovny jako FreeGLUT, GLFW nebo SDL.
Tyto knihovny se starají o vytvoření okna, ale také o interakci s klávesnicí nebo myší, protože ani to není součást OpenGL API (to se zaměřuje opravdu jen na kreslení pixelů).
OpenGL loading library
Knihovna GLFW nebo FreeGLUT se vám postará o inicializaci kontextu, vytvoření okna a interakci se vstupními zařízeními. Ale zbývá tu ještě jeden problém. Jak získat přistup k OpenGL funkcím?
Možná je na čase zavzpomínat na dynamické knihovny.
OpenGL Loading Library je knihovna, která se vám postará o načtení odkazů na OpenGL funkce.
Např. windows knihovna opengl32.dll obsahuje jen funkce z OpenGL verze 1.1. Novější funkce vám přináší ovadače grafické karty, jak už jsem popisoval výše. Funkce z novějších verzí OpenGL proto musíte načíst dynamicky. Jak se to dělá, to se liší systém od systému.
Proto vznikly knihovny jako je Glad nebo Glew, které vám načítání odkazů na OpenGL funkce ulehčí.
OpenGL rozšíření
Funkce, které jsou v jádru OpenGL, jsou dostupné všude, kde je daná verze OpenGL podporována. Kromě těchto základních funkcí však mohou ovladače vaší grafické karty podporovat další, ve formě rozšíření.
Použití takových rozšíření vypadá asi následovně. Hej, OpenGL Loading knihovno, máš tohle rozšíření? Jo? Tak já použiju tyhle super efektivní funkce. Ne? Tak použiju tyhle ošklivý nudný funkce z core, nebo řeknu uživateli ať si nas….
Taky můžete předpokládat, že ty rozšíření uživatel má. A když nemá, tak se dočká „neoprávněného přístupu do paměti“. Znáte to …
Rozšíření umožňují výrobcům grafických karet dodávat funkce specifické pro jejich karty, nebo nějaké modení rozhraní. Některé funkce z rosížení se v nových verzích OpenGL dostanou do core API.
Podívejte se na seznam rozšíření.
Název rozšíření začíná nějakými zkratkami, které vám napoví, o jaký typ rozšíření se jedná.
- ARB
- Rozšíření oficiálně schválené skupinou OpenGL Architecture Review Board, která se stará o rozvoj OpenGL. Tyto rozšíření se často dostanou v nových verzích OpenGL do Core profile
- EXT
- Rozšíření schválená mnoha výrobci OpenGL ovladačů
- HP
- Hewlett-Packard
- IBM
- International Business Machines
- KTX
- Kinetix,výrobce 3D Studio Max
- INTEL
- Intel
- NV
- NVIDIA Corporation
- MESA
- Brian Paul’s freeware portable OpenGL implementation
- SGI
- Silicon Graphics
- SGIX
- Silicon Graphics (experimental)
- SUN
- Sun Microsystems
- WIN
- Microsoft
V seznamu rozšíření odkazovaném výše najdete jejich popis. Jaké konstanty a funkce rozšíření definují, k čemu slouží atp. Tak daleko se v tomto tutoriálu ale nedostanu.
OpenGL pipeline a GLSL
Někdo říká, že je OpenGL 3D knihovna. To proto, že se používá pro kreslení 3D scén (hlavně her).
Někdo říká, že je OpenGL 2D knihovna. To proto, protože OpenGL neumí pracovat s 3D objekty. OpenGL umí vykreslit jen body, čáry (polygony) a trojúhelníky. Když chcete vykreslit kouli, musíte ji aproximovat pomocí trojúhelníků (viz obrázek).
A někdo říká, že je OpenGL 2.5D knihovna. Protože sice neví nic o 3D objektech, ale souřadnice se jí předávají ve 3D a OpenGL dokáže např. zobrazit jen ty části trojúhelníků, které nejsou překryté jinými trojúhelníky.
Podívejme se teď na to, jak se vykreslí takový trojúhelník. Zatím tedy jenom teoreticky.
-
První věc, kterou musíte udělat, je poslat do paměti (bufferu) grafické karty souřadnice vrcholů trojúhelníku. (Pro trojúhelník potřebujete 3, pro čáru 2 atp.) Říkejme těmto vrcholům vertexy.
Souřadnice vertexu můžeme nazývat vertex data. Jsou to nějaká data, která se vztahují k jednomu konkrétnímu vrcholu. Další vertex dato může být například barva.
Když požádáte o vykreslení takto definovaného trojúhelníka, začnou se dít věci. A to v pořadí definovaném tzv. graphics pipeline. Ta definuje, jak se s daty pracuje, krok za krokem.
Prvním krokem je tedy naplnění bufferu vertex daty.
-
Druhým krokem je tzv Vertex Shader. V tomto kroku se pro každý vrchol (vertext) spočítá glPosition (tedy výsledná pozice vrcholu).
O výpočet se stará program napsaný v OpenGL Shading Language (GLSL). To je nový programovací jazyk, který se budete muset naučit. Ale nebojte se, je jednoduchý a podobný C-čku.
Ukázka GLSL ve Vertex Shaderu:
#version 330 core
layout (location = 0) in vec3 position;
layout (location = 1) in vec3 color;
out vec3 ourColor;
void main()
{
gl_Position = vec4(position, 1.0f);
ourColor = color;
}Takto je definovaný jednoduchý program pro Vertex shader. Nedělá nic jiného, než že vezme pozici vektoru, kterou dostane v proměnné position typu
vec3
a předá jí do globální proměnné gl_Position typu vec4 (přidá čtvrtou homogenní souřdnici w).Pak ještě vezme barvu, kterou dostane v proměnné color a předá jí dále (do fragment shaderu).
Vertex shader je to místo, kde budete přepočítávat transformace souřadnic. Vertex shadery počítá grafická karta paralelně. To znamená, že se počítá pro stovky vrcholů v jeden okamžik. To samozřejmě neuvěřitelně urychluje výpočet 3D scény. Přesto je potřeba se snažit vertex shadery psát co nejjednoduššeji, neboť každá podmínka IF navíc negativně ovlivňuje celkový výkon.
-
Tak. Máme spočítané pozice vrcholů a můžeme pokračovat v pipeline na další krok. Tím je shape assembly. Tady si OpenGL vypočítá z vrcholů trojúhelníky (nebo čáry, body, podle toho, o co jste požádali). Do tohoto kroku nemůže zasahovat, takže není z našeho pohledu nijak zajímavý (narozdíl od pohledu implementátorů OpenGL).
-
Dalším krokem v pipeline je Geometry shader. V tomto kroku můžete ještě přidat nějaké další vrcholy. To se hodí například v případě, že aproximujete pomocí trojúhelníků kruh. Když si uživatel kruh hodně přiblíží, uvidí, že se skládá z malých úseček. Aby se to nestalo, můžete si tady přidat další vrcholy a křivku kruhu vyhladit. Gemoetry shaderu se však v tomto tutoriálu věnovat nebudu.
-
Dalším krokem je rasterizace. V tomto okamžiku si grafická knihovna rozloží trojúhelníky na shadery. Shader si můžete představit jako virtuální pixel. Nicméně shader nemusí být stejně velký jako bude výsledný pixel. Navíc se ani nemusí na obrazovku dostat, pokud bude překryt nějakým jiným shaderem. Do tohoto kroku, jako programátoři využívající OpenGL, nijak nezasahujete.
-
Dalším krokem je Fragment shader. To je důležitý krok, kde budete zase používat GLSL, tentokrát pro výpočet barvy shaderu. Shadery se zase počítají paralelně, tentokrát pro každý shader. Jde o mnohonásobně více výpočtů než pro Vertex shadery. Proto pro framgent shader platí ještě více, že by měl být co nejjednodušší. (Mělo by se v něm počítat jen to, co opravdu potřebujete počítat pro každý shader extra).
Ukázka GLSL ve Fragment shaderu:
V ukázce nedělám nic, než že jen vezmu vstupní barvu ourColor, přidám alfa složku (průhlednost 1.0 znamená totálně neprůhledné) a uložím do výstupní proměnné color.
Programování vertex a fragment shaderů se budu věnovat podrobně v některé z příštích kapitol. -
Posledním krokem je test and blending. Zde se OpenGL postará o převod shaderů na pixely. (V závislosti na pozici, průhlednosti apd. se nějak zkombinují barvy shaderů ve výsledný pixel). Tento krok může být ovlivněn nastavením kontextu, ale přímo do něj už zasahovat nemůžete.
Když to zrekapituluji, pak graphic pipeline v OpenGL vypadá zhruba takto:
- Nahrání vertex dat do bufferů a nastavení kontextu OpenGL, který ovlivňuje chování různých kroků v pipelnie
- Vertex shader vypočítá pozici vertexů (souřadnic), případně pozici textur (obrázků, které se vykreslují jako textury objektů).
- Shape assembly sestaví grafická primitiva (trojúhleníky, čáry, body) a předá je Geometry shaderu
- Geometry shader může přidat nějaké další vertexy
- Z výsledných vetextů se rastarizací vytvoří fragmenty
- Na každý fragment se aplikuje fragment shader
- Vypočítá se výsledná barva pixelů.
Tučně vyznačené části jsou ty, které budu v dalších kapitolách popisovat.
Závěr
V této kapitole jste se dozvěli, co je to OpenGL, v jakých různých verzích existuje, o co se stará (vykreslování grafických primitiv), o co se nestará (vytváření oken, vstup klávesnice nebo myši), jak se dostanete k referencím funkí OpenGL, co je to GLSL, kdy a proč ho budete používat, jak vypadá graphics pipeline a že vykreslení 3D scény nebude tak snadné, jak jste si možná představovali.
Díky předchozím kapitolám však už máte dobrý matematický a teoretický základ, takže to nejhorší je už za vámi :-).
V následující kapitole se už budu prakticky věnovat knihovnám GLFW a Freeglut pro vytvoření kontextu okna a zpracování vstupů klávesnice a myši. V další kapitole knihovnám Glad a Glew pro získání odkazů na OpenGL funkce, a až v následující GLSL a vykreslení prvního trojúhelníka.