Programare folosind DirectX9: Rotirea obiectelor. Cameră virtuală. Proiecția în perspectivă

ÎN grafica pe computer conceptele sunt definite matrice diferite. Acestea sunt World Matrix, View Matrix și Projection Matrix. Folosind aceste matrici în cod sursă Programul efectuează transformări matrice pe modele. Transformările matricelor implică înmulțirea fiecărui vârf al unui obiect cu una dintre matrice, sau mai degrabă înmulțirea secvențială a tuturor vârfurilor unui obiect cu fiecare dintre cele trei matrice. Această abordare vă permite să reprezentați corect modelul în spațiul tridimensional al monitorului dumneavoastră bidimensional. Tehnica trecerii modelului prin cele trei matrice enumerate reprezintă esența mecanismului de lucru cu date grafice în planul tridimensional al monitorului.

Matricea lumii

Matrice mondială – vă permite să efectuați diverse transformări matrice (transformare și scalare) ale unui obiect în sistemul de coordonate mondial. Sistemul mondial coordonatele este proprie sistem local coordonate a acestui obiect, care este înzestrat cu fiecare obiect care, să zicem, a trecut prin matricea lumii, deoarece fiecare vârf participă la produsul acestei matrice.

Noul sistem local de coordonate simplifică foarte mult transformările afine ale unui obiect în spațiu. De exemplu, pentru a muta un obiect din colțul din stânga sus al afișajului în colțul din dreapta jos al afișajului, adică pentru a muta obiectul de joc în spațiu, trebuie pur și simplu să-l mutați punct local referință, sistem de coordonate către o nouă locație. Dacă nu ar exista o matrice mondială, atunci acest obiect ar trebui să fie transferat câte un vârf la un moment dat. Prin urmare, orice obiect, sau mai degrabă toate vârfurile acestui obiect, trec prin matricea de transformare a lumii.

După cum am menționat, transformarea lumii a vârfurilor unui obiect poate consta în orice combinație de rotație, translație și scalare. În notația matematică, rotația unui vârf de-a lungul axei X arată astfel:


Matricea lumii

unde cos este unghiul de rotație în radiani.

Rotirea unui vârf în jurul axei Y arată astfel:


Rotirea unui vârf în jurul axei Y

Și rotația în jurul axei Z are loc conform următoarei formule:


rotație în jurul axei Z

Translația vârfurilor vă permite să mutați acest vârf cu coordonatele x, y, z la punct nou cu coordonate noi x1, y1, z1. În notație matematică arată astfel:

X1 = x + Tx y1 = y + Ty z1 = z + Tz

Translația unui vârf în notație matriceală arată astfel:


Translația unui vârf în notație matriceală

unde Tx, Ty și Tz sunt valorile offset-ului de-a lungul axelor X, Y și Z.

Puteți scala un vârf în spațiu (eliminați sau măriți) cu coordonatele x, y, z la un nou punct cu noi valori x1, y1, z1 folosind următoarea notație:

X1 = x * S y1 = y * S z1 = z * S

În notația matriceală aceasta se exprimă după cum urmează:


Scala Vertex

unde Sx, Sy, Sz sunt valorile coeficienților de întindere sau compresie de-a lungul axelor X, Y, Z.

Toate operațiunile de mai sus se pot face manual în codul sursă al programului, adică intrările date pot fi calculate așa cum tocmai le-am descris. Dar, firește, nimeni nu face asta (aproape nimeni), pentru că DirectX a făcut-o cantitate uriașă metode care vor face toate operațiunile de mai sus pentru tine.

Vizualizare Matrice

Matrice de vizualizare – specifică locația camerei în spațiu și este a doua matrice prin care se înmulțesc vârfurile obiectului. Această matrice ajută la determinarea direcției de vizualizare a unei scene 3D. O scenă tridimensională este tot ceea ce vedeți pe ecranul monitorului. E ca într-un teatru în care stai într-un portar sau în galerie și privești acțiunea de pe scenă. Așadar, stând în portar, veți avea o singură locație a camerei, iar așezarea în galerie este complet diferită.

De fapt, această matrice vă permite să determinați genul jocului. De exemplu, jocul DOOM la persoana întâi este primul rând al unui portar într-un teatru, în timp ce jocul Warcraft este o galerie pe balcon. Matricea de vizualizare este concepută pentru a determina poziția camerei în spațiu și puteți muta poziția camerei la stânga, la dreapta, în sus, în jos, o îndepărtați, măriți și așa mai departe.

Matricea de proiecție

Matricea de proiecție este o matrice mai complexă care creează o proiecție a unui obiect tridimensional pe planul unui ecran de monitor bidimensional. Folosind această matrice, sunt determinate zonele de tăiere din față și din spate ale spațiului tridimensional, ceea ce vă permite să reglați spațiul de tăiere al obiectelor invizibile pe ecran și, în același timp, să reduceți sarcina procesorului plăcii video. Figura prezintă mecanismul de proiectare a unui obiect într-un plan și de tăiere a spațiului.


Matricea de proiecție

