Shtëpi / Çati / ndriçimi opengl. Mësime dhe shembuj programimi Array(). Si funksionon ndriçimi

ndriçimi opengl. Mësime dhe shembuj programimi Array(). Si funksionon ndriçimi

Siç mund ta shihni, ne kemi prezantuar një matricë shtesë normale, është e nevojshme për të përkthyer normalet e objektit nga sistemi koordinativ lokal i objektit në atë botëror, kjo është e nevojshme për llogaritjen e ndriçimit në sistemin koordinativ botëror.

Duhet të theksohet se kur përdorni FFP OpenGL, ndriçimi u llogarit jo në sistemin e koordinatave botërore, por në pamje. Sipas mendimit tim, kjo nuk është shumë e përshtatshme, sepse. sistemi i koordinatave të pamjes është i lidhur me kamerën, dhe është i përshtatshëm për të vendosur burimet e dritës në sistemin e koordinatave botërore, dhe është aty që kryhet e gjithë llogaritja.

Llogaritja e ndriçimit

Ngjyrosja Phong përdoret për llogaritjet e ndriçimit në këtë tutorial. Kuptimi kryesor i modelit është se ndriçimi përfundimtar i objektit përbëhet nga tre komponentë:

  • Drita e sfondit (ambienti)
  • Drita e shpërndarë (e shpërndarë)
  • Drita e reflektuar (speculare)

Përveç këtyre parametrave, ne do të shtojmë shkëlqimin tonë material (emetim), ky parametër ju lejon të nënvizoni objektin edhe nëse ai nuk ndriçohet nga ndonjë burim drite.

Prandaj, secili nga komponentët llogaritet duke marrë parasysh parametrat e burimit të dritës dhe materialit të objektit. Mund të merrni më shumë informacion mbi këtë model ndriçimi në këtë shënim.

Llogaritja e ndriçimit mund të jetë ose ndriçim për kulm ose ndriçim për piksel. Në këtë mësim, ne do të shqyrtojmë ndriçimin pixel-nga-pixel, ju lejon të zbutni mungesën e detajeve në modelet poligonale dhe të llogarisni më saktë ndriçimin në secilën pikë të objektit. Llogaritja kryesore e ndriçimit për piksel bëhet në shaderin e fragmentit.

Para se të vazhdoni me llogaritjen e ndriçimit, është e nevojshme të llogaritni dhe të kaloni disa parametra të kulmit nga shaderi i kulmit në hijezuesin e fragmentit:

  • Normale në sipërfaqen e objektit në kulm (normale)
  • Drejtimi i dritës rënëse, nga kulmi në burimin e dritës (drejtimi i dritës)
  • Shikimi i drejtimit, nga kulmi në vëzhgues (drejtimi i shikimit)
  • Distanca nga burimi i pikës së dritës në majë (distanca)

Normalja në sipërfaqen e objektit dhe drejtimi i dritës rënëse përdoren për llogaritjen e dritës difuze (të përhapur) dhe të reflektuar (speculare), megjithatë, për të llogaritur dritën e reflektuar, duhet të dini edhe drejtimin e shikimit të vëzhguesit. . Distanca nga lart në burimin e dritës është e nevojshme për të llogaritur faktorin e përgjithshëm të dobësimit. Shaderi i kulmit do të duket kështu:

#version 330 core #define VERT_POSITION 0 #define VERT_TEXCOORD 1 #define VERT_NORMAL 2 layout(location = VERT_POSITION) në pozicionin vec3; faqosja (vendndodhja = VERT_TEXCOORD) në vec2 texcoord; faqosja (vendndodhja = VERT_NORMAL) në vec3 normale; // parametrat e transformimit Struktura uniforme Transformimi ( mat4 model; mat4 viewProjection; mat3 normal; vec3 viewPosition; ) transform; // pika parametrat e burimit të dritës Struktura uniforme PointLight ( pozicioni vec4; vec4 ambienti; vec4 i përhapur; vec4 specular; vec3 dobësimi; ) dritë; // parametrat për shaderin e fragmentit nga kulmi ( vec2 texcoord; vec3 normal; vec3 lightDir; vec3 viewDir; distanca notuese; ) Vert; kryesor i zbrazët (i zbrazët) ( // përkthen koordinatat e kulmit në sistemin e koordinatave botërore vec4 kulm = transformim.model * vec4(pozicioni, 1 .0 ); // drejtimi nga kulmi në burimin e dritës në sistemin e koordinatave botërore vec4 dritëDir = dritë.pozicioni - kulm; // kaloni disa parametra te shaderi i fragmentit // kaloj koordinatat e teksturës vert.texcoord = texcoord; // kalojnë normalen në sistemin e koordinatave botërore vert.normal = transformoj.normal * normal; // kaloni drejtimin te burimi i dritës Vert.dritëDir = vec3(dritë dritë); // kalojë drejtimin nga kulmi te vëzhguesi në sistemin koordinativ botëror Vert.viewDir = transform.viewPosition - vec3(kulmi) ; // kaloni distancën nga kulmi në burimin e dritës Vert.distanca = gjatësia(drita e dritës) ; // konverton koordinatat e kulmit në homogjene gl_Pozicioni = transformim.pamjeProjeksioni * kulmi; )

Pa një burim drite, imazhi nuk është i dukshëm. Për të inicializuar burimin dhe për të mundësuar mbajtësin për llogaritjen e efektit të burimit në objekte, mjafton të ekzekutoni komandat e mëposhtme: glEnable(gl_lighting);//aktivizo modalitetin e analizës së ndriçimit

GlEnable(gl_light0); // përfshijnë një burim specifik (null) në skenë, me karakteristikat e tij

Funksioni Disable() përdoret për të çaktivizuar burimin. Burimi i parazgjedhur i dritës ndodhet në hapësirë ​​me koordinata (0,0,∞). Mund të krijoni një burim drite në çdo pikë të hapësirës së imazhit.

Katër lloje burimesh drite mbështeten në bibliotekën OpenGl:

  • ndriçimi i sfondit (ndriçimi i ambientit),
  • burimet pika,
  • prozhektorët (prozhektorët),
  • burimet e largëta të dritës (drita e largët).
Çdo burim drite ka grupin e vet të karakteristikave.
Karakteristikat e burimit të dritës korrespondojnë me parametrat e modelit Phong.
Për të vendosur parametrat e vektorit, përdoret funksioni glLightfv(), i cili ka formatin e mëposhtëm:

glLightfv (burimi, parametri, treguesi_te_array);

Ekzistojnë katër parametra vektoriale që përcaktojnë pozicionin dhe drejtimin e rrezeve të burimit dhe përbërjen e ngjyrave të përbërësve të tij - sfond, difuzion dhe specular.
Për të vendosur parametra skalar në OpenGL, përdorni funksionin glLightf():

glLightf (burimi, parametri, vlera);

