Grafická knihovna OpenGL (30): automatické generování texturovacích souřadnic

27. 1. 2004
Doba čtení: 8 minut

Sdílet

V tomto pokračování seriálu o grafické knihovně OpenGL si popíšeme možnosti automatického generování texturovacích souřadnic. Tuto techniku lze využít zejména ve dvou případech: zobrazování kontur složitých ploch (při práci s prostorovými tělesy v CAD systémech) a mapování okolního prostředí na zobrazované těleso (tzv. environment mapping).

Texturování 9 – generování texturovacích souřadnic

Obsah

Manuální nastavení texturovacích souřadnic
Automatické generování texturovacích souřadnic
Mapování prostředí
Demonstrační příklady
Pokračování
Zkomprimovaný článek i s příklady pro modemisty
 

Manuální nastavení texturovacích souřadnic

Před vysvětlením techniky automatického generování texturovacích souřadnic si nejdříve zopakujme, jakým způsobem se texturovací souřadnice zadávají „manuálně“, tj. voláním funkcí OpenGL přímo z aplikace.

Při použití texturování je nutné ke každému vrcholu (vertexu) vykreslovaného polygonu zadat i jeho souřadnice v textuře. Jednorozměrná textura je přitom chápána jako jednorozměrné pole texelů, kde první texel má souřadnici [0.0] a poslední texel souřadnici [1.0]. Dvourozměrná textura představuje rastrovou pixmapu, kde texel v levém dolním rohu má souřadnici [0.0, 0.0] a texel v pravém horním rohu [1.0, 1.0]. U trojrozměrných textur je situace obdobná, pouze se přidává jedna dimenze pole.

K těmto souřadnicím se přidává ještě souřadnice čtvrtá, která má význam obdobný jako čtvrtá souřadnice při zadávání poloh jednotlivých vertexů v rovině či prostoru. To znamená, že po provedení veškerých transformací texturovacích souřadnic pomocí matice GL_TEXTURE je zajištěno, aby čtvrtá souřadnice byla rovna jedné.

Pro dodržení konzistence s dokumentací OpenGL budeme první souřadnici značit písmenem s, druhou písmenem t, třetí r a čtvrtou q.

Jak již víme z předchozích dílů, zadávají se souřadnice do textury pomocí příkazů:
void glTexCoord[1–4][sifd](souřad­nice);
resp.
void glTexCoord[1–4][sifd]v(ukazatel na souřadnice);

Čísla 1, 2, 3 nebo 4 značí počet souřadnic, které voláním funkcí měníme. Pomocí písmen [sifd] se specifikuje datový typ každé souřadnice, tj. GLshort, GLint, GLfloat a GLdouble.

Výše uvedenými funkcemi je tedy možné zadat pro každý vertex jeho souřadnici v textuře, což však nemusí být vždy triviální úloha. Pro jednoduchá tělesa, jako je kvádr, kužel nebo válec, lze najít takové jednoznačné mapování z texturovacích souřadnic na souřadnice povrchu těles, aby nanášená textura nebyla zborcena. Pro jiné typy těles, jako je koule nebo tělesa s obecnou plochou, jednoznačné mapování nelze nalézt, proto je nanášená textura v těchto případech vždy zborcena (natahována nebo zkrácena).

Pomocí funkcí OpenGL můžeme automaticky mapovat texturu na prakticky libovolné těleso, vždy je však nutné mít na paměti, že může dojít (resp. u složitějších těles skoro vždy dojde) ke zborcení textury.

Automatické generování texturovacích souřadnic

V OpenGL lze místo manuálního generování texturovacích souřadnic použít automatické generování, které můžeme rozdělit na dvě části: buď je použito jednoduché lineární mapování, nebo se používá průmět textury nanesené na jednotkovou kouli. V tomto odstavci si popíšeme lineární mapování, druhá možnost je uvedena v následujícím odstavci.

Lineární automatické mapování texturovacích souřadnic pracuje na principu vyčíslení hodnoty výrazu:
coord_v=p1x0+p20+p3z0+p4w0
kde p1p4 jsou hodnoty zadané v dále popsané funkci void glTexGen*() a [x0, y0, z0, w0] jsou souřadnice vertexu, pro který se texturovací souřadnice počítají.

