Kako podesiti pametne telefone i računare. Informativni portal
  • Dom
  • OS
  • Opća perspektivna transformacijska matrica. DirectX9 programiranje: rotirajući objekti

Opća perspektivna transformacijska matrica. DirectX9 programiranje: rotirajući objekti

Aksonometrija je paralelna projekcija. U tabeli 3.3 navedene su prve matrice ortografskih projekcija na koordinatne ravni dobijene iz njihovih definicija.

Tabela 3.3 Projektna transformacija i projekcijske matrice

Ortografska projekcija na XOY

Ortografska projekcija na YOZ

Ortografska projekcija na XOZ

Ortografska projekcija na ravan x = p

Trimetrijska transformacijska matrica na ravni XOY

Matrica izometrijske transformacije u ravan XOY

XOY izometrijska projekcijska matrica

Matrica kose projekcije na XOY

Besplatna projekcijska matrica na XOY

XOY Projekciona matrica kabineta

Matrica perspektivne transformacije s jednom tačkom nestajanja (ravnina slike okomita na osu apscise)

Matrica perspektivne transformacije s jednom tačkom nestajanja (ravnina slike okomita na ordinatu)

Perspektivna transformacijska matrica s jednom tačkom nestajanja (ravnina slike okomita na apliciranu osu)

Matrica perspektivne transformacije sa dvije tačke nestajanja (ravnina slike paralelna sa ordinatom)

Matrica transformacije perspektive sa tri tačke nestajanja (ravnina slike proizvoljnog položaja)

Izometrija, dimetrija i trimetrija se dobijaju kombinovanjem rotacija praćenih projekcijom iz beskonačnosti. Ako trebate opisati projekciju na ravninu XOY, prvo morate transformirati rotaciju pod kutom oko ordinatne ose, a zatim pod uglom u odnosu na osu apscise. Tabela 3.3 prikazuje matricu trimetrijske transformacije. Da bi se dobila matrica dimetrične transformacije, u kojoj će, na primjer, koeficijenti izobličenja duž apscisa i ordinatne osi biti jednaki, odnos između uglova rotacije mora biti u skladu s ovisnošću

Odnosno, odabirom ugla , možete izračunati ugao i odrediti matricu dimetrične projekcije. Za izometrijsku transformaciju, odnos ovih uglova se pretvara u striktno definisane vrednosti, a to su:

Tabela 3.3 prikazuje matricu izometrijske transformacije kao i matricu izometrijske projekcije na ravan XOY. Potreba za matricama prvog tipa leži u njihovoj upotrebi u algoritmima za uklanjanje nevidljivih elemenata.

U kosim projekcijama, isturene prave linije formiraju ugao sa ravninom projekcije koji se razlikuje od 90 stepeni. Tabela 3.3 prikazuje opštu matricu kosih projekcija na ravan XOY, kao i matricu slobodne i kabinetske projekcije, u kojoj:

Perspektivne projekcije (tabela 3.3) su takođe predstavljene transformacijama perspektive i perspektivnim projekcijama na ravan XOY. V X, V Y i V Z su centri projekcije - tačke na odgovarajućim osama. –V X, –V Y, –V Z će biti tačke u kojima se skupljaju snopovi pravih linija paralelnih odgovarajućim osama.

Koordinatni sistem posmatrača je lijevo koordinatni sistem (slika 3.3), u kojem je z e osa usmjerena iz ugla naprijed, x e osa je usmjerena udesno, a y e osa prema gore. Takvo pravilo je usvojeno za podudarnost x e i y e osa sa x s i y s osa na ekranu. Određivanje vrijednosti koordinata ekrana x s i y s za tačku P dovodi do potrebe da se podijeli sa koordinatom z e. Da biste izgradili tačan pogled iz perspektive, potrebno je podijeliti dubinu koordinata svake tačke.

U tabeli 3.4 prikazane su vrijednosti deskriptora vrha S (X, Y, Z) modela (slika 2.1), podvrgnutog rotacijskim transformacijama i izometrijskim transformacijama.

Tablica 3.4 Deskriptori vrhova modela

Originalni model

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

Motor ne pokreće brod.
Brod ostaje na mjestu, i
motori pokreću svemir
Oko njega.

Futurama

Ovo je jedna od najvažnijih lekcija. Pročitajte zamišljeno najmanje osam puta.

Homogene koordinate

U prethodnim lekcijama pretpostavili smo da se vrh nalazi na koordinatama (x, y, z). Dodajmo još jednu koordinatu - w. Od sada ćemo imati vrhove na koordinatama (x, y, z, w)

Uskoro ćete shvatiti šta je šta, ali za sada uzmite to zdravo za gotovo:

  • Ako je w == 1, tada je vektor (x, y, z, 1) pozicija u prostoru
  • Ako je w == 0, tada je vektor (x, y, z, 0) pravac.

Zapamtite ovo kao aksiom bez dokaza !!!

I šta nam to daje? Pa, ništa za rotaciju. Ako rotirate tačku ili smjer, dobit ćete isti rezultat. Ali ako rotirate pomak (kada pomičete tačku u određenom smjeru), onda se sve dramatično mijenja. Šta znači "smjer promjene"? Ništa posebno.

Homogene koordinate nam omogućavaju da radimo sa jednim uređajem za oba slučaja.

Transformacijske matrice

Uvod u matrice

Jednostavno rečeno, matrica je samo niz brojeva s fiksnim brojem redova i stupaca.