Le të, për shembull, kërkohet të përfshihet në skenë burimi GL_LIGHT0, i cili duhet të jetë i vendosur në pikën (1.0, 2.0, 3.0). Pozicioni i burimit ruhet në program si një pikë në koordinata homogjene:

GLfloat light0_pos=(1.0, 2.0, 3.0, 1.0);

Nëse përbërësi i katërt i kësaj pike është i barabartë me zero, atëherë burimi i pikës kthehet në një të largët, për të cilin vetëm drejtimi i rrezeve është i rëndësishëm:

GLfloat light0_dir=(1.0, 2.0, 3.0, 0.0);

Më pas, përcaktohet përbërja e ngjyrave të sfondit, difuzioni dhe përbërësit specularë të burimit. Nëse në këtë shembull burimi ka një komponent specular të bardhë dhe përbërësit e sfondit dhe difuzionit duhet të jenë të kuq, atëherë fragmenti i programit që formon burimin duket si ky:

GLfloat diffise0= (1.0, 0.0, 0.0, 1.0);

GLfloat ambient0=(1.0, 0.0, 0.0, 1.0);

GLfloat specular0=(1.0, 1.0, 1.0, 1.0);

GlEnable (GL_LIGHTING);

GlEnable (GL_LIGHT0);

GlLightfv(GL_LIGHT0, GL_POSITION, dritë0_pos);

GlLightfv(GL_LIGHT0, GL_AMBIENT, ambient0);

GlLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse0);

GlLightfv(GL_LIGHT0, GL_SPECULAR, specular0);

Ju gjithashtu mund të përfshini ndriçimin global të sfondit në skenë, i cili nuk shoqërohet me ndonjë burim të veçantë drite. Nëse, për shembull, dëshironi të nënvizoni në mënyrë të zbehtë të gjitha objektet në skenë me të bardhë, duhet të përfshini fragmentin e mëposhtëm të kodit në programin tuaj:

GLfloat global_ambient=(0.1, 0.1, 0.1, 1.0);

GlLightModelfv(GL_LIGHT_MODEL_AMBIENT, global_ambient);

Në modelin e ndriçimit, termi që merr parasysh distancën nga burimi ka formën:

K= 1/(a+ b*d+ c*d^2)

Dhe komponentë konstante, lineare dhe kuadratike. Koeficientët përkatës për çdo burim vendosen individualisht duke përdorur funksionin e vendosjes së parametrave skalar, për shembull:

GlLightf(GL_LIGHT0, GL_CONSTANT_ATTENATION, a);

Për të kthyer një burim pikë në një qendër të vëmendjes, duhet të specifikoni drejtimin e rrezes së dritës së vëmendjes (GL_SPOT_DIRECTION), indeksin e funksionit të shpërndarjes së intensitetit (GL_SPOT_EXPONENT) dhe këndin e shpërndarjes së rrezes (GL_SPOT_CUTTOF). Këto parametra vendosen duke përdorur funksionet glLightf() dhe glLightfv().

Parametrat e vendosur për burimet e paracaktuara të dritës janë paraqitur në tabelën 3.

Cilësimet e parazgjedhura për dritat

Tabela 3

Emri i parametrit Vlera e paracaktuar përmbajtja
GL_AMBIENT (0.0, 0.0, 0.0, 1.0) intensiteti RGBA i ambientit të dritës
GL_DIFFUSE (1.0, 1.0, 1.0, 1.0) intensiteti difuz RGBA i dritës
GL_SPECULAR (1.0, 1.0, 1.0, 1.0) intensiteti specular RGBA i dritës
GL_POSITION (0.0, 0.0, 1.0, 0.0) (x, y, z, w) pozicioni i dritës
GL_SPOT_DIRECTION (0.0, 0.0, -1.0) (x, y, z) drejtimi i vëmendjes
GL_SPOT_EXPONENT 0.0 eksponent në qendër të vëmendjes
GL_SPOT_CUTOFF 180.0 këndi i ndërprerjes së dritës së vëmendjes
GL_CONSTANT_ATTENUATION 1.0 faktor zbutjeje konstante
GL_LINEAR_ATTENUATION 0.0 faktori linear i dobësimit
GL_QUADRATIC_ATTENUATION 0.0 faktori kuadratik i dobësimit

Ndriçimi në OpenGL ES është një veçori e këndshme që mund t'u japë lojërave 3D një prekje të këndshme. Për të përdorur këtë funksionalitet, së pari duhet të kuptojmë modelin e ndriçimit OpenGL ES.

Si funksionon ndriçimi

Le të mendojmë se si funksionon ndriçimi. Së pari na duhet një burim drite që lëshon dritë. Do t'ju duhet gjithashtu një objekt i ndriçuar. Së fundi, ne kemi nevojë gjithashtu për një sensor, si sytë ose një aparat fotografik, që merr fotone që dërgohen nga burimi i dritës dhe reflektohen nga objekti. Ndriçimi ndryshon ngjyrën e perceptuar të një objekti në varësi të: llojit të burimit të dritës; ngjyra ose intensiteti i burimit të dritës; pozicioni i burimit të dritës dhe drejtimi i tij në lidhje me objektin e ndriçuar; materiali dhe tekstura e objektit.

Intensiteti me të cilin drita reflektohet nga një objekt varet nga shumë faktorë. Faktori më i rëndësishëm të cilit i kushtojmë vëmendje është këndi në të cilin rrezja e dritës godet sipërfaqen. Sa më afër të jetë ky kënd me një kënd të drejtë, aq më i madh është intensiteti me të cilin drita do të reflektohet nga objekti. Kjo është ilustruar në fig. 11.1.

Sapo një rreze drite godet një sipërfaqe, ajo do të kërcejë në dy drejtime të ndryshme. Shumica e dritës do të reflektohet në mënyrë difuze. Kjo do të thotë që rrezet e reflektuara të dritës shpërndahen në mënyrë të pabarabartë në mënyrë të rastësishme mbi sipërfaqen e objektit. Disa rreze reflektohen në mënyrë spekulative. Kjo do të thotë që rrezet e dritës do të kthehen mbrapsht sikur të ishin duke goditur një pasqyrë të përsosur. Në fig. Figura 11.2 tregon ndryshimin midis reflektimeve difuze dhe spekulare.

Oriz. 11.1. Sa më afër këndit të drejtë, aq më i madh është intensiteti i dritës së reflektuar.

Oriz. 11.2. Reflektime difuze dhe spekulare

Reflektimi spekulor do të shfaqet si pika kryesore në objekte. Nëse drita do të kërcejë nga një objekt në një mënyrë spekulare varet nga materiali nga i cili është bërë. Objektet me sipërfaqe të pabarabarta ose të përafërta të ngjashme me lëkurën kanë më shumë gjasa të mos kenë pika spekulare. Objektet që kanë një sipërfaqe të lëmuar si qelqi ose mermeri do të tregojnë këto objekte të lehta. Natyrisht, qelqi ose mermeri nuk janë krejtësisht të lëmuar, por në krahasim me drurin ose lëkurën e njeriut, ato janë.

