Miran Brajša

miran.brajsa@fer.hr

Seminar iz računalne grafike

DOT3 Preslikavanje izbočina

DOT3 preslikavanje

DOT3 Preslikavanje izbočina ( eng. DOT3 Bump Mapping )

 Kao i prijašnja tehnika, DOT3 Preslikavanje izbočina koristi teksturu koja svakoj točki modela pridružuje "lažnu" normalu, tako da se jačina odbijene svjetlosti računa ne po ravnoj površini trokuta nego po normalama zadanima teksturom. Rezultat je površina koja, iako se doima kao stvarni 3D prikaz, u stvar ne postoji. DOT3 tehnika je do sada najbolja Bump Mapping tehnika jer za razliku od ostalih, za svoje proračune koristi sklopove. Upotrebu tih sklopova omogućujemo programskim uključivanjem OpenGL dodataka ( eng. extension ).

 

 DOT3 tehnika u praksi

 U daljnjem tekstu prikazan je postupak korištenja ove metode unutar nekog OpenGL programa.

 

Prva stvar koju moramo napraviti  ( pod pretpostavkom da imamo relativno kompleksnu scenu sa dinamičnim izvorom svjetlosti ) je pohranjivanje podataka o našoj matrici projekcije, iz razloga što ćemo nakon toga tražiti njezin inverz. Pohranjivanje podataka o projekciji vrlo se jednostavno izvede slijedećom naredbom:

 

glGetFloatv(GL_MODELVIEW_MATRIX,nasaMatrica);

 

Parametar GL_MODELVIEW_MATRIX govori nam o kojoj matrici želimo pohraniti podatke, dok je nasaMatrica pokazivač na polje gdje te podatke pohranjujemo i tipa je float[16].

 

Nakon toga počinjemo sa izračunom inverza projekcijske matrice koji nam služi za transformaciju vektora L ( vidi Tangentni prostor ). Iako je izračun inverzne matrice čisto matematički posao i neće biti posebno pojašnjavan, priložen je programski kôd u C-u koji izvršava taj zadatak.

 

void InverzMatrice(float matrica[16])

{

            float temp[16];

            temp[0]=matrica[0];

            temp[1]=matrica[4];

            temp[2]=matrica[8];

            temp[3]=0.0f;

            temp[4]=matrica[1];

            temp[5]=matrica[5];

            temp[6]=matrica[9];

            temp[7]=0.0f;

            temp[8]=matrica[2];

            temp[9]=matrica[6];

            temp[10]=matrica[10];

            temp[11]=0.0f;

            temp[15]=1.0f;

  temp[12]=-(matrica[12]*matrica[0]) - (matrica[13]*matrica[1]) - (matrica[14]*matrica[2]);

  temp[13]=-(matrica[12]*matrica[4]) - (matrica[13]*matrica[5]) - (matrica[14]*matrica[6]);

  temp[14]=-(matrica[12]*matrica[8]) - (matrica[13]*matrica[9]) - (matrica[14]*matrica[10]);

            memcpy(matrica, temp, sizeof(float)*16);

}

Potrebno je napomenuti kako je gore spomenuti postupak matematički ispravan način računanja inverza matrice, iako se u praksi koristi nešto brži način proračuna.

Kada smo i taj dio posla završili, potrebno je još samo transformirati vektor L koristeći dobiveni inverz.

 

 

noviL[0]=(L.x*nasaMatrica[0])+(L.y*nasaMatrica[4])+(L.z*nasaMatrica[8]);

noviL[1]=(L.x*nasaMatrica[1])+(L.y*nasaMatrica[5])+(L.z*nasaMatrica[9]);

noviL[2]=(L.x*nasaMatrica[2])+(L.y*nasaMatrica[6])+(L.z*nasaMatrica[10]);

 

U redu. Završen je "dosadan" dio posla ( naravno, pod uvijetom da su već svi tangentni prostori točaka svih modela na sceni izračunati ), te se sada možemo pozabaviti interesantnijim stvarima. Kako sve Bump Mapping tehnike koriste više tekstura odjednom ( eng. multitexturing ), moramo učitati dodatke koji nam to i omogućuju kako te funkcije nisu implementirane u standardni OpenGL (potrebno je uključiti datoteku Glext.h).

 

PFNGLMULTITEXCOORD2FARBPROC glMultiTexCoord2fARB = NULL;

PFNGLACTIVETEXTUREARBPROC glActiveTextureARB = NULL;

 

glActiveTextureARB = (PFNGLACTIVETEXTUREARBPROC)wglGetProcAddress("glActiveTextureARB");

glMultiTexCoord2fARB = (PFNGLMULTITEXCOORD2FARBPROC)wglGetProcAddress("glMultiTexCoord2fARB");

 

