Hlavní navigace

Grafická knihovna OpenGL (5): transformační matice a lineární transformace

Pavel Tišnovský

V tomto díle si popíšeme důležitou součást knihovny OpenGL - transformační matice a s nimi související lineární transformace. Změnou obsahu transformačních matic lze v OpenGL provádět několik operací: nastavení viditelné části scény na obrazovce, nastavení kamery a transformace jednotlivých těles ve scéně.

Transformační matice a lineární transformace

Transformační matice představují v počítačové grafice prostředek pro vyjádření lineárních transformací. Mezi lineární transformace patří posun, otáčení, změna měřítka a zkosení. Jestliže máme tři body, které leží na jedné přímce, tak po aplikaci libovolné lineární transformace získáme nové tři body, které také leží na přímce. Všechny lineární transformace lze vyjádřit maticí o rozměrech n x n, kde n je dimenze vektoru či bodu, který transformujeme.

Pokud provádíme lineární transformace v ploše, vyjadřujeme souřadnici dvěma složkami – x a y. Lineární transformaci lze zapsat jako výpočet nových souřadnic x' a y':
x'=xa11+ya12,
y'=xa21+ya22.

Členy a11, a12, a21 aa22 představují parametry lineární transformace.

Přehlednější je však vektorově/maticový zápis, kdy dvojici [x, y] označíme jako v, dvojici [x', y'] jako v' a hodnotya11, a12, a21 a a22 zapíšeme jako prvky do matice M o rozměrech 2×2. Potom lze celou lineární transformaci zapsat jedním vztahem:
v'=M*v – v tomto případě jsou v a v' sloupcové vektory.

Pro zadání lineárních transformací v trojrozměrném prostoru by nám měla stačit transformační matice o rozměrech 3×3 prvky. To je skutečně pravda, ale v počítačové grafice často potřebujeme kromě lineárních transformací vyjádřit i perspektivní projekci. Proto se ke třem souřadnicím [x, y, z] přidává ještě čtvrtá souřadnice označovaná w ze slova weight – váha. Bod je potom vyjádřen čtveřicí [x, y, z, 1] a vektor [x, y, z, 0]. Transformační matice je poté zvětšena na rozměry 4×4 prvky.

