Matrice de perspectivă în API-ul grafic sau diavolul este în detalii. Matrice de identitate Matricea de transformare a perspectivei generale

La un moment dat, orice dezvoltator din domeniu grafica pe computer apare întrebarea: cum funcționează aceste matrici de perspectivă? Uneori răspunsul este foarte greu de găsit și, așa cum este de obicei cazul, majoritatea dezvoltatorilor renunță la această activitate la jumătatea drumului.

Aceasta nu este o soluție! Să ne dăm seama împreună!

Să fim realiști cu o părtinire practică și să luăm ca subiect de testare versiuni OpenGL 3.3. Începând cu această versiune, fiecare dezvoltator trebuie să implementeze independent modulul de operații cu matrice. Grozav, de asta avem nevoie. Să descompunem sarcina noastră dificilă cu tine și să evidențiem punctele principale. Câteva fapte din specificația OpenGL:

  • Matricele sunt stocate pe coloane (coloană-major);
  • Coordonate omogene;
  • Volum de tăiere canonic (CVV) într-un sistem de coordonate pentru stânga.
Există două moduri de a stoca matrice: coloana-major și row-major. În cursurile de algebră liniară, schema de rând major este folosită. În general, reprezentarea matricelor în memorie nu contează, deoarece o matrice poate fi întotdeauna tradusă dintr-un tip de reprezentare la altul prin simplă transpunere. Și deoarece nu există nicio diferență, atunci pentru toate calculele ulterioare vom folosi matricele clasice de rânduri majore. Când programați OpenGL, există un mic truc care vă permite să abandonați transpunerea matricelor, menținând în același timp calculele clasice de rânduri majore. Matricea trebuie trecută în programul shader așa cum este, iar în shader este necesar să se înmulțească nu un vector cu o matrice, ci o matrice cu un vector.

Coordonatele omogene nu sunt un sistem foarte complicat cu o serie reguli simple asupra translaţiei coordonatelor carteziene obişnuite în coordonate omogene şi invers. O coordonată omogenă este o matrice-rând de dimensiune . Pentru a converti coordonata carteziană într-o coordonată omogenă este necesar X, yși zînmulțiți cu orice număr real w(cu excepția lui 0). Apoi, trebuie să scrieți rezultatul în primele trei componente, iar ultima componentă va fi egală cu multiplicatorul w. Cu alte cuvinte:
- coordonate carteziene
w este un număr real care nu este egal cu 0

- coordonate omogene

Micul truc: Dacă w este egal cu unu, atunci tot ceea ce este necesar pentru traducere este transferul componentelor X, yși zși atribuiți unul ultimei componente. Adică, pentru a obține un rând de matrice:

Câteva cuvinte despre zero ca w. Din punctul de vedere al coordonatelor omogene, acest lucru este destul de acceptabil. Coordonatele omogene fac posibilă distincția între puncte și vectori. În sistemul de coordonate carteziene, însă, o astfel de împărțire este imposibilă.

- punctul în care ( x, y, z) – Coordonate carteziene

- vector, unde ( x, y, z) este vectorul rază

Translația inversă a unui vârf din coordonatele omogene în coordonatele carteziene se realizează după cum urmează. Toate componentele rândului-matrice trebuie împărțite în ultima componentă. Cu alte cuvinte:

- coordonate omogene
- coordonate carteziene

Principalul lucru de știut este că toți algoritmii de tăiere și rasterizare OpenGL funcționează în coordonate carteziene, dar înainte de asta toate transformările se fac în coordonate omogene. Trecerea de la coordonatele omogene la coordonatele carteziene se realizează în hardware.

Volumul canonic de tăiere sau volumul de vizualizare canonic (CVV) este una dintre părțile puțin documentate ale OpenGL. După cum se poate observa din fig. 1 CVV este un cub aliniat pe axă centrat la origine și cu o lungime a muchiei de două. Tot ceea ce se încadrează în zona CVV este supus rasterizării, tot ceea ce este în afara CVV este ignorat. Orice lucru care depășește parțial limitele CVV este supus unor algoritmi de tăiere. Cel mai important lucru de știut este că sistemul de coordonate CVV este stângaci!


Orez. 1. Volum canonic de tăiere OpenGL (CVV)

Sistem de coordonate pentru stângaci? Cum este, pentru că specificația pentru OpenGL 1.0 afirmă clar că sistemul de coordonate folosit este dreptaci? Să ne dăm seama.


Orez. 2. Sisteme de coordonate

După cum se poate observa din fig. 2 sisteme de coordonate diferă doar în direcția axei Z. OpenGL 1.0 folosește într-adevăr un sistem de coordonate pentru utilizator dreptaci. Dar sistemul de coordonate CVV și sistemul de coordonate utilizator sunt două lucruri complet diferite. Mai mult decât atât, începând cu versiunea 3.3, nu mai există așa ceva ca sistem standard Coordonatele OpenGL. După cum am menționat mai devreme, programatorul însuși implementează modulul de operații cu matrice. Formarea matricelor de rotație, formarea matricelor de proiecție, căutarea matricei inverse, înmulțirea matricelor sunt set minim operatii incluse in modulul de operatii matriceale. Sunt două întrebări logice. Dacă volumul de vizibilitate este un cub cu o lungime a muchiei de doi, atunci de ce este vizibilă pe ecran o scenă de câteva mii de unități convenționale? În ce moment are loc conversia sistemului de coordonate utilizator în sistemul de coordonate CVV. Matricele de proiecție sunt exact entitatea care se ocupă de aceste probleme.

Ideea principală a celor de mai sus este că dezvoltatorul însuși este liber să aleagă tipul de sistem de coordonate al utilizatorului și trebuie să descrie corect matricele de proiecție. Asta e tot cu faptele despre OpenGL și este timpul să aducem totul împreună.