Astăzi vom arunca o privire mai atentă asupra dispozitivului cu camera virtuală. Să începem cu poza.

În figură vedem spațiul de coordonate al camerei. Direcția („look”) camerei coincide întotdeauna cu direcția pozitivă a axei z, iar camera în sine este situată la origine.

Spațiul intern al piramidei prezentat în figură este acea parte a lumii virtuale pe care o va vedea utilizatorul.

Observați cele trei avioane. Primul este situat la o distanță de 1 de-a lungul axei z. Acesta este avionul apropiat. Jucătorul nu va vedea niciodată ce este înainte. În acest caz, valoarea lui z este egală cu unu, dar, în general, poate fi orice. Un defect de afișare grafică este asociat cu planul apropiat. Acest defect se manifestă în primul rând la trăgători (datorită libertății mari a camerei). Când te apropii prea mult de un obiect, poți ajunge „înăuntru”. Din ultimele jocuri Acest defect a fost mai ales pronunțat în Left 4 dead: când o mulțime de zombi cădeau asupra jucătorului, era foarte des posibil să se uite în interiorul altor personaje.

Planul situat la o distanță de 100 de unități de-a lungul axei z se numește plan îndepărtat. Din nou, valoarea poate fi arbitrară. Utilizatorul nu va vedea niciodată obiecte situate mai departe de acest plan.

Cele șase planuri care limitează spațiul pe care îl va vedea utilizatorul se numesc planuri de tăiere: stânga, dreapta, sus, jos, aproape și departe.

Avionul situat între aproape și departe este proiecție. În cele ce urmează, vom plasa acest plan la z=1, adică. va coincide cu cel mai apropiat. Aici am separat planurile de apropiere și de proiecție pentru a arăta că nu sunt același lucru. Planul de proiecție este destinat transformării coordonatelor finale: transformarea din spațiul camerei tridimensional în spațiul bidimensional.

Datorită planului de proiecție, utilizatorul îl va vedea lumea virtuală. De fapt, acest avion este ceea ce va vedea utilizatorul. Planul de proiecție este direct legat de concepte cum ar fi tampoanele de prim-plan/fond, fereastra programului și ecranul utilizatorului. Toate aceste concepte pot fi considerate ca o imagine dreptunghiulară, care este reprezentată în memoria computerului printr-o matrice de numere.

Conversia coordonatelor din lumea tridimensională în planul de proiecție este cea mai dificilă dintre cele de pe în acest moment au fost studiate de noi.

Câmp de vedere/zonă de vedere

În figura de mai sus, planul de proiecție (și deci imaginea pe care o va vedea utilizatorul) are o lățime mai mare decât înălțimea sa. Lățimea și înălțimea planului de proiecție sunt specificate folosind unghiuri. Există diferite nume pentru aceste unghiuri: câmpuri de vedere sau zone de vizualizare. În engleză - câmpuri de vedere.

Zonele de vizualizare sunt specificate prin două unghiuri. Să le numim: fovx - zonă de vizualizare orizontală, fovy - zonă de vizualizare verticală. Detalii despre zonele de vizualizare: mai jos.

Z-buffer / w-buffer / depth buffer (tampon z / w-buffer / tampon de adâncime)

Să ne uităm la imagine, care arată două triunghiuri: la o distanță de 25 și 50 de unități de cameră. Figura (a) arată locația triunghiurilor în spațiu (vedere de sus), iar figura (b) arată imaginea finală:

După cum ați putea ghici, imaginea trebuie desenată pornind de la elementele cele mai îndepărtate și terminând cu cele mai apropiate. Soluția evidentă este să calculați distanța de la origine (de la cameră) la fiecare obiect și apoi să comparați. Grafica computerizată folosește un mecanism puțin mai avansat. Acest mecanism are mai multe denumiri: z-buffer, w-buffer, depth buffer. Dimensiunea buffer-ului z în ceea ce privește numărul de elemente este aceeași cu dimensiunea buffer-ului de fundal și principal. Componenta z a obiectului cel mai apropiat de cameră este introdusă în bufferul z. ÎN în acest exemplu, unde triunghiul albastru se suprapune pe cel verde, coordonatele z ale celui albastru vor fi introduse în tamponul de adâncime. Vom vorbi despre z-buffers mai detaliat într-o lecție separată.

Proiecție ortografică / paralelă

Operația în care dimensiunea spațiului scade (a existat un spațiu tridimensional, a devenit bidimensional) se numește proiecție. În primul rând, ne interesează proiecția în perspectivă, dar mai întâi ne vom familiariza cu paralela (proiecția paralelă sau ortografică).

Pentru a calcula o proiecție paralelă, este suficient să renunțați la coordonatele suplimentare. Dacă avem un punct în spațiu [ 3 3 3 ], atunci cu o proiecție paralelă pe planul z=1, acesta va fi proiectat în punctul .

Proiecția în perspectivă(proiecție în perspectivă) pe planul de proiecție