Pokud jsou hodnoty p1p4 normalizovány, je výsledkem předchozího výrazu vzdálenost vertexu od roviny reprezentované těmito hodnotami.

Výsledek coord_v může být spočítán pro každou texturovací souřadnici, tj. s, t, r nebo q.

Specifikace parametrů pro automatické lineární mapování se provádí pomocí funkcí:
glTexGeni(GLenum coord, GLenum pname, GLint param);
glTexGenf(GLenum coord, GLenum pname, GLfloat param);
glTexGend(GLenum coord, GLenum pname, GLdouble param);
glTexGeniv(GLenum coord, GLenum pname, GLint *param);
glTexGenfv(GLenum coord, GLenum pname, GLfloat *param);
glTexGendv(GLenum coord, GLenum pname, GLdouble *param);

Prvním argumentem těchto funkcí, tj. coord, se specifikuje jedna souřadnice do textury, jejíž parametry nastavujeme. Do tohoto argumentu lze zadávat hodnoty GL_S, GL_T, GL_R nebo GL_Q, které po řadě odpovídají souřadnicím s, t, r neboq.

Druhým argumentem pname specifikujeme, že v posledním argumentu jsou zadány způsoby generování texturovacích souřadnic (hodnota argumentu je rovna GL_TEXTURE_GEN_MO­DE) nebo parametry roviny, pomocí které se provádí výpočet souřadnice (hodnota argumentu je rovna GL_OBJECT_PLANE nebo GL_EYE_PLANE).

Třetí argument param má dva významy. Pokud byl argument pname nastaven na hodnotu GL_TEXTURE_GEN_MO­DE, je v tomto argumentu zadán způsob generování texturovacích souřadnic, který nabývá jedné z hodnot GL_OBJECT_LINEAR, GL_EYE_LINEAR nebo GL_SPHERE_MAP. Pokud však byl argument pname nastaven na hodnotu GL_OBJECT_PLANE nebo GL_EYE_PLANE, jsou v argumentu param uvedeny parametry roviny p1p4.

Pokud tedy nastavíme lineární mapování, jsou texturovací souřadnice vypočteny pro každý vertex podle výše uvedené funkce. Toho lze využít například při vykreslování těles s konturami, tj. rovnoběžnými proužky. Tento způsob vykreslování se používá například v CAD systémech při zobrazování těles se složitě tvarovaným povrchem.

Při tvorbě kontur se mohou dokonce použít pouze jednorozměrné textury, u nichž se snižují nároky na pamět a současně se zrychluje výpočet texturovacích souřadnic. Funkce, která nastaví vykreslování těles s konturami rovnoběžnými se z-ovou rovinou, může vypadat následovně:

void setTextureParameters(void)
{
  // rovina, vuci ktere se souracnice pocitaji
  GLfloat params[]={0.0, 0.0, 1.0, 0.0};

  // nastaveni opakovani textury
  glTexParameteri(GL_TEXTURE_1D,
                  GL_TEXTURE_WRAP_S,
                  GL_REPEAT);

  // volba filtru pri zmene meritka
  glTexParameteri(GL_TEXTURE_1D,
                  GL_TEXTURE_MAG_FILTER,
                  GL_LINEAR);
  glTexParameteri(GL_TEXTURE_1D,
                  GL_TEXTURE_MIN_FILTER,
                  GL_LINEAR);

  // nahrani rastrovych dat do textury
  glPixelStorei(  GL_UNPACK_ALIGNMENT, 1);
  glTexImage1D(   GL_TEXTURE_1D, 0, 3,
                  TEXTURE_WIDTH, 0,
                  GL_RGB, GL_UNSIGNED_BYTE, texture);

  // nastaveni rezimu textury
  glTexEnvi( GL_TEXTURE_ENV,
             GL_TEXTURE_ENV_MODE,
             GL_MODULATE);

  // nastaveni mapovani texturovacich souradnic
  glHint(    GL_PERSPECTIVE_CORRECTION_HINT,
             GL_NICEST);
  glTexGeni( GL_S,
             GL_TEXTURE_GEN_MODE,
             GL_OBJECT_LINEAR);
  glTexGenfv(GL_S,
             GL_OBJECT_PLANE,
             params);
  glEnable(GL_TEXTURE_GEN_S);
  glEnable(GL_TEXTURE_1D);
}