Una dintre cele mai comune și mai greu de înțeles matrice este matricea de transformare a perspectivei. Deci, cum se raportează la CVV și sistemul de coordonate al utilizatorului? De ce obiectele devin mai mici odată cu creșterea distanței față de observator? Pentru a înțelege de ce obiectele devin mai mici odată cu creșterea distanței, să ne uităm la transformările matriceale ale unui model 3D pas cu pas. Nu este un secret pentru nimeni că orice model 3D constă dintr-o listă finită de vârfuri care suferă transformări de matrice complet independent unele de altele. Pentru a determina coordonatele unui vârf tridimensional pe un ecran de monitor bidimensional, trebuie să:

  1. Convertiți coordonatele carteziene în coordonate omogene;
  2. Înmulțiți coordonatele omogene cu matricea modelului;
  3. Înmulțiți rezultatul cu matricea de vizualizare;
  4. Înmulțiți rezultatul cu matricea de proiecție;
  5. Rezultatul este convertit din coordonate omogene în coordonate carteziene.
Translația unei coordonate carteziene într-o coordonată omogenă a fost discutată mai devreme. Sensul geometric al matricei modelului este de a traduce modelul din sistemul de coordonate local în sistem global coordonatele. Sau, după cum se spune, mutați vârfurile din spațiul model în spațiul mondial. Să spunem simplu, un obiect tridimensional încărcat dintr-un fișier este situat în spațiul model, unde coordonatele sunt măsurate în raport cu obiectul însuși. În plus, folosind matricea modelului, se realizează poziționarea, scalarea și rotația modelului. Ca rezultat, toate vârfurile modelului 3D obțin coordonatele uniforme reale în scena 3D. Spațiul model este local în raport cu spațiul mondial. Din spațiul model, coordonatele sunt transferate în spațiul mondial (de la local la global). Pentru aceasta, se folosește o matrice model.

Acum să trecem la pasul trei. Aici intervine spațiul de vedere. În acest spațiu, coordonatele sunt măsurate în raport cu poziția și orientarea observatorului ca și cum el ar fi centrul lumii. Spațiul de vizualizare este local în raport cu spațiul mondial, deci coordonatele trebuie introduse în el (și nu scoase, ca în cazul precedent). Transformarea directă a matricei scoate coordonatele dintr-un anumit spațiu. Pentru a le aduce în ea, dimpotrivă, este necesară inversarea transformării matricei, deci transformarea vederii este descrisă de matricea inversă. Cum se obține această matrice inversă? Pentru început, obținem o matrice directă a observatorului. Ce caracterizează un observator? Observatorul este descris de coordonatele în care se află și de vectorii direcției de vizualizare. Observatorul privește întotdeauna în direcția axei sale locale Z. Observatorul se poate deplasa în jurul scenei și se poate întoarce. În multe privințe, aceasta seamănă cu sensul matricei modelului. În mare, așa este. Cu toate acestea, pentru observator, operația de scalare este lipsită de sens, prin urmare, un semn egal nu poate fi pus între matricea model a observatorului și matricea model a unui obiect tridimensional. Matricea model a observatorului este matricea directă dorită. Prin inversarea acestei matrice, obținem matricea de vedere. În practică, aceasta înseamnă că toate vârfurile din coordonatele omogene globale vor primi noi coordonate omogene în raport cu observatorul. În consecință, dacă observatorul a văzut un anumit vârf, atunci valoarea coordonatei omogene z vârful dat în spațiul de vizualizare va fi cu siguranță un număr pozitiv. Dacă vârful era în spatele observatorului, atunci valoarea coordonatei sale omogene zîn spațiu de vizualizare va fi cu siguranță un număr negativ.

Pasul patru este cel mai interesant pas. Pașii anteriori au fost considerați atât de detaliat în mod intenționat, astfel încât cititorul să aibă o imagine completă a tuturor operanzilor pasului al patrulea. La al patrulea pas, coordonatele omogene sunt mutate din spațiul de vizualizare în spațiul CVV. Încă o dată, se subliniază faptul că toate vârfurile potențial vizibile vor avea o valoare pozitivă a coordonatei omogene. z.

Luați în considerare o matrice de forma:

Și un punct din spațiul omogen al observatorului:

Să înmulțim coordonata omogenă cu matricea considerată:

Să traducem coordonatele omogene rezultate în coordonate carteziene:

Să presupunem că există două puncte în spațiul de vedere cu aceleași coordonate Xși y, dar coordonate diferite z. Cu alte cuvinte, unul dintre puncte este în spatele celuilalt. Din cauza distorsiunii perspectivei, observatorul trebuie să vadă ambele puncte. Într-adevăr, se poate observa din formula că, datorită împărțirii la coordonate z, există o compresie la punctul de origine. Cu cât valoarea este mai mare z(cu cât punctul este mai departe de observator), cu atât compresia este mai puternică. Iată explicația efectului de perspectivă.

Specificația OpenGL spune că operațiunile de tăiere și rasterizare sunt efectuate în coordonate carteziene, iar procesul de conversie a coordonatelor omogene în coordonate carteziene se face automat.

Matricea (1) este un șablon pentru o matrice de proiecție în perspectivă. După cum am menționat mai devreme, sarcina matricei de proiecție constă în două lucruri: setarea unui sistem de coordonate personalizat (mâna stângă sau dreapta), transferul volumului de vizibilitate al observatorului către CVV. Să derivăm o matrice de perspectivă pentru sistemul de coordonate al utilizatorului din stânga.

Matricea de proiecție poate fi descrisă cu patru parametri (Fig. 3):

  • Unghiul de vizualizare în radiani ( fovy);
  • Raport de aspect ( aspect);
  • Distanța până la planul de tăiere aproape ( n);
  • Distanța până la planul de tăiere îndepărtat ( f).


Orez. 3. Perspectivă volum de vizibilitate

Luați în considerare proiecția unui punct în spațiul observatorului pe marginea frontală a tăieturii volumului de vizibilitate în perspectivă. Pentru o mai mare claritate, în fig. 4 este o vedere laterală. De asemenea, trebuie remarcat faptul că sistemul de coordonate utilizator coincide cu sistemul de coordonate CVV, adică sistemul de coordonate din stânga este folosit peste tot.


Orez. 4. Proiecția unui punct arbitrar

Pe baza proprietăților triunghiurilor similare, următoarele egalități sunt adevărate:

Să exprimăm yꞌ și xꞌ:

