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í matice
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:
- GL_MODELVIEW – bude se měnit ModelView matrix, tj. matice, ve které jsou uloženy modelové a pohledové transformace (transformace objektů a nastavení kamery).
- GL_PROJECTION – bude se měnit Projection matrix, tj. matice, která se používá pro nastavení perspektivní nebo ortogonální projekce kamery.
- 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_MATRIX_MODE, ¤tMode), po jehož provedení je v proměnné currentMode některá z konstant GL_MODELVIEW,GL_PROJECTION 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(),glTranslate(), glScale() a glRotate*().
Nejjednodušší z těchto funkcí je funkce void glLoadIdentity(void). 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(GLdouble x, GLdouble y, GLdouble z) a void glTranslatef(GLfloat 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_MATRIX, GL_PROJECTION_MATRIX neboGL_TEXTURE_MATRIX. 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.