Opengl - lucrează cu imagini

5.1 Cuvinte comune

Ați învățat deja cum să construiți obiecte primitive. Dar, cu greu va trebui să construiți scene 3D folosind doar primitive, și ele ar părea cumva ciudate și plictisitoare. Pentru a le revigora, primitivii sunt suprapuse cu imagini - texturi. De asemenea, este util să folosiți o imagine grafică ca fundal a scenei. Acest lucru face aplicația mai vie și interesantă. Astfel, în acest capitol vom învăța cum să lucrăm cu imagini.







5.2 Lucrul cu imaginile

Există multe formate grafice - bmp, pcx, gif, jpeg și altele. OpenGL nu suportă direct unul dintre ele. În OpenGL nu există funcții pentru citirea / scrierea fișierelor grafice. Dar lucrul cu pixeli este suportat. Descărcați un fișier grafic, utilizând bibliotecile altor companii, în memorie și lucrați cu ei folosind OpenGL. Într-o matrice, datele pixelilor pot fi aranjate în moduri diferite: RGB, BGR, RGBA; nu pot fi prezente toate componentele; fiecare element de matrice poate ocupa un octet, doi, patru sau opt; alinierea poate fi octet, cuvânt sau cuvânt dublu. În general, există o mulțime de formate pentru aranjarea datelor despre o imagine grafică în memorie. Voi lua în considerare unul dintre ele, cel mai frecvent utilizat, așa cum mi se pare. Informațiile despre fiecare pixel sunt stocate în format RGB și ocupă trei octeți, alinierea octeților. Biblioteca auxiliară are o funcție auxDIBImageLoad (LPCSTR), care încarcă un fișier bmp în memorie și returnează un pointer la structură:

Pentru simplitate, voi folosi această funcție. Printre programele incluse veți găsi utilitatea mea pentru descărcarea fișierelor de pe formatele pcx. Textul sursă al acestui utilitar este absolut portabil pentru orice platformă cu compilatorul ANSI C.

Înainte de a apela funcția auxMainLoop în funcția principală, introduceți linia:

Alinierea este setată prin apelarea glPixelStorei cu parametrul GL_UNPACK_ALIGNMENT, iar al doilea parametru, un număr care specifică alinierea. Imaginile sunt afișate direct pe ecran. Prin urmare, totul se întâmplă în coordonate bidimensionale. Poziția la care începe producția imaginii este indicată utilizând funcția glRasterPos2d (x, y). De asemenea, puteți seta dimensiunea pixelului apelând funcția glPixelZoom. Primul parametru al acestei funcții este lățimea, al doilea este înălțimea pixelului. Eu numesc această funcție cu argumentele (1,1), care corespund pixelului normal. Înlocuiți (1,1) cu (3,2) și veți vedea cum imaginea se întinde de trei ori pe orizontală și de două ori pe verticală. Acest lucru sa întâmplat, deoarece acum fiecare pixel al imaginii corespunde dreptunghiului 3x2 din fereastră. În cele din urmă, producția este furnizată de glDrawPixels. Primii doi parametri sunt lățimea și înălțimea. Apoi, specificați formatul în care sunt stocate informații în memorie și tipul elementelor de matrice. Ultimul este matricea de date. În funcția de afișare, lipiți următorul cod:

De asemenea, în OpenGL există o funcție glBitmap pentru afișarea imaginilor bitmap. Bitmap este o secvență de octeți care codifică o imagine cu două culori. În consecință, fiecare octet codifică 8 pixeli. Printre programele incluse veți găsi utilitatea mea pcx_2bpp. Se citește un fișier pcx format un bit pe pixel și se trimite o matrice în limba C la ieșirea standard.

Opengl - lucrează cu imagini

Fișierul sursă poate fi găsit aici. Executivul este aici. Fotografia mea e aici.

5.3 Exercițiul: "Fundal pentru jocul Arcanoid"