În principiu, expresiile (2) sunt suficiente pentru a obține coordonatele punctelor de proiecție. Cu toate acestea, pentru a ecraniza corect obiectele 3D, trebuie să cunoașteți adâncimea fiecărui fragment. Cu alte cuvinte, trebuie să stocați valoarea componentei z. Aceasta este valoarea folosită în testele de adâncime OpenGL. Pe fig. 3 arată că valoarea zꞌ nu este potrivit ca adâncime a fragmentului, deoarece toate proiecțiile punctuale au aceeași valoare zꞌ. Calea de ieșire din această situație este folosirea așa-numitei pseudo-adâncimi.

Proprietăți pseudo-adâncime:

  1. Pseudo adâncimea este calculată pe baza valorii z;
  2. Cu cât punctul este mai aproape de observator, cu atât pseudo-adâncimea este mai puțin importantă;
  3. Toate punctele situate pe planul frontal al volumului de vizibilitate au o valoare pseudo-adâncime de -1;
  4. Toate punctele situate pe planul de tăiere îndepărtat al volumului de vizibilitate au o valoare pseudo-adâncime de 1;
  5. Toate fragmentele aflate în interiorul volumului de vizibilitate au o valoare pseudo-adâncime în intervalul [-1 1].
Să derivăm formula prin care se va calcula pseudo-adâncimea. Să luăm ca bază următoarea expresie:

Cote Ași b trebuie calculate. Pentru a face acest lucru, folosim proprietățile pseudo-adâncimii 3 și 4. Obținem un sistem de două ecuații cu două necunoscute:

Să adăugăm ambele părți ale sistemului și să înmulțim rezultatul cu produsul fn, în care fși n nu poate fi egal cu zero. Primim:

Deschidem parantezele și rearanjam termenii astfel încât doar partea cu A, iar în dreapta doar cu b:

Să substituim (6) în (5). Să convertim expresia într-o fracție simplă:

Înmulțiți ambele părți cu -2fn, în care fși n nu poate fi egal cu zero. Dăm altele asemănătoare, rearanjam termenii și exprimăm b:

Înlocuiți (7) în (6) și exprimați A:

În consecință, componentele Ași b sunt egale:

Acum să substituim coeficienții obținuți în matricea piesei de prelucrat (1) și să vedem ce se va întâmpla cu coordonatele z pentru un punct arbitrar din spațiul omogen al observatorului. Inlocuirea se face astfel:

Lăsați distanța până la planul de tăiere frontal n este 2 și distanța până la planul de tăiere îndepărtat f este egal cu 10. Luați în considerare cinci puncte din spațiul omogen al observatorului:

Poziția reciprocă a punctului și a volumului de vizibilitate
Punct Sens Descriere
1 1 Punctul se află în fața planului de tăiere frontal al volumului de vizualizare. Nu devine rasterizat.
2 2 Punctul se află pe marginea frontală a decupării volumului de vizibilitate. Este rasterizat.
3 5 Punctul se află între marginea frontală de tăiere și marginea îndepărtată a volumului de vizibilitate. Este rasterizat.
4 10 Punctul se află pe marginea îndepărtată a decupării volumului vizibilității. Este rasterizat.
5 20 Punctul se află dincolo de capătul îndepărtat al decupării volumului vizibilității. Nu devine rasterizat.

Înmulțim toate punctele cu matricea (8), apoi traducem coordonatele omogene obținute în coordonate carteziene . Pentru a face acest lucru, trebuie să calculăm valorile noilor componente omogene și .
Punctul 1:

Rețineți că coordonatele omogene este poziționat absolut corect în CVV și, cel mai important, testul de adâncime OpenGL este acum posibil, deoarece pseudo-adâncimea îndeplinește pe deplin cerințele testelor.

Cu coordonata z mi-am dat seama, să trecem la coordonate Xși y. După cum am menționat mai devreme, întregul volum de vizibilitate în perspectivă trebuie să se încadreze în CVV. Lungimea marginii CVV este de două. În consecință, înălțimea și lățimea volumului de vizibilitate în perspectivă trebuie reduse la două unități arbitrare.

Avem un colț fovyși magnitudinea aspect. Să exprimăm înălțimea și lățimea folosind aceste valori.


Orez. 5. Domeniul de vizibilitate

Din fig. 5 arată că:

Acum puteți obține vizualizarea finală a matricei de proiecție în perspectivă pentru sistemul de coordonate personalizat pentru stânga, lucrând cu CVV OpenGL:

Aceasta completează derivarea matricelor.

Câteva cuvinte despre DirectX - principalul concurent al OpenGL. DirectX diferă de OpenGL doar prin dimensiunile CVV-ului și poziționarea acestuia. În DirectX, CVV este un cuboid cu lungimi de axă Xși y egal cu doi și de-a lungul axei z lungimea este egală cu unu. Gamă Xși y este [-1 1] și intervalul z este egal cu . În ceea ce privește sistemul de coordonate CVV, DirectX, ca și OpenGL, utilizează un sistem de coordonate pentru stângaci.

Pentru a afișa matrice de perspectivă pentru un sistem de coordonate personalizat pentru dreapta, trebuie să redesenați fig. 2, fig.3 si fig.4, tinand cont de noua directie a axei Z. Calculele ulterioare sunt complet similare, până la semn. Pentru matricele DirectX, proprietățile de pseudo-adâncime 3 și 4 sunt modificate pentru a se potrivi cu intervalul.

Pe această temă, matricele de perspectivă pot fi considerate închise.

Pentru a roti obiecte (sau o cameră), este nevoie de o bază matematică serioasă, cu ajutorul căreia se vor calcula coordonatele tuturor obiectelor atunci când sunt afișate pe un ecran de computer „plat”. Vreau să spun imediat că nu trebuie să vă fie frică, toate bibliotecile de matematică au fost deja scrise pentru noi, doar le vom folosi. În orice caz, textul următor nu trebuie sărit peste, indiferent de nivelul de cunoștințe de matematică.

1. Matrici, concepte generale

Ce sunt matricele? Reamintim matematica superioară: o matrice este un set de numere cu o dimensiune predeterminată 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 matricele ca programatori, le completăm și spunem ce să facem cu ele, toate calculele vor fi făcute de biblioteca matematică Direct3D, așa că trebuie să includem modulul de 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ă matricea) și să ne înmulțim cu matricea de transformare, rezultatul acestei operații este un nou obiect dat ca matrice.