În acest tip de proiecție, toate liniile converg într-un punct. Exact așa funcționează viziunea noastră. Și cu ajutorul proiecției în perspectivă este modelat „aspectul” din toate jocurile.


Comparați această imagine cu imaginea care arată coordonatele omogene din lecția anterioară. Pentru a trece din spațiul tridimensional în spațiul bidimensional, trebuie să împărțiți primele două componente ale vectorilor la a treia: [ x/z y/z z/z ] = [ x/z y/z 1 ].

După cum am scris mai sus, planul de proiecție poate fi situat oriunde între aproape și departe. Vom plasa întotdeauna planul de proiecție la z=1, dar în acest tutorial ne vom uita la alte opțiuni. Să ne uităm la poză:


Să notăm distanța până la planul de proiecție de la originea coordonatelor ca d. Vom lua în considerare două cazuri: d=1 și d=5. Punct important: a treia componentă a tuturor vectorilor după proiecție trebuie să fie egală cu d - toate punctele sunt situate în același plan z=d. Acest lucru poate fi realizat prin înmulțirea tuturor componentelor vectorului cu d: [ xd/z yd/z zd/z ]. Cu d=1, obținem: [ x/z y/z 1 ], aceasta este formula care a fost folosită pentru a transforma coordonatele omogene.

Acum, dacă mutăm planul de proiecție în punctul z=5 (respectiv d=5), obținem: [ xd/z yd/z zd/z ] = [ 5x/z 5y/z 5 ]. Ultima formulă proiectează toți vectorii spațiului într-un singur plan, unde d=5.
Avem o mică problemă aici. Formula anterioară funcționează cu vectori tridimensionali. Dar am fost de acord să folosim vectori cu patru dimensiuni. A patra componentă în acest caz poate fi pur și simplu aruncată. Dar nu vom face acest lucru, deoarece utilizarea sa oferă unele capacități specifice pe care le vom discuta mai târziu.

Trebuie să găsiți divizorul comun al componentei a treia și a patra, atunci când este împărțit la care valoarea d rămâne în a treia componentă și unitatea în a patra. Acest divizor este d/z. Acum, din vectorul obișnuit [ x y z 1 ] trebuie să pregătim un vector pentru proiecție (diviziune) [ x y z z/d ]. Acest lucru se face folosind matricea de transformare (verificați rezultatul înmulțind orice vector cu această matrice):


Ultima transformare nu este încă o proiecție. Aici pur și simplu reducem toți vectorii la forma de care avem nevoie. Permiteți-mi să vă reamintesc că vom plasa planul de proiecție la d=1, ceea ce înseamnă că vectorii vor arăta astfel: [ x y z z ].

Matricea de transformare a perspectivei

Ne vom uita la matricea de transformare a perspectivei utilizată în DirectX:

Acum știm pentru ce este destinat elementul _34. De asemenea, știm că elementele _11 și _22 scala imaginea pe orizontală și pe verticală. Să ne uităm la ce se ascunde exact în spatele numelor xScale și yScale.

Aceste variabile depind de zonele de vizualizare pe care le-am discutat mai sus. Prin creșterea sau scăderea acestor unghiuri, puteți scala (scala sau mări) imaginea - modificați dimensiunea și raportul de aspect al planului de proiecție. Mecanismul de zoom amintește vag de zoomul din camere/aparate foto – principiul este foarte asemănător. Să ne uităm la imagine:


Să împărțim unghiul fov în două părți și să luăm în considerare doar o jumătate. Ce vedem aici: prin creșterea unghiului fov/2 (și, în consecință, a unghiului fov), creștem sinul unghiului și micșorăm cos. Aceasta duce la o creștere a planului de proiecție și, în consecință, la o scădere a obiectelor proiectate. Unghiul ideal pentru noi ar fi fov/2 = P/4. Permiteți-mi să vă reamintesc că un unghi în P/4 radiani este egal cu 45 de grade. În acest caz, fov va fi egal cu 90 de grade. De ce este bun pentru noi un unghi de 45 de grade? În acest caz, nu există scalare, iar cos(P/4)/sin(P/4)=1.

Acum putem scala cu ușurință imaginea pe verticală (orizontală) folosind sinusul și cosinusul a jumătate din zona de vizualizare (funcția cotangentă în C++ se numește cot):

yScale = cos(fovY/2)/sin(fovY/2) = cot(fovY/2)
DirectX folosește numai câmpul vizual vertical (fovY), iar scalarea orizontală depinde de câmpul vizual vertical și de raportul de aspect.

Permiteți-mi să vă reamintesc că fereastra din programele noastre are dimensiunea de 500x500. Raport de aspect: 1 la 1. Prin urmare, variabilele vor fi egale: xScale=1, yScale=1.

Raport de aspect standard monitor/TV: 4:3. Acest raport corespunde rezoluțiilor ecranului: 640x480, 800x600, 1600x1200. Nu ne vom atinge încă modul ecran complet, dar putem schimba dimensiunea ferestrei programului. Puteți modifica dimensiunea ferestrei (în parametrii actuali), de exemplu, la 640X480. Dar pentru a preveni întinderea tuturor obiectelor (pătratele vor arăta ca dreptunghiuri), nu uitați să modificați variabilele corespunzătoare din matricea de proiecție.