Kur drita godet një sipërfaqe, reflektimi i saj gjithashtu ndryshon ngjyrën në varësi të përbërjes kimike të objektit që ndriçohet. Objektet që na duken të kuqe reflektojnë vetëm pjesë të kuqe të dritës dhe thithin të gjitha frekuencat e tjera. Një objekt i zi është ai që thith pothuajse të gjithë dritën që e godet.

OpenGL ES ju lejon të simuloni sjelljen e jetës reale duke përcaktuar burimet e dritës dhe materialet e objektit.

Burimet e dritës

Ne jemi të rrethuar nga një shumëllojshmëri e gjerë burimesh drite. Dielli po dërgon vazhdimisht fotonet e tij. Monitorët lëshojnë dritë që na rrethon me një shkëlqim të këndshëm gjatë natës. Llambat dhe fenerët na ndihmojnë të shmangim përplasjet me objekte të ndryshme në errësirë. OpenGL ES ju lejon të krijoni katër lloje burimesh drite.

Drita e prapme. Ai nuk është një burim drite në vetvete, por rezultat i shfaqjes së fotoneve nga burime të tjera drite. Së bashku, këto fotone të rastësishme krijojnë një nivel të vazhdueshëm ndriçimi që nuk ka drejtim dhe ndriçon të gjitha objektet në mënyrë të barabartë.

Burimet e dritës me pikë. Ata kanë një pozicion në hapësirë ​​dhe lëshojnë dritë në të gjitha drejtimet. Për shembull, një llambë është një burim pikash drite.

Burimet e drejtimit të dritës. Shprehur si udhëzime në OpenGL ES. Ata supozohet se janë pafundësisht larg. Idealisht, Dielli mund të jetë një burim i tillë. Mund të supozojmë se të gjitha rrezet e dritës që vijnë nga Dielli godasin Tokën në të njëjtin kënd për shkak të distancës midis Tokës dhe Diellit.

Oh llambat. Këto drita janë të ngjashme me dritat me pikë në atë që kanë një pozicion fiks në hapësirë. Përveç kësaj, ata kanë një drejtim në të cilin lëshojnë rrezet e dritës. Ata krijojnë një kon të lehtë të kufizuar nga një rreze e caktuar. Një shembull i një burimi të tillë drite është një llambë rruge.

Ne do të shqyrtojmë vetëm dritën e prapme, si dhe burimet e dritës së pikës dhe drejtimit. Dritat shpesh janë të vështira për t'u përdorur në GPU-të e kufizuara të pajisjeve Android për shkak të mënyrës se si llogaritet ndriçimi në OpenGL ES. Së shpejti do ta kuptoni pse është kështu.

Përveç pozicionit dhe drejtimit të burimit të dritës, OpenGL ES ju lejon të përcaktoni ngjyrën ose intensitetin e dritës. Këto karakteristika shprehen duke përdorur ngjyrën RGBA. Sidoqoftë, OpenGL ES kërkon që të përcaktohen katër ngjyra të ndryshme për të njëjtin burim në vend të vetëm një.

Theksoj - Intensiteti/ngjyra që kontribuon në hijezimin e objektit. Objekti do të ndriçohet në mënyrë të barabartë nga të gjitha drejtimet, pavarësisht nga pozicioni ose orientimi i tij në lidhje me burimin e dritës.

Difuze - intensiteti/ngjyra e dritës që do të ndriçojë objektin pas llogaritjes së reflektimit difuz. Skajet e objektit që nuk janë përballë burimit të dritës nuk do të ndriçohen, ashtu si në jetën reale.

Spekulare - intensitet/ngjyrë e ngjashme me ngjyrën e shpërndarë. Megjithatë, ajo prek vetëm ato pika të objektit që kanë një orientim të caktuar në lidhje me burimin e dritës dhe sensorin.

Emissive është një llogaritje shumë komplekse e ngjyrave që ka përdorim jashtëzakonisht të kufizuar në aplikacionet e fizikës në botën reale, kështu që ne nuk do ta mbulojmë këtu.

Më shpesh, ne do të përdorim intensitetet difuze dhe spekulare të burimit të dritës, dhe do të specifikojmë vlerat e paracaktuara për dy të tjerët. Gjithashtu, në shumicën e rasteve ne do të përdorim të njëjtën ngjyrë RGBA si për intensitetin e përhapur ashtu edhe për atë spekular.

Materiale

Të gjitha objektet në botën tonë janë bërë nga disa materiale. Çdo material përcakton se si drita që godet një objekt do të reflektohet dhe do të ndryshojë ngjyrën e dritës së reflektuar. OpenGL ES ju lejon të përcaktoni të njëjtat katër ngjyra RGBA për një material si për një burim drite.

Theksimi - Një ngjyrë që përzihet me ngjyrën e sfondit të çdo burimi drite në skenë.

Difuze - Një ngjyrë që kombinohet me ngjyrën e përhapur të çdo burimi drite.

Spekulare - Një ngjyrë që kombinohet me ngjyrën spekulare të çdo burimi drite. Përdoret për të krijuar pika kryesore në sipërfaqen e një objekti.

Emisionuese - ne vazhdojmë ta injorojmë këtë lloj ngjyre, pasi praktikisht nuk përdoret në kontekstin tonë.

Figura 11.3 ilustron tre llojet e para të vetive të materialit/dritës: drita e prapme, difuze dhe spekulare.

Oriz. 11.3. Llojet e ndryshme të materialeve/dritat: vetëm ndriçimi i pasëm (majtas), vetëm difuz (në mes), ndriçimi i pasmë dhe ngjyra difuze me thekse spekulare (djathtas)

Në fig. 11.3 tregon efektin e vetive të ndryshme të materialeve dhe burimeve të dritës në ngjyrë. Drita e prapme ndriçon madhësinë në mënyrë të barabartë. Drita e shpërndarë do të reflektohet në varësi të këndit në të cilin rrezet e dritës bien mbi objektin; zonat që janë drejtpërsëdrejti përballë burimit të dritës do të ndriçohen më shumë, zonat që drita nuk mund të arrijë do të jenë të errëta. Në imazhin e duhur, mund të shihni një kombinim të dritës së prapme, ambientit dhe dritës spekulare. Drita spekulare manifestohet si pika të bardha në sferë.

Si OpenGL ES llogarit ndriçimin: Normalet e kulmit

Ju e dini se intensiteti i dritës së reflektuar nga një objekt varet nga këndi i saj i rënies në objekt. OpenGL ES përdor këtë fakt për të llogaritur ndriçimin. Ai përdor normalet e kulmit për këtë, të cilat duhet të përcaktohen në kod në të njëjtën mënyrë si koordinatat e teksturës ose ngjyrat e kulmit. Në fig. Figura 11.4 tregon një sferë dhe normalet e kulmit të saj.

