Cameră virtuală. Proiecția în perspectivă. Calibrare internă a camerei. Cel mai simplu model de proiecție în perspectivă

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 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ă matricea) și să-l înmulțim cu matricea de transformare, rezultatul acestei operații este 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 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.

    Vizualizați Matricea- 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

    Noi creăm proiect nou, similar 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ăuga fișier antetși o bibliotecă 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 caracteristici standard funcționează în timp, 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);

    Pe în acest moment nu folosim iluminare, ci pictăm vârfurile înăuntru culoare specifică, deci stinge lumina:

    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ă, trebuie să obții ora sistemuluiși fiecare „instant” modifică 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.

  • La un moment dat, orice dezvoltator din domeniu grafica pe computer Apare întrebarea: cum funcționează aceste matrici promițătoare? Uneori, răspunsul este foarte greu de găsit și, așa cum se întâmplă de obicei, majoritatea dezvoltatorilor renunță la jumătatea sarcinii.

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

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

    • Matricele sunt stocate în 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ă, se utilizează schema de rânduri majore. De în general Reprezentarea matricelor în memorie nu contează, deoarece o matrice poate fi întotdeauna convertită dintr-o reprezentare în alta prin simplă transpunere. Și, deoarece nu există nicio diferență, atunci pentru toate calculele ulterioare vom folosi matrice clasice de rânduri majore. La programarea OpenGL există mic truc, care vă permite să refuzați transpunerea matricelor menținând în același timp calculele clasice de rânduri majore. Matricea trebuie transferată în programul shader așa cum este, iar în shader multiplicarea trebuie efectuată nu între un vector și o matrice, ci între o matrice și un vector.

    Coordonatele omogene nu sunt foarte bune sistem viclean chiar lângă reguli simple la conversia coordonatelor carteziene convenţionale în coordonate omogene şi invers. O coordonată omogenă este o matrice de rând de dimensiune. Pentru a converti o coordonată carteziană într-o coordonată omogenă, este necesar x, yŞi z multiplica cu oricare 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– număr real nu este egal cu 0

    - coordonate omogene

    Un mic 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ă, obțineți o matrice de rând:

    Câteva cuvinte despre calitate zero w. Din punctul de vedere al coordonatelor omogene, acest lucru este destul de acceptabil. Coordonatele omogene vă permit să faceți distincția între puncte și vectori. Într-un sistem de coordonate carteziene, o astfel de împărțire este imposibilă.

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

    - vector, unde ( x, y, z) – vector rază

    Translația inversă a unui vârf de la coordonate omogene în coordonate carteziene se realizează după cum urmează. Toate componentele unei matrice de rânduri trebuie împărțite la ultima componentă. Cu alte cuvinte:

    - coordonate omogene
    - coordonate carteziene

    Principalul lucru pe care trebuie să-l știți este că toți algoritmii de tăiere și rasterizare OpenGL funcționează în coordonate carteziene, dar înainte de asta toate transformările sunt efectuate în coordonate omogene. Trecerea de la coordonatele omogene la coordonatele carteziene se realizează în hardware.

    Volumul canonic de tăiere (CVV) este una dintre părțile cel mai puțin documentate ale OpenGL. După cum se poate observa din fig. 1 CVV este un cub aliniat pe axă cu un centru la origine și o lungime a muchiei egală cu 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 intră parțial în afara CVV este supus algoritmilor de tăiere. Cel mai important lucru pe care trebuie să-l știți 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 poate fi acest lucru, deoarece 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. Cele 2 sisteme de coordonate diferă doar în direcția axei Z. OpenGL 1.0 folosește de fapt dreptaci sistem utilizator coordonate Dar sistemul de coordonate CVV și sistemul de coordonate utilizator sunt două lucruri complet diferite. Mai mult, î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 unei matrici inverse, înmulțirea matricelor sunt set minim operațiuni incluse în modulul operațiuni matriceale. Apar două întrebări logice. Dacă volumul de vizibilitate este un cub cu o lungime a muchiei egală cu două, atunci de ce scena are o dimensiune de câteva mii? unități convenționale vizibil pe ecran? În ce moment se transformă sistemul de coordonate utilizator în sistemul de coordonate CVV? Matricele de proiecție sunt tocmai 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. Acest lucru completează faptele despre OpenGL și este timpul să punem 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 pe măsură ce distanța lor față de observator crește? Pentru a înțelege de ce obiectele se micșorează pe măsură ce distanța crește, să ne uităm la transformările matriceale ale unui model 3D pas cu pas. Nu este un secret pentru nimeni că orice model tridimensional constă dintr-o listă finită de vârfuri care suferă transformări de matrice complet independent unul de celălalt. 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. Rezultatul este înmulțit cu matricea de vizualizare;
    4. Înmulțiți rezultatul cu matricea de proiecție;
    5. Convertiți rezultatul din coordonate omogene în coordonate carteziene.
    Conversia coordonatelor carteziene în coordonate omogene a fost discutată mai devreme. Sensul geometric matricea modelului este de a traduce modelul din sistem local coordonate în sistem global coordonate Sau, după cum se spune, mutați vârfurile din spațiul model în spațiul lumii. 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. Apoi, folosind matricea modelului, modelul este poziționat, scalat și rotit. Ca rezultat, toate nodurile modelului 3D primesc coordonate omogene reale în scena 3D. Spațiul model în raport cu spațiul mondial este local. Din spațiul model, coordonatele sunt transferate în spațiul mondial (de la local la global). În acest scop, se utilizează 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 elimină coordonatele dintr-un anumit spațiu. Pentru a le introduce, dimpotrivă, în ea, este necesară inversarea transformării matriceale, prin urmare transformarea de tip este descrisă de matricea inversă. Cum să obții asta matrice inversă? Mai întâi, să obținem matricea observatorului direct. 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 stau lucrurile. Cu toate acestea, pentru un 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 a unui punct 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țiul de vizualizare va fi cu siguranță un număr negativ.

    Pasul patru este cel mai interesant pas. Pașii anteriori au fost discutaț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 a patra etapă, coordonatele omogene sunt transferate 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 în cauză:

    Să convertim 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 cu 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, din formulă reiese clar că datorită împărțirii prin coordonate z, compresia are loc 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ă. Aceasta este explicația efectului de perspectivă.

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

    Matricea (1) este un șablon pentru o matrice de proiecție în perspectivă. După cum sa menționat mai devreme, sarcina matricei de proiecție constă din două puncte: stabilirea unui sistem de coordonate utilizator (stângaci sau dreptaci), transferarea volumului de vizibilitate al observatorului către CVV. Să derivăm o matrice de perspectivă pentru un sistem de coordonate de utilizator stângaci.

    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 cel mai apropiat plan de tăiere ( n);
    • Distanța până la planul de tăiere îndepărtat ( f).


    Orez. 3. Perspectivă volum de vizibilitate

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


    Orez. 4. Proiectarea 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 tridimensionale, trebuie să cunoașteți adâncimea fiecărui fragment. Cu alte cuvinte, este necesar să stocați valoarea componentei z. Aceasta este valoarea folosită pentru testele de adâncime OpenGL. În fig. 3 este clar 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 pseudoadâncimea are mai puțină valoare;
    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 oŞi b trebuie calculat. Pentru a face acest lucru, folosim proprietățile pseudoadâ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 timp ce fŞi n nu poate fi egal cu zero. Primim:

    Să deschidem parantezele și să rearanjam termenii astfel încât doar partea cu O, iar în dreapta doar cu b:

    Să înlocuim (6) în (5). Să transformăm expresia într-o fracție simplă:

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

    Să substituim (7) în (6) și să exprimăm o:

    În consecință componentele oŞi b sunt egali:

    Acum să substituim coeficienții obținuți în matricea piesei de prelucrat (1) și să vedem ce se întâmplă cu coordonatele z pentru un punct arbitrar din spațiul omogen al observatorului. Înlocuirea se realizează după cum urmează:

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

    Poziția relativă a punctului și a volumului de vizibilitate
    Punct Sens Descriere
    1 1 Punctul este situat în fața planului de tăiere frontal al volumului de vizibilitate. Nu trece rasterizarea.
    2 2 Punctul este situat pe marginea frontală a decupării volumului de vizibilitate. În curs de rasterizare.
    3 5 Punctul este situat între marginea de tăiere frontală și marginea de tăiere îndepărtată a volumului de vizibilitate. În curs de rasterizare.
    4 10 Punctul este situat pe marginea îndepărtată a limitei volumului vizibilității. În curs de rasterizare.
    5 20 Punctul este situat dincolo de marginea îndepărtată a limitei de volum de vizibilitate. Nu trece rasterizarea.

    Să înmulțim toate punctele cu matricea (8) și apoi să convertim coordonatele omogene rezultate î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 satisface pe deplin cerințele testului.

    Cu coordonata z Ne-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 să fie comprimate la două unități convenționale.

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


    Orez. 5. Volumul vizibilității

    Din fig. 5 este clar că:

    Acum putem obține vizualizarea finală a matricei de proiecție a perspectivei pentru un sistem de coordonate personalizat pentru stânga care funcționează 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, un CVV este un paralelipiped dreptunghiular cu lungimi de-a lungul axelor sale xŞi y egal cu doi și de-a lungul axei z lungimea este egală cu unu. Gamă xŞi y este [-1 1], iar intervalul z egal cu . În ceea ce privește sistemul de coordonate CVV, DirectX, ca și OpenGL, utilizează un sistem de coordonate stângaci.

    Pentru retragere matrici promițătoare pentru un sistem de coordonate personalizat pentru dreapta, trebuie să redesenați figura. 2, Fig. 3 și Fig. 4 ținând cont de noua direcție 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.

    În acest moment, subiectul matricelor promițătoare poate fi considerat închis.

    Axonometria este o proiecție paralelă. Tabelul 3.3 listează mai întâi matricele proiecțiilor ortografice pe planuri de coordonate obținute din definițiile lor.

    Tabelul 3.3.Matrice de transformări de proiectare și proiecție

    Proiecție ortografică pe XOY

    Proiecție ortografică pe YOZ

    Proiecție ortografică pe XOZ

    Proiecție ortografică pe planul x=p

    Matricea de transformare trimetrică în planul XOY

    Matricea de transformare izometrică în planul XOY

    Matrice de proiecție izometrică pe planul XOY

    Matrice de proiecție oblică pe XOY

    Matrice de proiecție gratuită pe XOY

    Matrice de proiecție a cabinetului pe XOY

    Matrice de transformare a perspectivei cu un punct de fugă (planul imaginii este perpendicular pe axa x)

    Matrice de transformare a perspectivei cu un punct de fugă (planul imaginii este perpendicular pe axa y)

    Matrice de transformare a perspectivei cu un punct de fugă (planul imaginii este perpendicular pe axa aplicată)

    Matrice de transformare a perspectivei cu două puncte de fugă (planul imaginii este paralel cu axa y)

    Matrice de transformare a perspectivei cu trei puncte de fugă (planul imaginii de poziție arbitrară)

    Izometria, dimetria și trimetria sunt obținute printr-o combinație de rotații urmate de o proiecție de la infinit. Dacă trebuie să descrieți proiecția pe planul XOY, atunci trebuie mai întâi să efectuați o transformare de rotație printr-un unghi relativ la axa ordonatelor, apoi la unghi raportat la axa absciselor. Tabelul 3.3 prezintă matricea de transformare trimetrică. Pentru a obține o matrice de transformare dimetrică în care, de exemplu, coeficienții de distorsiune de-a lungul axelor de abscisă și ordonate vor fi egali, relația dintre unghiurile de rotație trebuie să respecte relația

    Adică prin alegerea unghiului , puteți calcula unghiul și determinați matricea de proiecție dimetrică. Pentru o transformare izometrică, relația dintre aceste unghiuri se transformă în valori strict definite, care sunt:

    Tabelul 3.3 prezintă matricea de transformare izometrică, precum și matricea de proiecție izometrică pe planul XOY. Necesitatea matricelor de primul tip constă în utilizarea lor în algoritmi pentru eliminarea elementelor invizibile.

    În proiecțiile oblice, liniile drepte proeminente formează cu planul de proiecție un unghi diferit de 90 de grade. Tabelul 3.3 prezintă matricea generală de proiecție oblică pe planul XOY, precum și matrice de proiecție liberă și cabinet, în care:

    Proiecțiile în perspectivă (Tabelul 3.3) sunt reprezentate și de transformări de perspectivă și proiecții de perspectivă pe planul XOY. V X, V Y și V Z sunt centre de proiecție - puncte pe axele corespunzătoare. –V X, -V Y, -V Z vor fi punctele în care converg fasciculele de drepte paralele cu axele corespunzătoare.

    Sistemul de coordonate al observatorului este stânga sistem de coordonate (Fig. 3.3), în care axa z e este îndreptată din punct de vedere înainte, axa x e este îndreptată spre dreapta, iar axa y e în sus. Această regulă este adoptată pentru a se asigura că axele x e și y e coincid cu axele xs și ys de pe ecran. Determinarea valorilor coordonatelor ecranului x s și y s pentru punctul P duce la necesitatea împărțirii la coordonata z e. Pentru a construi o imagine de perspectivă precisă, este necesar să se împartă la coordonatele de adâncime a fiecărui punct.

    Tabelul 3.4 prezintă valorile descriptorului de vârf S(X,Y,Z) al modelului (Fig. 2.1) supus transformărilor de rotație și transformării izometrice.

    Tabelul 3.4.Model de descriptori de vârf

    Model original

    M(R(z,90))xM(R(y,90))

    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.

    Înainte ca un vârf definit în sistemul de coordonate al scenei să poată fi afișat pe ecran, acesta trebuie să fie supus unui 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 de matrici în așa-numitele coordonate omogene.

    Î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. La proiecție în perspectivă

    Se 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 până la cadrele de tăiere apropiate și îndepărtate.

    Argumentul fovy (câmp de vedere) specifică câmpul de vedere, iar aspectul este raportul dintre lățimea casetei de tăiere și înălțimea acesteia. aproape și departe au întotdeauna valori pozitive și determină distanța din punct de vedere la cadrele de tăiere apropiate și îndepărtate.

    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.);

    Primul argument determină unghiul de rotație, iar restul de trei sunt coordonatele vectorului în jurul căruia se efectuează rotația.

    Stiva de matrice

    Un mecanism util pentru construirea de imagini complexe este o stivă de matrice.

    Folosind funcțiile glPushMatrix() și glPopMatrix(), puteți stoca matricea curentă pe stivă și o puteți restaura după orice modificări în sistemul de coordonate.

    Afișează liste 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ă. Este posibil ca nu toate comenzile să fie incluse.

    Formarea listei se încheie 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 memorie de program 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);<50; i++)
    {
    glVertex2d(-50., .0);
    glVertex2d(50., .0);
    {
    Pentru(int i=-50; i
    }
    glVertex2d(i, .0);
    {
    dacă (i % 5)
    }
    altfel
    {
    glVertex2d(i, -1.);
    }
    }
    altfel dacă (i % 10)

    void Remiză (void)
    glVertex2d(i, -2.);
    glVertex2d(i, -3.);
    glEnd();<50; j++)
    {
    glVertex2d(.0, -50.);
    glVertex2d(.0, 50.);
    {
    pentru(int j=-50; j
    }
    altfel dacă (j % ​​10)
    {
    glVertex2d(-2., j);
    }
    altfel
    {
    glVertex2d(-3., j);
    }
    }
    altfel dacă (i % 10)
    //Terminați execuția comenzii
    glFlush();
    }

    care ia ca argument identificatorul listei.
    {
    Funcția glCallList() poate fi apelată în orice memorie de program atunci când comenzile stocate în listă trebuie executate.
    glClear(GL_COLOR_BUFFER_BIT);
    //Setați culoarea afișajului
    Să ne uităm la un exemplu:

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

    Pentru(int i=0.; i<97; i++)
    {
    glVertex2d(-50., .0);
    glVertex2d(50., .0);
    {
    glVertex2d(i, 1.);
    }
    glVertex2d(i, .0);
    {
    glVertex2d(i, 2.);
    }
    altfel
    {
    glVertex2d(i, 3.);
    }
    }
    altfel dacă (i % 10)
    //Formarea săgeților poate fi adăugată ulterior
    glBegin(GL_LINE_STRIP);
    glVertex2d(97., 1.);
    glVertex2d(100.,.0);
    glVertex2d(97., -1.);
    altfel dacă (i % 10)
    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
    glFlush();
    }

    La un moment dat, orice dezvoltator din domeniul graficii pe computer are o întrebare: cum funcționează aceste matrici promițătoare? Uneori, răspunsul este foarte greu de găsit și, așa cum se întâmplă de obicei, majoritatea dezvoltatorilor renunță la jumătatea sarcinii.

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

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

    • Matricele sunt stocate în 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ă, se utilizează schema de rânduri majore. În general, reprezentarea matricelor în memorie nu contează, deoarece o matrice poate fi întotdeauna convertită de la un tip de reprezentare la altul prin simplă transpunere. Și, deoarece nu există nicio diferență, atunci pentru toate calculele ulterioare vom folosi matrice clasice de rânduri majore. Când programați OpenGL, există un mic truc care vă permite să evitați transpunerea matricelor, menținând în același timp calculele clasice de rânduri majore. Matricea trebuie transferată în programul shader așa cum este, iar în shader multiplicarea trebuie efectuată nu între un vector și o matrice, ci între o matrice și 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 de rând de dimensiune. Pentru a converti o coordonată 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– număr real nu este egal cu 0

    - coordonate omogene

    Un mic 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ă, obțineți o matrice de rând:

    Câteva cuvinte despre calitate zero w. Din punctul de vedere al coordonatelor omogene, acest lucru este destul de acceptabil. Coordonatele omogene vă permit să faceți distincția între puncte și vectori. Într-un sistem de coordonate carteziene, o astfel de împărțire este imposibilă.

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

    - vector, unde ( x, y, z) – vector rază

    Translația inversă a unui vârf de la coordonate omogene în coordonate carteziene se realizează după cum urmează. Toate componentele unei matrice de rânduri trebuie împărțite la ultima componentă. Cu alte cuvinte:

    - coordonate omogene
    - coordonate carteziene

    Principalul lucru pe care trebuie să-l știți este că toți algoritmii de tăiere și rasterizare OpenGL funcționează în coordonate carteziene, dar înainte de asta toate transformările sunt efectuate în coordonate omogene. Trecerea de la coordonatele omogene la coordonatele carteziene se realizează în hardware.

    Volumul canonic de tăiere (CVV) este una dintre părțile cel mai puțin documentate ale OpenGL. După cum se poate observa din fig. 1 CVV este un cub aliniat pe axă cu un centru la origine și o lungime a muchiei egală cu 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 intră parțial în afara CVV este supus algoritmilor de tăiere. Cel mai important lucru pe care trebuie să-l știți 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 poate fi acest lucru, deoarece 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. Cele 2 sisteme de coordonate diferă doar în direcția axei Z. OpenGL 1.0 folosește 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, înmulțirea matricelor - acesta este setul minim de operații inclus în modulul operații matrice. Apar două întrebări logice. Dacă volumul de vizibilitate este un cub cu o lungime a muchiei egală cu două, atunci de ce este vizibilă pe ecran o scenă cu dimensiuni de câteva mii de unități? În ce moment se transformă sistemul de coordonate utilizator în sistemul de coordonate CVV? Matricele de proiecție sunt tocmai 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. Acest lucru completează faptele despre OpenGL și este timpul să punem 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 pe măsură ce distanța lor față de observator crește? Pentru a înțelege de ce obiectele se micșorează pe măsură ce distanța crește, să ne uităm la transformările matriceale ale unui model 3D pas cu pas. Nu este un secret pentru nimeni că orice model tridimensional constă dintr-o listă finită de vârfuri care suferă transformări de matrice complet independent unul de celălalt. 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. Rezultatul este înmulțit cu matricea de vizualizare;
    4. Înmulțiți rezultatul cu matricea de proiecție;
    5. Convertiți rezultatul din coordonate omogene în coordonate carteziene.
    Conversia coordonatelor carteziene în coordonate omogene a fost discutată mai devreme. Sensul geometric al matricei modelului este de a transfera modelul de la un sistem de coordonate local la un sistem de coordonate global. Sau, după cum se spune, mutați vârfurile din spațiul model în spațiul lumii. 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. Apoi, folosind matricea modelului, modelul este poziționat, scalat și rotit. Ca rezultat, toate nodurile modelului 3D primesc coordonate omogene reale în scena 3D. Spațiul model în raport cu spațiul mondial este local. Din spațiul model, coordonatele sunt transferate în spațiul mondial (de la local la global). În acest scop, se utilizează 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 elimină coordonatele dintr-un anumit spațiu. Pentru a le introduce, dimpotrivă, în ea, este necesară inversarea transformării matriceale, prin urmare transformarea de tip este descrisă de matricea inversă. Cum se obține această matrice inversă? Mai întâi, să obținem matricea observatorului direct. 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 stau lucrurile. Cu toate acestea, pentru un 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 a unui punct 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țiul de vizualizare va fi cu siguranță un număr negativ.

    Pasul patru este cel mai interesant pas. Pașii anteriori au fost discutaț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 a patra etapă, coordonatele omogene sunt transferate 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 în cauză:

    Să convertim 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 cu 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, din formulă reiese clar că datorită împărțirii prin coordonate z, compresia are loc 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ă. Aceasta este explicația efectului de perspectivă.

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

    Matricea (1) este un șablon pentru o matrice de proiecție în perspectivă. După cum sa menționat mai devreme, sarcina matricei de proiecție constă din două puncte: stabilirea unui sistem de coordonate utilizator (stângaci sau dreptaci), transferarea volumului de vizibilitate al observatorului către CVV. Să derivăm o matrice de perspectivă pentru un sistem de coordonate de utilizator stângaci.

    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 cel mai apropiat plan de tăiere ( n);
    • Distanța până la planul de tăiere îndepărtat ( f).


    Orez. 3. Perspectivă volum de vizibilitate

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


    Orez. 4. Proiectarea 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 tridimensionale, trebuie să cunoașteți adâncimea fiecărui fragment. Cu alte cuvinte, este necesar să stocați valoarea componentei z. Aceasta este valoarea folosită pentru testele de adâncime OpenGL. În fig. 3 este clar 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 pseudoadâncimea are mai puțină valoare;
    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 oŞi b trebuie calculat. Pentru a face acest lucru, folosim proprietățile pseudoadâ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 timp ce fŞi n nu poate fi egal cu zero. Primim:

    Să deschidem parantezele și să rearanjam termenii astfel încât doar partea cu O, iar în dreapta doar cu b:

    Să înlocuim (6) în (5). Să transformăm expresia într-o fracție simplă:

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

    Să substituim (7) în (6) și să exprimăm o:

    În consecință componentele oŞi b sunt egali:

    Acum să substituim coeficienții obținuți în matricea piesei de prelucrat (1) și să vedem ce se întâmplă cu coordonatele z pentru un punct arbitrar din spațiul omogen al observatorului. Înlocuirea se realizează după cum urmează:

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

    Poziția relativă a punctului și a volumului de vizibilitate
    Punct Sens Descriere
    1 1 Punctul este situat în fața planului de tăiere frontal al volumului de vizibilitate. Nu trece rasterizarea.
    2 2 Punctul este situat pe marginea frontală a decupării volumului de vizibilitate. În curs de rasterizare.
    3 5 Punctul este situat între marginea de tăiere frontală și marginea de tăiere îndepărtată a volumului de vizibilitate. În curs de rasterizare.
    4 10 Punctul este situat pe marginea îndepărtată a limitei volumului vizibilității. În curs de rasterizare.
    5 20 Punctul este situat dincolo de marginea îndepărtată a limitei de volum de vizibilitate. Nu trece rasterizarea.

    Să înmulțim toate punctele cu matricea (8) și apoi să convertim coordonatele omogene rezultate î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 satisface pe deplin cerințele testului.

    Cu coordonata z Ne-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 să fie comprimate la două unități convenționale.

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


    Orez. 5. Volumul vizibilității

    Din fig. 5 este clar că:

    Acum putem obține vizualizarea finală a matricei de proiecție a perspectivei pentru un sistem de coordonate personalizat pentru stânga care funcționează 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, un CVV este un paralelipiped dreptunghiular cu lungimi de-a lungul axelor sale xŞi y egal cu doi și de-a lungul axei z lungimea este egală cu unu. Gamă xŞi y este [-1 1], iar intervalul z egal cu . În ceea ce privește sistemul de coordonate CVV, DirectX, ca și OpenGL, utilizează un sistem de coordonate 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 și Fig. 4 ținând cont de noua direcție 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.

    În acest moment, subiectul matricelor promițătoare poate fi considerat închis.