Aproape că am uitat, forum pentru xScale în DirectX:

xScale = yScale / raport de aspect
Rapoartele sunt setate simplu: 1/1, 4/3, 16/9 - acestea sunt cele standard.

Rămâne de aflat scopul elementelor _33, _34 ale matricei de transformare a perspectivei. zf este coordonata z a planului îndepărtat (de la departe - departe), iar zn este coordonata z a planului apropiat (de la aproape - aproape). Rețineți că elementul _43 = _33 * -zn.

Cel mai simplu mod de a înțelege exact ce fac aceste formule este cu exemple. Să înmulțim vectorul standard [ x y z w ] cu matricea prezentată mai sus. Vă recomand să faceți acest lucru luând o bucată de hârtie și un creion (sper că vă amintiți cum să înmulțiți două matrici). Componentele vectoriale vor lua următoarea formă.

1 = x*xScale
2 = y*yScale
a treia = z*(zf/(zf-zn)) + w*(-(zn*zf)/(zf-zn)) = (zf/(zf-zn))*(z - w*zn)
al 4-lea = (w*z)/d
Să efectuăm o transformare de proiecție (împărțim toate elementele în a patra componentă și presupunem că d=1 și w=1):

primul = (d*x*xScale)/(w*z) = (x*xScale)/z
2nd = (d*y*yScale)/(w*z) = (y*xScale)/z
a treia = (zf/(zf-zn))*(z - w*zn)*(w*d/z) = (zf/(zf-zn))*(1 - zn/z)
a 4-a = 1
Ca rezultat, am primit un vector de forma:

[ x/(z*xScale) y/(z*yScale) (zf/(zf-zn))*(1-zn/z) 1 ]
Acum, dacă specificați valori specifice pentru zf și zn, veți găsi următoarele (pentru valori pozitive): dacă vectorul este situat înaintea planului apropiat, atunci componenta z după transformare va fi mai mică decât zero, dacă vectorul este situat în spatele planului îndepărtat, atunci componenta z va fi unități mai mari.

Nu există nicio diferență unde se află exact planurile apropiate și îndepărtate: zn=1, zf=10 sau zn=10 și zf=100 (sau orice alte valori) - după transformare, zona vizibilă va fi localizată în interval de la zero la unu, inclusiv.

Tocmai pentru aceasta sunt destinate formulele din elementele _33, _34 ale matricei de proiecție - pentru a proiecta distanța de la planul apropiat la cel îndepărtat în segment. Verificați acest lucru calculând valorile mai multor vectori pentru valori specifice ale zn,zf (da, pe o bucată de hârtie!!!).

Ieșirea grafică este de obicei furnizată unei zone dreptunghiulare a ecranului sau ferestrei. În redarea OpenGL, această zonă se numește portul de ieșire. În această zonă dreptunghiulară biblioteca va plasa imaginea generată.

Dimensiunile sale sunt determinate în raport cu colțul din stânga sus al ferestrei și măsurate în pixeli. Pentru a determina portul de ieșire, aplicația trebuie să asculte evenimentul de redimensionare a ferestrei și să determine portul de ieșire folosind funcția:

void glViewport(GLint x, GLint y, GLsizei width, GLsizei height);

Argumentele (x, y) specifică poziția colțului din stânga sus al portului de ieșire, iar lățimea și înălțimea sunt dimensiunile acestuia. În mod implicit, biblioteca extinde portul de ieșire pentru a acoperi întreaga fereastră OpenGL.

Sistemul de coordonate

În primul rând, vârful este convertit într-o matrice 1X4 în care primele trei elemente reprezintă coordonatele x, y, z. Al patrulea număr este factorul de scară w, care este de obicei 1,0. Vârful este înmulțit cu matricea vederii, care descrie transformarea sistemului de coordonate a vederii. Obținem vârful în coordonatele vizuale. Acesta, la rândul său, este înmulțit cu matricea de proiecție și obținem vârful în coordonate de proiecție. În această etapă, unele vârfuri sunt aruncate (datorită faptului că nu se încadrează în volumul de vizualizare). Vârfurile sunt apoi normalizate pentru a transmite perspectiva (cu excepția cazului în care coordonata w este 1,0). Proiecția finală a vârfului pe suprafața ecranului bidimensional este realizată de biblioteca OpenGL însăși și nu poate fi interferată în acest proces.

Matricea de proiecție

Matricea de proiecție este responsabilă pentru care volumul spațiului se va vizualiza modul în care vârfurile primitive grafice va fi proiectat pe suprafața bidimensională a ecranului monitorului. Transformările matricei de proiecție determină schimbarea întregii imagini (scalare, mișcare sau rotire).

OpenGL acceptă două moduri de matrice de proiecție: perspectivă și ortografic.

Proiecția în perspectivă folosește faptul că ochiul uman lucrează cu un obiect de tip îndepărtat ale cărui dimensiuni au dimensiuni unghiulare.