Oriz. 11.4. Sfera dhe kulmi i saj janë normale

Normalet janë vektorë njësi që tregojnë drejtimin me të cilin përballet sipërfaqja. Në rastin tonë, sipërfaqja është një trekëndësh. Në vend që të përcaktojmë një sipërfaqe normale, ne përcaktojmë një kulm normal. Dallimi midis këtyre normaleve është se kulmi normal mund të mos tregojë në të njëjtin drejtim si sipërfaqja normale. Kjo shihet qartë në Fig. 11.4, ku çdo kulm normal është normalja mesatare e të gjithë trekëndëshave të cilëve u përket kulmi. Ky mesatarizimi bëhet për të krijuar një hije të qetë të objektit.

Kur jepni një objekt duke përdorur normale ndriçimi dhe kulmi, OpenGL ES do të përcaktojë këndin midis çdo kulmi dhe burimit të dritës. Nëse e njeh këtë kënd, ai mund të llogarisë ngjyrën e kulmit në bazë të vetive të materialit. Rezultati përfundimtar është ngjyra e çdo kulmi, e cila më pas aplikohet në çdo trekëndësh në kombinim me ngjyrat e llogaritura të kulmeve të tjera. Kjo ngjyrë e përdorur do të kombinohet me çdo transformim teksture që aplikojmë në objekt.

Tingëllon mjaft e frikshme, por në fakt nuk është edhe aq e keqe. Ne duhet të mundësojmë përdorimin e ndriçimit dhe të përcaktojmë burimet e dritës, materialin e objektit të dhënë dhe normalet e kulmit (përveç parametrave të kulmit që përcaktojmë normalisht, të tilla si koordinatat e pozicionit ose teksturës). Le të shohim se si mund të bëhet kjo me OpenGL ES.

Në praktikë

Tani le të përfundojmë të gjithë hapat e nevojshëm për të punuar me ndriçimin duke përdorur OpenGL ES. Le të krijojmë disa klasa të vogla ndihmëse që do ta bëjnë pak më të lehtë punën me dritat dhe t'i vendosim në paketën com.badlogi me .androi dgames.framework.gl.

Leja dhe ndalimi i ndriçimit

Ashtu si me shtetet e tjera të OpenGL ES, funksionaliteti i emërtuar duhet të aktivizohet së pari. Kjo mund të bëhet si kjo:

Pas kësaj, ndriçimi do të aplikohet në të gjitha objektet e paraqitura. Për të marrë rezultatin, duhet të përcaktoni burimet dhe materialet e dritës, si dhe normalet e kulmit. Sapo të përfundojmë vizatimin e të gjitha objekteve të nevojshme, ndriçimi mund të fiket:

Përcaktimi i burimeve të dritës

OpenGL ES ofron 4 lloje burimesh drite: dritën e prapme, pikën, drejtimin dhe ndriçuesin. Le të shohim se si të identifikojmë tre të parat. Në mënyrë që pajisjet të jenë efektive dhe të duken mirë, çdo model duhet të përbëhet nga një numër i madh trekëndëshash. Për shumë nga pajisjet mobile të sotme, kjo nuk është e mundur.

OpenGL ES ju lejon të përcaktoni një maksimum prej 8 dritash në të njëjtën kohë, si dhe një burim global drite. Secila nga 8 dritat ka një ID, nga GL10.GL LIGHT0 në GL10.GL LIGHT7. Nëse dëshironi të ndryshoni vetitë e njërës prej këtyre dritave, mund ta bëni këtë duke përcaktuar ID-në përkatëse.

Mund të aktivizoni burimet e ndriçimit duke përdorur sintaksën e mëposhtme:

Më pas, OpenGL ES do të marrë vetitë e këtij burimi drite dhe do t'i zbatojë ato në të gjitha objektet e paraqitura. Nëse duhet të çaktivizojmë burimin e dritës, mund ta bëjmë këtë me deklaratën e mëposhtme:

Theksimi është një rast i veçantë sepse nuk ka një ID. Mund të ketë vetëm një theksim për skenën OpenGL ES. Le ta shqyrtojmë këtë burim drite në më shumë detaje.

Drita e prapme

Drita e prapme është një lloj i veçantë ndriçimi. Nuk ka pozicion apo drejtim, vetëm një ngjyrë që zbatohet për të gjitha objektet e ndriçuara në të njëjtën mënyrë. OpenGL ES ju lejon të përcaktoni një theks global si kjo:

Ambi entCol ose grupi përmban vlerat RGBA të ngjyrës së dritës, të paraqitura si numra me pikë lundruese që variojnë nga 0 në 1. Metoda gl LightModel fv merr si parametër të parë një konstante duke specifikuar se ne duam të vendosim ngjyrën e burimit të dritës së sfondit , një grup numrash me pikë lundruese An që përmban ngjyrën e burimit dhe kompensimin për grupin e notave nga të cilat metoda do të fillojë të lexojë vlerat RGBA. Le të vendosim kodin që zgjidh këtë problem në një klasë të vogël. Kodi i tij tregohet në Listën 11.2.

Listimi 11.2. Klasa AmbientLight.java. abstraksion i thjeshtë i theksimit global të OdenGL ES

Gjithçka që po bëjmë është të ruajmë ngjyrën e theksuar në një grup notash dhe të ofrojmë dy metoda, njëra e përdorur për të vendosur ngjyrën dhe tjetra për t'i thënë OpenGL ES që të përdorë atë ngjyrë të veçantë. Ngjyra e paracaktuar është gri.

Burimet e dritës në pikë

Dritat e pikës kanë një pozicion dhe sfond, ngjyrë/intensitet të përhapur dhe specular (ne nuk e konsiderojmë ngjyrën/intensitetin emetues). Ju mund të përcaktoni lloje të ndryshme ngjyrash si më poshtë:

Parametri i parë është identifikuesi i burimit të dritës. Në këtë rast, ne përdorim burimin e katërt. Parametri tjetër specifikon atributin që duam të ndryshojmë. Parametri i tretë është një grup notash që përmban vlerat RGBA, dhe i fundit është një kompensim në këtë grup. Përcaktimi i pozicionit të burimit është po aq i lehtë:

Ne përsëri përcaktojmë atributin që duam të ndryshojmë (në këtë rast pozicionin), një grup prej katër elementësh që përmbajnë koordinatat x-, y- dhe z të burimit të dritës në botën që krijohet. Vini re se elementi i katërt i grupit duhet të jetë i barabartë me një nëse burimi i dritës ka një pozicion. Le ta vendosim këtë në një klasë ndihmëse. Kodi i tij është në Listën 11.3.

Listimi 11.3. Klasa Point.Light.java, një abstraksion i thjeshtë i dritës së pikës OpenGL ES

