Transformările sunt esențiale pentru grafica pe calculator. API-ul WebGL nu oferă nicio funcție pentru lucrul cu transformări. În Secțiunea 6.5, am folosit o bibliotecă JavaScript simplă pentru a reprezenta transformările de modelare în 2D. Lucrurile devin mai complexe în trei dimensiuni. Pentru grafica 3D cu WebGL, partea JavaScript va trebui de obicei să creeze atât o transformare modelview, cât și o transformare de proiecție și va trebui să aplice rotația, scalarea și translația matricei modelview, toate fără ajutorul WebGL. Acest lucru este mult mai ușor dacă aveți o bibliotecă JavaScript pentru a face treaba. O bibliotecă utilizată în mod obișnuit este glMatrix, o bibliotecă JavaScript gratuită pentru matematică vectorială și matricială, scrisă de Brandon Jones și Colin MacKenzie IV. Este disponibilă la http://glmatrix.net. Descărcarea de pe acel site web include un fișier JavaScript webgl/gl-matrix-min.js care definește biblioteca. Conform licenței sale, acest fișier poate fi utilizat și distribuit gratuit. Puteți găsi o copie în folderul sursă din descărcarea acestei cărți de pe site-ul web. Exemplele mele utilizează versiunea 2.3 a bibliotecii. Rețineți că gl-matrix-min.js este un fișier JavaScript „minificat”, care nu este conceput să fie lizibil de către om. Pentru a afla mai multe despre bibliotecă, consultați documentația de pe site-ul web (în prezent la http://glmatrix.net/docs/ în timp ce scriu aceste rânduri) sau citiți fișierele sursă din fișierul descărcat. (De asemenea, puteți citi sursa completă pentru versiunea 2.2, în formă lizibilă de către om, inclusiv comentarii, în fișierul webgl/gl-matrix.js, care poate fi găsit în directorul source/webgl în secțiunea de descărcare de pe site-ul web a acestei cărți.)
API-ul glMatrix poate fi pus la dispoziție pentru utilizare pe o pagină web cu un element de script, cum ar fi
<script src=”gl-matrix-min.js”></script>
Aceasta presupune că gl-matrix-min.js se află în același director ca și pagina web.
Biblioteca glMatrix definește ceea ce numește „clase” numite vec2, vec3 și vec4 pentru lucrul cu vectori de 2, 3 și 4 numere. Definește mat3 pentru lucrul cu matrici 3×3 și mat4 pentru matrici 4×4. Numele nu trebuie confundate cu tipurile GLSL cu aceleași nume; glMatrix se află în întregime pe partea JavaScript. Cu toate acestea, o clasă glMatrix mat4 poate fi transmisă unui program shader pentru a specifica valoarea unei matrici GLSL mat4 și, în mod similar, pentru celelalte tipuri de vectori și matrici.
Fiecare clasă glMatrix definește un set de funcții pentru lucrul cu vectori și matrici. De fapt, însă, deși documentația folosește termenul „clasă”, glMatrix nu este orientată pe obiecte. Clasele sale sunt de fapt doar obiecte JavaScript, iar funcțiile din clasele sale sunt ceea ce s-ar numi metode statice în Java. Vectorii și matricele sunt reprezentate în glMatrix ca matrice, iar funcțiile din clase precum vec4 și mat4 operează pur și simplu pe aceste matrici. Nu există obiecte de tip vec4 sau mat4 ca atare, ci doar matrice de lungime 4 sau respectiv 16. Matricele pot fi fie matrice JavaScript obișnuite, fie matrice tipizate de tip Float32Array. Dacă permiteți glMatrix să creeze matrice pentru dvs., acestea vor fi Float32Arrays, dar toate funcțiile glMatrix vor funcționa cu oricare dintre tipurile de matrice. De exemplu, dacă documentația glMatrix spune că un parametru ar trebui să fie de tip vec3, este în regulă să transmiteți fie o matrice Float32Array, fie o matrice JavaScript obișnuită de trei numere ca valoare a acelui parametru.
Rețineți că este posibil ca oricare dintre tipurile de tablouri să fie utilizate în funcții WebGL, cum ar fi glUniform3fv() și glUniformMatrix4fv(). glMatrix este conceput să funcționeze cu aceste funcții. De exemplu, un mat4 în glMatrix este o matrice de lungime 16 care conține elementele unei matrice de 4×4 în ordinea majoră a coloanelor, același format utilizat de glUniformMatrix4fv.
Fiecare clasă glMatrix are o funcție create() care creează o matrice de lungimea corespunzătoare și o umple cu valori implicite. De exemplu,
transform = mat4.create();
setează transform să fie un nou Float32Array de lungime 16, inițializat pentru a reprezenta matricea identitate. În mod similar,
vector = vec3.create();
creează un Float32Array de lungime 3, umplut cu zerouri. Fiecare clasă are, de asemenea, o funcție clone(x) care creează o copie a parametrului său x. De exemplu:
saveTransform = mat4.clone(modelview);
Majoritatea celorlalte funcții nu creează matrice noi. În schimb, modifică conținutul primului lor parametru. De exemplu, mat4.multiply(A,B,C) va modifica A astfel încât să conțină produsul matriceal dintre B și C. Fiecare parametru trebuie să fie un mat4 (adică o matrice de lungime 16) care există deja. Este în regulă ca unele dintre matrice să fie identice. De exemplu, mat4.multiply(A,A,B) are efectul de a înmulți A cu B și de a modifica A astfel încât să conțină răspunsul.
Există funcții pentru multiplicarea unei matrice prin transformări standard, cum ar fi scalarea și rotația. De exemplu, dacă A și B sunt mat4s și v este un vec3, atunci mat4.translate(A,B,v) face ca A să fie egal cu produsul dintre B și matricea care reprezintă translația prin vectorul v. În practică, vom folosi astfel de operații în principal pe o matrice care reprezintă transformarea modelview. Deci, să presupunem că avem un mat4 n numită modelview care conține transformarea curentă a lui modelview. Pentru a aplica o translație printr-un vector [dx,dy,dz], putem spune
mat4.translate(modelview, modelview, [dx,dy,dz] );
Acest lucru este echivalent cu apelarea funcției glTranslatef(dx,dy,dz) în OpenGL. Adică, dacă desenăm o geometrie după această instrucțiune, folosind modelview ca transformare a lui modelview, atunci geometria va fi mai întâi translată prin [dx,dy,dz] și apoi va fi transformată prin valoarea anterioară a funcției modelview. Rețineți utilizarea unui vector pentru a specifica translația în această comandă, în loc de trei parametri separați; acest lucru este tipic pentru glMatrix. Pentru a aplica o transformare de scalare cu factorii de scalare sx, sy și sz, utilizați
mat4.scale(modelview, modelview, [sx,sy,sz] );
Pentru rotație, glMatrix are patru funcții, inclusiv trei pentru cazurile comune de rotație în jurul axei x, y sau z. A patra funcție de rotație specifică axa de rotație ca fiind linia de la (0,0,0) la un punct (dx,dy,dz). Aceasta este echivalentă cu glRotatef(angle,dx,dy,dz). Din păcate, unghiul de rotație în aceste funcții este specificat în radiani și nu în grade:
mat4.rotateX(modelview, modelview, radians);
mat4.rotateY(modelview, modelview, radians);
mat4.rotateZ(modelview, modelview, radians);
mat4.rotate(modelview, modelview, radians, [dx,dy,dz]);
Aceste funcții ne permit să efectuăm toate transformările de modelare și vizualizare de bază de care avem nevoie pentru grafica 3D. Pentru a realiza grafică ierarhică, trebuie, de asemenea, să salvăm și să restaurăm transformarea pe măsură ce parcurgem graficul scenei. Pentru aceasta, avem nevoie de o stivă. Putem folosi o matrice JavaScript obișnuită, care are deja operații push și pop. Deci, putem crea stiva ca o matrice goală:
var matrixStack = [];
Putem apoi să inserăm o copie a matricei modelview curente pe stivă spunând
matrixStack.push( mat4.clone(modelview) );
și putem elimina o matrice din stivă și o putem seta să fie matricea modelview curentă cu
modelview = matrixStack.pop();
Aceste operații sunt echivalente cu glPushMatrix() și glPopMatrix() în OpenGL.
Punctul de plecare pentru transformarea modelview este de obicei o transformare de vizualizare. În OpenGL, funcția gluLookAt este adesea utilizată pentru a configura transformarea de vizualizare (Subsecțiunea 3.3.4). Biblioteca glMatrix are o funcție „lookAt” pentru a face același lucru:
mat4.lookAt( modelview, [eyex,eyey,eyez], [refx,refy,refz], [upx,upy,upz] );
Rețineți că această funcție folosește trei vec3 în locul celor nouă parametri separați din gluLookAt și plasează rezultatul în primul său parametru în loc de o variabilă globală. Acest apel de funcție este de fapt echivalent cu cele două comenzi OpenGL
glLoadIdentity();
gluLookAt( eyex,eyey,eyez,refx,refy,refz,upx,upy,upz );
Așadar, nu trebuie să setați modelview egal cu matricea de identitate înainte de a apela mat4.lookAt, așa cum ați face de obicei în OpenGL. Cu toate acestea, trebuie să creați matricea modelview la un moment dat înainte de a utiliza mat4.lookAt, cum ar fi apelând
var modelview = mat4.create();
Dacă doriți să setați un mat4 existent la matricea de identitate, puteți face acest lucru cu funcția mat4.identity. De exemplu,
mat4.identity( modelview );
Ați putea folosi acest lucru ca punct de plecare dacă doriți să compuneți transformarea vizualizării din transformări de bază de scară, rotire și translație.
În mod similar, glMatrix are funcții pentru configurarea transformărilor de proiecție. Are funcții echivalente cu glOrtho, glFrustum și gluPerspective (Subsecțiunea 3.3.3), cu excepția faptului că unghiul câmpului vizual din mat4.perspective este dat în radiani, nu în grade:
mat4.ortho(projecție, stânga, dreapta, jos, sus, aproape, departe );
mat4.frustum(projecție, stânga, dreapta, jos, sus, aproape, departe );
mat4.perspective(projecție, fovyInRadians, aspect, aproape, departe );
Ca și în cazul transformării modelview, nu este nevoie să încărcați proiecția cu identitatea înainte de a apela una dintre aceste funcții, dar trebuie să creați proiecția ca mat4 (sau o matrice de lungime 16).
Sursa: David J. Eck, Introduction to Computer Graphics (Eck), LibreTexts, licența CC BY-NC-SA 4.0. Traducere și adaptare Nicolae Sfetcu
Descoperă mai multe la MultiMedia
Abonează-te ca să primești ultimele articole prin email.
Lasă un răspuns