Documente Academic
Documente Profesional
Documente Cultură
Textarea unui obiect este procesul de mapare a unei imagini 2D (sau, uneori, 3D)
pe un model 3D, astfel încât să puteți obține detalii mult mai detaliate în model
fără a utiliza o mulțime de vârfuri. Fără texturi, singura modalitate de a obține
nivelul de detaliere care poate fi obținută prin folosirea cartografierii texturilor ar fi
specificarea unui vârf colorat diferit pentru fiecare pixel al ecranului. După cum vă
puteți imagina, adăugarea detaliilor unui model în acest mod poate fi foarte
ineficientă.
Lumina este necesară pentru a seta starea de spirit pentru o scenă. De asemenea,
iluminarea furnizează un indiciu despre direcția și forma unui obiect. Cu utilizarea
corectă a iluminatului putem face o scenă întunecată și sumbră sau luminoasă și
veselă.
Materialele sunt folosite pentru a determina modul în care lumina interacționează
cu suprafața modelului. Un model poate apărea foarte strălucitor sau foarte
plicticos în funcție de proprietățile materiale ale modelului.
În acest articol, voi descrie modul de aplicare a texturării, iluminării și materialelor
utilizând OpenGL și GLSL.
Pentru acest articol, mă voi baza pe mai multe biblioteci ale părților terțe pentru a
simplifica programarea.
Gratuit OpenGL Utility Toolkit (FreeGLUT 2.8.1) : FreeGLUT este o
alternativă open-source la biblioteca OpenGL Utility Toolkit (GLUT). Scopul
librăriei GLUT este de a furniza funcționalitate fereastră, tastatură și mouse în
mod independent de platformă.
OpenGL Extension Wrangler (GLEW 1.10.0) : Biblioteca OpenGL Extension
Wrangler oferă accesibilitatea la nucleul OpenGL și extensiile care nu sunt
disponibile în fișierele și bibliotecile de antet OpenGL furnizate de
compilatorul dvs.
Biblioteca OpenGL Math (GLM 0.9.5) : Biblioteca matematică OpenGL este
scrisă pentru a fi în concordanță cu primitivele matematice furnizate de
limbajul de umbrire GLSL. Acest lucru face ca funcțiile de scriere a
matematicii în C ++ să fie foarte asemănătoare cu funcțiile de matematică pe
care le veți vedea în codul shader GLSL.
SOIL : Biblioteca simplă OpenGL Image este cea mai ușoară cale pe care o
cunosc în prezent pentru a încărca texturi în OpenGL. Cu o singură metodă,
puteți încărca texturi și obține un obiect textura OpenGL. Puteți obține cea
mai recentă versiune de SOIL aici: http://www.lonesock.net/soil.html
Încărcarea texturilor
Deoarece există atât de multe formate de imagine diferite, nu voi intra în detaliu
despre cum să încărcați texturile în memorie. În schimb, mă voi lipi de biblioteca
simplă de imagini OpenGL ( SOIL ) pentru încărcarea texturilor în memoria
grafică. SOIL este o librărie liberă de imagini open source care poate încărca
imagini din mai multe formate de imagine. Dacă utilizați context OpenGL 3.0 sau
mai avansat compatibil, asigurați-vă că descărcați versiunea SOIL pe care o
furnizez în secțiunea Dependență de mai sus, altfel veți întâlni probleme atunci
când SOIL încearcă să utilizeze o funcție OpenGL 1.x care nu este disponibilă în
OpenGL 3.0 și peste.
Pentru a încărca o textură utilizând SOIL necesită un cod foarte mic:
GLuint textureObject = 0;
textureObject = SOIL_load_OGL_texture( "path/to/file.JPG",
SOIL_LOAD_AUTO, SOIL_CREATE_NEW_ID, SOIL_FLAG_MIPMAPS );
Mai intai vom defini shaderul de vertex care va fi folosit pentru a transforma
nodurile geometriei noastre in spatiu clip astfel incat acestea sa poata fi consumate
de rasterizator.
Funcțiile de iluminare vor fi definite în shader-ul fragmentului mai târziu. Un lucru
important este să ne amintim că pentru a realiza o iluminare adecvată, toate
vectorii și pozițiile trebuie să fie în același "spațiu". Spațiul în care doriți să
efectuați iluminarea este alegerea dvs., dar ar trebui să fie consecventă. Pentru
această demonstrație, am ales să calculam iluminatul în spațiul mondial, dar este
posibil și realizarea iluminării în spațiu-obiect, spațiu luminos sau spațiu de
vizualizare.
Pentru a realiza iluminarea în spațiul mondial, trebuie să transformați poziția
vârfului și vertexul normal într-un spațiu mondial în shaderul de vârf și să treci
atributele de spațiu mondial la shader-ul fragmentului. În plus, trebuie să vă
asigurați că vă asigurați poziția ochiului (poziția camerei) și poziția luminii în
spațiul mondial în shader-ul fragmentului.
Mai întâi, să aruncăm o privire la shaderul de vârfuri:
1 #version 330 core
10
11 // Model, View, Projection matrix.
14
15 void main()
16 {
18
21 v2f_texcoord = in_texcoord;
22 }
Coordonarea texturii nu este utilizată pentru calculele de iluminare, astfel încât este pur și simplu trecută ca fiind la
shader-ul fragmentului.
FRAGMENT SHADER
Shaderul fragmentului este puțin mai complicat. Acceptă atributele vârfului de la
shaderul de vârf în plus față de variabilele uniforme care sunt folosite pentru a
defini proprietățile luminoase și materiale care vor fi folosite pentru a lumina
corect obiectul nostru.
Mai întâi, să aruncăm o privire la variabilele de intrare.
1 #version 330 core
5 in vec2 v2f_texcoord;
10
11 uniform vec4 MaterialEmissive;
15
17
19
23 {
26
32
35 vec4 H = normalize( L + V );
40
42 }
234 {
241
243 }
Deoarece toate obiectele din scenă (pământul, luna și soarele) pot fi reprezentate de
o sferă, vom genera o singură sferă utilizând un obiect Vertex Array și
îl vom folosi pentru a reda fiecare obiect din scenă.
Voi crea o sferă procedurală care conține coordonatele texturii și normele
vertexului necesare pentru a face obiectele cu iluminare și textura.
Voi descrie această funcție în trei părți:
1. Configurarea atributelor vertex
2. Configurarea tamponului index
3. Configurarea obiectului Array de vârf
ATRIBUTELE VERTEXELOR
Mai întâi vom configura atributele de vârf pentru sferă. Fiecare vârf al sferei va
avea trei atribute: poziția , coordonatele normale și textura . Sfera va fi centrată
la origine (0, 0, 0) și va avea o anumită rază. Numărul de segmente de-a lungul
axei principale a sferei este determinat de parametrul stivei, iar numărul de
segmente în jurul circumferinței fiecărui coș este determinat
de parametrul secțiunilor .
O vizualizare în sârmă a sferei noastre poate arăta ca imaginea de mai jos.
Axa principală a sferei merge de la un pol la celălalt. Stivele traversează axa principală, iar felii se deplasează în
jurul stivei.
main.cpp
246 {
249
252
258 {
262
264 {
268
272
276 }
277 }
În această funcție, axa Y locală a sferei este axa principală. Dacă doriți să utilizați
o axă diferită ca axă principală, schimbați pur și simplu componenta Y cu
componenta axei principale (de exemplu componenta Z).
TAMPON DE INDICE
Acum, avem atributele vertex pentru sfera noastră, dar nu putem să renderăm pur și
simplu vertexele în această ordine (dacă nu dorim doar să renderăm puncte)
deoarece trebuie să trecem geometria sferică la GPU folosind triunghiuri, trebuie
să construim un buffer tampon care să definească ordinea în care trebuie trimise
nodurile la GPU. De asemenea, trebuie să ne asigurăm că ordonarea vârfurilor din
fiecare triunghi este înfășurată corect folosind o ordine de înfășurare în sensul
invers acelor de ceasornic, astfel încât partea exterioară a sferei să nu fie distrusă
atunci când se utilizează sacrificarea din spate.
main.cpp
281
283 {
284 indicies.push_back( i );
287
289 indicies.push_back( i );
290 indicies.push_back( i + 1 );
291 }
Fiecare față a sferei este formată din două triunghiuri. Un triunghi superior și un triunghi inferior. Fiecare iterație
prin această buclă va crea 2 triunghiuri pentru fiecare față a sferei noastre. Dacă
schimbați axa principală așa cum este sugerat în pasul anterior, asigurați-vă că
schimbați ordinea în care sunt împinse vârfurile în tamponul index pentru a se
potrivi. De exemplu, dacă realizați axa Z axa principală, schimbați indicii 2 și 3
pentru fiecare triunghi în această metodă.
Ultimul pas este de a crea obiectul Vertex Array care încapsulează atributele
vertexului sferei și tamponul index.
296
299
304
309
314
317
318 glBindVertexArray( 0 );
321
323 }
Principal
328
332
334 InitGLEW();
335
339
342
344 shaders.push_back(vertexShader);
345 shaders.push_back(fragmentShader);
346
349
350 // Retrieve the location of the color uniform variable in the simple shader program.
Pe liniile 337 și 338, cele două texturi care vor fi folosite pentru a face pământul și
luna în scena noastră sunt
353 vertexShader = LoadShader( GL_VERTEX_SHADER, "../data/shaders/texturedDiffuse.vert" );
355
356 shaders.clear();
357
358 shaders.push_back(vertexShader);
359 shaders.push_back(fragmentShader);
362
366
370
373
379
380 glutMainLoop();
381 }
400 {
404 if ( g_vaoSphere == 0 )
405 {
407 }
Sfera VAO este creată dintr-o sferă cu 32 de felii și 32 de stive. Desigur, puteți
crea o sferă mai detaliată, cu mai multe felii și stive, dacă credeți că această sferă
nu are suficiente detalii, dar pentru scopurile mele acest lucru pare să fie
suficient. Dacă aș fi fost ambițios, aș avea funcția SolidSphere să returneze un
obiect de sferă care stochează numărarea indexului și ID-urile VBO-urilor interne
care sunt folosite pentru a stoca geometria sferei, dar care nu sunt necesare pentru
implementarea minimă aici. Vă încurajez să creați un obiect sferic pe cont propriu,
care încapsulează datele sferei.
Următoarea parte a funcției de randare va configura proprietățile uniforme în
shader și va face soarele, pământul și luna. Să tragem mai întâi soarele folosind
programul Shadow Shader (de vreme ce soarele nu este texturat sau aprins, nu este
nevoie să folosim programul Shurer TextureLit pentru asta).
main.cpp
413 glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
414
416 glBindVertexArray(g_vaoSphere);
417
424
Pe liniile 409-411 sunt definite câteva variabile constante. Aceste valori vor fi
folosite pentru a seta variabilele uniforme în shadere.
Pe linia 413, buffer-ul de culoare și buffer-ul de adâncime al framebuffer-ului legat
în prezent sunt șterse.
Pe linia 416, VAO pentru obiectul sferic este legat. Acest obiect de sferă va fi
folosit pentru a face soarele, pământul și luna, astfel încât să nu mai trebui să îl
deblocăm din nou până la sfârșitul funcției de randare.
Soarele va fi redat folosind un shader de culoare simplu. Nu se va aplica lumina
sau textura la soare. Este pur și simplu o minge albă în spațiu. Pentru a face
soarele, legăm programul simplu de shader pe linia 418.
Pentru a face soarele, trebuie să setăm MVP și variabilele uniforme de culoarecare
sunt definite în programul shader. Pentru a stabili o uniformă de matrice,
folosim glUniformMatrix4fv și pentru a seta o variabilă uniformă a vectorului cu
4 componente utilizăm glUniform4fv .
Pe linia 419, matricea mondială pentru soare este calculată separat pentru că vom
folosi poziția lumii soarelui pentru a seta poziția sursei de lumină în etapele
următoare.
Pe linia 425, sfera reprezentând soarele este redată
folosind metoda glDrawElements .
Apoi vom trage pământul.
main.cpp
430
435
439
443
449
454
457
460
465
468 glBindVertexArray(0);
469 glUseProgram(0);
470 glBindTexture( GL_TEXTURE_2D, 0 );
471
472 glutSwapBuffers();
473 }