Hlavní navigace

Grafická knihovna OpenGL (6): využití transformačních matic

Pavel Tišnovský

V dnešním dílu si ukážeme využití transformačních matic při skládání transformací. Také si popíšeme zásobník matic, který se využívá zejména při vykreslování složitých, hierarchicky uspořádaných trojrozměrných scén.

Použití transformačních matic, skládání transformací a zásobník matic

Jak jsme již napsali v minulém dílu, lze transformační matice použít k několika operacím:

  1. Změna polohy, velikosti a orientace těles – k tomuto účelu se používá ModelView matice, pomocí které lze specifikovat transformace translace (posuvu), rotace a změny měřítka.
  2. Změna polohy a natočení kamery – k tomuto účelu se taktéž používá ModelView matice, protože na změnu polohy kamery se lze dívat také jako na změnu polohy celé scény v opačném směru. Totéž platí pro rotace a změnu měřítka.
  3. Změna tělesa záběru – používá se Projection matice, pomocí které lze zadat tvar výřezu prostoru, který je kamerou snímaný. Používají se dvě tělesa: kvádr (ortogonální projekce) a komolý jehlan (perspektivní projekce). Více o nastavení kamery bude řečeno v dalších dílech seriálu.
  4. Změna transformace texturovacích souřadnic – používá se Texture matice, kde lze zadat transformaci prováděnou s texturovacími souřadnicemi. Více viz další díly věnované texturování.
  5. Změna okna výřezu, který se zobrazí na obrazovce. Nepoužívá se „plnohodnotná“ transformační matice, ale lze zadat tzv. Viewport, který specifikuje mapování ve 2D z abstraktních souřadnic do souřadnic okna.

Použití transformačních matic

Některé transformace se při vykreslování scény provádí pouze jednou. Typickou operací je nastavení tělesa záběru kamery pomocí projekční matice (Projection matrix) a výřezu pomocí změny Viewportu. Tyto operace se většinou provádí v callback funkci vyvolávané při změně velikosti okna – v demonstračních příkladech je to funkce void onResize(int w, int h). Další změny projekční matice a výřezu se většinou neprovádí. Výjimkou bývá současné zobrazení trojrozměrné scény a „dvojrozměrných textů“. V tomto případě se provádí změna projekční matice dvakrát; poprvé pro nastavení perspektivní projekce pro zobrazení trojrozměrné scény a podruhé pro nastavení ortogonální projekce pro vykreslení textů.

V době vykreslování je však velmi často měněna ModelView matice, protože s tělesy ve scéně je většinou nějakým způsobem manipulováno. Manipulace ponejvíce zahrnuje posun tělesa, změnu měřítka a rotaci. Tyto lineární transformace lze přímo zadat pomocí funkcí glTranslate*(),glSca­le() a glRotate() (viz předchozí díl tohoto seriálu). Před zadáváním samostatných transformací je však vždy zapotřebí nastavit transformační matici na jednotkovou zavoláním funkce glLoadIdentity(), jinak se transformace budou skládat, což v některých případech může způsobit chybnou funkci programu (jak vyplyne z dalšího textu, je skládání transformací v některých případech žádoucí).

Příklad na použití matice ModelView pro posun těles je demonstrován v příkladu číslo 7 (zde je i zdrojový kód s obarvenou syntaxí), kde jsou vykresleny čtyři trojúhelníky, z nichž každý je posunut o jiný vektor. Důsledkem použití transformační matice je, že se ve funkci void drawTriangle(GLflo­at red, GLfloat green, GLfloat blue) nemusí složitě počítat souřadnice trojúhelníků, neboť požadovaná transformace je už předem do transformační matice zadaná. Tento příklad je samozřejmě velmi jednoduchý, ale už z něj můžeme poznat, že například i složitou rotaci tělesa lze zadat pouze jedním příkazem a nemusí se programově přepočítávat pozice každého vertexu.

Skládání transformací

Pokud mezi zadáváním jednotlivých transformací nevkládáme příkaz glLoadIdentity(), dochází při modifikaci transformační matice k vynásobení původní hodnoty matice s dočasnou maticí, která je pro každou transformaci vytvořena. Důsledkem je, že výsledná transformační matice se chová tak, jakoby se transformace skládaly, tj. postupně prováděly. Jedná se praktickou vlastnost, protože sice můžeme zadat libovolné množství transformací, ale při výsledném transformování jednotlivých vrcholů (vertexů) se bude provádět pouze násobení čtyřsložkového vektoru jednou maticí velikosti 4×4. Protože však násobení matic není komutativní, musíme dát pozor na pořadí zadávání transformací.