Klasa jonë ndihmëse përmban përbërësit e ngjyrave të sfondit, të përhapur dhe specularë të dritës, si dhe pozicionin (elementi i katërt është një). Përveç kësaj, ne ruajmë identifikuesin e fundit të përdorur për një burim të caktuar, kështu që bëhet e mundur krijimi i një metode disableO që do të fikë dritën nëse është e nevojshme. Kemi gjithashtu metodën enableO, e cila merr një shembull të klasës GL10 dhe një ID të lehtë (për shembull, GL10.GL LIGHT6). Ai mundëson përdorimin e ndriçimit, vendos atributet e tij dhe ruan identifikuesin e përdorur. Metoda disableO thjesht çaktivizon përdorimin e ndriçimit duke përdorur grupin e anëtarëve të klasës 1ast.Ligh.tId në metodën enable.

Ne përdorim parazgjedhje të arsyeshme për ngjyrat e sfondit, të përhapura dhe spekulare kur inicializojmë grupet e anëtarëve të klasës. Drita do të jetë e bardhë dhe nuk do të krijojë asnjë shkëlqim, sepse komponenti i saj spekulor është i zi.

Burimet e drejtimit të dritës

Burimet e drejtimit të dritës janë pothuajse identike me ato pika. I vetmi ndryshim është se ata kanë një drejtim në vend të një pozicioni. Mënyra se si shprehet drejtimi është disi konfuze. Në vend që të përdorim një vektor për të treguar drejtimin, OpenGL ES pret që ne të përcaktojmë një pikë të vetme. Më pas drejtimi do të përcaktohet duke përdorur një vektor që lidh këtë pikë dhe origjinën. Fragmenti i mëposhtëm ju lejon të krijoni një dritë drejtimi që vjen nga ana e djathtë e botës:

Ne mund ta shndërrojmë atë në një vektor:

Pjesa tjetër e atributeve, si ngjyra e sfondit ose e ambientit, janë identike me ato të një drite pikë. Lista 11.4 tregon kodin për një klasë të vogël ndihmëse të përdorur për të krijuar dritat e drejtimit.

Listimi 11.4. Klasa Directi onLi ght.java, një abstraksion i thjeshtë i dritave të drejtimit në OpenGL ES

Kjo klasë ndihmëse është pothuajse identike me klasën PointLight. Dallimi i vetëm është se në direkti në grup, elementi i katërt është një. Përveç kësaj, në vend të metodës setPosition, është shfaqur metoda setDirecti on. Kjo ju lejon të specifikoni drejtimin, për shembull: (-1; 0; 0), në këtë rast, drita do të vijë nga ana e djathtë. Brenda metodës, të gjithë komponentët e vektorit ndryshojnë shenjën e tyre, kështu që ne e kthejmë drejtimin në formatin e pritur nga OpenGL ES.

Ne përcaktojmë materialet

Një material përcaktohet nga disa atribute. Ashtu si me çdo objekt tjetër OpenGL ES, një material është një gjendje që do të jetë aktive derisa ta ndryshojmë përsëri ose derisa konteksti OpenGL ES të humbasë. Për të vendosur atributet aktuale të materialit, mund të bëjmë sa më poshtë:

Si zakonisht, ne duhet të përcaktojmë sfondin RGBA, ngjyrat e përhapura dhe speculare. Kjo mund të bëhet në të njëjtën mënyrë si më parë - duke përdorur grupe numrash me pikë lundruese, të përbërë nga katër elementë.

Kombinimi i këtyre veprimeve në një klasë ndihmëse është shumë e lehtë. Ju mund ta shihni rezultatin në Listimin 11.5.

Listimi 11.5. Materiali i klasës Java, një abstraksion i thjeshtë i materialeve OpenGL ES

As këtu nuk ka asgjë për t'u habitur. Ne thjesht mbajmë tre komponentët që përshkruajnë materialin dhe ofrojmë funksione për të vendosur vlerat e tyre dhe një metodë aktivizimi që i kalon ato në OpenGL ES.

OpenGL ES ka një tjetër mashtrim në mëngë kur bëhet fjalë për materialet. Zakonisht përdor diçka që quhet ngjyra e materialit në vend të metodës glMaterialfvO. Kjo do të thotë që në vend të sfondit dhe ngjyrave difuze të përcaktuara nga metoda glMaterial al fv, OpenGL ES do të marrë ngjyrën e kulmeve të modeleve tona si sfond dhe ngjyrat e përhapura të materialit. Për të aktivizuar këtë veçori, thjesht duhet ta telefononi:

Kjo është ajo që bëj zakonisht, sepse sfondi dhe ngjyrat e përhapura janë shpesh të njëjta. Meqenëse nuk përdor pika kryesore spekulare në shumicën e lojërave dhe demonstrimeve të mia, mund ta përdor lehtësisht këtë metodë dhe të mos telefonoj glMaterial fv. Cila metodë do të përdorni varet nga ju.

Përcaktimi i normave

Në mënyrë që ndriçimi të funksionojë në OpenGL ES, ju duhet të përcaktoni normalet e kulmit për çdo kulm të modelit. Normalja e kulmit duhet të jetë një vektor njësi që tregon (zakonisht) në drejtimin drejt sipërfaqes së cilës i përket kulmi. Në fig. Figura 11.5 ilustron normalet e kulmit për kubin tonë.

Oriz. 11.5. Normalet e kulmit për çdo kulm të kubit tonë

Një kulm normal është një tjetër atribut i një kulmi, ashtu si pozicioni ose ngjyra. Për të përfituar nga normalet e kulmit, duhet të modifikojmë përsëri klasën Vertices3. Për t'i treguar OpenGL ES se ku mund të gjejë normalet për çdo kulm, ne do të përdorim metodën gl Normal PointerO, ashtu si kemi përdorur metodat gl VertexPointer ose gl Col ose Pointer më parë. Lista 11-6 tregon versionin përfundimtar të klasës Vertices3.

Listimi 11.6. Klasa Vertices3.Java, versioni përfundimtar që mbështet normalet

Klasa ka një anëtar të ri ka Normal.s që mban shënim nëse kulmet kanë normale.

Konstruktori tani pranon gjithashtu një parametër hasNormals. Ne ende duhet të modifikojmë llogaritjen e anëtarit vertexSize duke shtuar tre nota për kulm aty ku është e mundur.

Siç mund ta shihni, metodat setVertices dhe setIndices mbeten të pandryshuara.

Në metodën bind që sapo demonstruam, ne përdorim të njëjtat truket me buferin ByteBuffer si më parë, por këtë herë shtojmë normale duke përdorur metodën gl Normal Pointer. Për të llogaritur kompensimin e treguesit normal, është e nevojshme të merret parasysh nëse janë specifikuar koordinatat dhe ngjyrat e teksturës.

Siç mund ta shihni, as metoda e tërheqjes nuk ka ndryshuar; i gjithë veprimi ndodh në metodën bind O.