Iako ovo vjerojatno izgleda komplicirano, u stvari nije. Ovim naredbama samo kažemo OpenGL-u da od sada prve dvije ekstenzije zovemo glActiveTexture i glMultiTexCoord2f.

Što se DOT3 Bump Mapping-a tiče, dodaci koje za njega moramo učitati su slijedeći:

 

#define GL_COMBINE_ARB                        0x8570

#define GL_RGB_SCALE_ARB                    0x8573

 

Da bismo pripremili naše teksture koje ćemo koristiti na modelu trebamo odrediti načine na koje će se te dvije teksture međusobno spajati ( naredbe tipa a). Prvu teksturu ćemo koristiti kao temelj za izračunavanje "lažnih" normala ( naredba b) i to tako da RGB vrijednosti gledamo kao XYZ vrijednosti vektora i to u intervalu [-1, 1] ( naredba c). Nakon toga još je samo potrebno definirati da drugu teksturu koristimo kao temeljnu ( naredbe tipa d ). Naravno obje teksture je potrebno aktivirati i potom omogućiti njihovo korištenje ( naredbe tipa e ).

 

 

e glActiveTextureARB(GL_TEXTURE0_ARB);         //bump mapa

e glBindTexture(GL_TEXTURE_2D,bumpmap.texID);

e glEnable(GL_TEXTURE_2D);

 

a glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);

b glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_PRIMARY_COLOR_EXT);

c glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_DOT3_RGB_EXT);

a glTexEnvf(GL_TEXTURE_ENV, GL_OPERAND0_RGB_EXT, GL_SRC_COLOR);

d glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_TEXTURE);

d glTexEnvf(GL_TEXTURE_ENV, GL_OPERAND1_RGB_EXT, GL_SRC_COLOR);

 

e glActiveTextureARB(GL_TEXTURE1_ARB);         //temeljna tekstura

e glBindTexture(GL_TEXTURE_2D,tekstura.texID);

e glEnable(GL_TEXTURE_2D);

 

Nakon što smo prošli ovaj dio kôda, potrebno je izračunati kojom bojom će svaka točka biti obojana. Bojati točke je potrebno zbog kasnijeg zbrajanja tih boja sa onima na teksturi kako bi se dobio dojam 3D izobličenja.

 

float m[9],tc[3];

CVector3 lv;

 

Polje m[] će sadržavati x,y i z vrijednosti tangentnog prostora za i-tu točku modela, dok varijabla lv predstavlja relativno osvjetljenje te točke ( tip CVector3 predstavlja razred koji između ostalog sadrži x, y i z varijable tipa float ). Polje tc[] označava boju točke a predstavljeno je RGB vrijednostima u intervalu [0, 1].

 

lv.x=noviL[0]-tocka[i].x;

lv.y=noviL[1]-tocka[i].y;

lv.z=noviL[2]-tocka[i].z;

normaliziraj(lv);

 

m[0]=Tangenta[tocka[i]].x;

m[1]=Binormala[tocka[i]].x;

m[2]=Normal[tocka[i]].x;

m[3]=Tangenta[tocka[i]].y;

m[4]=Binormala[tocka[i]].y;

m[5]=Normal[tocka[i]].y;

m[6]=Tangenta[tocka[i]].z;

m[7]=Binormala[tocka[i]].z;

m[8]=Normal[tocka[i]].z;

 

Nakon što smo u matricu m[] upisali željene vrijednosti i pronašli relativno osvjetljenje točke lv, možemo izračunati boju kojom ćemo obojati našu točku modela.

 

tc[0]=(lv.x*m[0])+(lv.y*m[3])+(lv.z*m[6]);

tc[1]=(lv.x*m[1])+(lv.y*m[4])+(lv.z*m[7]);

tc[2]=(lv.x*m[2])+(lv.y*m[5])+(lv.z*m[8]);

 

Kako je već prije spomenuto, potrebno je smanjiti intenzitet ( ne nužno na polovicu iznosa ) boja kako nebi bilo prevelikog kontrasta na modelu.

 

tc[0]=(tc[0]*0.5f)+0.5f;

tc[1]=(tc[1]*0.5f)+0.5f;

tc[2]=(tc[2]*0.5f)+0.5f;

 

Sada nam je preostalo samo iscrtati našu točku, te tako koristeći ovu metodu i cijeli model.

 

glMultiTexCoord2fARB(GL_TEXTURE0_ARB,teks[i].x, teks[i].y); //bump mapa

glMultiTexCoord2fARB(GL_TEXTURE1_ARB,teks[i].x, teks[i].y); //temeljna tekstura

glColor3f(tc[0], tc[1], tc[2]); //bojanje točke

glVertex3f(tocka[i].x, tocka[i].y, tocka[i].z); //crtanje točke