Cu cât un obiect este mai departe, cu atât ni se pare mai mic. Astfel, volumul de spațiu care este vizualizat este o piramidă.

Matricea de proiecție în perspectivă este definită folosind funcția:

void glFrustum(GLduble stânga, GLdouble dreapta, GLdouble fund, GLdouble top, GLdouble near, GLdouble departe);

(stânga, jos, -aproape) și (dreapta, sus, -aproape) definesc coordonatele celei mai apropiate casete de tăiere; aproape și departe au întotdeauna valori pozitive și determină distanța din punct de vedere la cadrele de tăiere apropiate și îndepărtate.

Pentru a seta matricea de proiecție a perspectivei, puteți utiliza și funcția gluPerspective(), care are argumente diferite

Proiecția în perspectivă este de obicei folosită în jocuri și aplicații în care este necesar să se realizeze obiecte extrem de realiste care pot fi vizualizate cu ochiul. Proiecția ortografică este utilizată în mod obișnuit pentru vizualizarea 2D și 3D a datelor științifice și tehnice. Să ne uităm mai întâi la configurarea proiecției ortografice pentru randarea 2D. Cu proiecția ortografică, volumul spațiului care este vizualizat este un paralelipiped:

Particularitatea proiecției ortografice este că distanța de la cameră la obiecte nu afectează imaginea finală.

Pentru a seta și ulterior modifica matricea de proiecție, executați funcția glMatrixMode(GL_PROJECTION). Pentru început, ar trebui să anulați și toate setările și transformările anterioare, făcând din matricea de proiecție una folosind funcția glLoadIdentity(). Matricea de proiecție ortografică este setată folosind o funcție care are următorul prototip:

void glOrtho(GLduble stânga, GLdouble dreapta, GLdouble jos, GLdouble sus, GLdouble aproape, GLdouble departe);

(stânga, jos, -aproape) și (dreapta, sus, -aproape) sunt puncte care definesc cel mai apropiat cadru de tăiere. (stânga, jos, -departe) și (dreapta, sus, -departe) sunt puncte care definesc cadrul de decupare departe. După aplicarea acestei comenzi, direcția de proiecție este paralelă cu axa z către valori negative

//Funcție pentru redimensionarea și setarea coordonatelor
void Reshape (lățime int, înălțime int)
{
//Setați portul de ieșire
glViewport(0, 0, lățime, înălțime);

//Modul matricei de proiecție
glMatrixMode(GL_PROJECTION);
//Matricea identitară
glLoadIdentity();

//Setarea unui sistem de coordonate ortografic bidimensional
glOrtho(-50., 50., -50., 50., -1., 1.);

//Modul matricei de vizualizare
glMatrixMode(GL_MODELVIEW);
}

În special pentru randarea 2D, puteți utiliza o funcție care are următorul prototip:

void gluOrtho2D(GLdublu stânga, GLdouble dreapta, GLdublu jos, GLdouble sus);

Această funcție este similară cu glOrtho(), care apelează argumentul near=-1.0 și far=1.0. În timpul redării 2D, coordonata z de la vârfuri are valoarea 0, ceea ce înseamnă că obiectele sunt pe planul mediu.

Dacă este necesar să se mențină proporțiile, sistemul de coordonate trebuie setat ținând cont de raportul dintre lățimea și înălțimea ferestrei.

//Setarea sistemului de coordonate ortografice
aspect dublu=latime/dublu(inaltime);
dacă (lățime>=înălțime)
{
gluOrtho2D(-50.*aspect, 50.*aspect, -50., 50.);
}
altfel
{
gluOrtho2D(-50., 50., -50./aspect, 50./aspect);
}

Vizualizare matrice

Matricea de vedere este responsabilă pentru sistemul de coordonate al modelului tridimensional creat. În timpul procesului de creare a unui model, matricea de vizualizare poate fi schimbată de mai multe ori pentru a modifica imaginea primitivelor grafice individuale (transformați un pătrat într-un dreptunghi, un cub într-un paralelipiped, o sferă într-un elipsoid). Pentru a instala și ulterior modifica matricea de vizualizare, executați funcția glMatrixMode(GL_MODELVIEW). Mai întâi ar trebui să anulați totul

instalatii anterioare și transformări, făcând matricea de proiecție singulară folosind funcția glLoadIdentity(). Dacă coordonatele vârfurilor unui obiect sunt specificate atunci când este creat, atunci nu sunt necesare transformări suplimentare ale sistemului de coordonate. Cu toate acestea, acest lucru este adesea dificil sau pur și simplu imposibil. OpenGL oferă trei funcții pentru a efectua transformări ale sistemului de coordonate: glTranslated(), glRotated() și glScaled(). Aceste comenzi generează matrice de translație, rotație și scalare, care sunt înmulțite cu matricea de vizualizare folosind funcția glMultMatrix(). După cum puteți vedea, OpenGL preia controlul operații cu matriceși le execută conform specialului

algoritmi rapizi

cu eficienta maxima.

De exemplu:

Transfer