Po provedení transformace získáme souřadnice nového bodu, které mají obecně tvar [x', y', z', w']. My však víme, že pro body platí, že čtvrtá souřadnice je rovna jedničce. Proto musíme ostatní tři souřadnice vydělit souřadnicí poslední (w'), čímž získáme normovaný bod: [x'/w', y'/w', z'/w', w'/w']=[x'/w', y'/w', z'/w', 1]. Toto vydělení poslední souřadnicí se v počítačové grafice někdy poněkud nesprávně nazývá perspektivní korekce.

Důležitou vlastností lineárních transformací je, že je lze skládat. Složením dvou transformací vyjádřených maticemi M1 aM2 vznikne transformace Mc=M2x M1, kde operátor x značí maticový součin. Takto lze skládat libovolné množství transformací, což přináší značné urychlení při vlastním vykreslování, neboť složení transformací se provede pouze jednou a teprve výsledná transformace se aplikuje na body v rovině nebo prostoru. Je pouze zapotřebí zajistit správné pořadí provádění transformací, protože maticový součin není komutativní operace.

Transformační matice v OpenGL

V OpenGL existují tři transformační matice, které se postupně aplikují na body (vrcholy, vertexy) popř. i na normály vrcholů. První transformační matice se jmenuje ModelView matrix. Na tuto matici se můžeme dívat jako na spojení modelové matice a pohledové matice, protože se používá jak pro nastavení pozice kamery, tak i pro manipulaci s objekty (modely) ve scéně. Druhá transformační matice se jmenuje Projection matrix a používá se pro nastavení perspektivní projekce kamery. Třetí transformační matice se jmenuje Viewport matrix a používá se po provedení perspektivní projekce k mapování objektů z abtraktních souřadnic do souřadnic okna. Tato poslední matice ve skutečnosti pouze provádí transformaci v dvojrozměrné ploše, proto se s ní v OpenGL nepracuje jako s „plnohodnotnou“ maticí. Kromě těchto tří matic můžeme měnit matici, která se používá při mapování textur na povrch objektů. Tato matice se nazývá Texture matrix.

Změna transformačních matic a nastavení aktuální transformační ma­tice

Při změně některé z transformačních matic musíme nejprve určit, kterou transformační matici budeme měnit. K tomuto účelu se používá funkce void glMatrixMode(GLenum mode). Tato funkce má jeden parametr mode, jímž určujeme matici, kterou budeme dalšími příkazy změnit. Parametr může nabývat tří hodnot, reprezentovaných symbolickými konstantami:

  1. GL_MODELVIEW – bude se měnit ModelView matrix, tj. matice, ve které jsou uloženy modelové a pohledové transformace (transformace objektů a nastavení kamery).
  2. GL_PROJECTION – bude se měnit Projection matrix, tj. matice, která se používá pro nastavení perspektivní nebo ortogonální projekce kamery.
  3. GL_TEXTURE – bude se měnit Texture matrix, tj. matice, která se používá při mapování textur na povrch objektů.

Aktuálně nastavenou matici lze zjistit pomocí příkazu glGetIntegerv(GL_MAT­RIX_MODE, &currentMode), po jehož provedení je v proměnné currentMode některá z konstant GL_MODELVIEW,GL_PRO­JECTION nebo GL_TEXTURE.

Změna obsahu aktuálně nastavené transformační matice

S obsahem aktuálně nastavené matice lze manipulovat pomocí funkcí glLoadIdentity(), glLoadMatrix(), glMultMatrix(),glTran­slate(), glScale() a glRotate*().

Nejjednodušší z těchto funkcí je funkce void glLoadIdentity(vo­id). Tato funkce nahraje do aktuálně nastavené transformační matice koeficienty odpovídající jednotkové matici, tj. matici, ve které jsou všechny prvky vynulovány s výjimkou prvků hlavní diagonály, které jsou nastaveny na jedničku. Tato matice hraje úlohu neutrálního prvku při násobení matic nebo při násobení vektoru maticí. Při nastavování některé transformační matice se v naprosté většině případů začíná touto funkcí, neboť pomocí ní matici „připravíme“ na aplikaci dalších transformací.

Funkce glLoadMatrix*() se používá pro přímé nastavení prvků matice. Tato funkce existuje ve dvou variantách lišících se pouze typem pole, které funkci předáváme jako parametr. První varianta je nadeklarována jako void glLoadMatrixd(const GLdouble *m), druhá varianta jako void glLoadMatrixf(const GLfloat *m). U první varianty má pole jako své prvky hodnoty typu GLdouble, ve druhé variantě jsou to prvky typuGLfloat.

Další funkce glMultMatrix*() slouží k vynásobení aktuálně nastavené transformační matice maticí zadanou jako parametr této funkce. Opět existují dvě varianty, které se liší typem prvků předávaného pole. Tyto varianty jsou nadeklarovány jako void glMultMatrixd(const GLdouble *m) a void glMultMatrixf(const GLfloat *m). U první varianty se používají hodnoty typu GLdouble, u druhé typu GLfloat.

Další tři funkce, glTranslate(), glScale() a glRotate*() jsou používány mnohem častěji než předchozí dvě funkce. U těchto funkcí se nemanipuluje přímo s jednotlivými prvky matice, ale zadávají se základní lineární transformace – posun, změna měřítka a rotace. Pro zadané transformace se vytvoří dočasná matice a aktuální matice (většinou je to matice ModelView) je touto dočasnou maticí vynásobena.

Funkce glTranslate*(), která existuje ve dvou variantách void glTranslated(GLdou­ble x, GLdouble y, GLdouble z) a void glTranslatef(GLflo­at x, GLfloat y, GLfloat z), specifikuje posun o vektor[x, y, z].

Funkce glScale*() s variantami void glScaled(GLdouble x, GLdouble y, GLdouble z) a void glScalef(GLfloat x, GLfloat y, GLfloat z) slouží k zadání transformace změny měřítka, kdy je těleso nezávisle zvětšeno/zmenšeno ve třech směrech odpovídajících jednotlivým souřadným osám.

Funkce glRotate*(), která má opět dvě varianty void glRotated(GLdouble angle, GLdouble x, GLdouble y, GLdouble z) a void glRotatef(GLfloat angle, GLfloat x, GLfloat y, GLfloat z), specifikuje transformaci rotace. Těleso je otočeno o úhel angle okolo osy procházející počátkem a bodem (x, y, z). Úhel angle je v obou variantách zadán ve stupních. Bod, jímž osa rotace prochází, by neměl být nastaven na souřadnice (0, 0, 0).

Získání hodnot prvků jednotlivých transformačních matic

Pro získání hodnot, které mají jednotlivé prvky transformačních matic, lze použít funkci void glGetDoublev(GLenum pname, GLdouble * params) nebo void glGetFloatv(GLenum pname, GLfloat * params). Parametr pname musí obsahovat jednu z těchto symbolických konstant: GL_MODELVIEW_MAT­RIX, GL_PROJECTION_MAT­RIX neboGL_TEXTURE_MAT­RIX. V poli params jsou potom vráceny prvky příslušné transformační matice.

Demonstrační příklad číslo 6 ukazuje použití některých funkcí popsaných v tomto dílu. V příkladu se využívá především výstup na konzoli, který však lze běžnými prostředky shellu přesměrovat do souboru. Po spuštění aplikace se čeká na stisk některé alfanumerické klávesy. Po jejím stisku se postupně mění prvky v ModelView matici a po změně je matice vždy vypsána. Po stisknutí klávesy ESC se zavře hlavní okno aplikace a program se ukončí. K dispozici je i zdrojový kód se zvýrazněním syntaxe.

V příštím dílu si ukážeme jedno z možných použití transformačních matic, skládání transformací a zásobník matic.

Našli jste v článku chybu?

6. 8. 2003 20:36

xrubicmaster (neregistrovaný)

A prave proto posun NENI linearni transformace, jenze tato veta: "Mezi lineární transformace patří posun, otáčení, změna měřítka a zkosení." z Vaseho clanku tvrdi opak.

Homogenni souradnice toto resi pridanim dalsiho koordinatu, coz je vlastne rozsireni na ctyrrozmerny prostor, tam se provede nejaka transformace (avsak zase to neni posun) a vhodnou reprezentaci ctyrrozmernych koordinatu v trojrozmernem prostoru se novy vektor jevi posunuty.

Avsak toto funguje spravne pouze v pripade, kdy (…



1. 8. 2003 14:38

Pavel Tisnovsky (neregistrovaný)

Dobrý den,

s průhledností (resp. obecně blendingem) je to trošku ošidné, protože z principu fungování grafického akcelerátoru vyplývá, že u průhledných objektů opravdu záleží na pořadí vykreslování jednotlivých primitiv.

Tento problém se obecně řeší několika způsoby:

1. pokud vykreslujete POUZE neprůhledné objekty, lze bez dalších komplikací použít Z-buffer (resp. depth buffer). Ten si alokujete při startu aplikace a povolíte příkazem glEnable(GL_DEPTH_TEST). Objekty se mohou vykreslova…





Měšec.cz: Komu musí od ledna zvýšit mzdu?

Komu musí od ledna zvýšit mzdu?

Vitalia.cz: Vychytané vály a válečky na vánoční cukroví

Vychytané vály a válečky na vánoční cukroví

Lupa.cz: Insolvenční řízení kvůli cookies? Vítejte v ČR

Insolvenční řízení kvůli cookies? Vítejte v ČR

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

120na80.cz: 5 nejčastějších mýtů o kondomech

5 nejčastějších mýtů o kondomech

Podnikatel.cz: Podnikatelům dorazí varování od BSA

Podnikatelům dorazí varování od BSA

Vitalia.cz: Láska na vozíku: Přitažliví jsme pro tzv. pečovatelky

Láska na vozíku: Přitažliví jsme pro tzv. pečovatelky

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

Jmenuje se Janina a žije bez cukru

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

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

Měšec.cz: Stavební spoření: alternativa i pro seniory

Stavební spoření: alternativa i pro seniory

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

mBank cenzuruje, zrušila mFórum

Podnikatel.cz: Snížení DPH na 15 % se netýká všech

Snížení DPH na 15 % se netýká všech

Vitalia.cz: Mondelez stahuje rizikovou čokoládu Milka

Mondelez stahuje rizikovou čokoládu Milka

Vitalia.cz: Pamlsková vyhláška bude platit jen na základkách

Pamlsková vyhláška bude platit jen na základkách

DigiZone.cz: Flix TV: dva set-top boxy za korunu

Flix TV: dva set-top boxy za korunu

Lupa.cz: Co se dá měřit přes Internet věcí

Co se dá měřit přes Internet věcí

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

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

Root.cz: Certifikáty zadarmo jsou horší než za peníze?

Certifikáty zadarmo jsou horší než za peníze?

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

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