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.

GLview

GLview

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).

Sphere

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.

  1. 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.

    Graphics pipeline

    Prvním krokem je tedy naplnění bufferu vertex daty.

  2. 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.

  3. 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).

  4. 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.

  5. 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.

  6. 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:

    #version 330 core
    in vec3 ourColor;

    out vec4 color;

    void main()
    {
            color = vec4(ourColor, 1.0);
    }

    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.
  7. 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:

  1. Nahrání vertex dat do bufferů a nastavení kontextu OpenGL, který ovlivňuje chování různých kroků v pipelnie
  2. Vertex shader vypočítá pozici vertexů (souřadnic), případně pozici textur (obrázků, které se vykreslují jako textury objektů).
  3. Shape assembly sestaví grafická primitiva (trojúhleníky, čáry, body) a předá je Geometry shaderu
  4. Geometry shader může přidat nějaké další vertexy
  5. Z výsledných vetextů se rastarizací vytvoří fragmenty
  6. Na každý fragment se aplikuje fragment shader
  7. 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.

Komentář Hlášení chyby
Created: 24.12.2016
Last updated: 5.3.2018
Tato stánka používá ke svému běhu cookies, díky kterým je možné monitorovat, co tu provádíte (ne že bych to bez cookies nezvládl). Také vás tu bude špehovat google analytics. Jestli si myslíte, že je to problém, vypněte si cookies ve vašem prohlížeči, nebo odejděte a už se nevracejte :-). Prohlížením tohoto webu souhlasíte s používáním cookies. Dozvědět se více..