Ve výše zobrazené funkci se nastavuje generování souřadnic do textury přímo podle polohy jednotlivých vertexů v prostoru. Výsledkem je textura, která je na těleso mapována bez ohledu na pozici pozorovatele vůči zobrazovanému tělesu.

Existuje však ještě jedna metoda výpočtu texturovacích souřadnic, která zohledňuje vzájemnou pozici vykreslovaného tělesa a pozorovatele. V této metodě se souřadnice do textury počítají podle upraveného vzorce:
coord_v=p1‚xe+p‘ye+p3‚ze+p4‘we
ve kterém se veškeré výpočty provádějí v pohledových souřadnicích, tj. s polohou vertexu transformovanou do pohledových souřadnic a s rovinou transformovanou (násobenou) inverzní ModelView maticí.

Následuje ukázka funkce, pomocí které se nastaví výpočet souřadnice jednorozměrné textury v pohledových souřadnicích:

void setTextureParameters(void)
{
  // rovina, vuci ktere se souracnice pocitaji
  GLfloat params[]={0.0, 0.0, 1.0, 0.0};

  // nastaveni opakovani textury
  glTexParameteri(GL_TEXTURE_1D,
                  GL_TEXTURE_WRAP_S,
                  GL_REPEAT);

  // volba filtru pri zmene meritka
  glTexParameteri(GL_TEXTURE_1D,
                  GL_TEXTURE_MAG_FILTER,
                    GL_LINEAR);
  glTexParameteri(GL_TEXTURE_1D,
                  GL_TEXTURE_MIN_FILTER,
                  GL_LINEAR);
  // nahrani rastrovych dat do textury
  glPixelStorei(  GL_UNPACK_ALIGNMENT, 1);
  glTexImage1D(   GL_TEXTURE_1D, 0, 3,
                  TEXTURE_WIDTH, 0,
                  GL_RGB, GL_UNSIGNED_BYTE, texture);

  // nastaveni rezimu textury
  glTexEnvi( GL_TEXTURE_ENV,
             GL_TEXTURE_ENV_MODE,
             GL_MODULATE);

  // nastaveni mapovani texturovacich souradnic
  glHint(    GL_PERSPECTIVE_CORRECTION_HINT,
             GL_NICEST);
  glTexGeni( GL_S,
             GL_TEXTURE_GEN_MODE,
             GL_EYE_LINEAR);      // zde je zmena
  glTexGenfv(GL_S,
             GL_EYE_PLANE,        // a zde take
             params);
  glEnable(GL_TEXTURE_GEN_S);
  glEnable(GL_TEXTURE_1D);
}

Způsob výpočtu jednotlivých texturovacích souřadnic lze nastavovat nezávisle na sobě, tj. každá souřadnice může být vypočtena s pomocí jiné roviny.

Mapování prostředí

Existuje ještě jeden způsob, jakým lze automaticky vypočítat souřadnice do textury. Tento způsob se nazývá mapování (okolního) prostředí – environment mapping.

Při tomto způsobu výpočtu texturovacích souřadnic je vykreslované těleso jakoby obaleno koulí, na kterou je namapována textura. Tuto texturu lze získat například pomocí raytraceru s vhodně nastavenou kamerou typu „rybí oko“. Vlastní obrázek textury má v rastrovém obrázku tvar kruhu.

U každého vertexu musí být specifikována normála. Tato normála je chápána jako paprsek (polopřímka) vycházející z povrchu tělesa. Posléze je vypočten průsečík tohoto paprsku s koulí, na které je namapována textura. Podle souřadnic průsečíku na kouli je vyčíslena i souřadnice v textuře, protože mapování ze souřadnic na povrchu koule a souřadnic v rovině textury je jednoznačné.