V OpenGL platí, že transformace jsou na vertexy aplikovány v opačném pořadí, než jsou zavolány jejich korespondující příkazy. Jestliže například bude v programovém kódu sekvence příkazů glTranslatef(); glRotatef();, ve skutečnosti bude objekt (resp. jeho vertexy) nejprve otočen a teprve poté posunut. Na tuto vlastnost, která může při prvních pokusech s OpenGL působit problémy, se můžeme také dívat tak, že se neprovádí transformace se samotným objektem, ale postupně s celým souřadným systémem (nyní už ve správném pořadí).

Tato vlastnost OpenGL je demonstrována na příkladu číslo 8, který je k dispozici i ve formě zdrojového kódu s obarvenou syntaxí. Po spuštění se zobrazí čtyři trojúhelníky, na každý z nich je přitom aplikováno jiné pořadí transformací:

  1. Na bílý trojúhelník je aplikována pouze transformace rotace pomocí funkce glRotatef(). Trojúhelník je tedy zobrazen tak, že jeho levý vrchol je umístěn v počátku, což je levý dolní roh okna aplikace.
  2. Na zelený trojúhelník jsou aplikovány dvě transformace glRotatef()a glTranslatef(). Tyto transformace jsou však provedeny v opačném pořadí, tj. trojúhelník je nejprve posunut a teprve poté orotován okolo osy z – tj. počátku.
  3. Na červený trojúhelník je aplikována pouze transformace posunu glTranslatef(). Trojúhelník je vykreslen posunutý ze základní polohy bez jakékoliv rotace.
  4. Na modrý trojúhelník jsou aplikovány dvě transformace glTranslatef() a glRotatef(). Jelikož jsou transformace opět provedeny v opačném pořadí, je trojúhelník nejprve orotován okolo osy z(počátku) a teprve poté posunut dál od počátku. Výsledkem je, že trojúhelník zdánlivě nerotuje okolo počátku, ale okolo bodu, jehož souřadnice jsou zadány v příkazu glTranslatef().

Běh aplikace lze ovládat pomocí pěti kláves. Klávesa Esc ukončuje program a vrací řízení zpět operačnímu systému. Pomocí kláves , (čárka) a . (tečka) lze změnit úhel rotace trojúhelníků. Tuto rotaci lze změnit i pomocí kláves < a >, což jsou většinou stejné klávesy jako tečka a čárka, ale stisknuté spolu s modifikátorem­Shift.

Zásobník matic

Transformační matice lze v OpenGL ukládat do takzvaného zásobníku matic. Zásobník matic není nic jiného než datová oblast vyhrazená uvnitř bloku OpenGL, která se používá pro uložení šestnácti koeficientů transformační matice. Pro různé typy transformačních matic jsou vyhrazeny různé zásobníky s obecně odlišnou kapacitou. Aktuálně vybranou matici lze uložit na vrchol zásobníku zavoláním funkce void glPushMatrix(void), odstranění matice z vrcholu zásobníku obstará funkce void glPopMatrix(void). Ta matice, která je uložená na vrcholu zásobníku, je použita při transformacích.

Jak již bylo řečeno, je pro každý typ transformační matice (zejména ModelView a projekční matice) vyhrazen vlastní zásobník, který může mít odlišnou kapacitu. Většinou mívá zásobník pro ModelView matici největší kapacitu, protože se tato matice nejčastěji mění. Kapacitu jednotlivých zásobníků lze zjistit pomocí funkce void glGetIntegerv(GLe­num pname, GLint *params), kde za parametr pname můžete dosadit symbolické konstantyGL_MAX_MO­DELVIEW_STACK_DEP­TH resp. GL_MAX_PROJETI­ON_STACK_DEPTH. Pomocí této funkce je také možné zjistit aktuální obsazenost zásobníku – stačí použít parametry GL_MODELVIEW_STAC­K_DEPTH resp. GL_PROJECTION_STAC­K_DEPTH. Každá implementace OpenGL by měla mít zásobník pro ModelView matice s kapacitou minimálně třiceti dvou matic, pro zásobník projekčních a texturovacích matic je vyžadována pouze kapacita dvou matic.