Na primjer, matrica 2x3 bi izgledala ovako:

U 3D grafici skoro uvijek koristimo 4x4 matrice. Ovo nam omogućava da transformišemo naše (x, y, z, w) vrhove. Vrlo je jednostavno - množimo vektor položaja sa matricom transformacije.

Matrica * Vertex = Transformirani vrh

Nije tako strašno kao što izgleda. Uperite prst lijeve strane u a, a desni prst u x. Ovo će biti sjekira. Pomjerite lijevi prst do sljedećeg broja b, a desni prst dolje do sljedećeg broja y. Prošli smo. Još jednom - cz. I opet - dw. Sada zbrajamo sve rezultirajuće brojeve - ax + by + cz + dw. Dobili smo naš novi x. Ponovite ovo za svaki red i dobićete novi vektor (x, y, z, w).

Međutim, ovo je prilično dosadna operacija, pa neka to uradi kompjuter umjesto nas.

U C ++ koristeći GLM biblioteku:

glm :: mat4 myMatrix;


glm :: vec4 myVector;



glm:: vec 4 transformedVector = myMatrix * myVector; // Ne zaboravite na red !!! Ovo je izuzetno važno!!!

Na GLSL-u:

mat4 myMatrix;


vec4 myVector;


// ispunimo matricu i vektor našim vrijednostima ... ovo preskačemo


vec 4 transformedVector = myMatrix * myVector; // baš kao u GLM-u

(Nešto mi se čini da niste kopirali ovaj dio koda u svoj projekat i niste ga isprobali... hajde, probajte, zanimljivo je!)

Matrica pomaka

Matrica pomaka je vjerovatno najjednostavnija matrica od svih. Evo je:


Ovdje su X, Y, Z vrijednosti koje želimo dodati poziciji našeg vrha.

Dakle, ako treba da pomerimo vektor (10,10,10,1) za 10 tačaka, na poziciji X, onda:
(Probajte sami, pa, molim vas!)

... I dobijamo (20,10,10,1) u homogenom vektoru. Kao što se nadam da se sjećate, 1 znači da je vektor pozicija, a ne pravac.

Sada pokušajmo transformirati smjer (0,0, -1,0) na isti način:

I na kraju smo dobili isti vektor (0,0, -1,0).
Kao što sam rekao, nema smisla kretati se u pravcu.

Kako da kodiramo ovo?

U C ++ sa GLM:

#include // poslije


glm :: mat4 myMatrix = glm :: translate (10.0f, 0.0f, 0.0f);


glm :: vec4 myVector (10.0f, 10.0f, 10.0f, 0.0f);


glm:: vec 4 transformedVector = myMatrix * myVector; // i koji je rezultat?


I u GLSL-u: U GLSL-u, tako rijetko ko radi. Najčešće se koristi funkcija glm :: translate (). Prvo kreiraju matricu u C ++, a zatim je pošalju u GLSL i već tamo rade samo jedno množenje:

vec4 transformedVector = myMatrix * myVector;

Identity Matrix

Ovo je posebna matrica. Ona ne radi ništa. Ali to spominjem jer je važno znati da množenjem A sa 1,0 dobije se A:

glm :: mat4 myIdentityMatrix = glm :: mat4 (1.0f);

Scaling Matrix

Matrica skaliranja je također prilično jednostavna:

Dakle, ako želite udvostručiti vektor (položaj ili smjer, nije važno) u svim smjerovima:

A w koordinata se nije promijenila. Ako pitate: "Šta je skaliranje smjera?" Nije često korisno, ali ponekad korisno.

(imajte na umu da skaliranje matrice identiteta sa (x, y, z) = (1,1,1))

C ++:

// Koristi#include i#include


glm :: mat4 myScalingMatrix = glm :: skala (2.0f, 2.0f, 2.0f);

Rotation Matrix

Ali ova matrica je prilično komplikovana. Stoga se neću zadržavati na detaljima njegove interne implementacije. Ako zaista želite, bolje pročitajte (često postavljana pitanja o matricama i kvaternionima)

VWITH++:

// Koristi#include i#include


glm :: vec3 myRotationAxis (??, ??, ??);


glm :: rotirati (ugao_u_stepenima, moja osa rotacije);

Kompozitne transformacije

Sada znamo kako rotirati, pomicati i skalirati naše vektore. Bilo bi lijepo znati kako sve ovo iskombinirati. Ovo se radi jednostavnim množenjem matrica jedna s drugom.

Transformirani vektor = TranslationMatrix * RotationMatrix * ScaleMatrix * OriginalVector;

I opet red!!! Prvo morate promijeniti veličinu, zatim skrolovati i tek onda premjestiti.

Ako transformacije primijenimo drugim redoslijedom, nećemo dobiti isti rezultat. Probaj:

  • Napravite korak naprijed (nemojte srušiti kompjuter sa stola) i skrenite lijevo
  • Skrenite lijevo i napravite jedan korak naprijed.

Da, uvijek morate zapamtiti redoslijed radnji kada upravljate, na primjer, likom igre. Prvo, ako je potrebno, izvršite skaliranje, zatim postavite smjer (rotaciju) i zatim pomaknite. Pogledajmo mali primjer (uklonio sam rotaciju da olakšam proračune):

Pogrešan način:

  • Premjestite brod na (10,0,0). Njegov centar je sada 10 X od centra.
  • Povećavamo veličinu našeg broda 2 puta. Svaka koordinata se množi sa 2 u odnosu na centar, koji je daleko ... I kao rezultat, dobijamo brod potrebne veličine, ali na poziciji 2 * 10 = 20. Što nije baš ono što smo željeli.