Dacă argumentul este mai mare decât 0, atunci când este afișat obiectul va fi deplasat către valori pozitive de-a lungul axei. Dacă argumentul este mai mic de 0, atunci când este afișat obiectul va fi deplasat către valori negative de-a lungul axei.

Scalare

Transfer

Acest lucru se face folosind o funcție care are următorul prototip:
Dacă argumentul este mai mare decât 1, atunci obiectul va fi mărit când este afișat. Dacă argumentul este mai mic de 1, atunci obiectul va fi redus atunci când este afișat. Dacă argumentul este negativ, atunci și obiectul va fi reflectat atunci când este afișat. Este permisă o valoare nulă pentru argument, dar va avea ca rezultat dimensiunile obiectului zero.
Întoarce-te
void glRotated(unghi dublu, x dublu, y dublu, z dublu);
glRotated(30.,0.,0.,1.); //Rotiți în jurul lui z
glBegin(GL_LINE_LOOP);
//Setarea vârfurilor
glVertex2d(-2., 2.);

glVertex2d(2., 2.);

glVertex2d(2., -2.);

glVertex2d(-2., -2.);

glEnd();

Un mecanism interesant și foarte eficient pentru crearea unei scene sunt listele. Acesta este un mecanism care vă permite să vă amintiți secvențe de comenzi OpenGL și să le executați din nou. Acest lucru poate îmbunătăți semnificativ eficiența imaginii cantitate mare

obiecte identice.

Fiecare listă de afișare trebuie să aibă un identificator. Acesta poate fi un număr întreg arbitrar pe care îl puteți atribui singur. Pentru a evita conflictele de identificare a listei, biblioteca OpenGL recomandă utilizarea funcției

GLuint glGenLists(gama GLsizei);

care găsește un identificator liber și îl returnează. Argumentul funcției specifică numărul de liste consecutive pentru care ar trebui obținute identificatorii. Dacă nu au mai rămas identificatori liberi, funcția returnează zero.

Pentru a începe generarea unei liste, trebuie să apelați funcția

void glNewList(lista GLuint, modul GLenum);

Primul argument specifică identificatorul listei generate, iar al doilea determină dacă lista va fi doar generată (GL_COMPILE) sau afișată imediat (GL_COMPILE_AND_EXECUTE).

În continuare pot fi comenzile OpenGL care trebuie salvate în listă. Nu toate comenzile pot fi incluse în el.

Formarea listei se termină cu funcția:

void glEndList(void);

Odată generate, listele de afișare sunt stocate în structura de date internă a ferestrei OpenGL și vor fi șterse atunci când fereastra este închisă sau distrusă.

Pentru a executa lista de afișare, utilizați comanda:

void glCallList(lista GLuint);

care ia ca argument identificatorul listei.

Funcția glCallList() poate fi apelată în orice meme a programului atunci când comenzile stocate în listă trebuie executate.
{
Să ne uităm la un exemplu:

void Remiză (void)

//Ștergerea tamponului de culoare
glColor3d(1.0, 1.0, 0.0);
glBegin(GL_LINES);

glVertex2d(-50., .0);<50; i++)
{
glVertex2d(50., .0);
Pentru(int i=-50; i
{
glVertex2d(i, .0);
}
dacă (i % 5)
{
glVertex2d(i, -1.);
}
altfel
{
altfel dacă (i % 10)
}
}
glVertex2d(i, -2.);

//Ștergerea tamponului de culoare
glVertex2d(i, -3.);
glEnd();
glVertex2d(.0, -50.);<50; j++)
{
glVertex2d(.0, 50.);
pentru(int j=-50; j
{
glVertex2d(.0, j);
}
dacă (j % 5)
{
glVertex2d(-1., j);
}
altfel
{
altfel dacă (j % ​​10)
}
}
glVertex2d(i, -2.);
glVertex2d(-2., j);
glVertex2d(-3., j);
}