Opengl - lucrează cu imagini

Fișierul sursă poate fi găsit aici. Executivul este aici. Cerul înstelat este aici.

5.4 Crearea unei texturi în memorie

O singură ieșire de imagini nu este suficientă pentru a crea scene tridimensionale cu drepturi depline. Deseori, este nevoie să se suprapună o imagine pe obiecte tridimensionale și să se rotească / să se schimbe. În aceste scopuri, există o textură. De asemenea, texturile vă vor ajuta să acoperiți întregul obiect sub forma unui mozaic. Spuneți, atunci când aveți un zid de cărămidă, atunci nu este nevoie să încărcați o imagine cu o grămadă de cărămizi. Este suficient să încărcați o cărămidă și să indicați că această textură trebuie multiplicată pe întregul plan.

Mai întâi vom analiza crearea și suprapunerea texturilor pe un avion. Apoi, luați în considerare cartografierea texturilor la obiectele descrise în secțiunea 4.1. Și în final, pentru toți ceilalți creați din poligoane; în special, un torus și un ceainic.

Pentru a aplica o textura unui obiect, trebuie:

  1. Încărcați fișierul imagine în memorie
  2. Creați un nume de identificator pentru textură
  3. Faceți-l activ
  4. Creați textura însăși în memorie
  5. Setați opțiunile de textură
  6. Setați parametrii de interacțiune a texturii cu obiectul
  7. Asociați coordonatele texturii cu obiectul

Primul pe care l-ați învățat deja în secțiunea anterioară. Creați un proiect numit Textură. Declarați următoarele variabile globale:

Variabilele photo_tex și space_tex vor servi drept identificatori de textură. Și în photos_image și space_image vom încărca fișierele bmp. Aici trebuie remarcat faptul că texturile din OpenGL ar trebui să aibă o dimensiune de 2n x 2m, unde n și m sunt numere întregi. Acest lucru este făcut pentru a accelera munca, pentru că comprimați sau întindeți aceste texturi mai rapid și mai convenabil. Desigur, puteți încărca o imagine de orice altă dimensiune, dar va trebui să fie redimensionată. În opinia mea, acest lucru este greșit. Rezultatul scalării nu vă poate potrivi. Deci, folosesc fișiere grafice cu o dimensiune care este un multiplu al puterii a două. Este mai convenabil pentru mine să editez o imagine într-un pachet grafic, să o taie sau, dimpotrivă, să o completez, decât să aflu de ce este distorsionată. Cu toate acestea, depinde mult de cazul specific. Artistul care face textura, oricum este cât de mare este de făcut, deci este mai ușor să-l rogi să facă o imagine cu dimensiunile corespunzătoare. Lipiți următorul cod în funcția principală.

Luați fotografiile din programul meu - Textură. Puteți face o fotografie proprie ;-) Numai dimensiunea acesteia ar trebui să rămână 512x512.

Acum trebuie să creați un nume de identificator al texturii. Ar trebui să fie creat atunci când aveți mai multe texturi în aplicația dvs., astfel încât să puteți distinge cumva între ele. În caz contrar, atunci când textura este una singură, nu are nevoie de un identificator. În următorul exemplu, atunci când suprapuneți o textură pe o sferă, vom avea exact o textură și voi arăta ce funcții sunt opționale. Pentru moment, presupun că trebuie să utilizați mai multe texturi. Apropo, m-am uitat la multe exemple când scriu o carte. Printre acestea s-au numărat exemple din Cartea Roșie cunoscută, exemple din MSDN, Internet și alte surse, dar tot ceea ce sa referit la texturi a lucrat cu o singură textură. Pentru un program de exemplu elementar, desigur, o textura va face, dar pentru aplicatii serioase este putin probabil. Vrem să scriem aplicații serioase, așa că va trebui să folosim mai multe texturi. Funcția glGenTextures are două parametri în intrare. Primul specifică numărul de nume de identificatori de texturi pe care doriți să le creați. Al doilea parametru este un pointer la o serie de elemente int nesemnate. Numărul elementelor din matrice trebuie să se potrivească cu numărul specificat ca primul parametru. De exemplu, următorul cod creează zece nume de textură.