Së fundi, ne modifikojmë pak metodën unbindO. Ne çaktivizojmë përdorimin e treguesve normalë, nëse ka, duke pastruar gjendjen OpenGL ES në përputhje me rrethanat.

Aplikimi i klasës së modifikuar Verti ces3 është po aq i lehtë sa më parë. Konsideroni një shembull të vogël:

Ne krijojmë një grup notash për të mbajtur tre kulme, secila me një pozicion (tre numrat e parë në secilën rresht) dhe një normal (tre numrat e fundit në secilën rresht). Në këtë rast, ne përcaktojmë një trekëndësh në rrafshin xy, me normalet e tij të drejtuara në drejtim të boshtit pozitiv z.

Gjithçka që duhet të bëjmë është të krijojmë një shembull të klasës Vertices3 dhe të vendosim vlerat e kulmit. Shumë e lehtë, apo jo?

Të gjitha punët e lidhjes, vizatimit dhe çlidhjes kryhen saktësisht në të njëjtën mënyrë si në versionin e mëparshëm të klasës. Si më parë, ne mund të shtojmë ngjyrat e kulmit dhe koordinatat e teksturës.

Duke i bashkuar të gjitha

Le t'i bashkojmë të gjitha. Ne duhet të vizatojmë një skenë që ka ndriçim global, pikë dhe burime drite drejtimi. Ata do të ndriçojnë kubin e vendosur në origjinë. Ne gjithashtu duhet të thërrasim metodën gl uLookAt. për të pozicionuar kamerën. Në fig. 11.6 tregon pamjen e botës sonë.

Si për të gjithë shembujt e tjerë, ne do të krijojmë një klasë që do të quhet LightTest, si zakonisht duke zgjeruar klasën GLGame. Ai do të kthejë një shembull të klasës LightScreen duke përdorur metodën getStartScreenO. Klasa LightScreen trashëgon nga klasa GLScreen (Lista 11-7).

Oriz. 11.6. Skena jonë e parë e ndriçuar

Listimi 11.7. Fragmente të klasës LightTest.java. krijimi i ndriçimit me OpenGL ES

Le të fillojmë duke përshkruar disa anëtarë të klasës. Anëtari i këndit ruan informacione rreth rrotullimit aktual të kubit rreth boshtit y. Anëtari Vertices3 ruan kulmet e modelit të kubit, të cilin do ta përcaktojmë së shpejti. Përveç kësaj, ne kemi shembuj të klasave AmbientLight, PointLight dhe Directional Light, si dhe një shembull të klasës Material.

Më pas vjen konstruktori. Këtu krijohen kulmet e modelit të kubit dhe ngarkohet gjithashtu tekstura e kutisë. Ne gjithashtu inicializojmë dritat dhe materialet. Ngjyra e ndriçimit është jeshile e lehtë. Burimi i drejtimit është i kuq dhe ndodhet në pikën (3; 3; 0) të botës sonë. Burimi i drejtimit të dritës ka një ngjyrë blu të përhapur, drita bie nga e majta. Për materialin, përdorni vlerat e paracaktuara (disi sfond, i bardhë për komponentin e përhapur dhe i zi për komponentin specular).

Në metodën e rifillimit, sigurohemi që tekstura jonë të (ri)ngarkohet nëse konteksti humbet.

Metoda CreativeCube nuk ka ndryshuar shumë nga shembujt e mëparshëm. Megjithatë, këtë herë shtojmë normale për çdo kulm, siç tregohet në Fig. 11.5. Përveç kësaj, gjithçka mbetet e njëjtë.

Në metodën e përditësimit, ne thjesht rrisim këndin e rrotullimit të kubit.

Këtu është më interesante. Linjat e para janë boilerplate për të pastruar zbutësin e ngjyrës dhe të thellësisë, për të mundësuar testimin e thellësisë dhe për të vendosur shtrirjen.

Më pas, vendosim matricën e projeksionit të barabartë me matricën e projeksionit të perspektivës duke përdorur metodën gl uPerspective, dhe përdorim gjithashtu metodën gl uLookAt në matricën model-view, në mënyrë që kamera të funksionojë njësoj si në Fig. 11.6.

Më pas lejojmë përdorimin e ndriçimit. Në këtë pikë, ende nuk janë përcaktuar dritat, kështu që ne i përcaktojmë ato në rreshtat e ardhshëm me një thirrje metodë për dritat dhe materialet.

Si zakonisht, ne gjithashtu mundësojmë teksturimin dhe lidhim teksturën e kutisë. Së fundi, ne e quajmë metodën gl RotatefC) për të rrotulluar kubin dhe më pas vizatojmë kulmet e tij me thirrje të instancës të vendosura mirë në klasën Vertices3.

Në fund të metodës, ne fikim dritat e pikës dhe drejtimit (mos harroni, theksimi është një gjendje globale), si dhe testimi i teksturës dhe thellësisë. Kjo është ajo për ndriçimin në OpenGL ES.

Pjesa tjetër e klasës është bosh; ne nuk kemi nevojë të bëjmë asgjë në rast të një pauze. Në fig. 11.7 tregon rezultatin e programit.

Oriz. 11.7. Skena e paraqitur në Fig. 11.6 e dhënë me OpenGL ES

Disa shënime mbi ndriçimin në OpenGL ES

Ndërsa përdorimi i ndriçimit mund t'i shtojë dhunti lojës tuaj, ai ka kufizimet dhe kurthet e veta. Ka disa gjëra për të cilat duhet të keni parasysh.

Përdorimi i ndriçimit konsumon shumë burime, veçanërisht të dukshme në pajisjet e ngadalta. Aplikoni ndriçimin me kujdes. Sa më shumë drita të përshkruani, aq më shumë llogaritje do të duhen për të paraqitur skenën.

Pozicioni/drejtimi i burimeve të dritës në pikë/drejtim duhet të përcaktohet pasi të ngarkohen matricat e kamerës dhe përpara se matrica e pamjes së modelit të shumëzohet me çdo matricë tjetër për të lëvizur dhe rrotulluar objektet. Kjo është kritike. Mosndjekja e këtyre udhëzimeve mund të rezultojë në artefakte drite të pashpjegueshme.

Kur përdorni metodën gl Seal ef për të ndryshuar madhësinë e një modeli, normalet e tij gjithashtu do të shkallëzohen. Kjo është e keqe sepse OpenGL ES pret që normalet të jenë në njësitë e dhëna. Për të zgjidhur këtë problem, mund të përdorni komandën glEnable(GL10.GL NORMALIZE) ose në disa rrethana gl Enable(GL10 .GL RESCALE N0RMAL). Unë mendoj se komanda e parë duhet të përdoret sepse e dyta ka kufizime dhe gracka. Problemi është se normalizimi ose rishkallëzimi i normaleve kërkon shumë fuqi përpunuese. Zgjidhja më e mirë për sa i përket performancës është të mos shkallëzoni objektet e ndriçuara.