Trei matrice de bază sunt definite și utilizate în Direct3D: matricea mondială, matricea de vizualizare și matricea de proiecție. Să le luăm în considerare mai detaliat.

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 punctului 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 translație și rotație.
    D3DXMatrixLookAtLH() și D3DXMatrixLookAtRH() determină poziția camerei și unghiul de vizualizare pentru sistemele de coordonate din stânga și, respectiv, din dreapta.

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

    Prin completarea acestor matrici și făcând transformări, creați o scenă tridimensională în care obțineți capacitatea de a vă muta, roti, mări, elimina și efectua alte acțiuni asupra obiectelor, în funcție de nevoile dvs.

    2. Creați un 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ă lizibilitate a codului. Proiectul nostru este î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 (matrici, desene primitive, ...)
    Ca urmare, vom avea 3 fișiere - window.cpp, init3d.h, render.h cu următorul conținut: init3d.h- transfer de variabile și structuri globale, declarație de funcții, funcții InitDirectX(), InitBufferVertex(), Destroy3D() redă.h- mutați funcția RenderScene(), tot ce rămâne este fereastra principală, 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

    Vom avea nevoie și noi funcții standard lucrează 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 ( PLUTI x, y, z; DWORD culoare; );

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

    PDirectDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);

    Pe acest moment nu folosim iluminare, ci pictăm peste vârfuri într-o anumită culoare, așa că stingeți iluminarea:

    PDirectDevice->SetRenderState(D3DRS_LIGHTING, FALSE);

    Să ne simplificăm inima reprezentând-o sub forma a trei triunghiuri. Vom folosi sistemul 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 matricelor de transformare

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

    Să creăm matrice:

  • D3DXMATRIX MatrixWorld; - matricea lumii
  • D3DXMATRIX MatrixView; - matrice de vizualizare
  • D3DXMATRIX MatrixProjection; - matricea de proiectie
    Instalarea matricei mondiale

    Pentru ca obiectul să se rotească, este necesar să obțineți ora sistemului și în fiecare „instant” să schimbați unghiul dintre sistemul de coordonate local și sistemul de coordonate mondial. Ne vom roti în jurul axei 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); Setarea matricei de vizualizare

    Instalați camera în locul potrivit și îndreptați-o către obiect

  • D3DXMatrixLookAtLH(&MatrixView, - rezultatul executării funcției
  • &D3DXVECTOR3(0.0f, 0.0f, -8.0f), - punctul în care se află camera
  • &D3DXVECTOR3(0.0f, 0.0f, 0.0f), - punctul la 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.

  • Ieșirea grafică este de obicei realizată într-o zonă dreptunghiulară a ecranului sau a ferestrei. În redarea OpenGL, această zonă se numește portul de ieșire. În această zonă dreptunghiulară va fi plasată imaginea generată de bibliotecă. Dimensiunile sale sunt relativ la colțul din stânga sus al ferestrei și sunt 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 specifică dimensiunile acestuia. În mod implicit, biblioteca extinde portul de ieșire la întreaga fereastră OpenGL.

    Sistem de coordonate

    Înainte de a fi afișat pe ecran, un vârf specificat în sistemul de coordonate al scenei trebuie să treacă printr-un proces de proiecție. Pentru a descrie și a efectua transformări ale sistemelor de coordonate din biblioteca OpenGL, se folosește un aparat matrice. Sistemul de coordonate însuși și transformările sale sunt descrise prin matrice în așa-numitele coordonate omogene.

    În primul rând, vârful este convertit într-o matrice 1X4 în care primele trei elemente sunt coordonate 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 transformările sistemului de coordonate a vederii. Obțineți vârful în coordonatele vizualizării. Acesta, la rândul său, este înmulțit cu matricea de proiecție și obținem vârful în coordonatele de proiecție. În această etapă, unele vârfuri sunt eliminate (din cauza lipsei volumului de randare). Vârfurile sunt apoi normalizate pentru a transmite perspectiva (cu excepția cazului în care coordonata w este 1,0). Proiectia finală a vârfului pe suprafața ecranului 2D este gestionată chiar de biblioteca OpenGL și nu poate fi interferată.

    Matricea de proiecție

    Matricea de proiecție este responsabilă de cât spațiu va fi redat, de modul în care vârfurile primitivelor grafice vor fi proiectate pe suprafața bidimensională a ecranului monitorului. Transformările matricei de proiecție duc la faptul că întreaga imagine se va schimba (scalată, mutată sau rotită). În OpenGL este posibil să utilizați două moduri de matrice de proiecție: perspectivă și ortografic.

    În proiecția în perspectivă se folosește faptul că pentru ochiul uman se 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 determinată 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 casetei de tăiere din apropiere; aproape și departe sunt întotdeauna valori pozitive și definesc distanța din punct de vedere până la casetele de tăiere aproape și departe.

    De asemenea, puteți utiliza funcția gluPerspective() pentru a seta matricea de proiecție a perspectivei, care are alte argumente

    void gluPerspective(GLdouble fovy, GLdouble aspect, GLdouble near, GLdouble far);

    Argumentul fovy (câmpul vizual) definește câmpul vizual, iar aspectul este raportul dintre lățimea și înălțimea casetei de tăiere. aproape și departe sunt întotdeauna valori pozitive și definesc distanța din punct de vedere până la casetele de tăiere aproape și departe.

    Proiecția în perspectivă este folosită în mod obișnuit în jocuri și aplicații care necesită ca obiectele să fie extrem de realiste, spre deosebire de a fi redate de ochi. Proiecția ortografică este utilizată în mod obișnuit pentru vizualizarea 2D și 3D a datelor științifice și tehnice. Luați în considerare configurarea unei proiecții ortografice mai întâi pentru randarea 2D. Cu o proiecție ortografică, volumul spațiului redat este un paralelipiped:

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

    Pentru a seta și apoi a 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 identitatea matricei de proiecție 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 fund, GLdouble top, GLdouble near, GLdouble departe);

    (stânga, jos, -aproape) și (dreapta, sus, -aproape) sunt puncte care definesc caseta de tăiere din apropiere. (stânga, jos, -departe) și (dreapta, sus, -departe) sunt puncte care definesc caseta 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)
    {
    //Setarea portului de ieșire
    glViewport(0, 0, lățime, înălțime);

    //Modul matricei de proiecție
    glMatrixMode(GL_PROJECTION);
    // Matrice de identitate
    glLoadIdentity();

    //Configurarea unui sistem de coordonate ortografic 2D
    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() în care argumentul este aproape=-1,0 și departe=1,0. În timpul redării 2D, coordonata z a vârfurilor are valoarea 0, adică obiectele sunt în planul mijlociu.

    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 vizualizare este responsabilă pentru sistemul de coordonate al modelului 3D creat. În procesul 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 seta și apoi a modifica matricea de vizualizare, executați funcția glMatrixMode(GL_MODELVIEW). Pentru început, ar trebui să anulați și toate setările și transformările anterioare, făcând identitatea matricei de proiecție folosind funcția glLoadIdentity (). Dacă coordonatele vârfurilor obiectului sunt specificate în timpul creării sale, 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 transformarea sistemului de coordonate: glTranslated(), glRotated() și glScaled(). Aceste comenzi generează matrice de translație, rotație și scalare care sunt multiplicate cu matricea de vizualizare folosind funcția glMultMatrix(). După cum puteți vedea, OpenGL preia operațiunile cu matrice și le efectuează conform unor algoritmi speciali, rapidi, cu eficiență maximă. De exemplu:

    Transfer

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

    Zoom

    Este implementat 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 a argumentului nulă, dar va avea ca rezultat dimensiunile obiectului zero.

    Întoarce-te

    Este implementat folosind o funcție care are următorul prototip:

    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);
    // Setează vârfuri
    glVertex2d(-2., 2.);
    glVertex2d(2., 2.);
    glVertex2d(2., -2.);
    glVertex2d(-2., -2.);
    gland();

    Primul argument definește unghiul de rotație, iar restul de trei - coordonatele vectorului în jurul căruia se efectuează rotația.

    Stiva de matrice

    Un mecanism util pentru construirea de imagini complexe este stiva de matrice. Folosind funcțiile glPushMatrix() și glPopMatrix(), puteți salva matricea curentă pe stivă și o puteți restaura după orice modificare în sistemul de coordonate.

    Afișează liste

    Listele sunt un mecanism interesant și foarte eficient pentru crearea unei scene. 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 considerabil performanța imaginii. un numar mare obiecte identice.

    Fiecare listă de afișare trebuie să aibă un ID. Acesta poate fi un număr întreg arbitrar pe care îl puteți atribui singur. Pentru a evita conflictele de identificare a listei, 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 să se obțină identificatori. Dacă nu au mai rămas identificatori liberi, atunci funcția returnează zero.

    Pentru a începe să formați o listă, trebuie să apelați funcția

    void glNewList(lista GLuint, modul GLenum);

    Primul argument specifică identificatorul listei generate, iar al doilea specifică dacă lista va fi doar formată (GL_COMPILE) sau imediat și afișată (GL_COMPILE_AND_EXECUTE). În continuare pot fi comenzile OpenGL care trebuie stocate în listă. Nu toate comenzile pot fi incluse în el.

    Formarea listei se încheie cu funcția:

    void glEndList(void);

    Odată generate, listele de afișare sunt stocate în structura internă de date a unei ferestre 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 un identificator de listă.

    Funcția glCallList() poate fi apelată în orice memorie de program atunci când este necesară executarea comenzilor stocate în listă.

    Luați în considerare un exemplu:

    void Remiză (void)
    {
    //Ștergerea tamponului de culoare

    glColor3d(1.0, 1.0, 0.0);

    glBegin(GL_LINES);
    glVertex2d(-50., .0);
    glVertex2d(50., .0);

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

    glBegin(GL_LINES);
    glVertex2d(.0, -50.);
    glVertex2d(.0, 50.);
    pentru(int j=-50; j<50; j++)
    {
    glVertex2d(.0, j);
    dacă (j % 5)
    {
    glVertex2d(-1., j);
    }
    altfel dacă (j % ​​10)
    {
    glVertex2d(-2., j);
    }
    altfel
    {
    glVertex2d(-3., j);
    }
    }
    gland();
    //Executarea completă a comenzilor
    glFlush();
    }

    void Remiză (void)
    {
    //Ștergerea tamponului de culoare
    glClear(GL_COLOR_BUFFER_BIT);
    //Setați culoarea afișajului
    glColor3d(1.0, 1.0, 0.0);

    //Formarea axei
    int axis = glGenLists(1);
    dacă (axa != 0)
    {
    glNewList(axa, GL_COMPILE);
    glBegin(GL_LINES);
    glVertex2d(0., .0);
    glVertex2d(100., .0);

    Pentru(int i=0.; i<97; i++)
    {
    glVertex2d(i, .0);
    dacă (i % 5)
    {
    glVertex2d(i, 1.);
    }
    altfel dacă (i % 10)
    {
    glVertex2d(i, 2.);
    }
    altfel
    {
    glVertex2d(i, 3.);
    }
    }
    gland();
    // Forma săgeții poate fi adăugată mai târziu
    glBegin(GL_LINE_STRIP);
    glVertex2d(97., 1.);
    glVertex2d(100.,.0);
    glVertex2d(97., -1.);
    gland();
    glEndList();
    }
    //Desenați axa orizontală
    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();

    //Executarea completă a comenzilor
    glFlush();
    }

    La un moment dat, orice dezvoltator din domeniul graficii pe computer are o întrebare: cum funcționează aceste matrici de perspectivă? Uneori răspunsul este foarte greu de găsit și, așa cum este de obicei cazul, majoritatea dezvoltatorilor renunță la această activitate la jumătatea drumului.

    Aceasta nu este o soluție! Să ne dăm seama împreună!

    Să fim realiști cu o părtinire practică și să luăm OpenGL versiunea 3.3 ca una experimentală. Începând cu această versiune, fiecare dezvoltator trebuie să implementeze independent modulul de operații cu matrice. Grozav, de asta avem nevoie. Să descompunem sarcina noastră dificilă cu tine și să evidențiem punctele principale. Câteva fapte din specificația OpenGL:

    • Matricele sunt stocate pe coloane (coloană-major);
    • Coordonate omogene;
    • Volum de tăiere canonic (CVV) într-un sistem de coordonate pentru stânga.
    Există două moduri de a stoca matrice: coloana-major și row-major. În cursurile de algebră liniară, schema de rând major este folosită. În general, reprezentarea matricelor în memorie nu contează, deoarece o matrice poate fi întotdeauna tradusă dintr-un tip de reprezentare la altul prin simplă transpunere. Și deoarece nu există nicio diferență, atunci pentru toate calculele ulterioare vom folosi matricele clasice de rânduri majore. Când programați OpenGL, există un mic truc care vă permite să abandonați transpunerea matricelor, menținând în același timp calculele clasice de rânduri majore. Matricea trebuie trecută în programul shader așa cum este, iar în shader este necesar să se înmulțească nu un vector cu o matrice, ci o matrice cu un vector.

    Coordonatele omogene nu sunt un sistem foarte complicat, cu o serie de reguli simple pentru transformarea coordonatelor carteziene familiare în coordonate omogene și invers. O coordonată omogenă este o matrice-rând de dimensiune . Pentru a converti coordonata carteziană într-o coordonată omogenă este necesar X, yși zînmulțiți cu orice număr real w(cu excepția lui 0). Apoi, trebuie să scrieți rezultatul în primele trei componente, iar ultima componentă va fi egală cu multiplicatorul w. Cu alte cuvinte:
    - coordonate carteziene
    w este un număr real care nu este egal cu 0

    - coordonate omogene

    Micul truc: Dacă w este egal cu unu, atunci tot ceea ce este necesar pentru traducere este transferul componentelor X, yși zși atribuiți unul ultimei componente. Adică, pentru a obține un rând de matrice:

    Câteva cuvinte despre zero ca w. Din punctul de vedere al coordonatelor omogene, acest lucru este destul de acceptabil. Coordonatele omogene fac posibilă distincția între puncte și vectori. În sistemul de coordonate carteziene, însă, o astfel de împărțire este imposibilă.

    - punctul în care ( x, y, z) – Coordonate carteziene

    - vector, unde ( x, y, z) este vectorul rază

    Translația inversă a unui vârf din coordonatele omogene în coordonatele carteziene se realizează după cum urmează. Toate componentele rândului-matrice trebuie împărțite în ultima componentă. Cu alte cuvinte:

    - coordonate omogene
    - coordonate carteziene

    Principalul lucru de știut este că toți algoritmii de tăiere și rasterizare OpenGL funcționează în coordonate carteziene, dar înainte de asta toate transformările se fac în coordonate omogene. Trecerea de la coordonatele omogene la coordonatele carteziene se realizează în hardware.

    Volumul canonic de tăiere sau volumul de vizualizare canonic (CVV) este una dintre părțile puțin documentate ale OpenGL. După cum se poate observa din fig. 1 CVV este un cub aliniat pe axă centrat la origine și cu o lungime a muchiei de două. Tot ceea ce se încadrează în zona CVV este supus rasterizării, tot ceea ce este în afara CVV este ignorat. Orice lucru care depășește parțial limitele CVV este supus unor algoritmi de tăiere. Cel mai important lucru de știut este că sistemul de coordonate CVV este stângaci!


    Orez. 1. Volum canonic de tăiere OpenGL (CVV)

    Sistem de coordonate pentru stângaci? Cum este, pentru că specificația pentru OpenGL 1.0 afirmă clar că sistemul de coordonate folosit este dreptaci? Să ne dăm seama.


    Orez. 2. Sisteme de coordonate

    După cum se poate observa din fig. 2 sisteme de coordonate diferă doar în direcția axei Z. OpenGL 1.0 folosește într-adevăr un sistem de coordonate pentru utilizator dreptaci. Dar sistemul de coordonate CVV și sistemul de coordonate utilizator sunt două lucruri complet diferite. În plus, începând cu versiunea 3.3, nu mai există un sistem de coordonate OpenGL standard. După cum am menționat mai devreme, programatorul însuși implementează modulul de operații cu matrice. Formarea matricelor de rotație, formarea matricelor de proiecție, căutarea unei matrici inverse și înmulțirea matricelor sunt setul minim de operații incluse în modulul de operații cu matrice. Sunt două întrebări logice. Dacă volumul de vizibilitate este un cub cu o lungime a muchiei de doi, atunci de ce este vizibilă pe ecran o scenă de câteva mii de unități convenționale? În ce moment are loc conversia sistemului de coordonate utilizator în sistemul de coordonate CVV. Matricele de proiecție sunt exact entitatea care se ocupă de aceste probleme.

    Ideea principală a celor de mai sus este că dezvoltatorul însuși este liber să aleagă tipul de sistem de coordonate al utilizatorului și trebuie să descrie corect matricele de proiecție. Asta e tot cu faptele despre OpenGL și este timpul să aducem totul împreună.

    Una dintre cele mai comune și mai greu de înțeles matrice este matricea de transformare a perspectivei. Deci, cum se raportează la CVV și sistemul de coordonate al utilizatorului? De ce obiectele devin mai mici odată cu creșterea distanței față de observator? Pentru a înțelege de ce obiectele devin mai mici odată cu creșterea distanței, să ne uităm la transformările matriceale ale unui model 3D pas cu pas. Nu este un secret pentru nimeni că orice model 3D constă dintr-o listă finită de vârfuri care suferă transformări de matrice complet independent unele de altele. Pentru a determina coordonatele unui vârf tridimensional pe un ecran de monitor bidimensional, trebuie să:

    1. Convertiți coordonatele carteziene în coordonate omogene;
    2. Înmulțiți coordonatele omogene cu matricea modelului;
    3. Înmulțiți rezultatul cu matricea de vizualizare;
    4. Înmulțiți rezultatul cu matricea de proiecție;
    5. Rezultatul este convertit din coordonate omogene în coordonate carteziene.
    Translația unei coordonate carteziene într-o coordonată omogenă a fost discutată mai devreme. Sensul geometric al matricei modelului este de a traduce modelul din sistemul de coordonate local în sistemul de coordonate global. Sau, după cum se spune, mutați vârfurile din spațiul model în spațiul mondial. Să spunem simplu, un obiect tridimensional încărcat dintr-un fișier este situat în spațiul model, unde coordonatele sunt măsurate în raport cu obiectul însuși. În plus, folosind matricea modelului, se realizează poziționarea, scalarea și rotația modelului. Ca rezultat, toate vârfurile modelului 3D obțin coordonatele uniforme reale în scena 3D. Spațiul model este local în raport cu spațiul mondial. Din spațiul model, coordonatele sunt transferate în spațiul mondial (de la local la global). Pentru aceasta, se folosește o matrice model.

    Acum să trecem la pasul trei. Aici intervine spațiul de vedere. În acest spațiu, coordonatele sunt măsurate în raport cu poziția și orientarea observatorului ca și cum el ar fi centrul lumii. Spațiul de vizualizare este local în raport cu spațiul mondial, deci coordonatele trebuie introduse în el (și nu scoase, ca în cazul precedent). Transformarea directă a matricei scoate coordonatele dintr-un anumit spațiu. Pentru a le aduce în ea, dimpotrivă, este necesară inversarea transformării matricei, deci transformarea vederii este descrisă de matricea inversă. Cum se obține această matrice inversă? Pentru început, obținem o matrice directă a observatorului. Ce caracterizează un observator? Observatorul este descris de coordonatele în care se află și de vectorii direcției de vizualizare. Observatorul privește întotdeauna în direcția axei sale locale Z. Observatorul se poate deplasa în jurul scenei și se poate întoarce. În multe privințe, aceasta seamănă cu sensul matricei modelului. În mare, așa este. Cu toate acestea, pentru observator, operația de scalare este lipsită de sens, prin urmare, un semn egal nu poate fi pus între matricea model a observatorului și matricea model a unui obiect tridimensional. Matricea model a observatorului este matricea directă dorită. Prin inversarea acestei matrice, obținem matricea de vedere. În practică, aceasta înseamnă că toate vârfurile din coordonatele omogene globale vor primi noi coordonate omogene în raport cu observatorul. În consecință, dacă observatorul a văzut un anumit vârf, atunci valoarea coordonatei omogene z vârful dat în spațiul de vizualizare va fi cu siguranță un număr pozitiv. Dacă vârful era în spatele observatorului, atunci valoarea coordonatei sale omogene zîn spațiu de vizualizare va fi cu siguranță un număr negativ.

    Pasul patru este cel mai interesant pas. Pașii anteriori au fost considerați atât de detaliat în mod intenționat, astfel încât cititorul să aibă o imagine completă a tuturor operanzilor pasului al patrulea. La al patrulea pas, coordonatele omogene sunt mutate din spațiul de vizualizare în spațiul CVV. Încă o dată, se subliniază faptul că toate vârfurile potențial vizibile vor avea o valoare pozitivă a coordonatei omogene. z.

    Luați în considerare o matrice de forma:

    Și un punct din spațiul omogen al observatorului:

    Să înmulțim coordonata omogenă cu matricea considerată:

    Să traducem coordonatele omogene rezultate în coordonate carteziene:

    Să presupunem că există două puncte în spațiul de vedere cu aceleași coordonate Xși y, dar coordonate diferite z. Cu alte cuvinte, unul dintre puncte este în spatele celuilalt. Din cauza distorsiunii perspectivei, observatorul trebuie să vadă ambele puncte. Într-adevăr, se poate observa din formula că, datorită împărțirii la coordonate z, există o compresie la punctul de origine. Cu cât valoarea este mai mare z(cu cât punctul este mai departe de observator), cu atât compresia este mai puternică. Iată explicația efectului de perspectivă.

    Specificația OpenGL spune că operațiunile de tăiere și rasterizare sunt efectuate în coordonate carteziene, iar procesul de conversie a coordonatelor omogene în coordonate carteziene se face automat.

    Matricea (1) este un șablon pentru o matrice de proiecție în perspectivă. După cum am menționat mai devreme, sarcina matricei de proiecție constă în două lucruri: setarea unui sistem de coordonate personalizat (mâna stângă sau dreapta), transferul volumului de vizibilitate al observatorului către CVV. Să derivăm o matrice de perspectivă pentru sistemul de coordonate al utilizatorului din stânga.

    Matricea de proiecție poate fi descrisă folosind patru parametri (Fig. 3):

    • Unghiul de vizualizare în radiani ( fovy);
    • Raport de aspect ( aspect);
    • Distanța până la planul de tăiere aproape ( n);
    • Distanța până la planul de tăiere îndepărtat ( f).


    Orez. 3. Perspectivă volum de vizibilitate

    Luați în considerare proiecția unui punct în spațiul observatorului pe marginea frontală a tăieturii volumului de vizibilitate în perspectivă. Pentru o mai mare claritate, în fig. 4 este o vedere laterală. De asemenea, trebuie remarcat faptul că sistemul de coordonate utilizator coincide cu sistemul de coordonate CVV, adică sistemul de coordonate din stânga este folosit peste tot.


    Orez. 4. Proiecția unui punct arbitrar

    Pe baza proprietăților triunghiurilor similare, următoarele egalități sunt adevărate:

    Să exprimăm yꞌ și xꞌ:

    În principiu, expresiile (2) sunt suficiente pentru a obține coordonatele punctelor de proiecție. Cu toate acestea, pentru a ecraniza corect obiectele 3D, trebuie să cunoașteți adâncimea fiecărui fragment. Cu alte cuvinte, trebuie să stocați valoarea componentei z. Aceasta este valoarea folosită în testele de adâncime OpenGL. Pe fig. 3 arată că valoarea zꞌ nu este potrivit ca adâncime a fragmentului, deoarece toate proiecțiile punctuale au aceeași valoare zꞌ. Calea de ieșire din această situație este folosirea așa-numitei pseudo-adâncimi.

    Proprietăți pseudo-adâncime:

    1. Pseudo adâncimea este calculată pe baza valorii z;
    2. Cu cât punctul este mai aproape de observator, cu atât pseudo-adâncimea este mai puțin importantă;
    3. Toate punctele situate pe planul frontal al volumului de vizibilitate au o valoare pseudo-adâncime de -1;
    4. Toate punctele situate pe planul de tăiere îndepărtat al volumului de vizibilitate au o valoare pseudo-adâncime de 1;
    5. Toate fragmentele aflate în interiorul volumului de vizibilitate au o valoare pseudo-adâncime în intervalul [-1 1].
    Să derivăm formula prin care se va calcula pseudo-adâncimea. Să luăm ca bază următoarea expresie:

    Cote Ași b trebuie calculate. Pentru a face acest lucru, folosim proprietățile pseudo-adâncimii 3 și 4. Obținem un sistem de două ecuații cu două necunoscute:

    Să adăugăm ambele părți ale sistemului și să înmulțim rezultatul cu produsul fn, în care fși n nu poate fi egal cu zero. Primim:

    Deschidem parantezele și rearanjam termenii astfel încât doar partea cu A, iar în dreapta doar cu b:

    Să substituim (6) în (5). Să convertim expresia într-o fracție simplă:

    Înmulțiți ambele părți cu -2fn, în care fși n nu poate fi egal cu zero. Dăm altele asemănătoare, rearanjam termenii și exprimăm b:

    Înlocuiți (7) în (6) și exprimați A:

    În consecință, componentele Ași b sunt egale:

    Acum să substituim coeficienții obținuți în matricea piesei de prelucrat (1) și să vedem ce se va întâmpla cu coordonatele z pentru un punct arbitrar din spațiul omogen al observatorului. Inlocuirea se face astfel:

    Lăsați distanța până la planul de tăiere frontal n este 2 și distanța până la planul de tăiere îndepărtat f este egal cu 10. Luați în considerare cinci puncte din spațiul omogen al observatorului:

    Poziția reciprocă a punctului și a volumului de vizibilitate
    Punct Sens Descriere
    1 1 Punctul se află în fața planului de tăiere frontal al volumului de vizualizare. Nu devine rasterizat.
    2 2 Punctul se află pe marginea frontală a decupării volumului de vizibilitate. Este rasterizat.
    3 5 Punctul se află între marginea frontală de tăiere și marginea îndepărtată a volumului de vizibilitate. Este rasterizat.
    4 10 Punctul se află pe marginea îndepărtată a decupării volumului vizibilității. Este rasterizat.
    5 20 Punctul se află dincolo de capătul îndepărtat al decupării volumului vizibilității. Nu devine rasterizat.

    Înmulțim toate punctele cu matricea (8), apoi traducem coordonatele omogene obținute în coordonate carteziene . Pentru a face acest lucru, trebuie să calculăm valorile noilor componente omogene și .
    Punctul 1:

    Rețineți că coordonatele omogene este poziționat absolut corect în CVV și, cel mai important, testul de adâncime OpenGL este acum posibil, deoarece pseudo-adâncimea îndeplinește pe deplin cerințele testelor.

    Cu coordonata z mi-am dat seama, să trecem la coordonate Xși y. După cum am menționat mai devreme, întregul volum de vizibilitate în perspectivă trebuie să se încadreze în CVV. Lungimea marginii CVV este de două. În consecință, înălțimea și lățimea volumului de vizibilitate în perspectivă trebuie reduse la două unități arbitrare.

    Avem un colț fovyși magnitudinea aspect. Să exprimăm înălțimea și lățimea folosind aceste valori.


    Orez. 5. Domeniul de vizibilitate

    Din fig. 5 arată că:

    Acum puteți obține vizualizarea finală a matricei de proiecție în perspectivă pentru sistemul de coordonate personalizat pentru stânga, lucrând cu CVV OpenGL:

    Aceasta completează derivarea matricelor.

    Câteva cuvinte despre DirectX - principalul concurent al OpenGL. DirectX diferă de OpenGL doar prin dimensiunile CVV-ului și poziționarea acestuia. În DirectX, CVV este un cuboid cu lungimi de axă Xși y egal cu doi și de-a lungul axei z lungimea este egală cu unu. Gamă Xși y este [-1 1] și intervalul z este egal cu . În ceea ce privește sistemul de coordonate CVV, DirectX, ca și OpenGL, utilizează un sistem de coordonate pentru stângaci.

    Pentru a afișa matrice de perspectivă pentru un sistem de coordonate personalizat pentru dreapta, trebuie să redesenați fig. 2, fig.3 si fig.4, tinand cont de noua directie a axei Z. Calculele ulterioare sunt complet similare, până la semn. Pentru matricele DirectX, proprietățile de pseudo-adâncime 3 și 4 sunt modificate pentru a se potrivi cu intervalul.

    Pe această temă, matricele de perspectivă pot fi considerate închise.

    În grafica computerizată, sunt definite conceptele diferitelor matrici. Acestea sunt World Matrix, View Matrix și Projection Matrix. Cu ajutorul acestor matrici din codul sursă al programului se realizează transformări matrice pe modele. Transformările matricelor implică înmulțirea fiecărui vârf al obiectului cu una dintre matrice, sau mai degrabă, înmulțirea secvențială a tuturor vârfurilor obiectului 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 de coordonate mondial este propriul său sistem de coordonate local al unui obiect dat, care este dotat cu fiecare obiect, să spunem, 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ă-i mutați punctul de referință local, sistemul de coordonate, la o nouă locație. Dacă nu ar exista o matrice mondială, atunci acest obiect ar trebui să fie mutat de-a lungul unui vârf. Prin urmare, orice obiect, sau mai degrabă toate vârfurile acestui obiect, trec prin matricea de transformare a lumii.

    După cum sa menționat deja, 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 vârfului de-a lungul axei X este următoarea:


    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 coordonate x, y, z într-un nou punct cu noi coordonate x1, y1, z1. În notație matematică, arată astfel:

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

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


    Traducerea vârfurilor în notație matriceală

    unde Tx, Ty și Tz sunt valorile de decalaj X, Y și Z.

    Puteți scala un vârf în spațiu (ștergeț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 este exprimată după cum urmează:


    Scala Vertex

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

    Toate operațiunile enumerate pot fi efectuate manual în codul sursă al programului, adică intrările date pot fi calculate așa cum tocmai le-am descris. Dar, desigur, nimeni nu face acest lucru (aproape nimeni), deoarece DirectX are un număr mare de metode care vor face toate operațiunile de mai sus pentru tine.

    Vizualizare Matrice

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

    De fapt, această matrice vă permite să determinați genul jocului. De exemplu, un joc DOOM la persoana întâi este ca rândurile din față ale unui portar într-un teatru, în timp ce un joc Warcraft este ca o galerie pe un 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, dreapta, sus, jos, îndepărtați-o, 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. Cu ajutorul acestei matrice, se determină regiunile 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 proiecției unui obiect într-un plan și tăierea spațiului.


    Matricea de proiecție