Funcția glCallList() poate fi apelată în orice meme a programului atunci când comenzile stocate în listă trebuie executate.
{
Să ne uităm la un exemplu:
//Terminați execuția comenzii
glFlush();
void Remiză (void)

glClear(GL_COLOR_BUFFER_BIT);
//Setați culoarea afișajului
//Formarea axei
{
int axa = glGenLists(1);
//Ștergerea tamponului de culoare
dacă (axa != 0)
glNewList(axa, GL_COMPILE);

glVertex2d(0., .0);<97; i++)
{
glVertex2d(50., .0);
Pentru(int i=-50; i
{
glVertex2d(100., .0);
}
dacă (i % 5)
{
Pentru(int i=0.; i
}
altfel
{
glVertex2d(i, 1.);
}
}
glVertex2d(i, -2.);
//Formarea săgeților poate fi adăugată ulterior
glBegin(GL_LINE_STRIP);
glVertex2d(97., 1.);
glVertex2d(100.,.0);
glVertex2d(97., -1.);
glVertex2d(i, -2.);
glEndList();
}
//Desenarea axei orizontale
glPushMatrix();
glTranslated(-50.,0.,0.);
glRotated(180.,1.,0.,0.);
glCallList(axa);
glPopMatrix();

//Desenarea axei verticale
glPushMatrix();
glTranslated(0.,-50.,0.);
glRotated(90.,0.,0.,1.);
glCallList(axa);
glPopMatrix();

//Terminați execuția comenzii
glVertex2d(-3., j);
}

Pentru a roti obiectele (sau camera), este nevoie de o bază matematică serioasă, cu ajutorul căreia coordonatele tuturor obiectelor vor fi calculate atunci când sunt afișate pe un ecran de computer „plat”. Vreau să spun imediat că nu trebuie să vă sperii, toate bibliotecile de matematică au fost deja scrise pentru noi, doar le vom folosi. În orice caz, nu trebuie să săriți peste următorul text, indiferent de nivelul de cunoștințe de matematică.

1. Matrici, concepte generale

Ce sunt matricele? Să ne amintim de matematica superioară: o matrice este un set de numere cu o dimensiune cunoscută anterior de rânduri și coloane.

Se pot adăuga matrici, se înmulțesc cu un număr, se înmulțesc între ele și multe alte lucruri interesante, dar vom sări peste acest moment, pentru că este descris suficient de detaliat în orice manual de matematică superioară (manele pot fi căutate pe google.com). Vom folosi matrice ca programatori, le completăm și le spunem ce să facă cu ele, toate calculele vor fi efectuate de biblioteca matematică Direct3D, așa că trebuie să includem modulul antet d3dx9.h (și biblioteca d3dx9.lib) în proiect.

Sarcina noastră este să creăm un obiect, de ex. umpleți matricea cu coordonatele vârfurilor obiectului. Fiecare vârf este un vector (X, Y, Z) în spațiul 3D. Acum, pentru a efectua o acțiune, trebuie să luăm obiectul nostru (adică o matrice) și să-l înmulțim cu matricea de transformare, rezultatul acestei operații este un obiect nou, specificat ca o matrice.

Direct3D definește și utilizează trei matrice principale: matricea mondială, matricea de vizualizare și matricea de proiecție. Să le aruncăm o privire mai atentă.

Matricea lumii- vă permite să rotiți, să transformați și să scalați un obiect și, de asemenea, oferă fiecărui obiect propriul său sistem de coordonate local.

Funcții pentru lucrul cu matricea lumii:

  • D3DXMatrixRotationX(), D3DXMatrixRotationY(), D3DXMatrixRotationZ() - rotirea unui punct relativ la una dintre axe;
  • D3DXMatrixTranslation() - mutarea unui punct în altă poziție;
  • D3DXMatrixScale() - scalare.

    Vizualizare Matrice- definește locația camerei de vizualizare a scenei și poate consta din orice combinație de difuzare și rotație.
    D3DXMatrixLookAtLH() și D3DXMatrixLookAtRH() determină poziția camerei și unghiul de vizualizare pentru sistemele de coordonate pentru stângaci și, respectiv, dreptaci.

    Matricea de proiecție- creează o proiecție a unei scene 3D pe ecranul monitorului. Cu ajutorul acestuia, obiectul este transformat, originea coordonatelor este transferată în partea din față și se determină planurile de tăiere din față și din spate.

    Prin completarea acestor matrici și prin transformări, creați o scenă tridimensională în care puteți să vă mutați, să rotiți, să măriți, să eliminați și să efectuați alte acțiuni asupra obiectelor, în funcție de nevoile dvs.

    2. Crearea unui obiect

    Cream un nou proiect, asemanator cu primul. Înainte de a continua să ne complicăm codul, să-l împărțim în părți pentru o mai bună citire a codului. Proiectul nostru poate fi împărțit în mod logic în trei componente:
    1. Fereastra Windows (inițializarea ferestrei, mesaje, ...)
    2. Inițializare 3D (încărcarea coordonatelor obiectului, ștergerea resurselor, ...)
    3. Redarea scenei (matrice, primitive de desen, ...)
    Ca urmare, vom avea 3 fișiere - window.cpp, init3d.h, render.h cu următorul conținut: init3d.h- transfera variabile și structuri globale, declarații de funcții, funcții InitDirectX(), InitBufferVertex(), Destroy3D() redă.h- mutați funcția RenderScene() tot ce rămâne se referă la fereastra principală, acesta va fi un fișier - window.cpp.

    Adăugarea unui fișier antet și a unei biblioteci pentru utilizarea funcțiilor matriceale

    #include //sau C:\DXSDK\Include\d3dx9.h #pragma comment(lib, "d3dx9.lib") //sau C:\\DXSDK\\Lib\\d3dx9.lib

    De asemenea, avem nevoie de funcții standard pentru a lucra cu timpul, așa că includem fișierul antet corespunzător:

    #include

    Să schimbăm formatul de reprezentare a vârfurilor:

    #define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ/D3DFVF_DIFFUSE) struct CUSTOMVERTEX ( FLOTĂ x, y, z; DWORD culoare; );

    Vom folosi un tip de vârf neconvertit, deoarece Vom face transformările folosind matrice.
    Schimbăm codul funcției InitDirectX(). În această funcție este necesar să adăugați setarea a două moduri de afișare.
    Opriți modul de tăiere, astfel încât atunci când rotiți să puteți vedea toate părțile obiectului:

    PDirectDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);

    Momentan nu folosim iluminare, ci pictăm vârfurile într-o anumită culoare, așa că stingem iluminarea:

    PDirectDevice->SetRenderState(D3DRS_LIGHTING, FALSE);

    Să ne simplificăm inima imaginându-i-o sub forma a trei triunghiuri. Vom folosi un sistem de coordonate local.


    CUSTOMVERTEX stVertex= ( ( -1.0f, 0.5f, 0.0f, 0x00ff0000 ), ( -0.5f, 1.0f, 0.0f, 0x00ff0000 ), ( 0.0f, 0.5f, 0.0f, 0x0.0 , (0x0.0 ), (0.0f, 0.0f), (0.0f f, 0.0f, 0x000000ff), ( 0.5f, 1.0f, 0.0f, 0x000000ff), ( 1.0f, 0.5f, 0.0f, 0x000000ff), ( -1.0f, 0.5f, 0.5f, 0,0. f, 0,5f, 0,0f, 0x0000ff00), (0,0f, -1,0f, 0,0f, 0x0000ff00), );

    3. Crearea matricilor de transformare

    Să scriem în fișierul render.h funcția SetupMatrix() în care vor avea loc toate acțiunile asupra matricelor.

    Să creăm matrice:

  • D3DXMATRIX MatrixWorld; - matricea lumii
  • D3DXMATRIX MatrixView; - matricea formei
  • D3DXMATRIX MatrixProjection; - matricea de proiectie
    Configurarea matricei mondiale

    Pentru ca un obiect să se rotească, este necesar să obțineți ora sistemului și, la fiecare „instant”, să schimbați unghiul dintre sistemul de coordonate local și sistemul de coordonate mondial. Ne vom roti în raport cu axa X, așa că folosim funcția D3DXMatrixRotationX. După calcularea matricei mondiale, trebuie să aplicați valorile acesteia folosind funcția SetTransform:

    UINT iTime=timeGetTime()%5000; FLOAT fAngle=iTime*(2.0f*D3DX_PI)/5000.0f; D3DXMatrixRotationX(&MatrixWorld, fAngle); pDirectDevice->SetTransform(D3DTS_WORLD, &MatrixWorld); Configurarea unei matrice de vizualizare

    Instalăm camera în locul potrivit și o îndreptăm spre obiect

  • D3DXMatrixLookAtLH(&MatrixView, - rezultatul funcției
  • &D3DXVECTOR3(0.0f, 0.0f, -8.0f), - punctul în care se află camera
  • &D3DXVECTOR3(0.0f, 0.0f, 0.0f), - punctul în care ne uităm
  • &D3DXVECTOR3(0,0f, 1,0f, 0,0f)); - partea de sus a obiectului

    După calcul, este necesar să se aplice valorile obținute.

  • În ultima prelegere am vorbit despre cele mai importante proiecții utilizate în geometria afină. Să trecem acum să luăm în considerare geometria perspectivei și câteva tipuri noi de proiecție.

    În fotografii, tablouri și ecrane, imaginile ni se par naturale și corecte. Aceste imagini se numesc perspectivă. Proprietățile lor sunt astfel încât obiectele mai îndepărtate sunt reprezentate la o scară mai mică, liniile paralele sunt în general neparalele. Ca urmare, geometria imaginii se dovedește a fi destul de complexă și imagine terminată este dificil de determinat dimensiunea anumitor părți ale unui obiect.

    Proiecția obișnuită în perspectivă este o proiecție centrală pe un plan cu raze drepte care trec printr-un punct, centrul proiecției. Una dintre razele proiectante este perpendiculara pe planul de proiectie si se numeste principala. Punctul de intersecție al acestei raze și planul de proiecție este punctul principal al imaginii.

    Există trei sisteme de coordonate. De obicei, un programator lucrează și stochează date despre obiecte geometrice în coordonatele lumii. Pentru a crește realismul, atunci când vă pregătiți pentru afișarea unei imagini pe ecran, datele despre obiecte din coordonatele lumii sunt convertite în coordonatele de vizualizare. Și numai în momentul în care imaginea este afișată direct pe ecranul de afișare, acestea se deplasează la coordonatele ecranului, care sunt numerele de pixeli ale ecranului.

    Primele două sisteme pot fi utilizate în sisteme de coordonate multidimensionale, dar ultimele doar în cele bidimensionale. Operațiile sunt ireversibile, adică este imposibil să restabiliți o imagine tridimensională dintr-o imagine de proiecție bidimensională.

    Matricea de transformare a perspectivei generale

    În această matrice elementele o, d, e sunt responsabili de scalare, m, n, L pentru deplasare, p, q, r pentru proiecție, s pentru scalare cuprinzătoare, X pentru rotatie.