Në këtë mësim, ne do të mësojmë se si të ndriçojmë dhe hijezojmë modelet tona 3D. Këtu është një listë e asaj që do të mësojmë:

  • Si ta bëni një objekt më të ndritshëm kur është afër një burimi drite.
  • Si të bëjmë reflektime kur shohim dritën e reflektuar në një objekt (ndriçim specular)
  • Si ta bëni një objekt të duket pak me hije kur drita nuk është drejtpërdrejt në objekt (ndriçim difuz)
  • Ndriçimi i skenës (ndriçimi i ambientit)
  • Hijet. Kjo temë meriton një mësim të veçantë (ose mësime, nëse jo edhe libra).
  • Pasqyrë reflektimi (p.sh. ujë)
  • nëntokësoreshpërndarje (për shembull, si dylli)
  • Anizotropike materiale (të lyera metal, për shembull)
  • Hije bazuar në proceset fizike për të imituar realitetin edhe më mirë.
  • Bllokimi i dritës (Mbyllja e ambientit nëse diçka bllokon dritën, ajo bëhet më e errët)
  • Reflektimi i ngjyrave (Qilimi i kuq do të bëjë që tavani i bardhë të duket paksa i kuqërremtë)
  • Transparenca
  • Ndriçimi Global (në parim, gjithçka që kemi treguar më lart mund të quhet ky term)

Me fjalë të tjera, ndriçimi dhe hijezimi më i thjeshtë.

Normale

Në mësimin e fundit kemi punuar me normalë, por pa e kuptuar shumë pse duhen fare.

Normalet e trekëndëshit

Normalja me një plan është një vektor njësi që është pingul me atë rrafsh.

Normalja në një trekëndësh është një vektor njësi i drejtuar pingul me trekëndëshin. Normalja llogaritet shumë thjesht duke përdorur prodhimin kryq të dy anëve të trekëndëshit (nëse ju kujtohet, prodhimi kryq i dy vektorëve na jep një vektor pingul me të dy) dhe normalizohet: gjatësia e tij është vendosur në një.

Këtu është pseudokodi normal i llogaritjes:

trekëndësh (v1, v2, v3)
anë1=v2-v1
anë2=v3-v1
trekëndëshi.normal = vectProduct(ana1, ana2).normalize()

Vertex Normal

Kjo është normalja e paraqitur për lehtësinë e llogaritjeve. Kjo është normalja e kombinuar nga normalet e trekëndëshave që rrethojnë kulmin e dhënë. Kjo është shumë e përshtatshme, sepse në shaderat e kulmeve kemi të bëjmë me kulme, jo me trekëndësha. Në çdo rast, në Në OpenGL, ne pothuajse kurrë nuk merremi me trekëndësha.

krye v1, v2, v3, ....
trekëndëshi tr1, tr2, tr3 // të gjithë përdorin kulmin v1
v1.normal = normalize(tr1.normal + tr2.normal + tr3.normal)

Përdorimi i normaleve të kulmit në OpenGL

Përdorimi i normaleve në OpenGL është shumë i thjeshtë. Një normale është thjesht një atribut kulmi, ashtu si pozicioni, ngjyra ose koordinatat UV... Pra, nuk ka asgjë të re për të mësuar... edhe funksioni ynë i thjeshtë loadOBJ tashmë ngarkon normalet.

GLint normalbufer;
glGenBuffers(1, &normalbuffer);

glBufferData(GL_ARRAY_BUFFER, normals.size() * sizeof(glm::vec3), &normals, GL_STATIC_DRAW);

// Third Atribute Buffer: Normals
glEnableVertexAttribArray(2);

glBindBuffer(GL_ARRAY_BUFFER, normalbuffer);
glVertexAttribPointer(
2, // atribut
3, // madhësia
GL_FLOAT, //lloji
GL_FALSE, // normalizuar?
0, // hap
(i pavlefshëm*)0 // kompensimi i tamponit
);

Dhe kjo është e mjaftueshme për të filluar:


ndriçim difuz

Rëndësia e normales së sipërfaqes

Kur një rreze drite godet një sipërfaqe, pjesa më e madhe e saj reflektohet në të gjitha drejtimet. Ky quhet "komponenti difuz". Ne do të shohim pjesën tjetër të komponentëve pak më vonë.

Pas rënies së rrezes, sipërfaqja reflekton dritën në mënyra të ndryshme, në varësi të këndit në të cilin kjo rreze bie në sipërfaqe. Nëse rrezja bie pingul me sipërfaqen, atëherë përqendrohet në një zonë të vogël, nëse është tangjenciale, atëherë shpërndahet në një sipërfaqe shumë më të madhe:


Nga pikëpamja e grafikës kompjuterike, ngjyra e një piksel varet shumë nga ndryshimi në këndet e drejtimit të dritës dhe nga sipërfaqja normale.


//
//
float cosTheta = pikë(n,l);

Në këtë kod, "n" është normalja dhe "l" është vektori njësi që shkon nga sipërfaqja në dritë (jo anasjelltas, megjithëse kjo mund të duket konfuze)

Kujdes me shenjën

Ndonjëherë formula jonë nuk funksionon. Për shembull, kur drita është prapa trekëndëshit, n dhe l do të jenë të kundërta, kështu që n.l do të jetë negative. Dhe në fund, do të kemi një lloj ngjyre negative, dhe si rezultat, një lloj marrëzie. Prandaj, ne do t'i konvertojmë të gjithë numrat negativë në 0 duke përdorur funksionin e kapëses.

// Kosinusi i këndit ndërmjet drejtimit normal dhe të dritës
// 1 - nëse drita është pingul me trekëndëshin
// 0 - nëse drita është paralele me trekëndëshin
// 0 - nëse drita është prapa trekëndëshit
float cosTheta = kapëse (pika (n, l), 0.1);
ngjyra = LightColor * cosTheta;

Ngjyra e materialit

Sigurisht, ngjyra e objektit duhet të varet shumë nga ngjyra e materialit. Drita e bardhë ka tre komponentë - të kuqe, blu dhe jeshile. Kur drita godet një sipërfaqe të kuqe, përbërësit e gjelbër dhe blu përthithen dhe e kuqja reflektohet.



Ne mund ta modelojmë këtë me një shumëzim të thjeshtë:

ngjyra = MaterialDiffuseColor * LightColor * cosTheta;

modelimi i dritës

Le të supozojmë se kemi një burim drite me pikë që lëshon dritë në të gjitha drejtimet, si një qiri.

Me një burim të tillë drite, niveli i ndriçimit të sipërfaqes do të varet nga distanca në burimin e dritës: sa më larg, aq më e errët. Kjo varësi llogaritet si kjo:

ngjyra = MaterialDiffuseColor * LightColor * cosTheta / (distanca*distanca);

Së shpejti do të na duhet një parametër më shumë për të kontrolluar nivelin e intensitetit të dritës - ngjyrën e dritës, por tani për tani, le të supozojmë se kemi një llambë të bardhë me një fuqi të caktuar (për shembull, 60 watts).

