Prav² Φas vrßtit se zpßtky na zaΦßtek a zaΦφt si opakovat. NovßΦk∙m v OpenGL se absolutn∞ nedoporuΦuje! Pokud, ale mßte odvahu, m∙₧ete zkusit dobrodru₧stvφ s nadupanou grafikou. V tΘto lekci modifikujeme k≤d z ÜestΘ lekce, aby podporoval hardwarov² multi texturing p°es opravdu skv∞l² vizußlnφ efekt nazvan² bump mapping.
P°i p°ekladu tΘto lekce jsem zva₧oval zda mßm n∞kterΘ termφny p°eklßdat do ΦeÜtiny. Ale vzhledem k tomu, ₧e jsou to v∞tÜinou nßzvy, kterΘ se b∞₧n∞ v oboru poΦφtaΦovΘ grafiky objevujφ, rozhodl jsem se nechat je v p∙vodnφm zn∞nφ. Aby vÜak i ti, kte°φ se s nimi setkßvajφ poprvΘ, v∞d∞li o Φem je °eΦ, tak je zde v rychlosti vysv∞tlφm:
OpenGL extension je funkce, kterß nenφ v b∞₧nΘ specifikaci OpenGL dostupnß, ale kv∙li nov²m mo₧nostem grafick²ch akcelerßtor∙ a nov²m postup∙m p°i programovßnφ byla do OpenGL dodateΦn∞ p°idßna. Tyto funkce ve svΘm nßzvu obsahujφ EXT nebo ARB. Firmy se samoz°ejm∞ sna₧φ, aby jejich akcelerßtor podporoval t∞chto rozÜφ°enφ co nejvφce, proto₧e mnohΘ z nich zrychlujφ prßci, p°idßvajφ novΘ mo₧nosti nebo zvyÜujφ v²kon.
Bumpmapa je textura, kterß obsahuje informace o reliΘfu. V∞tÜinou b²vß ve stupnφch Üedi, kde tmavß mφsta udßvajφ vyv²Üeniny a sv∞tlß r²hy, nebo naopak - to zßle₧φ na programßtorovi.
Emboss bumpmapping je postup vytvß°enφ reliΘfovan²ch textur, u kter²ch se zdß, ₧e jsou tvarovanΘ i do hloubky - hlavnφ tΘma tΘto lekce.
Alpha kanßl je poslednφ slo₧ka RGBA barvy, kterß obsahuje informace o pr∙hlednosti. Pokud je alpha maximßlnφ (255 nebo 1.0f), tak nenφ objekt v∙bec pr∙hledn². Pokud je alpha nulovß je objekt neviditeln².
Blending je mφchßnφ alpha kanßlu s barevnou texturou. Dociluje se jφm pr∙hlednosti.
Artefakt je n∞jak² vizußlnφ prvek, kter² by se v renderovanΘ scΘn∞ nem∞l objevovat. NicmΘn∞ vzhledem k tomu, ₧e postupy, kterΘ by je nezanechßvaly jsou v∞tÜinou velmi pomalΘ, musφ se pou₧φvat jinΘ, kterΘ na ·kor kvality zv²Üφ rychlost renderovßnφ.
DalÜφ nßzvy typu vertex, pipeline, ... by m∞ly b²t dob°e znßmΘ z p°edchozφch tutorißl∙.
Doufßm, ₧e Vßm p°eklad i tΘma budou srozumitelnΘ a ₧e Vßm pomohou vytvß°et kvalitnφ OpenGL aplikace. Pokud byste narazili na n∞jak² problΘm, nenφ nic jednoduÜÜφho ne₧ poslat dotaz na wessan@email.cz. Rßd Vßm na vÜechny otßzky odpovφm, p°φpadn∞ opravφm nedostatky v textu.
Vßclav SlovßΦek - Wessan
Tato lekce byla napsßna Jensem Schneiderem. Voln∞ vychßzφ z 6. lekce, i kdy₧ vzniklo mnoho zm∞n. NauΦφte se zde:
Tak₧e, jdeme na to:
#include <windows.h>// HlaviΦkov² soubor pro Windows
#include <stdio.h>// HlaviΦkov² soubor pro standardnφ vstup/v²stup
#include <gl\gl.h>// HlaviΦkov² soubor pro OpenGL32 knihovnu
#include <gl\glu.h>// HlaviΦkov² soubor pro Glu32 knihovnu
#include <gl\glaux.h>// HlaviΦkov² soubor pro Glaux knihovnu
#include "glext.h"// HlaviΦkov² soubor pro multitexturing
#include <string.h>// HlaviΦkov² soubor pro °et∞zce
#include <math.h>// HlaviΦkov² soubor pro matematiku
GLfloat MAX_EMBOSS udßvß "sφlu" bumpmappingu. VyÜÜφ hodnoty hodn∞ zv²raznφ efekt, ale stejn∞ tak snφ₧φ kvalitu obrazu tφm, ₧e zanechßvajφ v rozφch ploch takzvanΘ "artefakty".
#define MAX_EMBOSS (GLfloat)0.008f// Maximßlnφ posunutφ efektem
Fajn, p°ipravφme se na pou₧itφ GL_ARB_multitexture. Je to celkem jednoduchΘ:
V∞tÜina grafick²ch akcelerßtor∙ mß dnes vφce ne₧ jednu texturovacφ jednotku. Abychom mohli tΘto v²hody vyu₧φt, musφme prov∞°it, zda akcelerßtor podporuje GL_ARB_multitexture, kter² umo₧≥uje namapovat dv∞ nebo vφce textur na jeden ·tvar p°i jednom pr∙chodu pipeline. Neznφ to p°φliÜ v²znamn∞, ale opak je pravdou! Skoro v₧dy kdy₧ n∞co programujete, p°idßnφm dalÜφ textury na objekt, razantn∞ zv²Üφte jeho vizußlnφ kvalitu. D°φve bylo nutno pou₧φt dv∞ proklßdanΘ textury p°i vφcenßsobnΘm vykreslovßnφ geometrie, co₧ m∙₧e vΘst k velkΘmu poklesu v²konu. Dßle v tutorißlu bude multitexturing jeÜt∞ podrobn∞ji popsßn.
Te∩ zp∞t ke k≤du: __ARB_ENABLE je u₧ito pro urΦenφ toho, zda chceme vyu₧φt multitexturingu, kdy₧ bude dostupn². Pokud chcete poznat vaÜφ kartou podporovanß OpenGL rozÜφ°enφ, pouze odkomentujte #define EXT_INFO. Dßle chceme prov∞°it podporu extensions p°i b∞hu programu, abychom zajistili p°enositelnost k≤du. Proto pot°ebujeme mφsto pro pßr °et∞zc∙. Dßle chceme rozliÜovat mezi mo₧nostφ pou₧φvat extensions a samotn²m pou₧φvßnφm. Nakonec pot°ebujeme v∞d∞t, kolik texturovacφch jednotek mßme k dispozici (pou₧ijeme ale pouze dv∞). Alespo≥ jedna texturovacφ jednotka je v₧dy p°φtomna na akcelerßtoru podporujφcφm OpenGL, tak₧e nastavφme maxTexelUnits na hodnotu 1.
#define __ARB_ENABLE true// Pou₧ito pro vy°azenφ multitexturingu
// #define EXT_INFO// Odkomentujte, pokud chcete p°i startu vid∞t podporovanß rozÜφ°enφ OpenGL
#define MAX_EXTENSION_SPACE 10240// Mφsto pro °et∞zce s OpenGL rozÜφ°enφmi
#define MAX_EXTENSION_LENGTH 256// Maximum znak∙ v jednom °et∞zci s rozÜφ°enφm
bool multitextureSupported = false;// Indikßtor podpory multitexturingu
bool useMultitexture = true;// Pou₧it multitexturing?
GLint maxTexelUnits = 1;// PoΦet texturovacφch jednotek - nejmΘn∞ 1
Nßsledujφcφ °ßdky slou₧φ k tomu, aby spojily rozÜφ°enφ s volßnφm funkcφ v C++. Pouze vyu₧ijeme PNF-kdo-to-kdy-p°eΦetl jako p°eddefinovanΘho datovΘho typu schopnΘho popsat volßnφ funkcφ. ZpoΦßtku nenφ jistΘ, zda zφskßme p°φstup k t∞mto prototyp∙m funkcφ, tudφ₧ je nastavφme na NULL. P°φkazy glMultiTexCoordifARB odkazujφ na dob°e znßmΘ p°φkazy glTexCoordif(), udßvajφcφ i-rozm∞rnΘ sou°adnice textury. VÜimn∞te si, ₧e proto mohou ·pln∞ nahradit p°φkazy glTexCoordif. D°φve jsme pou₧φvali pouze verzi pro typ GLfloat, my pot°ebujeme pouze prototypy k p°φkaz∙m konΦφcφm na "f" - ostatnφ jsou potom taky dostupnΘ (fv, i, ...). Poslednφ dva prototypy slou₧φ k urΦenφ texturovacφ jednotky, kterß bude p°ijφmat informace o textu°e (glActiveTextureARB()) a k urΦenφ, kterß texturovacφ jednotka je asociovßna s p°φkazem ArrayPointer (glClientActiveTextureARB). Mimochodem: ARB je zkratkou "Architectural Review Board". RozÜφ°enφ s ARB v nßzvu nejsou vy₧adovßny pro implementaci kompatibilnφ s OpenGL, ale jsou Üiroce vyu₧φvßny a podporovßny.
PFNGLMULTITEXCOORD1FARBPROC glMultiTexCoord1fARB = NULL;
PFNGLMULTITEXCOORD2FARBPROC glMultiTexCoord2fARB = NULL;
PFNGLMULTITEXCOORD3FARBPROC glMultiTexCoord3fARB = NULL;
PFNGLMULTITEXCOORD4FARBPROC glMultiTexCoord4fARB = NULL;
PFNGLACTIVETEXTUREARBPROC glActiveTextureARB = NULL;
PFNGLCLIENTACTIVETEXTUREARBPROC glClientActiveTextureARB = NULL;
Pot°ebujeme globßlnφ prom∞nnΘ:
GLuint filter=1;// Jak² filtr pou₧φt
GLuint texture[3];// Mφsto pro t°i textury
GLuint bump[3];// NaÜe bumpmapy
GLuint invbump[3];// InvertovanΘ bumpmapy
GLuint glLogo;// Mφsto pro OpenGL Logo
GLuint multiLogo;// Mφsto pro logo s multitexturingem
GLfloat LightAmbient[] = { 0.2f, 0.2f, 0.2f};// Barva ambientnφho sv∞tla je 20% bφlß
GLfloat LightDiffuse[] = { 1.0f, 1.0f, 1.0f};// Dif·znφ sv∞tlo je bφlΘ
GLfloat LightPosition[] = { 0.0f, 0.0f, 2.0f};// Pozice je n∞kde uprost°ed scΘny
GLfloat Gray[] = { 0.5f, 0.5f, 0.5f, 1.0f };// Barva okraje textury
bool emboss = false;// Jenom Emboss, ₧ßdnß zßkladnφ textura
bool bumps = true;// Pou₧φvat bumpmapping?
GLfloat xrot;// X rotace
GLfloat yrot;// Y rotace
GLfloat xspeed;// Rychlost x rotace
GLfloat yspeed;// Rychlost y rotace
GLfloat z = -5.0f;// Hloubka v obrazovce
DalÜφ Φßst k≤du obsahuje sou°adnice kostky sestavenΘ z GL_QUADS. Ka₧d²ch p∞t Φφsel reprezentuje jednu sadu 2D texturovacφch sou°adnic a jednu sadu 3D vertexov²ch sou°adnic bodu. Data jsou uvedena v poli kv∙li snazÜφmu vykreslovßnφ ve for smyΦkßch. B∞hem jednoho renderovacφho cyklu budeme tyto sou°adnice pot°ebovat vφcekrßt.
GLfloat data[] =
{
// P°ednφ st∞na
0.0f, 0.0f, -1.0f, -1.0f, +1.0f,
1.0f, 0.0f, +1.0f, -1.0f, +1.0f,
1.0f, 1.0f, +1.0f, +1.0f, +1.0f,
0.0f, 1.0f, -1.0f, +1.0f, +1.0f,
// Zadnφ st∞na
1.0f, 0.0f, -1.0f, -1.0f, -1.0f,
1.0f, 1.0f, -1.0f, +1.0f, -1.0f,
0.0f, 1.0f, +1.0f, +1.0f, -1.0f,
0.0f, 0.0f, +1.0f, -1.0f, -1.0f,
// Hornφ st∞na
0.0f, 1.0f, -1.0f, +1.0f, -1.0f,
0.0f, 0.0f, -1.0f, +1.0f, +1.0f,
1.0f, 0.0f, +1.0f, +1.0f, +1.0f,
1.0f, 1.0f, +1.0f, +1.0f, -1.0f,
// Dolnφ st∞na
1.0f, 1.0f, -1.0f, -1.0f, -1.0f,
0.0f, 1.0f, +1.0f, -1.0f, -1.0f,
0.0f, 0.0f, +1.0f, -1.0f, +1.0f,
1.0f, 0.0f, -1.0f, -1.0f, +1.0f,
// Pravß st∞na
1.0f, 0.0f, +1.0f, -1.0f, -1.0f,
1.0f, 1.0f, +1.0f, +1.0f, -1.0f,
0.0f, 1.0f, +1.0f, +1.0f, +1.0f,
0.0f, 0.0f, +1.0f, -1.0f, +1.0f,
// Levß st∞na
0.0f, 0.0f, -1.0f, -1.0f, -1.0f,
1.0f, 0.0f, -1.0f, -1.0f, +1.0f,
1.0f, 1.0f, -1.0f, +1.0f, +1.0f,
0.0f, 1.0f, -1.0f, +1.0f, -1.0f
};
DalÜφ Φßst k≤du rozhoduje o pou₧itφ OpenGL extensions za b∞hu programu.
P°edpoklßdejme, ₧e mßme dlouh² °et∞zec obsahujφcφ nßzvy vÜech podporovan²ch rozÜφ°enφ odd∞len²ch znakem novΘho °ßdku -'\n'. Pot°ebujeme vyhledat znak novΘho °ßdku a tuto Φßst zaΦφt porovnßvat s hledan²m °et∞zcem, dokud nenarazφme na dalÜφ znak novΘho °ßdku, nebo dokud nalezen² °et∞zec neodpovφdß tomu hledanΘmu. V prvnφm p°φpad∞ vrßtφme true, v druhΘm p°φpad∞ vezmeme dalÜφ sub-°et∞zec dokud nenarazφme na konec °et∞zce. Budeme si muset dßt pozor na to, zda °et∞zec nezaΦφnß znakem novΘho °ßdku.
Poznßmka: Kontrola podpory rozÜφ°enφ by se m∞la VÄDY provßd∞t a₧ za b∞hu programu.
bool isInString(char *string, const char *search)
{
int pos = 0;
int maxpos = strlen(search)-1;
int len = strlen(string);
char *other;
for (int i=0; i<len; i++)
{
if ((i==0) || ((i>1) && string[i-1]=='\n'))// NovΘ rozÜφ°enφ zaΦφnß zde
{
other = &string[i];
pos=0;// ZaΦφt novΘ hledßnφ
while (string[i]!='\n')// Hledßnφ celΘho °et∞zce jmΘna rozÜφ°enφ
{
if (string[i]==search[pos])
pos++;// DalÜφ znak
if ((pos>maxpos) && string[i+1]=='\n')
return true; // A mßme to!
i++;
}
}
}
return false;// Sm∙la, nic jsme nenaÜli!
}
Te∩ musφme zφskat °et∞zec obsahujφcφ nßzvy extensions a p°evΘst ho tak, aby jednotlivΘ nßzvy byly odd∞leny znakem novΘho °ßdku. Pokud najdeme sub-°et∞zec "GL_ARB_multitexture", tak je tato funkce podporovanß. Ale my jφ pou₧ijeme, jen kdy₧ je __ARB_ENABLE nastaveno na true. JeÜt∞ pot°ebujeme zjistit podporu GL_EXT_texture_env_combine. Toto rozÜφ°enφ zavßdφ nov² zp∙sob interakce s texturovacφmi jednotkami. My to pot°ebujeme, proto₧e GL_ARB_multitexture pouze p°enßÜφ v²stup z jednΘ texturovacφ jednotky do dalÜφ s vyÜÜφm Φφslem. Ne₧ abychom pou₧φvali dalÜφ komplexnφ rovnice pro v²poΦet blendingu (kterΘ by ale mohly mφt odliÜn² efekt), rad∞ji zajistφme podporu tohoto rozÜφ°enφ. Pokud jsou vÜechna rozÜφ°enφ podporovßna, zjistφme kolik texturovacφch jednotek mßme k dispozici a hodnotu ulo₧φme do maxTexelUnits. Pak musφme spojit funkce s naÜimi jmΘny. To provedeme pomocφ funkce wglGetProcAdress() s parametrem obsahujφcφm nßzev funkce.
bool initMultitexture(void)
{
char *extensions;
extensions = strdup((char *) glGetString(GL_EXTENSIONS));// Zφskßnφ °et∞zce s rozÜφ°enφmi
int len = strlen(extensions);// DΘlka °et∞zce
for (int i = 0; i<len; i++)// Rozd∞lit znakem novΘho °ßdku mφsto mezery
if (extensions[i] == ' ')
extensions[i] = '\n';
#ifdef EXT_INFO
MessageBox(hWnd,extensions,"supported GL extensions",MB_OK | MB_ICONINFORMATION);
#endif
if (isInString(extensions,"GL_ARB_multitexture")// Je multitexturing podporovßn?
&& __ARB_ENABLE// P°φznak pro povolenφ multitexturingu
&& isInString(extensions,"GL_EXT_texture_env_combine"))// Je podporovßno texture-environment-combining?
{
glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &maxTexelUnits);
glMultiTexCoord1fARB = (PFNGLMULTITEXCOORD1FARBPROC)wglGetProcAddress("glMultiTexCoord1fARB");
glMultiTexCoord2fARB = (PFNGLMULTITEXCOORD2FARBPROC)wglGetProcAddress("glMultiTexCoord2fARB");
glMultiTexCoord3fARB = (PFNGLMULTITEXCOORD3FARBPROC)wglGetProcAddress("glMultiTexCoord3fARB");
glMultiTexCoord4fARB = (PFNGLMULTITEXCOORD4FARBPROC)wglGetProcAddress("glMultiTexCoord4fARB");
glActiveTextureARB = (PFNGLACTIVETEXTUREARBPROC)wglGetProcAddress("glActiveTextureARB");
glClientActiveTextureARB = (PFNGLCLIENTACTIVETEXTUREARBPROC)wglGetProcAddress("glClientActiveTextureARB");
#ifdef EXT_INFO
MessageBox(hWnd,"The GL_ARB_multitexture extension will be used.","feature supported!",MB_OK | MB_ICONINFORMATION);
#endif
return true;
}
useMultitexture = false;// Nem∙₧eme to pou₧φvat, pokud to nenφ podporovßno!
return false;
}
InitLights() pouze inicializuje osv∞tlenφ. Je volßna funkcφ initGL().
void initLights(void)
{
glLightfv(GL_LIGHT1, GL_AMBIENT, LightAmbient);// NaΦtenφ informace o sv∞tlech do GL_LIGHT1
glLightfv(GL_LIGHT1, GL_DIFFUSE, LightDiffuse);
glLightfv(GL_LIGHT1, GL_POSITION, LightPosition);
glEnable(GL_LIGHT1);
}
V tΘto lekci vytvo°φme hodn∞ textur. Nynφ k naÜφ naΦφtacφ funkci. Nejd°φve loadujeme zßkladnφ bitmapu a p°ipravφme z nφ t°i filtrovanΘ textury (GL_NEAREST, GL_LINEAR, GL_LINEAR_MIPMAP_NEAREST). Pou₧ijeme pouze jednu datovou strukturu na ulo₧enφ bitmap. Navφc zavedeme novou strukturu nazvanou alpha, kterß bude obsahovat informace o alpha kanßlu (pr∙hlednosti) textury. Proto ulo₧φme RGBA obrßzky jako dv∞ bitmapy: jednu 24 bitovou RGB a jednu osmi bitovou ve stupnφch Üedi pro alpha kanßl. Aby fungovalo naΦφtßnφ sprßvn∞, musφme po ka₧dΘm naΦtenφ smazat Image, jinak nebudeme upozorn∞ni na p°φpadnΘ chyby p°i nahrßvßnφ textur.
TakΘ je u specifikace typu textury vhodnΘ uvΘst mφsto Φφsla 3 prom∞nnou GL_RGB8, a to kv∙li lepÜφ kompatibilit∞ s dalÜφmi verzemi OpenGL. Tato zm∞na je oznaΦena v k≤du podbarvenß.
int LoadGLTextures()// Loading bitmapy a konverze na texturu
{
bool status=true;// Indikuje chyby
AUX_RGBImageRec *Image=NULL;// Uklßdß bitmapu
char *alpha=NULL;
if (Image = auxDIBImageLoad("Data/Base.bmp"))// Nahraje bitmapu
{
glGenTextures(3, texture);// Generuje t°i textury
// Vytvo°enφ nelineßrn∞ filtrovanΘ textury
glBindTexture(GL_TEXTURE_2D, texture[0]);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, Image->sizeX, Image->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, Image->data);
// Vytvo°enφ lineßrn∞ filtrovanΘ textury
glBindTexture(GL_TEXTURE_2D, texture[1]);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, Image->sizeX, Image->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, Image->data);
// Vytvo°enφ mipmapovanΘ textury
glBindTexture(GL_TEXTURE_2D, texture[2]);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_NEAREST);
gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB8, Image->sizeX, Image->sizeY, GL_RGB, GL_UNSIGNED_BYTE, Image->data);
}
else
status = false;
if (Image)// Pokud obrßzek existuje
{
if (Image->data)// Pokud existujφ data obrßzku
delete Image->data;// Uvolnφ data obrßzku
delete Image;// Uvolnφ strukturu obrßzku
Image = NULL;// Nastavφ ukazatel na NULL
}
NaΦteme bumpmapu. Z d∙vod∙ uveden²ch nφ₧e musφ mφt pouze 50% intenzitu, tak₧e ji musφme n∞jak²m zp∙sobem ztmavit. Jß jsem se rozhodl pou₧φt funkci glPixelTransferf(), kterß udßvß jak²m zp∙sobem budou bitmapy p°evedeny na textury. My tuto funkci pou₧ijeme na ztmavenφ jednotliv²ch RGB kanßl∙ bitmapy na 50% p∙vodnφ intenzity. Pokud dosud nepou₧φvßte rodinu funkcφ glPixelTransfer(), m∞li byste se na n∞ podφvat - jsou celkem u₧iteΦnΘ.
// Loading bumpmap
if (Image = auxDIBImageLoad("Data/Bump.bmp"))
{
glPixelTransferf(GL_RED_SCALE,0.5f);// Snφ₧enφ intenzity RGB na 50% - poloviΦnφ intenzita
glPixelTransferf(GL_GREEN_SCALE,0.5f);
glPixelTransferf(GL_BLUE_SCALE,0.5f);
DalÜφ problΘm je, ₧e nechceme, aby se bitmapa v textu°e po°ßd opakovala, chceme ji namapovat pouze jednou na texturovacφ sou°adnice od (0.0f,0.0f) do (1.0f,1.0f). VÜe kolem nich by m∞lo b²t namapovßno Φernou barvou. Toho dosßhneme zavolßnφm dvou funkcφ glTexParameteri(), kterΘ nenφ t°eba popisovat.
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP);// Bez wrappingu (zalamovßnφ)
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP);
glTexParameterfv(GL_TEXTURE_2D,GL_TEXTURE_BORDER_COLOR,Gray);// Barva okraje textury
glGenTextures(3, bump);// Vytvo°φ t°i textury
// Vytvo°enφ nelineßrn∞ filtrovanΘ textury
>-<
// Vytvo°enφ lineßrn∞ filtrovanΘ textury
>-<
// Vytvo°enφ mipmapovanΘ textury
>-<
Nynφ musφme vytvo°it jeÜt∞ invertovanou bumpmapu, o kterΘ jsme ji₧ psali a jejφ₧ v²znam bude vysv∞tlen dßle. OdeΦtenφm barvy ka₧dΘho bodu bumpmapy od bφlΘ barvy {255, 255, 255} zφskßme obrßzek s invertovan²mi barvami. P°edtφm nesmφme nastavit intenzitu zp∞t na 100% (ne₧ jsem na to p°iÜel strßvil jsem nad tφm asi 3 hodiny), invertovanß bitmapa musφ b²t tedy takΘ ztmavenß na 50%.
for (int i = 0; i < 3 * Image->sizeX * Image->sizeY; i++)// Invertovßnφ bumpmapy
Image->data[i] = 255 - Image->data[i];
glGenTextures(3, invbump);// Vytvo°φ t°i textury
// Vytvo°enφ nelineßrn∞ filtrovanΘ textury
>-<
// Vytvo°enφ lineßrn∞ filtrovanΘ textury
>-<
// Vytvo°enφ mipmapovanΘ textury
>-<
glPixelTransferf(GL_RED_SCALE,1.0f);// Vrßcenφ intenzity RGB zp∞t na 100%
glPixelTransferf(GL_GREEN_SCALE,1.0f);
glPixelTransferf(GL_BLUE_SCALE,1.0f);
}
else
status = false;
if (Image)// Pokud obrßzek existuje
{
if (Image->data)// Pokud existujφ data obrßzku
delete Image->data;// Uvolnφ data obrßzku
delete Image;// Uvolnφ strukturu obrßzku
Image = NULL;// Nastavφ ukazatel na NULL
}
NaΦφtßnφ bitmap log je velmi jednoduchΘ a₧ na zkombinovßnφ RGB-A kanßl∙, nicmΘn∞ k≤d by m∞l b²t dostateΦn∞ jasn². VÜimn∞te si, ₧e tato textura je vytvo°ena z dat alpha, nikoliv z dat Image. Bude zde pou₧it pouze jeden filtr.
// NaΦte bitmapy log
if (Image = auxDIBImageLoad("Data/OpenGL_ALPHA.bmp"))
{
alpha = new char[4*Image->sizeX*Image->sizeY];// Alokuje pam∞¥ pro RGBA8-Texturu
for (int a=0; a < Image->sizeX * Image->sizeY; a++)
alpha[4*a+3] = Image->data[a*3];// Vezme pouze Φervenou barvu jako alpha kanßl
if (!(Image = auxDIBImageLoad("Data/OpenGL.bmp")))
status = false;
for (a = 0; a < Image->sizeX * Image->sizeY; a++)
{
alpha[4*a]=Image->data[a*3];// R
alpha[4*a+1]=Image->data[a*3+1];// G
alpha[4*a+2]=Image->data[a*3+2];// B
}
glGenTextures(1, &glLogo);// Vytvo°φ jednu texturu
// Vytvo°φ lineßrn∞ filtrovanou RGBA8-Texturu
glBindTexture(GL_TEXTURE_2D, glLogo);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, Image->sizeX, Image->sizeY, 0, GL_RGBA, GL_UNSIGNED_BYTE, alpha);
delete alpha;// Uvolnφ alokovanou pam∞¥
}
else
status = false;
if (Image)// Pokud obrßzek existuje
{
if (Image->data)// Pokud existujφ data obrßzku
delete Image->data;// Uvolnφ data obrßzku
delete Image;// Uvolnφ strukturu obrßzku
Image = NULL;// Nastavφ ukazatel na NULL
}
if (Image = auxDIBImageLoad("Data/multi_on_alpha.bmp"))
{
alpha = new char[4*Image->sizeX*Image->sizeY];// Alokuje pam∞¥ pro RGBA8-Texturu
for (int a = 0; a < Image->sizeX * Image->sizeY; a++)
alpha[4*a+3]=Image->data[a*3];// Vezme pouze Φervenou barvu jako alpha kanßl
if (!(Image=auxDIBImageLoad("Data/multi_on.bmp")))
status = false;
for (a=0; a < Image->sizeX * Image->sizeY; a++)
{
alpha[4*a] = Image->data[a*3];// R
alpha[4*a+1] = Image->data[a*3+1];// G
alpha[4*a+2] = Image->data[a*3+2];// B
}
glGenTextures(1, &multiLogo);// Vytvo°φ jednu texturu
// Vytvo°φ lineßrn∞ filtrovanou RGBA8-Texturu
glBindTexture(GL_TEXTURE_2D, multiLogo);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, Image->sizeX, Image->sizeY, 0, GL_RGBA, GL_UNSIGNED_BYTE, alpha);
delete alpha;
}
else
status = false;
if (Image)// Pokud obrßzek existuje
{
if (Image->data)// Pokud existujφ data obrßzku
delete Image->data;// Uvolnφ data obrßzku
delete Image;// Uvolnφ strukturu obrßzku
Image = NULL;// Nastavφ ukazatel na NULL
}
return status;// Vrßtφ status
}
Nßsleduje funkce doCube(), kterß kreslφ krychli spolu s normßlami. VÜimn∞te si, ₧e tato verze zat∞₧uje pouze texturovacφ jednotku #0, glTexCoord(s, t) pracuje stejn∞ jako glMultiTexCoord(GL_TEXTURE0_ARB, s, t). Krychle m∙₧e b²t taky vykreslena pomocφ proklßdan²ch polφ, to ale te∩ nebudeme °eÜit. Nem∙₧e vÜak b²t ulo₧ena na display listu, ty pou₧φvajφ pravd∞podobn∞ p°esnost r∙znou od GLfloat, co₧ vede k nep∞kn²m vedlejÜφm efekt∙m.
void doCube(void)
{
int i;
glBegin(GL_QUADS);
// P°ednφ st∞na
glNormal3f( 0.0f, 0.0f, +1.0f);
for (i=0; i<4; i++)
{
glTexCoord2f(data[5*i],data[5*i+1]);
glVertex3f(data[5*i+2],data[5*i+3],data[5*i+4]);
}
// Zadnφ st∞na
glNormal3f( 0.0f, 0.0f,-1.0f);
for (i=4; i<8; i++)
{
glTexCoord2f(data[5*i],data[5*i+1]);
glVertex3f(data[5*i+2],data[5*i+3],data[5*i+4]);
}
// Hornφ st∞na
glNormal3f( 0.0f, 1.0f, 0.0f);
for (i=8; i<12; i++)
{
glTexCoord2f(data[5*i],data[5*i+1]);
glVertex3f(data[5*i+2],data[5*i+3],data[5*i+4]);
}
// Spodnφ st∞na
glNormal3f( 0.0f,-1.0f, 0.0f);
for (i=12; i<16; i++)
{
glTexCoord2f(data[5*i],data[5*i+1]);
glVertex3f(data[5*i+2],data[5*i+3],data[5*i+4]);
}
// Pravß st∞na
glNormal3f( 1.0f, 0.0f, 0.0f);
for (i=16; i<20; i++)
{
glTexCoord2f(data[5*i],data[5*i+1]);
glVertex3f(data[5*i+2],data[5*i+3],data[5*i+4]);
}
// Levß st∞na
glNormal3f(-1.0f, 0.0f, 0.0f);
for (i=20; i<24; i++)
{
glTexCoord2f(data[5*i],data[5*i+1]);
glVertex3f(data[5*i+2],data[5*i+3],data[5*i+4]);
}
glEnd();
}
P°ichßzφ Φas na inicializaci OpenGL. VÜe je jako v lekci 06, krom∞ toho, ₧e zavolßme funkci initLights(), mφsto toho, abychom sv∞tla nastavovali zde. A jeÜt∞ samoz°ejm∞ volßme nastavenφ p°φpadnΘho multitexturingu.
int InitGL(GLvoid)// VÜechno nastavenφ OpenGL
{
multitextureSupported = initMultitexture();
if (!LoadGLTextures())// Vytvo°enφ textur
return false;
glEnable(GL_TEXTURE_2D);// Zapne texturovΘ mapovßnφ
glShadeModel(GL_SMOOTH);// Zapne smooth shading
glClearColor(0.0f, 0.0f, 0.0f, 0.5f);// ╚ernΘ pozadφ
glClearDepth(1.0f);// Nastavenφ hloubkovΘho bufferu
glEnable(GL_DEPTH_TEST);// Povolenφ testovßnφ hloubky
glDepthFunc(GL_LEQUAL);// Typ testovßnφ hloubky
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);// Kvalitnφ v²poΦty perspektivy
initLights();// Inicializace sv∞tel
return true;// VÜe v po°ßdku
}
ZaΦßtek teorie (Emboss Bump Mapping)
Zde je asi 95% prßce. VÜe u Φeho bylo napsßno, ₧e bude vysv∞tleno pozd∞ji, je v nßsledujφcφ teoretickΘ sekci.
Pokud mßte nainstalovan² prohlφ₧eΦ pro PowerPoint, doporuΦuji abyste si stßhli nßsledujφcφ prezentaci: "Emboss Bump Mapping" by Michael I. Gold, nVidia Corp. [.ppt, 309K] - anglicky!. Pro ty bez prohlφ₧eΦe jsem se pokusil p°evΘst tyto informace do html. Tady je:
Emboss Bump Mapping
Michael I. Gold - NVidia Corporation
Bump Mapping
SkuteΦn² bump mapping pou₧φvß per-pixel osv∞tlenφ.
Emboss Bump Mapping
Emboss Bump Mapping je pouze nßhra₧ka.
V²poΦet dif·znφho osv∞tlenφ
C = (L * N) x Dl x Dm
P°ibli₧n² stupe≥ rozptylu L * N
Textura reprezentuje v²Ükovou mapu
P°ibli₧nΘ odvozenφ
Zohledn∞nφ p°ibli₧n²ch ·daj∙
SpoΦφtßnφ reliΘfu
1) P∙vodnφ reliΘf (H0).
2) P∙vodnφ reliΘf (H0) prolo₧en² druh²m (H1), kter² je mφrn∞ posunut² sm∞rem ke sv∞tlu.
3) OdeΦtenφ p∙vodnφho od posunutΘho reliΘfu (H0-H1) - vede ke vzniku sv∞tl²ch (B) a tmav²ch (D) ploch.
V²poΦet osv∞tlenφ
UrΦφme hodnotu barvy (Cf) danΘ plochy
Je to vÜe? Takhle jednoduchΘ?!
JeÜt∞ nejsme ·pln∞ hotovφ. Stßle musφme:
Tvorba textury
Uchovßvejte textury!
V²poΦet offsetu textury
PootoΦenφ vektoru sv∞tla
V²poΦet offsetu textury (pokraΦovßnφ)
Pou₧ijte pro posunutφ vektor sv∞tla normßlnφho prostoru
Implementace na TNT
SpoΦφtejte vektory, texturovacφ sou°adnice na hostiteli
Implementace na TNT (pokraΦovßnφ)
Nastavenφ alpha kanßlu na combineru
Konec teorie (Emboss Bump Mapping)
My to ale ud∞lßme trochu jinak ne₧ podle TNT implementace, abychom umo₧nili naÜemu programu b∞₧et na VèECH akcelerßtorech. Zde se m∙₧eme p°iuΦit dv∞ nebo t°i v∞ci. Jedna z nich je, ₧e bumpmapping je vφce fßzov² algoritmus na v∞tÜin∞ karet (ne na TNT, kde se to dß nahradit jednou dvou-texturovacφ fßzφ). U₧ byste si m∞li b²t schopni p°edstavit, jak hezk² multitexturing ve skuteΦnosti je. Nynφ implementujeme 3-fßzov² netexturovacφ algoritmus, kter² pak m∙₧e b²t (a bude) vylepÜen na 2 fßzov² texturovacφ algoritmus.
Te∩ byste si m∞li uv∞domit, ₧e musφme ud∞lat n∞jakΘ nßsobenφ matice maticφ (a nßsobenφ vektoru maticφ). Ale to nenφ nic Φeho bychom se m∞li obßvat: OpenGL zvlßdne nßsobenφ matice maticφ za nßs a nßsobenφ vektoru maticφ je celkem jednoduchΘ: funkce VMatMult(M,v) vynßsobφ matici M s vektorem v a v²sledek ulo₧φ zp∞t ve v: v = M * v. VÜechny matice a vektory p°edanΘ funkci musejφ mφt stejn² tvar: matice 4x4 a 4-rozm∞rnΘ vektory. To je pro zajiÜt∞nφ kompatibility s OpenGL.
void VMatMult(GLfloat *M, GLfloat *v)
{
GLfloat res[3];
res[0] = M[0]*v[0]+M[1]*v[1]+M[ 2]*v[2]+M[ 3]*v[3];
res[1] = M[4]*v[0]+M[5]*v[1]+M[ 6]*v[2]+M[ 7]*v[3];
res[2] = M[8]*v[0]+M[9]*v[1]+M[10]*v[2]+M[11]*v[3];
v[0]=res[0];
v[1]=res[1];
v[2]=res[2];
v[3]=M[15];// Homogennφ sou°adnice
}
ZaΦßtek teorie (algoritmy pro Emboss Bump Mapping)
Zde se zmφnφme o dvou odliÜn²ch algoritmech. Prvnφ z nich jsem naÜel na strßnce:
http://www.nvidia.com/marketing/Developer/DevRel.nsf/TechnicalDemosFrame?OpenPage
Program se jmenuje GL_BUMP a napsal ho Diego Tßrtara v roce 1999. I p°es pßr nev²hod velmi p∞kn∞ implementuje bumpmapping. Te∩ se na tento algoritmus podφvßme:
To nevypadß Üpatn∞! V podstat∞ je to algoritmus popsan² Michaelem I. Goldem v²Üe. Mß vÜak zßsadnφ nev²hodu: Tßmara pou₧φvß projekci pouze pro rovinu xy. To pro naÜe pot°eby nestaΦφ, proto₧e zjednoduÜuje promφtacφ krok pouze na slo₧ky x a y a se slo₧kou z vektoru v v∙bec nepoΦφtß.
Ale tato implementace vytvo°φ rozpt²lenΘ sv∞tlo stejn²m zp∙sobem, jako ho budeme d∞lat my: s pou₧itφm v OpenGL zabudovanΘ podpory osv∞tlenφ. Tak₧e nem∙₧eme pou₧φt metodu kombiner∙, jakou navrhuje Gold (Chceme, aby naÜe programy b∞₧ely i na jin²ch ne₧ TNT kartßch!), nem∙₧eme ulo₧it stupe≥ rozptylu do alpha kanßlu. Tak ji₧ mßme problΘm s 3 fßzov²m netexturovanφm a 2 fßzov²m texturovßnφm, proΦ na poslednφ pr∙chod nepou₧φt OpenGL-Lighting, aby za nßs dod∞lal ambientnφ sv∞tlo a barvy? Je to mo₧nΘ (a v²sledek vypadß celkem dob°e), ale jen proto, ₧e nynφ nepou₧φvßme slo₧itou geometrii. Tohle byste si m∞li zapamatovat. Pokud budete chtφt renderovat n∞kolik tisφc bumpmapovan²ch troj·helnφk∙, zkuste objevit n∞co jinΘho.
Navφc, pou₧φvß multitexturing (jak m∙₧eme vid∞t) ne tak jednoduÜe jako my s ohledem na tento specißlnφ p°φpad.
Ale te∩ k naÜφ implementaci. Vypadß podobn∞ jako algoritmus p°edtφm, krom∞ projekΦnφ fßze, kde pou₧ijeme vlastnφ postup:
ProΦ je to dobrΘ?
Nev²hody:
Tento nßΦrtek ukazuje, kde se nachßzejφ jednotlivΘ vektory. M∙₧ete jednoduÜe zφskat t a s odeΦtenφm jesnosti jednotliv²ch vektor∙, ale ujist∞te se, ₧e jsou sprßvn∞ natoΦenΘ a normalizovanΘ. Modr² bod oznaΦuje vertex, kde je namapovßn texCoord2f(0.0f, 0.0f).
Konec teorie (algoritmy pro Emboss Bump Mapping)
Te∩ se podφvejme na generßtor posunutφ textury. Tato funkce se jmenuje SetUpBumps().
// Funkce nastavφ posunutφ textury
// n : normßla k ploÜe, musφ mφt dΘlku 1
// c : n∞jak² bod na povrchu
// l : pozice sv∞tla
// s : sm∞r texturovacφch sou°adnic s (musφ b²t normalizovßn!)
// t : sm∞r texturovacφch sou°adnic t (musφ b²t normalizovßn!)
void SetUpBumps(GLfloat *n, GLfloat *c, GLfloat *l, GLfloat *s, GLfloat *t)
{
GLfloat v[3];// Vertex z aktußlnφ pozice ke sv∞tlu
GLfloat lenQ;// Pou₧ito p°i normalizaci
// SpoΦφtßnφ v z aktußlnφho vertexu c ke sv∞tlu a jeho normalizace
v[0] = l[0] - c[0];
v[1] = l[1] - c[1];
v[2] = l[2] - c[2];
lenQ = (GLfloat) sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]);
v[0] /= lenQ;
v[1] /= lenQ;
v[2] /= lenQ;
// Zohledn∞nφ v tak, abychom dostali texturovacφ sou°adnice
c[0] = (s[0]*v[0] + s[1]*v[1] + s[2]*v[2]) * MAX_EMBOSS;
c[1] = (t[0]*v[0] + t[1]*v[1] + t[2]*v[2]) * MAX_EMBOSS;
}
Nep°ipadß vßm to tak komplikovanΘ jako p°edtφm? Teorie je ale d∙le₧itß, abyste pochopili jak efekt funguje a jak ho ovlßdat. B∞hem psanφ tutorißlu jsem se to sßm nauΦil :-]
V₧dycky jsem cht∞l zobrazit logo p°i b∞hu ukßzkovΘho programu. My te∩ taky dv∞ zobrazφme. Zavolßme funkci doLogo(). Ta vyresetuje GL_MODELVIEW matici, kterß musφ b²t p°i poslednφm pr∙chodu zavolßna.
Tato funkce zobrazφ dv∞ loga: OpenGl logo a logo multitexturingu, pokud je povolen. Loga jsou zΦßsti pr∙hlednß. Proto₧e majφ alpha kanßl, smφchßme je pomocφ GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA podle OpenGL dokumentace. Ob∞ dv∞ jsou plochΘ, nemßme pro n∞ sou°adnici z. ╚φsla pou₧itß pro hrany jsou zjiÜt∞ny "empiricky" (pokus-chyba), tak aby loga padla p∞kn∞ do ro₧k∙. Musφme zapnout blending a vypnout sv∞tla, abychom se vyhli chybn²m efekt∙m. Abychom zajistili, ₧e loga budou v₧dy vep°edu, vyresetujeme GL_MODELVIEW matici a nastavφme funkci na testovßnφ hloubky na GL_ALWAYS.
void doLogo(void)// MUS═ SE ZAVOLAT AÄ NAKONEC!!! Zobrazφ dv∞ loga
{
glDepthFunc(GL_ALWAYS);
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
glDisable(GL_LIGHTING);
glLoadIdentity();
glBindTexture(GL_TEXTURE_2D,glLogo);
glBegin(GL_QUADS);
glTexCoord2f(0.0f,0.0f); glVertex3f(0.23f, -0.4f,-1.0f);
glTexCoord2f(1.0f,0.0f); glVertex3f(0.53f, -0.4f,-1.0f);
glTexCoord2f(1.0f,1.0f); glVertex3f(0.53f, -0.25f,-1.0f);
glTexCoord2f(0.0f,1.0f); glVertex3f(0.23f, -0.25f,-1.0f);
glEnd();
if (useMultitexture)
{
glBindTexture(GL_TEXTURE_2D,multiLogo);
glBegin(GL_QUADS);
glTexCoord2f(0.0f,0.0f); glVertex3f(-0.53f, -0.4f,-1.0f);
glTexCoord2f(1.0f,0.0f); glVertex3f(-0.33f, -0.4f,-1.0f);
glTexCoord2f(1.0f,1.0f); glVertex3f(-0.33f, -0.3f,-1.0f);
glTexCoord2f(0.0f,1.0f); glVertex3f(-0.53f, -0.3f,-1.0f);
glEnd();
}
glDepthFunc(GL_LEQUAL);
}
Te∩ p°ichßzφ funkce na bumpmapping bez texturingu. Je to t°φ-pr∙chodovß implementace. Jako prvnφ GL_MODELVIEW matice se p°evrßtφ pomocφ aplikace vÜech proveden²ch krok∙ v opaΦnΘm po°adφ a obrßcen∞ na matici danΘ identity. V²sledkem je matice, kterß p°i aplikaci na objekt "vracφ" GL_MODELVIEW. My jφ jednoduÜe zφskßme funkcφ glGetFloatv(). Pamatujte, ₧e matice musφ b²t pole s 16 prvky a ₧e je tato matice "p°esunuta"!
Mimochodem: Kdy₧ p°esn∞ nevφte, jak se s maticφ manipuluje, zva₧te pou₧itφ globßlnφch sou°adnic, proto₧e p°evracenφ matice je slo₧itΘ a nßroΦnΘ na Φas. Ale pokud pou₧φvßte mnoho vertex∙, p°evracenφ matice m∙₧e b²t daleko rychlejÜφ.
bool doMesh1TexelUnits(void)
{
GLfloat c[4] = {0.0f, 0.0f, 0.0f, 1.0f};// Aktußlnφ vertex
GLfloat n[4] = {0.0f, 0.0f, 0.0f, 1.0f};// Normalizovanß normßla danΘho povrchu
GLfloat s[4] = {0.0f, 0.0f, 0.0f, 1.0f};// Sm∞r texturovacφch sou°adnic s, normalizovßno
GLfloat t[4] = {0.0f, 0.0f, 0.0f, 1.0f};// Sm∞r texturovacφch sou°adnic t, normalizovßno
GLfloat l[4];// Pozice sv∞tla, kterß bude transformovßna do prostoru objektu
GLfloat Minv[16];// P°evrßcenß modelview matice
int i;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);// Sma₧e obrazovku a hloubkov² buffer
// Sestavenφ p°evrßcenΘ modelview matice; nahradφ funkce Push a Pop jednou funkcφ glLoadIdentity()
// JednoduchΘ sestavenφ tφm, ₧e vÜechny transformace provedeme opaΦn∞ a v opaΦnΘm po°adφ
glLoadIdentity();
glRotatef(-yrot,0.0f,1.0f,0.0f);
glRotatef(-xrot,1.0f,0.0f,0.0f);
glTranslatef(0.0f,0.0f,-z);
glGetFloatv(GL_MODELVIEW_MATRIX,Minv);
glLoadIdentity();
glTranslatef(0.0f,0.0f,z);
glRotatef(xrot,1.0f,0.0f,0.0f);
glRotatef(yrot,0.0f,1.0f,0.0f);
// Transformace pozice sv∞tla do sou°adnic objektu:
l[0] = LightPosition[0];
l[1] = LightPosition[1];
l[2] = LightPosition[2];
l[3] = 1.0f;// Homogenφ sou°adnice
VMatMult(Minv,l);
Prvnφ fßze:
Tohle vyrenderuje krychli pouze z bumpmap.
glBindTexture(GL_TEXTURE_2D, bump[filter]);
glDisable(GL_BLEND);
glDisable(GL_LIGHTING);
doCube();
Druhß fßze:
Tohle vyrendruje krychli se sprßvn²m emboss bumpmappingem, ale bez barev.
Mohli bychom uÜet°it Φas rotacφ vektoru sv∞tla opaΦn²m sm∞rem. To vÜak nefunguje ·pln∞ sprßvn∞, tak to ud∞lßme jinou cestou: otoΦφme ka₧dou normßlu a prost°ednφ bod stejn∞ jako naÜi geometrii.
glBindTexture(GL_TEXTURE_2D,invbump[filter]);
glBlendFunc(GL_ONE,GL_ONE);
glDepthFunc(GL_LEQUAL);
glEnable(GL_BLEND);
glBegin(GL_QUADS);
// P°ednφ st∞na
n[0] = 0.0f;
n[1] = 0.0f;
n[2] = 1.0f;
s[0] = 1.0f;
s[1] = 0.0f;
s[2] = 0.0f;
t[0] = 0.0f;
t[1] = 1.0f;
t[2] = 0.0f;
for (i=0; i<4; i++)
{
c[0] = data[5*i+2];
c[1] = data[5*i+3];
c[2] = data[5*i+4];
SetUpBumps(n,c,l,s,t);
glTexCoord2f(data[5*i]+c[0], data[5*i+1]+c[1]);
glVertex3f(data[5*i+2], data[5*i+3], data[5*i+4]);
}
// Zadnφ st∞na
n[0] = 0.0f;
n[1] = 0.0f;
n[2] = -1.0f;
s[0] = -1.0f;
s[1] = 0.0f;
s[2] = 0.0f;
t[0] = 0.0f;
t[1] = 1.0f;
t[2] = 0.0f;
for (i=4; i<8; i++)
{
c[0] = data[5*i+2];
c[1] = data[5*i+3];
c[2] = data[5*i+4];
SetUpBumps(n,c,l,s,t);
glTexCoord2f(data[5*i]+c[0], data[5*i+1]+c[1]);
glVertex3f(data[5*i+2], data[5*i+3], data[5*i+4]);
}
// Hornφ st∞na
n[0] = 0.0f;
n[1] = 1.0f;
n[2] = 0.0f;
s[0] = 1.0f;
s[1] = 0.0f;
s[2] = 0.0f;
t[0] = 0.0f;
t[1] = 0.0f;
t[2] = -1.0f;
for (i=8; i<12; i++)
{
c[0] = data[5*i+2];
c[1] = data[5*i+3];
c[2] = data[5*i+4];
SetUpBumps(n,c,l,s,t);
glTexCoord2f(data[5*i]+c[0], data[5*i+1]+c[1]);
glVertex3f(data[5*i+2], data[5*i+3], data[5*i+4]);
}
// Spodnφ st∞na
n[0] = 0.0f;
n[1] = -1.0f;
n[2] = 0.0f;
s[0] = -1.0f;
s[1] = 0.0f;
s[2] = 0.0f;
t[0] = 0.0f;
t[1] = 0.0f;
t[2] = -1.0f;
for (i=12; i<16; i++)
{
c[0] = data[5*i+2];
c[1] = data[5*i+3];
c[2] = data[5*i+4];
SetUpBumps(n,c,l,s,t);
glTexCoord2f(data[5*i]+c[0], data[5*i+1]+c[1]);
glVertex3f(data[5*i+2], data[5*i+3], data[5*i+4]);
}
// Pravß st∞na
n[0] = 1.0f;
n[1] = 0.0f;
n[2] = 0.0f;
s[0] = 0.0f;
s[1] = 0.0f;
s[2] = -1.0f;
t[0] = 0.0f;
t[1] = 1.0f;
t[2] = 0.0f;
for (i=16; i<20; i++)
{
c[0] = data[5*i+2];
c[1] = data[5*i+3];
c[2] = data[5*i+4];
SetUpBumps(n,c,l,s,t);
glTexCoord2f(data[5*i]+c[0], data[5*i+1]+c[1]);
glVertex3f(data[5*i+2], data[5*i+3], data[5*i+4]);
}
// Levß st∞na
n[0] = -1.0f;
n[1] = 0.0f;
n[2] = 0.0f;
s[0] = 0.0f;
s[1] = 0.0f;
s[2] = 1.0f;
t[0] = 0.0f;
t[1] = 1.0f;
t[2] = 0.0f;
for (i=20; i<24; i++)
{
c[0] = data[5*i+2];
c[1] = data[5*i+3];
c[2] = data[5*i+4];
SetUpBumps(n,c,l,s,t);
glTexCoord2f(data[5*i]+c[0], data[5*i+1]+c[1]);
glVertex3f(data[5*i+2], data[5*i+3], data[5*i+4]);
}
glEnd();
T°etφ fßze:
Tohle dokonΦφ renderovßnφ krychle s osv∞tlenφm. Nejd°φve musφme nastavit texture environment na GL_MODULATE. M∙₧eme zapφnat a vypφnat multitexturing. Tuto fßzi provedeme, jen pokud u₧ivatel nechce vid∞t pouze emboss.
if (!emboss)
{
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glBindTexture(GL_TEXTURE_2D,texture[filter]);
glBlendFunc(GL_DST_COLOR,GL_SRC_COLOR);
glEnable(GL_LIGHTING);
doCube();
}
Poslednφ fßze:
xrot += xspeed;
yrot += yspeed;
if (xrot > 360.0f)
xrot -= 360.0f;
if (xrot < 0.0f)
xrot += 360.0f;
if (yrot > 360.0f)
yrot -= 360.0f;
if (yrot < 0.0f)
yrot += 360.0f;
doLogo();// Nakonec loga
return true;
}
DalÜφ funkce ud∞lß tohle vÜechno ve dvou fßzφch s podporou multitexturingu. Pou₧ijeme dv∞ texturovacφ jednotky. Vφce by bylo extrΘmn∞ obtφ₧nΘ vzhledem k blendingov²m rovnicφm. LΘpe pou₧φt TNT. VÜimn∞te si, ₧e se funkce liÜφ od doMesh1TexelUnits() jen tφm, ₧e posφlßme dv∞ sady texturovacφch sou°adnich na ka₧d² vertex!
bool doMesh2TexelUnits(void)
{
GLfloat c[4] = {0.0f,0.0f,0.0f,1.0f};// Aktußlnφ vertex
GLfloat n[4] = {0.0f,0.0f,0.0f,1.0f};// Normalizovanß normßla povrchu
GLfloat s[4] = {0.0f,0.0f,0.0f,1.0f};// Sm∞r texturovacφch sou°adnic s, normalizovßno
GLfloat t[4] = {0.0f,0.0f,0.0f,1.0f};// Sm∞r texturovacφch sou°adnic t, normalizovßno
GLfloat l[4];// Pozice sv∞tla k p°evedenφ na sou°adnice objektu
GLfloat Minv[16];// P°evrßcenß modelview matice
int i;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);// Sma₧e obrazovku a hloubkov² buffer
// Sestavenφ p°evrßcenΘ modelview matice, tohle nahradφ funkce Push a Pop jednou funkcφ glLoadIdentity()
// JednoduchΘ sestavenφ tφm, ₧e vÜechny transformace provedeme opaΦn∞ a v opaΦnΘm po°adφ
glLoadIdentity();
glRotatef(-yrot,0.0f,1.0f,0.0f);
glRotatef(-xrot,1.0f,0.0f,0.0f);
glTranslatef(0.0f,0.0f,-z);
glGetFloatv(GL_MODELVIEW_MATRIX,Minv);
glLoadIdentity();
glTranslatef(0.0f,0.0f,z);
glRotatef(xrot,1.0f,0.0f,0.0f);
glRotatef(yrot,0.0f,1.0f,0.0f);
// Transformace pozice sv∞tla na sou°adnice objektu:
l[0] = LightPosition[0];
l[1] = LightPosition[1];
l[2] = LightPosition[2];
l[3] = 1.0f;// Homogenφ sou°adnice
VMatMult(Minv,l);
Prvnφ fßze:
Nastavenφ texture combineru 0 na
Nastavenφ texture combineru 1 na
Tohle vyrenderuje krychli sklßdajφcφ se z Üed²ch map.
// TEXTUROVAC═ JEDNOTKA #0:
glActiveTextureARB(GL_TEXTURE0_ARB);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, bump[filter]);
glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
glTexEnvf (GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_REPLACE);
// TEXTUROVAC═ JEDNOTKA #1:
glActiveTextureARB(GL_TEXTURE1_ARB);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, invbump[filter]);
glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
glTexEnvf (GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_ADD);
// ObecnΘ p°epφnaΦe
glDisable(GL_BLEND);
glDisable(GL_LIGHTING);
Te∩ pouze vyrenderujeme st∞ny jednu po druhΘ jako v doMesh1TexelUnits(). Pouze jedna novinka: pou₧φvß glMultiTexCoordfARB() mφsto glTexCoord2f(). VÜimn∞te si, ₧e v prvnφm parametru je uvedeno, kterΘ texturovacφ jednotce p°φsluÜφ sou°adnice. Parametr musφ b²t GL_TEXTUREi_ARB, kde i je v intervalu od 0 do 31.
glBegin(GL_QUADS);
// P°ednφ st∞na
n[0] = 0.0f;
n[1] = 0.0f;
n[2] = 1.0f;
s[0] = 1.0f;
s[1] = 0.0f;
s[2] = 0.0f;
t[0] = 0.0f;
t[1] = 1.0f;
t[2] = 0.0f;
for (i=0; i<4; i++)
{
c[0] = data[5*i+2];
c[1] = data[5*i+3];
c[2] = data[5*i+4];
SetUpBumps(n,c,l,s,t);
glMultiTexCoord2fARB(GL_TEXTURE0_ARB, data[5*i], data[5*i+1]);
glMultiTexCoord2fARB(GL_TEXTURE1_ARB, data[5*i]+c[0], data[5*i+1]+c[1]);
glVertex3f(data[5*i+2], data[5*i+3], data[5*i+4]);
}
// Zadnφ st∞na
n[0] = 0.0f;
n[1] = 0.0f;
n[2] = -1.0f;
s[0] = -1.0f;
s[1] = 0.0f;
s[2] = 0.0f;
t[0] = 0.0f;
t[1] = 1.0f;
t[2] = 0.0f;
for (i=4; i<8; i++)
{
c[0] = data[5*i+2];
c[1] = data[5*i+3];
c[2] = data[5*i+4];
SetUpBumps(n,c,l,s,t);
glMultiTexCoord2fARB(GL_TEXTURE0_ARB,data[5*i], data[5*i+1]);
glMultiTexCoord2fARB(GL_TEXTURE1_ARB,data[5*i]+c[0], data[5*i+1]+c[1]);
glVertex3f(data[5*i+2], data[5*i+3], data[5*i+4]);
}
// Hornφ st∞na
n[0] = 0.0f;
n[1] = 1.0f;
n[2] = 0.0f;
s[0] = 1.0f;
s[1] = 0.0f;
s[2] = 0.0f;
t[0] = 0.0f;
t[1] = 0.0f;
t[2] = -1.0f;
for (i=8; i<12; i++)
{
c[0] = data[5*i+2];
c[1] = data[5*i+3];
c[2] = data[5*i+4];
SetUpBumps(n,c,l,s,t);
glMultiTexCoord2fARB(GL_TEXTURE0_ARB,data[5*i], data[5*i+1]);
glMultiTexCoord2fARB(GL_TEXTURE1_ARB,data[5*i]+c[0], data[5*i+1]+c[1]);
glVertex3f(data[5*i+2], data[5*i+3], data[5*i+4]);
}
// Dolnφ st∞na
n[0] = 0.0f;
n[1] = -1.0f;
n[2] = 0.0f;
s[0] = -1.0f;
s[1] = 0.0f;
s[2] = 0.0f;
t[0] = 0.0f;
t[1] = 0.0f;
t[2] = -1.0f;
for (i=12; i<16; i++)
{
>c[0] = data[5*i+2];
c[1] = data[5*i+3];
c[2] = data[5*i+4];
SetUpBumps(n,c,l,s,t);
glMultiTexCoord2fARB(GL_TEXTURE0_ARB,data[5*i], data[5*i+1]);
glMultiTexCoord2fARB(GL_TEXTURE1_ARB,data[5*i]+c[0], data[5*i+1]+c[1]);
glVertex3f(data[5*i+2], data[5*i+3], data[5*i+4]);
}
// Pravß st∞na
n[0] = 1.0f;
n[1] = 0.0f;
n[2] = 0.0f;
s[0] = 0.0f;
s[1] = 0.0f;
s[2] = -1.0f;
t[0] = 0.0f;
t[1] = 1.0f;
t[2] = 0.0f;
for (i=16; i<20; i++)
{
c[0] = data[5*i+2];
c[1] = data[5*i+3];
c[2] = data[5*i+4];
SetUpBumps(n,c,l,s,t);
glMultiTexCoord2fARB(GL_TEXTURE0_ARB,data[5*i], data[5*i+1]);
glMultiTexCoord2fARB(GL_TEXTURE1_ARB,data[5*i]+c[0], data[5*i+1]+c[1]);
glVertex3f(data[5*i+2], data[5*i+3], data[5*i+4]);
}
// Levß st∞na
n[0] = -1.0f;
n[1] = 0.0f;
n[2] = 0.0f;
s[0] = 0.0f;
s[1] = 0.0f;
s[2] = 1.0f;
t[0] = 0.0f;
t[1] = 1.0f;
t[2] = 0.0f;
for (i=20; i<24; i++)
{
c[0] = data[5*i+2];
c[1] = data[5*i+3];
c[2] = data[5*i+4];
SetUpBumps(n,c,l,s,t);
glMultiTexCoord2fARB(GL_TEXTURE0_ARB,data[5*i], data[5*i+1]);
glMultiTexCoord2fARB(GL_TEXTURE1_ARB,data[5*i]+c[0], data[5*i+1]+c[1]);
glVertex3f(data[5*i+2], data[5*i+3], data[5*i+4]);
}
glEnd();
Druhß fßze:
Tohle vyrenderuje celou bumpmapovanou krychli.
glActiveTextureARB(GL_TEXTURE1_ARB);
glDisable(GL_TEXTURE_2D);
glActiveTextureARB(GL_TEXTURE0_ARB);
if (!emboss)
{
glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glBindTexture(GL_TEXTURE_2D,texture[filter]);
glBlendFunc(GL_DST_COLOR,GL_SRC_COLOR);
glEnable(GL_BLEND);
glEnable(GL_LIGHTING);
doCube();
}
Poslednφ fßze:
xrot += xspeed;
yrot += yspeed;
if (xrot>360.0f)
xrot -= 360.0f;
if (xrot<0.0f)
xrot += 360.0f;
if (yrot>360.0f)
yrot -= 360.0f;
if (yrot<0.0f)
yrot += 360.0f;
doLogo();// Nakonec loga
return true;
}
KoneΦn∞ funkce na renderovßnφ bez bumpmappingu - abychom mohli vid∞t ten rozdφl!
bool doMeshNoBumps(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);// Sma₧e obrazovku a hloubkov² buffer
glLoadIdentity();// Reset matice
glTranslatef(0.0f,0.0f,z);
glRotatef(xrot,1.0f,0.0f,0.0f);
glRotatef(yrot,0.0f,1.0f,0.0f);
if (useMultitexture)
{
glActiveTextureARB(GL_TEXTURE1_ARB);
glDisable(GL_TEXTURE_2D);
glActiveTextureARB(GL_TEXTURE0_ARB);
}
glDisable(GL_BLEND);
glBindTexture(GL_TEXTURE_2D,texture[filter]);
glBlendFunc(GL_DST_COLOR,GL_SRC_COLOR);
glEnable(GL_LIGHTING);
doCube();
xrot += xspeed;
yrot += yspeed;
if (xrot>360.0f)
xrot -= 360.0f;
if (xrot<0.0f)
xrot += 360.0f;
if (yrot>360.0f)
yrot -= 360.0f;
if (yrot<0.0f)
yrot += 360.0f;
doLogo();// Nakonec loga
return true;
}
VÜe co musφ drawGLScene() ud∞lat je rozhodnout jakou doMesh funkci zavolat.
bool DrawGLScene(GLvoid)// VÜechno kreslenφ
{
if (bumps)
{
if (useMultitexture && maxTexelUnits > 1)
return doMesh2TexelUnits();
else
return doMesh1TexelUnits();
}
else
return doMeshNoBumps();
}
Hlavnφ funkce Windows, p°idßny n∞kterΘ klßvesy:
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
// ZaΦßtek z∙stßvß nezm∞n∞n
if (keys['E'])
{
keys['E']=false;
emboss=!emboss;
}
if (keys['M'])
{
keys['M']=false;
useMultitexture=((!useMultitexture) && multitextureSupported);
}
if (keys['B'])
{
keys['B']=false;
bumps=!bumps;
}
if (keys['F'])
{
keys['F']=false;
filter++;
filter%=3;
}
if (keys[VK_PRIOR])
{
z-=0.02f;
}
if (keys[VK_NEXT])
{
z+=0.02f;
}
if (keys[VK_UP])
{
xspeed-=0.01f;
}
if (keys[VK_DOWN])
{
xspeed+=0.01f;
}
if (keys[VK_RIGHT])
{
yspeed+=0.01f;
}
if (keys[VK_LEFT])
{
yspeed-=0.01f;
}
// Konec takΘ nezm∞n∞n
}
Te∩ kdy₧ jsme zvlßdli tento tutorißl, pßr slov o generovßnφ textur a bumpmapov²ch objekt∙. P°edtφm, ne₧ zaΦnete programovat ambici≤znφ hry a budete se divit, proΦ bumpmapping nenφ tak rychl² a nevypadß tak dob°e, p°eΦt∞te si toto:
Pod∞kovßnφ:
napsal: Jens Schneider
p°elo₧il: Vßclav SlovßΦek - Wessan