Ukázka funkce, pomocí které se nastaví environment mapping:

void setTextureParameters(void)
{
  // nastaveni opakovani textury
  glTexParameteri(GL_TEXTURE_2D,
                  GL_TEXTURE_WRAP_S,
                  GL_REPEAT);
  glTexParameteri(GL_TEXTURE_2D,
                  GL_TEXTURE_WRAP_T,
                  GL_REPEAT);

  // volba filtru pri zmene meritka
  glTexParameteri(GL_TEXTURE_2D,
                  GL_TEXTURE_MAG_FILTER,
                  GL_LINEAR);
  glTexParameteri(GL_TEXTURE_1D,
                  GL_TEXTURE_MIN_FILTER,
                  GL_LINEAR);

  // nahrani rastrovych dat do textury
  glPixelStorei(  GL_UNPACK_ALIGNMENT, 1);
  glTexImage2D(   GL_TEXTURE_2D, 0, 4,
                  TEXTURE_WIDTH, TEXTURE_HEIGHT,
                  0, GL_RGBA, GL_UNSIGNED_BYTE, texture);

  // nastaveni rezimu textury
  glTexEnvi( GL_TEXTURE_ENV,
             GL_TEXTURE_ENV_MODE,
             GL_MODULATE);

  // nastaveni mapovani texturovacich souradnic
  glHint(    GL_PERSPECTIVE_CORRECTION_HINT,
             GL_NICEST);

  // nastaveni environment mappingu
  glTexGeni(GL_S, GL_SPHERE_MAP, 0);
  glTexGeni(GL_T, GL_SPHERE_MAP, 0);
  glEnable(GL_TEXTURE_GEN_S);
  glEnable(GL_TEXTURE_GEN_T);
  glEnable(GL_TEXTURE_2D);
} 

Demonstrační příklady

První příklad (obarvená verze): vykreslení čajové konvičky s nanesenou dvourozměrnou texturou. U tohoto modelu jsou texturovací souřadnice explicitně zadány, stejně jako normály jednotlivých vertexů. Kromě texturování je vypočteno i osvětlení objektu, přičemž je použita modulace textur.

Screenshot z prvního demonstračního příkladu
Obrázek 1: Screenshot z prvního demonstračního příkladu

Druhý příklad (obarvená verze): vykreslení čajové konvičky, na které jsou pomocí jednorozměrné textury vykresleny kontury. Výpočet texturovacích souřadnic je prováděn přímo z polohy vertexů.

Screenshot ze druhého demonstračního příkladu
Obrázek 2: Screenshot ze druhého demonstračního příkladu

Třetí příklad (obarvená verze): vykreslení čajové konvičky, na které jsou taktéž vykresleny kontury. V tomto případě se však výpočet texturovacích souřadnic provádí v pohledovém prostoru po transformaci vertexů maticí ModelView.

Screenshot ze třetího demonstračního příkladu
Obrázek 3: Screenshot ze třetího demonstračního příkladu

Čtvrtý příklad (obarvená verze): vykreslení čajové konvičky, na které je nanesena textura metodou environment mappingu. Při rotaci tělesa se tedy textura po povrchu tělesa přesouvá.

Screenshot ze čtvrtého demonstračního příkladu
Obrázek 4: Screenshot ze čtvrtého demonstračního příkladu

Pátý příklad (obarvená verze): kombinace lineárního a sférického mapování (environment mappingu). Každá texturovací souřadnice je v tomto příkladě generována podle jiného vzorce.

Screenshot z pátého demonstračního příkladu
Obrázek 5: Screenshot z pátého demonstračního příkladu

bitcoin_skoleni

Pokračování

V dalším pokračování si popíšeme vztah mezi vykreslovacím řetězcem a framebufferem. Také si vysvětlíme princip práce stencil bufferu a accumulation bufferu.

Zkomprimovaný článek i s příklady pro modemisty

Pro majitele pomalejšího připojení k internetu je zde k dispozici celý článek i s přílohami zabalený do jednoho zip souboru.

Autor článku

Vystudoval VUT FIT a v současné době pracuje na projektech vytvářených v jazycích Python a Go.