Păstrați identificatorii texturilor într-o matrice nu este întotdeauna convenabilă. Această metodă este potrivită pentru stocarea fundalurilor sau a tipurilor de pereți - cărămidă, piatră etc. În general, matricele stochează acele elemente, între care există ceva în comun. În cazul nostru, două imagini sunt conectate, deoarece sunt utilizate într-o singură cerere, așa că am creat două identificatori diferiți. Prin urmare, adăugați următorul cod la funcția principală.







Acum suntem atașați de textura fotografiei, adică face activ. Pentru aceasta, utilizați funcția glBindTexture. Primul parametru trebuie să fie GL_TEXTURE_2D sau GL_TEXTURE_1D. Arată dacă o imagine unidimensională sau bidimensională va funcționa. Toate exemplele se referă aici la texturi bidimensionale. Pentru o textură unidimensională, pur și simplu nu am găsit un exemplu frumos. Cu toate acestea, în Cartea Roșie există un exemplu cu textura unidimensională. Acolo fierbătorul este decorat cu o panglică roșie. Unde să luați aceste exemple și mai multe, consultați apendicele "A". Al doilea parametru glBindTexture este identificatorul pe care l-am creat mai sus cu glGenTextures. Acum adăugați apelul la această funcție în principal.

Acum trebuie să creăm textura în memorie. matrice octet structura AUX_RGBImageRec nu este chiar textura, deoarece textura o mulțime de opțiuni diferite. După ce am creat o textură, îi vom împărți anumite proprietăți. Printre parametrii textura specificați nivelul de detaliu, metoda de scalare și a legării textura cu un obiect. Nivelul de detaliu este necesar pentru a aplica textura obiectelor mai mici, adică Când zona de pe ecran este mai mică decât dimensiunea imaginii. Nivelul zero detaliu corespunde originalului 2nx2m dimensiunea imaginii, primul nivel - 2n-1x2m-1, la nivel k - 2n-kx2m-k. Numărul de niveluri corespunde cu min (n, m). Pentru a crea textura are două funcții glTexImage [1/2] D și DMipmaps gluBuild [1/2].

Principala diferență este că prima funcție creează o textura de un anumit nivel de detaliu și percepe doar imagini. a cărui mărime este un multiplu de gradul doi. A doua funcție este mai flexibilă. Acesta generează texturi la toate nivelele de detalii. De asemenea, această funcție nu necesită ca dimensiunea imaginii să fie mai mare decât puterea a două. Aceasta va comprima / întinde imaginea într-un mod adecvat, deși se poate dovedi că nu este în întregime adecvată. Voi folosi funcția glTexImage2D. Primul parametru al acestei funcții trebuie să fie GL_TEXTURE_2D. Al doilea este nivelul de detaliu. Avem nevoie de imaginea originală, deci nivelul de detaliere este zero. Al treilea parametru indică numărul de componente de culoare. Imaginea noastră este stocată în format RGB. Prin urmare, valoarea acestui parametru este de trei. Al patrulea și al cincilea parametru sunt lățimea și înălțimea imaginii. A șasea este lățimea graniței; nu vom avea o frontieră, deci valoarea acestui parametru este zero. În continuare, al șaptelea parametru este formatul pentru stocarea pixelilor în matrice - GL_RGB și tipul - GL_UNSIGNED_BYTE. În sfârșit, al optulea parametru este un indicator pentru o serie de date. De asemenea, trebuie să apelați funcția glPixelStorei și să specificați că alinierea în matricea de date este byte. Adăugați următorul cod la funcția principală.

Un rezultat similar poate fi obținut prin introducerea unui apel la gluBuild2DMipmaps cu parametrii enumerați mai jos.

