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
|