ngjyra = MaterialDiffuseColor * LightColor * LightPower * cosTheta / (distanca*distanca);

Duke i bashkuar të gjitha

Që ky kod të funksionojë, ne kemi nevojë për një grup të caktuar parametrash (ngjyra dhe fuqi) dhe disa kode shtesë.

MaterialDiffuseColor - mund ta marrim direkt nga tekstura.

LightColor dhe LightPower do të duhet të vendosen në shader duke përdorur një uniformë GLSL.

CosTheta do të varet nga vektorët n dhe l. Mund të llogaritet për secilën nga hapësirat, këndi do të jetë i njëjtë. Ne do të përdorim hapësirën e kamerës, pasi është shumë e lehtë të llogaritet pozicioni i burimit të dritës këtu:

// Fragment normal në hapësirën e kamerës
vec3 n = normalize(Normal_kamerapace);
// Drejtimi i dritës (nga fragmenti në burim drite
vec3 l = normalize(LightDirection_kamerapace);

Normal _cameraspace dhe LightDirection _cameraspace llogariten në shader vertex dhe kalohen në shader fragment për përpunim të mëtejshëm:

// Pozicioni i kulmit në hapësirën e kamerës: pozicioni MVP *
gl_Pozicioni= MVP * vec4 (vertexPosition_modelspace,1);
// Pozicioni i kulmit në hapësirën botërore: M * pozicioni
Hapësira_botërore e pozitës = (M * vec4(vertexPosition_modelspace,1)).xyz;
// Vektor që vjen nga lartkamera në hapësirën e kamerës
// Në hapësirën e kamerës, kamera është në pozicionin (0,0,0)
vec 3 kulmi Pozicioni _ hapësira e kamerave = ( V * M * vec 4( kulmi Pozicioni _ hapësirë ​​modeli ,1)). xyz ;
EyeDirection_kamerahapësirë ​​= vec3(0,0,0) - kulmi i pozicionit_kamera;
// Një vektor që shkon nga kulmi në burimin e dritës në hapësirën e kamerës.
//Matrica M hiqet, pasi është njëjës në këtë hapësirë.
vec3 LightPosition_kameraspace = (V * vec4(LightPosition_worldspace,1)).xyz;
LightDirection_cameraspace = LightPosition_cameraspace +
EyeDirection_kamerapace;
// Normale majat V hapësirë kamerat
Hapësira_normale e kamerës = (V * M * vec4 (vertexNormal_modelspace,0)).xyz; // do puna vetëm V vëllimi rast , Kur matricë modele Jo ndryshimet saj madhësia .

Në pamje të parë, kodi mund të duket mjaft kompleks dhe konfuz, por në fakt, nuk ka asgjë të re këtu që nuk ishte në mësimin 3: Matricat. Unë u përpoqa t'i jap emra kuptimplotë secilës variabël në mënyrë që të jetë e lehtë për ju të kuptoni se çfarë po ndodh dhe si.

Sigurohuni që të provoni!!!

M dhe V janë matricat Model dhe View që kalohen në shader ashtu si MVP-ja jonë e vjetër e mirë.

Koha e testimit

Unë ju thashë gjithçka që duhet të dini për të bërë ndriçim difuz. Vazhdo, provoje.

Rezultati

Me vetëm një komponent të përhapur, ne marrim një pamje të tillë këtu (më falni për teksturat e shëmtuara).



Duket se është më mirë se më parë, por ende mungon shumë. Problemi është veçanërisht i dukshëm me pjesët e pandriçuara. Pjesa e pasme e kokës së majmunit tonë të dashur Suzanne është plotësisht e zezë (në fund të fundit kemi përdorur kapëse ()).

Ndriçimi i ambientit

Ndriçimi i ambientit është mashtrim i pastër.

Pjesa e pasme e kokës së Suzanës nuk duhet të jetë plotësisht e zezë, sepse në jetën reale drita e llambës duhet të bjerë në mur, dysheme, tavan, të reflektojë pjesërisht prej tij dhe të ndriçojë pjesën e hijes së objektit.

Megjithatë, kjo është shumë e shtrenjtë nga ana llogaritëse për t'u bërë në kohë reale. Dhe kjo është arsyeja pse ne do të shtojmë disa komponentë të vazhdueshëm. Është sikur vetë objekti lëshon pak dritë në mënyrë që të mos jetë plotësisht i zi.

vec3 MaterialAmbientColor = vec3(0.1,0.1,0.1) * MaterialDiffuseColor;
ngjyra=
// Ambient ndriçimi : simulojnë indirekte ndriçimi
MaterialAmbientColor +
// difuze : " ngjyrë " vetë objekti
MaterialDiffuseColor * LightColor * LightPower * cosTheta /
(distanca*distanca);

Rezultati

Këtu bëhet pak më mirë. Ju mund të luani me koeficientët (0.1, 0.1, 0.1) për të provuar të merrni rezultatin më të mirë.



Drita e reflektuar

Pjesa e dritës që reflektohet reflektohet kryesisht drejt rrezes së reflektuar drejt sipërfaqes.



Siç mund ta shohim në figurë, drita e reflektuar formon një pikë drite. Në disa raste, kur komponenti difuz është zero, kjo pikë drite është shumë shumë e ngushtë (e gjithë drita reflektohet plotësisht në një drejtim) dhe marrim një pasqyrë.

(megjithatë, edhe pse mund t'i ndryshoni parametrat për të marrë një pasqyrë, në rastin tonë ajo do të marrë parasysh vetëm reflektimin e burimit tonë të dritës. Kështu që do të rezultojë të jetë një pasqyrë e çuditshme)


// vektor i vështrimit (drejt kamerës)
vec3 E = normalize(EyeDirection_kamerapace);
//Drejtimi në të cilin trekëndëshi reflekton dritën
vec 3 R = pasqyrim (- l , n );
// Kosinusi i këndit ndërmjet vektorit të pamjes dhe vektorit të reflektimit të prerë në zero nëse është e nevojshme
// - Shiko drejtpërdrejt reflektimin -> 1
// - Ne shikojmë diku në drejtimin tjetër -\u003e< 1
float cosAlpha = kapëse (pika (E,R), 0.1);
ngjyra=
// Ndriçimi i Ambientit: Simuloni ndriçimin indirekt
MaterialAmbientNgjyra +
// difuze : " ngjyrë " vetë objekti
MaterialDiffuseColor * LightColor * LightPower * cosTheta /
(distanca*distanca) ;
// Reflektuar: reflektime të pasqyruara si një pasqyrë
Materiali SpecularNgjyra * Ngjyra e lehtë * Fuqia e dritës * Pow (cosAlpha, 5) /

Në mësimin tjetër, ne do të analizojmë se si mund të përshpejtojmë paraqitjen e VBO-së sonë.