Acum trebuie să setați parametrii texturii. În acest scop, funcția

Primul parametru are valoarea GL_TEXTURE_1D sau GL_TEXTURE_2D. Al doilea - pname - determină parametrul texturii, pe care îl veți schimba. Și al treilea parametru este valoarea de setare. Dacă ați folosit gluBuild2DMipmaps în loc de glTexImage2D, atunci nu este necesar să setați următorii parametri, deoarece texturi de toate nivelele de detaliu sunt deja formate, iar OpenGL va putea sa adune textura la nivelul dorit daca zona obiectului nu coincide cu zona texturii. În caz contrar, trebuie să adăugați următoarele linii:

Ați indicat că algoritmul GL_NEAREST este utilizat pentru a reduce și a mări textura. Aceasta înseamnă că culoarea celui mai apropiat pixel al elementului de textura devine culoarea pixelului obiectului pe care este aplicată textura. În loc de GL_NEAREST, puteți specifica GL_LINEAR, adică culoarea elementului obiectului va fi calculată ca media aritmetică a celor patru elemente ale texturii. Există patru alți algoritmi pentru calcularea culorii unui element obiect. Ele pot fi stabilite atunci când creați o textură cu toate nivelele de detaliu, deoarece Aplicați algoritmii GL_NEAREST și GL_LINEAR la unul sau două dintre cele mai apropiate nivele de detaliu.

De asemenea, puteți seta interacțiunea texturii cu obiectul. Există două moduri aici când utilizați cele trei componente color. Primul mod este implicit atunci când ia în considerare culoarea culoarea obiectului și textura. Culoarea rezultată se obține prin înmulțirea componentelor de culoare la textura componentelor de culoare obiect. De exemplu, în cazul în care textura de culoare - (r, g, b) și culoarea obiectului căruia i se aplică, - (r0, G0, b0), culoarea rezultată va - (r * r0, g * g0, b * b0) . În cazul în care culoarea obiectului negru - (0,0,0), atunci nu vei vedea pe textura, asa ca va fi totul negru. Al doilea mod de interacțiune, atunci când culoarea obiectului nu este luată în considerare. Culoarea rezultată este culoarea texturii. Acești parametri pot fi setați după cum urmează.

În mod implicit, așa cum am spus, este modul GL_MODULATE. Acum faceți textura activă a space_tex. Și repetă pentru ea același lucru. Aceasta finalizează crearea texturii. Rămâne să asociați coordonatele texturii cu coordonatele obiectului. Editați funcția de afișare astfel:

După cum probabil ați ghicit, glTexCoord2d compară coordonatele texturii cu vârfurile patrulaterului. Voi spune doar că colțul din stânga jos al texturii are coordonate (0,0), iar colțul din dreapta sus (1,1).

Opengl - lucrează cu imagini

Fișierul sursă poate fi găsit aici. Executivul este aici.
Fotografia mea e aici. Cerul înstelat este aici.

5.5 Repetarea texturii

Multiplicarea texturii pe plan nu este dificilă. Să editați ușor programul din secțiunea anterioară. Pentru a putea repeta textura, trebuie să setați parametrul GL_REPEAT pentru coordonatele S și T. Coordonata S a texturii este coordonatul orizontal, coordonata T fiind coordonata verticală. Al doilea parametru care poate fi setat pentru coordonate este GL_CLAMP. Se garantează că textura nu va fi duplicată. Valoarea implicită este GL_REPEAT. Dar, tot dau codul corespunzător pentru a vă putea imagina cum să setați acest parametru. În funcția principală, adăugați următoarele rânduri:

Acum editați funcția de afișare.