Ukázka použití zásobníku matic je demonstrována na příkladu číslo 9, který je k dispozici i ve formě zdrojového kódu s obarvenou synaxí. Po spuštění je zobrazen jednoduchý stromeček, který se skládá z jednoho kmene a dvou větví. Stromečkem lze otáčet pomocí kláves . (tečka) a , (čárka). Lze také měnit úhel větvení; pro tento účel se používají klávesy >a < („většítko“ a „menšítko“).

Při vykreslování stromečku se používá několik transformací. Vykreslování začíná na pozici [200, 200], proto je po provedení všech transformací nutné provést posun do tohoto bodu příkazem glTranslatef(200­.0f, 200.0f, 0.0f). Otáčení celého obrazce v ploše (tedy kolem roviny z) zajistí příkaz glRotatef(angle, 0.0f, 0.0f, 1.0f). Dále jsou použity transformace pro posun počátku vykreslování na konec kmene (příkaz glTranslatef(0.0f, 100.0f, 0.0f)) a vykreslení obou větví. Při této operaci použijeme zásobník matic – nejprve se souřadný systém natočí tak, aby se vykreslila první větev. Potom vyjmeme ze zásobníku původní stav souřadného systému a vykreslíme druhou větev.

V příští části seriálu si ukážeme vykreslování bitmap, tj. jednobarevných rastrových obrázků.

Našli jste v článku chybu?

11. 8. 2003 13:06

Pavel Tisnovsky (neregistrovaný)

Přeji dobrý den,

problém může být v tom, jak jste double-buffer zapnul. Nejprve je třeba pomocí funkce glutInitDisplayMode() specifikovat, které buffery chcete použít. Jako parametr je pro double-buffering zapotřebí nastavit parametr GLUT_RGB | GLUT_DOUBLE (dvě konstanty, mezi nimi operátor OR).

Potom je po vykreslení scény (v našich příkladech je to ve funkci onDisplay()) zapotřebí provést glFlush() a následně glutSwapBuffers().

Co se týče nějaké minimální konfigurace pro ukázkové přík…





DigiZone.cz: „Black Friday 2016“: závěrečné zhodnocení

„Black Friday 2016“: závěrečné zhodnocení

Podnikatel.cz: Přehledná titulka, průvodci, responzivita

Přehledná titulka, průvodci, responzivita

Vitalia.cz: Jsou čajové sáčky toxické?

Jsou čajové sáčky toxické?

DigiZone.cz: Flix TV startuje i na Slovensku

Flix TV startuje i na Slovensku

Měšec.cz: Zdravotní a sociální pojištění 2017: Připlatíte

Zdravotní a sociální pojištění 2017: Připlatíte

Lupa.cz: Propustili je z Avastu, už po nich sahá ESET

Propustili je z Avastu, už po nich sahá ESET

Podnikatel.cz: K EET. Štamgast už peníze na stole nenechá

K EET. Štamgast už peníze na stole nenechá

Podnikatel.cz: EET: Totálně nezvládli metodologii projektu

EET: Totálně nezvládli metodologii projektu

Podnikatel.cz: Udávání a účtenková loterie, hloupá komedie

Udávání a účtenková loterie, hloupá komedie

Vitalia.cz: Proč vás každý zubař posílá na dentální hygienu

Proč vás každý zubař posílá na dentální hygienu

Lupa.cz: Proč firmy málo chrání data? Chovají se logicky

Proč firmy málo chrání data? Chovají se logicky

Vitalia.cz: „Připluly“ z Německa a možná obsahují jed

„Připluly“ z Německa a možná obsahují jed

Měšec.cz: mBank cenzuruje, zrušila mFórum

mBank cenzuruje, zrušila mFórum

Vitalia.cz: Když přijdete o oko, přijdete na rok o řidičák

Když přijdete o oko, přijdete na rok o řidičák

DigiZone.cz: Recenze Westworld: zavraždit a...

Recenze Westworld: zavraždit a...

Měšec.cz: Kdy vám stát dá na stěhování 50 000 Kč?

Kdy vám stát dá na stěhování 50 000 Kč?

120na80.cz: Na ucho teplý, nebo studený obklad?

Na ucho teplý, nebo studený obklad?

Vitalia.cz: Jmenuje se Janina a žije bez cukru

Jmenuje se Janina a žije bez cukru

120na80.cz: Pánové, pečujte o svoje přirození a prostatu

Pánové, pečujte o svoje přirození a prostatu

Podnikatel.cz: Chaos u EET pokračuje. Jsou tu další návrhy

Chaos u EET pokračuje. Jsou tu další návrhy