na pravi način:

  • Povećavamo veličinu broda za 2 puta. Sada imamo veliki brod u centru.
  • Pomeramo brod. Veličina broda nije promijenjena i nalazi se na pravom mjestu.
Množenje matrice-matrice radi se na isti način kao i množenje matrice-vektora. Nećemo ulaziti u detalje, ali neka radoznali to pročitaju iz specijalizovanih izvora. Samo ćemo se osloniti na GLM biblioteku.
VS ++:
glm :: mat4 myModelMatrix = myTranslationMatrix * myRotationMatrix * myScaleMatrix;
glm :: vec4 myTransformedVector = myModelMatrix * myOriginalVector;
Na GLSL-u:
mat4 transform = mat2 * mat1;
vec4 out_vec = transformacija * in_vec;

Model, pogled i projekcijske matrice

Ilustracije radi, pretpostavit ćemo da već znamo kako nacrtati u OpenGL-u naš omiljeni 3D model Blendera - glavu majmuna Suzanne.

Matrice modela, pogleda i projekcije su vrlo pogodna metoda za razdvajanje transformacija. Ne morate ih koristiti ako to zaista želite (nismo ih koristili u lekcijama 1 i 2). Ali toplo preporučujem da ih koristite. Samo što ih skoro sve 3D biblioteke, igre itd. koriste za razdvajanje transformacija.

Model Matrix

Ovaj model, kao i naš omiljeni trokut, definiran je skupom vrhova. X, Y, Z koordinate su specificirane u odnosu na centar objekta. Dakle, ako se vrh nalazi na koordinatama (0,0,0), onda je u centru cijelog objekta

Sada smo u mogućnosti da pomjerimo naš model. Na primjer, zato što korisnik njime upravlja pomoću tastature i miša. Vrlo je jednostavno za napraviti: skaliranje * rotiranje * pomicanje i to je to. Primjenjujete svoju matricu na sve vrhove u svakom okviru (u GLSL-u, a ne C++) i sve se kreće. Sve što se ne kreće nalazi se u centru "sveta".

Vrhovi su u svjetskom prostoru Crna strelica na slici pokazuje kako idemo iz modela prostora u svjetski prostor (Svi vrhovi su specificirani u odnosu na centar modela, a čelik u odnosu na centar svijeta)

Ova transformacija se može prikazati sa sljedećim dijagramom:


View Matrix

Pročitajmo ponovo citat iz futurame:

“Motor ne pokreće brod. Brod ostaje na mjestu, a motori pokreću svemir oko njega."


Isto se može primijeniti i na kameru. Ako želite da fotografišete planinu iz bilo kog ugla, možete pomeriti kameru ... ili planinu. To je nemoguće u stvarnom životu, ali je vrlo lako i zgodno u kompjuterskoj grafici.

Podrazumevano, naša kamera je u centru svjetskih koordinata. Da bismo pokrenuli naš svijet, moramo stvoriti novu matricu. Na primjer, trebamo pomaknuti našu kameru 3 jedinice udesno (+ X). Ovo je isto kao pomicanje cijelog svijeta 3 jedinice ulijevo (-X). I dok vam se mozgovi tope, hajde da probamo:


// Koristi #include i #include


glm :: mat4 ViewMatrix = glm :: translate (-3.0f, 0.0f, 0.0f);

Slika ispod to demonstrira: krećemo se iz prostora svijeta (svi vrhovi su postavljeni u odnosu na centar svijeta kao što smo učinili u prethodnom dijelu) u prostor kamere (svi vrhovi su postavljeni relativno u odnosu na kameru).

I prije nego vam glava potpuno eksplodira, pogledajte ovu sjajnu funkciju našeg dobrog starog GLM-a:

glm :: mat4 CameraMatrix = glm :: LookAt (


cameraPosition, // Položaj kamere u svjetskim koordinatama


cameraTarget, // tačka koju želimo pogledati u svjetskim koordinatama


upVector// najvjerovatnije glm:: vec3 (0,1,0) i (0, -1,0) će pokazati sve naopačke, što je ponekad i cool.


Evo ilustracije gore navedenog:


Ali na naše zadovoljstvo, to nije sve.

Projekciona matrica

Sada imamo koordinate u prostoru kamere. To znači da će nakon svih ovih transformacija, čiji vrh ima sreću da bude na x == 0 i y == 0, biti prikazan u centru ekrana. Ali ne možemo samo koristiti koordinate X, Y da bismo otkrili gdje da nacrtamo vrh: udaljenost do kamere (Z) također se mora uzeti u obzir! Ako imamo dva vrha, onda će jedan od njih biti bliže centru ekrana od drugog, jer ima veću Z koordinatu.

Ovo se zove perspektivna projekcija:


I na našu sreću, 4x4 matrica također može predstavljati transformaciju perspektive:

glm :: mat4 projectionMatrix = glm :: perspektiva (


FoV, // Horizontalno vidno polje u stepenima. Or magnitudeaproksimacije. Kakokao da « sočivo» nakamera. Obično između 90 (super širok, poput ribljeg oka) i 30 (kao mala špijunska stakla)


4.0 f / 3.0 f, // Omjer. Zavisi od veličine vašeg prozora. Na primjer, 4/3 == 800/600 == 1280/960 zvuči poznato, zar ne?


0.1 f, // Near clipping field. Treba ga postaviti što je moguće veće, inače će biti problema s preciznošću.


100.0 f // Daleko polje za odsecanje. Trebalo bi da bude što manji.


);

Ponovimo šta smo sada uradili:

Udaljili smo se od prostora kamere (svi vrhovi su postavljeni u koordinatama u odnosu na kameru) u homogeni prostor (svi vrhovi su u koordinatama male kocke (-1,1). Sve u kocki je na ekranu.)

I konačni dijagram:


Evo još jedne slike da bude jasnije šta se dešava kada pomnožimo sve ove gluposti sa projekcijskom matricom. Prije množenja sa matricom projekcije, imamo plave objekte definirane u prostoru kamere i crveni objekt koji predstavlja vidno polje kamere: prostor koji pada u objektiv kamere:

Nakon množenja sa matricom projekcije, dobijamo sljedeće:

Na prethodnoj slici vidno polje se pretvorilo u savršenu kocku (sa koordinatama vrha od -1 do 1 u svim osama.), a svi objekti su deformisani u perspektivi. Svi plavi objekti koji su blizu kamere postali su veliki, a oni dalje - mali. Isto kao u životu!

Evo pogleda koji imamo iz "objektiva":

Međutim, ona je kvadratna i potrebno je primijeniti još jednu matematičku transformaciju kako bi se slika prilagodila veličini prozora.

Za rotiranje objekata (ili kamere) potrebna je ozbiljna matematička osnova uz pomoć koje će se izračunati koordinate svih objekata kada se prikažu na "ravni" ekran računara. Odmah želim reći da se ne treba plašiti, sve matematičke biblioteke su već napisane za nas, samo ćemo ih koristiti. U svakom slučaju, sljedeći tekst ne treba preskočiti, bez obzira na nivo znanja matematike.

1. Matrice, opći pojmovi

Šta su matrice? Podsjećamo na višu matematiku: matrica ¬ je skup brojeva s prethodno poznatom dimenzijom redova i stupaca.

Matrice se mogu sabirati, množiti brojem, množiti jedna s drugom i mnoge druge zanimljive stvari, ali ovaj trenutak ćemo preskočiti, jer dovoljno je detaljno opisano u bilo kojem udžbeniku iz više matematike (udžbenici se mogu pretraživati ​​na google.com). Koristićemo matrice kao programeri, popunjavamo ih i kažemo šta da radimo sa njima, sve proračune će vršiti Direct3D matematička biblioteka, tako da treba da uključite modul zaglavlja d3dx9.h (i biblioteku d3dx9.lib) u projekat.

Naš zadatak je kreiranje objekta, tj. ispunite matricu koordinatama vrhova objekta. Svaki vrh je vektor (X, Y, Z) u 3D prostoru. Sada, da bismo izvršili neku radnju, trebamo uzeti naš objekt (tj. matricu) i pomnožiti sa matricom transformacije, rezultat ove operacije je novi objekt specificiran u obliku matrice.

Postoje tri glavne matrice definirane i korištene u Direct3D-u: matrica svijeta, matrica pogleda i matrica projekcije. Razmotrimo ih detaljnije.

World Matrix- omogućava rotaciju, transformaciju i skaliranje objekta, a također daje svakom od objekata vlastiti lokalni koordinatni sistem.

Funkcije za rad sa svjetskom matricom:

  • D3DXMatrixRotationX (), D3DXMatrixRotationY (), D3DXMatrixRotationZ () - rotacija tačke oko jedne od osi;
  • D3DXMatrixTranslation () - premjestiti tačku na drugu poziciju;
  • D3DXMatrixScale () - skaliranje.

    View Matrix- definira lokaciju kamere za gledanje scene i može se sastojati od bilo koje kombinacije emitiranja i rotacije.
    D3DXMatrixLookAtLH () i D3DXMatrixLookAtRH () definišu poziciju kamere i ugao gledanja za levoruki i desnoruki koordinatni sistem, respektivno.

    Projekciona matrica- kreira projekciju 3D scene na ekran monitora. On transformiše objekat, pomera ishodište na prednju stranu i definiše prednju i zadnju ravninu odsecanja.

    Popunjavanjem ovih matrica i izvođenjem transformacija stvarate trodimenzionalnu scenu u kojoj dobivate mogućnost pomicanja, rotiranja, zumiranja, uklanjanja i obavljanja drugih radnji na objektima, ovisno o vašim potrebama.

    2. Kreiranje objekta

    Kreiramo novi projekat, sličan prvom. Prije nego što nastavimo da komplikujemo naš kod, hajde da ga razbijemo na dijelove radi bolje čitljivosti koda. Logično je naš projekat podijeliti na tri komponente:
    1. Windows prozor (inicijalizacija prozora, poruke,...)
    2. 3D inicijalizacija (učitavanje koordinata objekta, brisanje resursa,...)
    3. Renderiranje scene (matrice, primitivi za crtanje,...)
    Kao rezultat, imaćemo 3 fajla - window.cpp, init3d.h, render.h sa sledećim sadržajem: init3d.h- prenosimo globalne varijable i strukture, deklaracije funkcija, funkcije InitDirectX (), InitBufferVertex (), Destroy3D () render.h- prenosimo funkciju RenderScene (), sve što ostane dodiruje glavni prozor, to će biti datoteka - window.cpp.

    Dodavanje datoteke zaglavlja i biblioteke za korištenje matričnih funkcija

    #include // ili C: \ DXSDK \ Uključi \ d3dx9.h #pragma komentar (lib, "d3dx9.lib") // ili C: \\ DXSDK \\ Lib \\ d3dx9.lib

    Potrebne su nam i standardne funkcije za rad s vremenom, tako da uključujemo odgovarajući fajl zaglavlja:

    #include

    Promijenimo format predstavljanja vrhova:

    #define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ / D3DFVF_DIFFUSE) struct CUSTOMVERTEX ( Float x, y, z; DWORD boja; );

    Koristićemo nekonvertovani tip vrha, pošto transformacije će se vršiti pomoću matrica.
    Promijenite kod funkcije InitDirectX (). Ovoj funkciji mora se dodati postavka dva načina prikaza.
    Isključite način izrezivanja tako da kada rotirate možete vidjeti sve strane objekta:

    PDirectDevice-> SetRenderState (D3DRS_CULLMODE, D3DCULL_NONE);

    Trenutno ne koristimo rasvjetu, već farbamo vrhove u određenu boju, pa gasimo rasvjetu:

    PDirectDevice-> SetRenderState (D3DRS_LIGHTING, FALSE);

    Pojednostavimo naše srce tako što ćemo ga predstaviti kao tri trougla. Koristićemo lokalni koordinatni sistem.


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

    3. Kreiranje transformacijskih matrica

    Upišimo u datoteku render.h funkciju SetupMatrix () u kojoj će se odvijati sve radnje na matricama.

    Kreirajmo matrice:

  • D3DXMATRIX MatrixWorld; - svjetska matrica
  • D3DXMATRIX MatrixView; - matrica forme
  • D3DXMATRIX MatrixProjection; - projekcijska matrica
    Postavljanje matrice svijeta

    Da bi se objekat rotirao potrebno je dobiti sistemsko vrijeme i svaki "trenutak" promijeniti ugao između lokalnog i svjetskog koordinatnog sistema. Rotiraćemo oko X ose, tako da koristimo funkciju D3DXMatrixRotationX. Nakon izračunavanja svjetske matrice, potrebno je primijeniti njene vrijednosti pomoću funkcije SetTransform:

    UINT iTime = timeGetTime ()% 5000; FLOAT FAngle = iTime * (2.0f * D3DX_PI) /5000.0f; D3DXMatrixRotationX (& MatrixWorld, fAngle); pDirectDevice-> SetTransform (D3DTS_WORLD, & MatrixWorld); Postavljanje matrice prikaza

    Instalirajte kameru na pravo mjesto i usmjerite je prema objektu

  • D3DXMatrixLookAtLH (& MatrixView, - rezultat funkcije
  • & D3DXVECTOR3 (0.0f, 0.0f, -8.0f), - tačka na kojoj se kamera nalazi
  • & D3DXVECTOR3 (0.0f, 0.0f, 0.0f), - tačka u kojoj gledamo
  • & D3DXVECTOR3 (0.0f, 1.0f, 0.0f)); - vrh objekta

    Nakon izračuna, potrebno je primijeniti dobivene vrijednosti.

  • Motor ne pokreće brod. Brod ostaje na mjestu, a motor pomiče svemir u odnosu na njega.

    Ovo je vrlo važan dio lekcije, obavezno ga pročitajte nekoliko puta i dobro razumite.

    Homogene koordinate

    Do sada smo radili sa 3-dimenzionalnim vrhovima kao (x, y, z) trojkama. Uvedemo još jedan parametar w i operujmo vektorima oblika (x, y, z, w).

    Zauvijek zapamtite to:

    • Ako je w == 1, tada je vektor (x, y, z, 1) pozicija u prostoru.
    • Ako je w == 0, tada je vektor (x, y, z, 0) pravac.

    Šta nam to daje? Ok, ovo ništa ne mijenja za rotaciju, jer u slučaju rotacije točke iu slučaju rotacije vektora smjera, dobivate isti rezultat. Međutim, u slučaju transfera postoji razlika. Pomicanjem vektora smjera dat će se isti vektor. O tome ćemo se detaljnije zadržati kasnije.

    Homogene koordinate nam omogućavaju da radimo sa vektorima u oba slučaja koristeći jednu matematičku formulu.

    Transformacijske matrice

    Uvod u matrice

    Najlakši način da zamislite matricu je kao niz brojeva, sa strogo određenim brojem redova i stupaca. Na primjer, matrica 2x3 izgleda ovako:

    Međutim, u 3D grafici ćemo koristiti samo 4x4 matrice koje će nam omogućiti da transformiramo naše vrhove (x, y, z, w). Transformirani vrh je rezultat množenja matrice sa samim vrhom:

    Matrica x Vertex (tim redoslijedom!!) = Transformacija. vertex

    Prilično jednostavno. Ovo ćemo koristiti prilično često, tako da ima smisla dati instrukcije računaru da uradi ovo:

    U C++ koristeći GLM:

    glm :: mat4 myMatrix; glm :: vec4 myVector; glm :: // Obratite pažnju na narudžbu! On je važan!

    Na GLSL-u:

    mat4 myMatrix; vec4 myVector; // Ne zaboravite popuniti matricu i vektor traženim vrijednostima ovdje vec4 transformedVector = myMatrix * myVector; // Da, ovo je vrlo slično GLM :)

    Pokušajte eksperimentirati s ovim isječcima.

    Transfer matrica

    Matrica prijenosa izgleda ovako:

    gdje su X, Y, Z vrijednosti koje želimo dodati našem vektoru.

    Dakle, ako želimo da pomerimo vektor (10, 10, 10, 1) za 10 jedinica u pravcu X, onda dobijamo:

    … Dobijamo (20, 10, 10, 1) homogeni vektor! Ne zaboravite da 1 u parametru w znači položaj, a ne smjer, a naša transformacija nije promijenila činjenicu da radimo sa pozicijom.

    Sada da vidimo šta se dešava ako je vektor (0, 0, -1, 0) pravac:

    ... i dobijamo naš originalni vektor (0, 0, -1, 0). Kao što je već rečeno, vektor sa parametrom w = 0 ne može se prenijeti.

    I sada je vrijeme da to premjestite u kod.

    U C ++, sa GLM:

    #include // poslije glm :: mat4 myMatrix = glm :: translate (glm :: mat4 (), glm :: vec3 (10.0 f, 0.0 f, 0.0 f)); glm :: vec4 myVector (10.0 f, 10.0 f, 10.0 f, 0.0 f); glm :: vec4 transformedVector = myMatrix * myVector;

    Na GLSL-u:

    vec4 transformedVector = myMatrix * myVector;

    Zapravo, to nikada nećete raditi u shaderu, najčešće ćete izvršiti glm :: translate () u C++ da biste izračunali matricu, proslijedite je GLSL-u, a zatim izvršite množenje u shaderu.

    Unit Matrix

    Ovo je posebna matrica koja ne radi ništa, ali mi je dodirujemo, jer je važno zapamtiti da A pomnoženo sa 1,0 daje A:

    U C ++:

    glm :: mat4 myIdentityMatrix = glm :: mat4 (1.0 f);

    Matrica skaliranja

    Takođe izgleda jednostavno:

    Dakle, ako želite primijeniti vektorsko skaliranje (položaj ili smjer - nije važno) za 2,0 u svim smjerovima, onda trebate:

    Imajte na umu da se w ne mijenja, a također imajte na umu da je matrica identiteta poseban slučaj matrice skaliranja sa faktorom skale 1 na svim osama. Također, matrica identiteta je poseban slučaj matrice prijenosa, gdje je (X, Y, Z) = (0, 0, 0), respektivno.

    U C ++:

    // dodaj #include i #include glm :: mat4 myScalingMatrix = glm :: skala (2,0 f, 2,0 f, 2,0 f);

    Matrica rotacije

    Teže nego što je ranije diskutovano. Ovdje ćemo preskočiti detalje jer ne morate biti sigurni za svakodnevnu upotrebu. Za više informacija, možete pratiti link Matrice i Quaternions FAQ (prilično popularan resurs i možda je vaš jezik tamo dostupan)

    U C ++:

    // dodaj #include i #include glm :: vec3 myRotationAxis (??, ??, ??); glm :: rotirati (ugao_u_stepenima, moja osa rotacije);

    Spajanje transformacija

    Dakle, sada možemo rotirati, translirati i skalirati naše vektore. Sljedeći korak bi bilo lijepo kombinirati transformacije, koje se implementiraju pomoću sljedeće formule:

    Transformirani vektor = TranslationMatrix * RotationMatrix * ScaleMatrix * OriginalVector;

    PAŽNJA! Ova formula zapravo pokazuje da se prvo vrši skaliranje, zatim rotacija i tek zadnje je translacija. Ovako funkcionira množenje matrice.

    Obavezno zapamtite kojim redoslijedom se sve ovo radi, jer redoslijed je zaista važan, na kraju možete i sami provjeriti:

    • Napravite korak naprijed i skrenite lijevo
    • Skrenite lijevo i napravite korak naprijed

    Razliku je zaista važno razumjeti, jer ćete se s tim stalno suočavati. Na primjer, kada radite sa likovima igre ili nekim objektima, uvijek prvo zumirajte, zatim rotirajte i tek onda prenesite.

    U stvari, gornji redoslijed je ono što vam je obično potrebno za likove za igranje i druge stavke: prvo ga povećajte ako je potrebno; zatim postavite njegov smjer i zatim ga pomaknite. Na primjer, za model broda (zaokreti su uklonjeni radi jednostavnosti):

    • Pogrešan način:
      • Premjestite brod na (10, 0, 0). Njegov centar je sada 10 jedinica od početka.
      • Vaš brod povećavate 2x. Svaka koordinata se množi sa 2 "u odnosu na original", što je daleko... Dakle, nađete se u velikom brodu, ali njegov centar je 2 * 10 = 20. Nije ono što ste htjeli.
    • na pravi način:
      • Vaš brod povećavate 2x. Dobijate veliki brod u centru polazišta.
      • Vi nosite svoj brod. I dalje je iste veličine i na ispravnoj udaljenosti.

    U C ++, sa GLM:

    glm :: mat4 myModelMatrix = myTranslationMatrix * myRotationMatrix * myScaleMatrix; glm :: vec4 myTransformedVector = myModelMatrix * myOriginalVector;

    Na GLSL-u:

    mat4 transform = mat2 * mat1; vec4 out_vec = transformacija * in_vec;

    Matrice svijeta, pogleda i projekcija

    Za ostatak ovog tutorijala pretpostavit ćemo da znamo kako prikazati naš omiljeni 3D model iz Blendera - majmun Suzanne.

    Matrice svijeta, pogleda i projekcije su pogodan alat za odvajanje transformacija.

    World Matrix

    Ovaj model, baš kao i naš crveni trokut, postavljen je skupom vrhova čije su koordinate postavljene u odnosu na centar objekta, tj. vrh sa koordinatama (0, 0, 0) će biti u centru objekat.

    Zatim bismo željeli pomjeriti naš model, budući da igrač njime upravlja pomoću tastature i miša. Sve što radimo je skaliranje, zatim rotiranje i prevođenje. Ove akcije se izvode za svaki vrh, u svakom okviru (izvode se u GLSL-u, a ne u C ++!) I tako se naš model kreće po ekranu.

    Sada su naši vrhovi u svjetskom prostoru. To je prikazano crnom strelicom na slici. Prešli smo iz prostora objekata (svi vrhovi su relativni u odnosu na centar objekta) u svjetski prostor (svi vrhovi su relativni u odnosu na centar svijeta).

    Šematski je prikazano kako slijedi:

    View matrix

    Da ponovo citiram Futuramu:

    Motor ne pokreće brod. Brod ostaje na istom mjestu, a motor pokreće svemir oko njega.

    Pokušajte to zamisliti u odnosu na kameru. Na primjer, ako želite da fotografišete planinu, onda ne pomerate kameru, već pomerate planinu. Ovo nije moguće u stvarnom životu, ali je neverovatno jednostavno u kompjuterskoj grafici.

    Dakle, u početku je vaša kamera u centru svjetskog koordinatnog sistema. Da biste pomjerili svijet, morate ući u drugu matricu. Recimo da želite da pomerite kameru 3 jedinice DESNO (+ X), što je ekvivalent pomeranju celog sveta za 3 jedinice LIJEVO (-X). U kodu to izgleda ovako:

    // Dodaj #include i #include glm :: mat4 ViewMatrix = glm :: translate (glm :: mat4 (), glm :: vec3 (- 3.0 f, 0.0 f, 0.0 f));

    Opet, slika ispod to u potpunosti ilustruje. Prešli smo sa svjetskog koordinatnog sistema (svi vrhovi su specificirani u odnosu na centar svjetskog sistema) na koordinatni sistem kamere (svi vrhovi su specificirani u odnosu na kameru):

    I dok vaš mozak ovo probavi, mi ćemo pogledati funkciju koju nam pruža GLM, odnosno glm :: LookAt:

    glm :: mat4 CameraMatrix = glm :: LookAt (cameraPosition, // Položaj kamere u svjetskom prostoru cameraTarget, // Označava gdje gledate u svjetskom prostoru upVector // Vektor usmjeren prema gore. Obično (0, 1, 0));

    A evo i dijagrama koji pokazuje šta radimo:

    Međutim, ovo nije kraj.

    Projekciona matrica

    Dakle, sada smo u prostoru kamere. To znači da će vrh koji prima koordinate x == 0 i y == 0 biti prikazan u centru ekrana. Međutim, kada se prikazuje objekat, udaljenost do kamere (z) također igra veliku ulogu. Za dva vrha sa istim x i y, vrh sa većom z vrednošću će izgledati bliže od drugog.

    Ovo se zove perspektivna projekcija:

    I na našu sreću, 4x4 matrica može napraviti ovu projekciju:

    // Stvara stvarno teško čitljivu matricu, ali bez obzira na to je ovo standardna 4x4 matrica glm :: mat4 projectionMatrix = glm :: perspektiva (glm :: radijani (FoV), // Vertikalno vidno polje u radijanima. Obično između 90° (veoma širok) i 30° (uzak) 4,0 f / 3,0 f, // Omjer. Zavisi od veličine vašeg prozora. Imajte na umu da je 4/3 == 800/600 == 1280/960 0,1 f, // Blizu ravni za odsecanje. Mora biti veći od 0. 100,0 f // Daleka ravnina za odsecanje.);

    Prešli smo iz Camera Space (svi vrhovi su postavljeni u odnosu na kameru) u Homogeni prostor (svi vrhovi su u maloj kocki. Sve unutar kocke je prikazano).

    Sada pogledajmo sljedeće slike kako biste bolje razumjeli šta se dešava sa projekcijom. Prije projekcije imamo plave objekte u prostoru kamere, dok crveni oblik pokazuje pogled kamere, odnosno sve ono što kamera vidi.

    Upotreba projekcijske matrice ima sljedeće efekte:

    Na ovoj slici, pogled kamere je kocka i svi objekti su deformisani. Objekti koji su bliže kameri izgledaju veliki, a oni dalje mali. Baš kao u stvarnosti!

    Ovako će to izgledati:

    Slika je kvadratna, tako da se primjenjuju sljedeće matematičke transformacije kako bi se slika proširila tako da odgovara stvarnoj veličini prozora:

    A ova slika je ono što će zapravo biti prikazano.

    Transformacije spajanja: matrica ModelViewProjection

    ... Samo standardne matrične transformacije koje već volite!

    // C ++: izračunavanje matrice glm :: mat4 MVPmatrix = projekcija * pogled * model; // Zapamti! Obrnutim redoslijedom!

    // GLSL: Primijenite matricu transformed_vertex = MVP * in_vertex;

    Stavljajući sve zajedno

    • Prvi korak je kreiranje naše MVP matrice. Ovo se mora uraditi za svaki model koji prikazujete.

    // Projekcioni niz: 45° vidno polje, 4:3 omjer širine i visine, domet: 0,1 jedinica<->100 jedinica glm :: mat4 Projekcija = glm :: perspektiva (glm :: radijani (45,0 f), 4,0 f / 3,0 f, 0,1 f, 100,0 f); // Ili, za ortokameru glm :: mat4 View = glm :: lookAt (glm :: vec3 (4, 3, 3), // Kamera je u svjetskim koordinatama (4,3,3) glm :: vec3 (0, 0, 0), // I usmjereno na ishodište glm :: vec3 (0, 1, 0) // "Glava" je na vrhu); // Matrica modela: matrica identiteta (Model je na početku) glm :: mat4 Model = glm :: mat4 (1.0 f); // Pojedinačno za svaki model // Rezultirajuća matrica ModelViewProjection, koja je rezultat množenja naše tri matrice glm :: mat4 MVP = Projekcija * Pogled * Model; // Zapamtite da se množenje matrice vrši obrnutim redoslijedom

    • Drugi korak je proslijediti ovo na GLSL:

    // Dohvati ručicu varijable u shaderu // Samo jednom tokom inicijalizacije. GLuint MatrixID = glGetUniformLocation (ID programa, "MVP"); // Proslijedite naše transformacije u trenutni shader // Ovo se radi u glavnoj petlji, budući da će svaki model imati različitu MVP matricu (barem dio M) glUniformMatrix4fv (MatrixID, 1, GL_FALSE, & MVP [0] [0]);

    • Treći korak je korištenje primljenih podataka u GLSL-u za transformaciju naših vrhova.

    // Vertex ulazni podaci, različiti za sva izvršenja ovog shadera. raspored (lokacija = 0) u vec3 vertexPosition_modelspace; // Vrijednosti koje ostaju konstantne za cijelu mrežu. uniforma mat4 MVP; void main () ( // Izlazna pozicija našeg vrha: MVP * pozicija gl_Position = MVP * vec4 (vertexPosition_modelspace, 1); )

    • Spremni! Sada imamo isti trougao kao u lekciji 2, koji se još uvek nalazi na početku (0, 0, 0), ali ga sada vidimo u perspektivi iz tačke (4, 3, 3).

    U lekciji 6 naučit ćete kako dinamički mijenjati ove vrijednosti koristeći tastaturu i miš da biste kreirali kameru koju ste navikli vidjeti u igricama. Ali prvo ćemo naučiti kako našim modelima dati boje (lekcija 4) i teksture (lekcija 5).

    Zadaci

    • Pokušajte promijeniti vrijednosti glm :: perspektive
    • Umjesto korištenja perspektivne projekcije, pokušajte koristiti ortografsku (glm: orto)
    • Modificirajte ModelMatrix da biste pomicali, rotirali i skalirali trokut
    • Koristite prethodni zadatak, ali s drugačijim redoslijedom operacija. Obratite pažnju na rezultat.

    Perspektivna projekcija

    Razmotrili smo važne projekcije koje se koriste u afinoj geometriji. Sada pređimo na razmatranje geometrije perspektive i nekoliko novih tipova projekcija.

    Na fotografijama, slikama, ekranu, slike nam deluju prirodno i korektno. Ove slike se nazivaju perspektivne slike. Njihova svojstva su takva da se udaljeniji objekti prikazuju u manjem obimu, paralelne linije uglavnom nisu paralelne. Kao rezultat toga, geometrija slike je prilično složena i teško je odrediti veličinu određenih dijelova objekta iz gotove slike.

    Konvencionalna perspektivna projekcija je centralna projekcija na ravan s ravnim zrakama koje prolaze kroz tačku - centar projekcije. Jedna od zraka projekcije je okomita na ravan projekcije i naziva se glavna. Tačka preseka ove zrake i ravni projekcije je glavna tačka slike.

    Postoje tri koordinatna sistema. Obično programer radi i čuva podatke o geometrijskim objektima u svjetskim koordinatama. Da bi se povećao realizam u pripremi za prikazivanje slike na ekranu, podaci o objektima iz svjetskih koordinata se pretvaraju u koordinate prikaza. I tek u trenutku prikazivanja slike direktno na ekranu, oni se pomeraju na koordinate ekrana, a to su brojevi piksela ekrana.

    Prva dva sistema se mogu koristiti u višedimenzionalnim koordinatnim sistemima, ali potonji samo u 2D. Operacije su nepovratne, odnosno nemoguće je vratiti trodimenzionalnu sliku iz dvodimenzionalne projekcijske slike.

    U ovoj matrici, elementi a, d, e odgovorni su za skaliranje, m, n, L- za pomjeranje, str, q, r- za projektovanje, s- za složeno skaliranje, X- za rotaciju.

    Projekcija u jednoj tački na ravan z = 0

    Suština ove projekcije je sljedeća: što je objekt dublji, to je veća vrijednost z-koordinate i nazivnik rz + 1 postaje, a samim tim i manji objekt izgleda na ravni projekcije. Izvršimo jednostavne proračune i objasnimo ih grafički:
    jednadžba x "/ F = x / (F + z pr) je ekvivalentna: x" = xF / (F + z pr) = x / (1 + z pr / F) = x / (1 + rz pr) , gdje je r = 1 / F, F - fokus.

    Za tačke koje leže na pravoj paralelnoj osi z, nisu se gubile jedna za drugom, koristi se projekcija u jednoj tački na pravu (vidi matricu transformacije i pirinač. 4.2); z-koordinata je nestala, ali pošto su udaljeni objekti postali manji od sličnih bliskih, posmatrač ima osećaj dubine. Zapamtite: ovo je prvi način prenošenja dubine u avion!

    Top srodni članci