Funcția glTexCoord leagă coordonatele texturii de vârfurile obiectului. Așa cum am spus, colțul din stânga jos al texturii are o coordonată (0,0), iar colțul din dreapta sus (1,1). Dacă specificați o valoare mai mare decât una ca legare, textura se repetă. În exemplul nostru, am legat coordonata (0,0) texturii cu vârful inferior inferior al planului cu coordonatele (-4, -4) și coordonatele (3,2) ale texturii cu vârful de sus (4,4). Astfel, am obținut reproducerea texturii pe orizontală într-o cantitate de trei bucăți și pe verticală în număr de două bucăți. Am legat celelalte două vârfuri în consecință. Dacă specificați numere greșite, imaginea se va îndoi.

Opengl - lucrează cu imagini

Fișierul sursă poate fi găsit aici. Executivul este aici.
Fotografia mea e aici. Cerul înstelat este aici.

5.6 Exercițiul: "Rotirea texturii"

Rotiți planul cu fotografia în jurul axelor X și Y. De asemenea, lăsați-o să oscileze uniform de-a lungul axei Z de la 3 la 7.

Opengl - lucrează cu imagini

Fișierul sursă poate fi găsit aici. Executivul este aici.
Fotografia mea e aici. Cerul înstelat este aici.

5.7 Textura pe sferă

Aici voi arăta cum să lucrați cu o singură textură și să aplicați texturi în sfere. Creați un nou proiect numit sferă. Adăugați o variabilă globală.

În funcția principală, încărcați imaginea și creați o textură. Deoarece nu avem o singură textură în această aplicație, nu este nevoie să creați un identificator pentru aceasta.

Editați funcția de afișare. Aici sunteți familiarizați cu 4.1, cu excepția gluQuadricTexture. Această funcție permite sau dezactivează aplicarea unei texturi unui obiect 3D. Al doilea parametru este GL_TRUE sau GL_FALSE. Implicit, suprapunerea cu textură este dezactivată.

Opengl - lucrează cu imagini

Fișierul sursă poate fi găsit aici. Executivul este aici.
Fotografia mea e aici.

5.8 Exercițiul "Textura la viață"

Plasați textura pe cilindru, con, discuri și disc parțial. Ca imagine, luați mozaic, mazăre etc. pentru că ceva semnificativ nu va arăta foarte bine.

5.9 Textura pe ceainic

Textura poate fi impusă unui obiect de complexitate. Pentru a face acest lucru, trebuie să permiteți generarea automată a coordonatelor textură - glEnable (GL_TEXTURE_GEN_S) și glEnable (GL_TEXTURE_GEN_T). Apoi, trebuie să setați unul dintre cei trei algoritmi pentru generarea coordonatelor de textură.

  1. GL_OBJECT_LINEAR
  2. GL_EYE_LINEAR
  3. GL_SPHERE_MAP

Algoritmul de generare a coordonatelor este setat folosind funcția glTexGeni. Primul parametru al funcției indică tipul de coordonate pentru care algoritmul va fi setat. GL_S este o coordonată orizontală, GL_T este o coordonată verticală. Al doilea parametru al acestei funcții trebuie să fie GL_TEXTURE_GEN_MODE. Și al treilea parametru este unul dintre algoritmii de mai sus. Creați un alt proiect numit ceainic. Editați funcția principală, ca și în programul anterior, unde am aplicat o imagine în sferă. Adăugați acolo linia glEnable (GL_AUTO_NORMAL) pentru a face ca fierbătorul să arate mai bine. Acest mod permite calcularea vectorilor normali, ceea ce vă permite să obțineți imagini îmbunătățite, însă este nevoie de ceva timp. Și editați funcția de afișare, după cum se arată mai jos.

Opengl - lucrează cu imagini

Fișierul sursă poate fi găsit aici. Executivul este aici.
Fotografia mea e aici.

Opengl - lucrează cu imagini

Opengl - lucrează cu imagini

Fișierul sursă poate fi găsit aici. Executivul este aici.

5.10 Exercițiul "Textura pe tors"

Faceți același program numai pentru torus.







Trimiteți-le prietenilor: