Ituro ang pinagmulan ng liwanag sa opengl. Ipinagpapatuloy namin ang aming pag-aaral ng OpenGL: pag-iilaw ayon kay Phong. Pinagsasama-sama ang lahat

Ang pag-iilaw sa OpenGL ES ay isang kapaki-pakinabang na tampok na maaaring magdagdag ng magandang ugnayan sa mga 3D na laro. Para magamit ang functionality na tulad nito, kailangan muna nating maunawaan ang OpenGL ES lighting model.

Paano gumagana ang pag-iilaw

Pag-isipan natin kung paano gumagana ang pag-iilaw. Una kailangan natin ng ilaw na pinagmumulan na naglalabas ng liwanag. Kakailanganin mo rin ang isang iluminadong bagay. Sa wakas, kailangan din namin ng sensor, tulad ng mata o camera, na tumatanggap ng mga photon na ipinadala ng pinagmumulan ng liwanag at ipinapakita ng bagay. Binabago ng liwanag ang nakikitang kulay ng isang bagay depende sa: ang uri ng pinagmumulan ng liwanag; kulay o intensity ng pinagmumulan ng liwanag; posisyon ng pinagmumulan ng liwanag at direksyon nito na may kaugnayan sa iluminado na bagay; bagay na materyal at texture.

Ang intensity kung saan ang liwanag ay makikita ng isang bagay ay nakasalalay sa maraming mga kadahilanan. Ang pinakamahalagang salik na tinitingnan natin ay ang anggulo kung saan tumama ang sinag ng liwanag sa ibabaw. Kung mas malapit ang anggulong ito sa tamang anggulo, mas malaki ang intensity kung saan ang liwanag ay makikita mula sa bagay. Ito ay inilalarawan sa Fig. 11.1.

Kapag ang isang light beam ay tumama sa isang ibabaw, ito ay makikita sa dalawang magkaibang direksyon. Karamihan sa liwanag ay masasalamin sa diffusely. Nangangahulugan ito na ang mga sinasalamin na liwanag na sinag ay nakakalat nang hindi pantay at random sa ibabaw ng bagay. Ang ilang mga sinag ay nakikita sa specularly. Nangangahulugan ito na ang mga sinag ng liwanag ay makikita pabalik na parang nakamamanghang salamin. Sa Fig. Ipinapakita ng Figure 11.2 ang pagkakaiba sa pagitan ng diffuse at specular reflection.

kanin. 11.1. Kung mas malapit ang anggulo sa tamang anggulo, mas malaki ang intensity ng sinasalamin na liwanag

kanin. 11.2. Mga nakakalat at specular na pagmuni-muni

Lalabas ang specular reflection bilang mga highlight sa mga bagay. Kung specularly sumasalamin ang liwanag sa isang bagay ay depende sa materyal kung saan ito ginawa. Ang mga bagay na may ibabaw na hindi pantay o magaspang, tulad ng balat, ay malamang na walang specular na highlight. Ang mga bagay na may makinis na ibabaw tulad ng salamin o marmol ay magpapakita ng mga magaan na artifact na ito. Siyempre, ang salamin o marmol ay hindi perpektong makinis, ngunit kumpara sa kahoy o balat ng tao, sila ay.

Kapag tumama ang liwanag sa isang ibabaw, nagbabago rin ang kulay ng repleksyon nito depende sa komposisyong kemikal bagay na may ilaw. Ang mga bagay na mukhang pula sa amin ay sumasalamin lamang sa mga pulang bahagi ng liwanag at sumisipsip ng lahat ng iba pang mga frequency. Ang isang itim na bagay ay isa na sumisipsip ng halos lahat ng liwanag na nahuhulog dito.

Binibigyang-daan ka ng OpenGL ES na gayahin ang pag-uugali sa totoong mundo sa pamamagitan ng pagtukoy sa mga pinagmumulan ng liwanag at mga materyal na bagay.

Mga pinagmumulan ng ilaw

Napapaligiran kami ng maraming iba't ibang pinagmumulan ng ilaw. Ang araw ay patuloy na nagpapadala ng mga photon nito. Ang mga monitor ay naglalabas ng liwanag na pumapalibot sa amin ng isang kaaya-ayang liwanag sa gabi. Tinutulungan tayo ng mga bombilya at headlight na maiwasan ang mga banggaan sa iba't ibang bagay sa dilim. Binibigyang-daan ka ng OpenGL ES na lumikha ng apat na uri ng mga light source.

Backlight. Ito ay hindi isang pinagmumulan ng liwanag sa kanyang sarili, ngunit ang resulta ng paglitaw ng mga photon mula sa iba pang mga pinagmumulan ng liwanag. Magkasama, ang mga random na photon na ito ay lumikha ng isang pare-parehong antas ng pag-iilaw na walang direksyon at nagpapailaw sa lahat ng mga bagay nang pantay.

Ituro ang mga pinagmumulan ng liwanag. Mayroon silang posisyon sa kalawakan at naglalabas ng liwanag sa lahat ng direksyon. Halimbawa, ang isang puntong pinagmumulan ng liwanag ay isang bumbilya.

Mga mapagkukunan ng ilaw ng direksyon. Ipinahayag bilang mga direksyon sa OpenGL ES. Ipinapalagay na sila ay walang katapusan na malayo. Sa isip, ang Araw ay maaaring maging isang mapagkukunan. Maaari nating ipagpalagay na ang lahat ng liwanag na sinag na nagmumula sa Araw ay tumama sa Earth sa parehong anggulo dahil sa distansya sa pagitan ng Earth at ng Araw.

Tungkol sa Lamp. Ang mga ilaw na ito ay katulad ng mga point light dahil mayroon silang ibinigay na posisyon sa espasyo. Bilang karagdagan, mayroon silang direksyon kung saan naglalabas sila ng mga light ray. Lumilikha sila ng isang light cone na limitado sa isang tiyak na radius. Ang isang halimbawa ng naturang ilaw na mapagkukunan ay isang lampara sa kalye.

Isasaalang-alang lang namin ang backlighting, pati na rin ang point at directional light source. Kadalasang mahirap gamitin ang mga ilaw sa mga Android device na limitado sa GPU dahil sa paraan ng pagkalkula ng OpenGL ES sa pag-iilaw. Malalaman mo sa lalong madaling panahon kung bakit ganito.

Bilang karagdagan sa posisyon at direksyon ng pinagmumulan ng liwanag, pinapayagan ka ng OpenGL ES na matukoy ang kulay o intensity ng liwanag. Ang mga katangiang ito ay ipinahayag gamit ang kulay ng RGBA. Gayunpaman, hinihiling sa iyo ng OpenGL ES na tukuyin ang apat na magkakaibang kulay bawat pinagmulan sa halip na isa lamang.

Highlight - Ang intensity/kulay na nakakatulong sa pagtatabing ng isang bagay. Ang bagay ay iilaw nang pantay mula sa lahat ng panig, anuman ang posisyon o oryentasyon nito na may kaugnayan sa pinagmumulan ng liwanag.

Diffuse – intensity/kulay ng liwanag na magpapailaw sa bagay pagkatapos kalkulahin ang diffuse reflection. Ang mga gilid ng bagay na hindi nakaharap sa pinagmumulan ng liwanag ay hindi maiilaw, tulad ng sa totoong buhay.

Specular – intensity/kulay na katulad ng diffuse na kulay. Gayunpaman, naaapektuhan lamang nito ang mga puntong iyon ng bagay na may partikular na oryentasyon na may kaugnayan sa pinagmumulan ng liwanag at sensor.

Ang Emissive ay isang napakakomplikadong kalkulasyon ng kulay na napakalimitado ang paggamit sa mga application sa real world physics, kaya hindi namin ito sasaklawin.

Kadalasan, gagamit tayo ng diffuse at specular na intensity ng light source, at ibibigay ang dalawa pang default na value. Gayundin, kadalasan ay gagamitin namin ang parehong kulay ng RGBA para sa parehong diffuse at specular intensity.

Mga materyales

Ang lahat ng mga bagay sa ating mundo ay binubuo ng ilang uri ng materyal. Tinutukoy ng bawat materyal kung paano masasalamin ang liwanag na bumabagsak sa isang bagay at babaguhin ang kulay ng sinasalamin na liwanag. Binibigyang-daan ka ng OpenGL ES na tukuyin ang parehong apat na kulay ng RGBA para sa isang materyal tulad ng para sa isang light source.

Ang backlight ay isang kulay na pinagsama sa kulay ng background ng anumang pinagmumulan ng liwanag sa eksena.

Ang diffuse ay isang kulay na pinagsama sa nagkakalat na kulay ng anumang pinagmumulan ng liwanag.

Ang specular ay isang kulay na pinagsama sa specular na kulay ng anumang pinagmumulan ng liwanag. Ito ay ginagamit upang lumikha ng mga highlight sa ibabaw ng isang bagay.

Emissive - patuloy naming binabalewala ang ganitong uri ng kulay, dahil halos hindi ito ginagamit sa aming konteksto.

Ang Figure 11.3 ay naglalarawan ng unang tatlong uri ng mga katangian ng materyal/ilaw na pinagmumulan: backlight, diffuse, at specular.

kanin. 11.3. Iba't ibang uri ng materyales/light source: backlight lang (kaliwa), diffuse lang (gitna), backlight at diffuse na kulay na may specular na highlight (kanan)

Sa Fig. Ipinapakita ng Figure 11.3 ang epekto ng iba't ibang katangian ng mga materyales at pinagmumulan ng liwanag sa kulay. Ang backlight ay nag-iilaw sa laki nang pantay-pantay. Ang nakakalat na liwanag ay masasalamin depende sa anggulo kung saan tumama ang mga sinag ng liwanag sa bagay; Ang mga lugar na direktang nakaharap sa pinagmumulan ng liwanag ay iilaw nang mas maliwanag, ang mga lugar na hindi maabot ng liwanag ay magiging madilim. Sa kanang larawan, makikita mo ang kumbinasyon ng backlight, diffuse at specular light. Lumilitaw ang specular na liwanag bilang mga puting highlight sa globo.

Paano kinakalkula ng OpenGL ES ang pag-iilaw: normal ang vertex

Alam mo na ang intensity ng liwanag na sinasalamin mula sa isang bagay ay nakasalalay sa anggulo ng saklaw nito sa bagay. Ginagamit ng OpenGL ES ang katotohanang ito upang kalkulahin ang pag-iilaw. Gumagamit ito ng vertex normals para dito, na dapat tukuyin sa code sa parehong paraan tulad ng texture coordinate o vertex color. Sa Fig. Ipinapakita ng Figure 11.4 ang isang globo at ang vertex nito ay normal.

kanin. 11.4. Ang sphere at ang vertex nito ay normal

Ang mga normal ay mga unit vector na nagsasaad ng direksyon kung saan iniikot ang isang ibabaw. Sa aming kaso, ang ibabaw ay isang tatsulok. Sa halip na tukuyin ang normal na ibabaw, tinutukoy namin ang normal na vertex. Ang pagkakaiba sa pagitan ng mga normal na ito ay ang vertex normal ay maaaring hindi tumuro sa parehong direksyon gaya ng surface normal. Ito ay malinaw na nakikita sa Fig. 11.4, kung saan ang bawat vertex normal ay ang average na normal ng lahat ng triangles kung saan kabilang ang vertex. Ang pag-average na ito ay ginagawa upang lumikha ng makinis na pagtatabing ng bagay.

Kapag nag-render ng object gamit ang lighting at vertex normals, tutukuyin ng OpenGL ES ang anggulo sa pagitan ng bawat vertex at ang pinagmulan ng liwanag. Kung alam niya ang anggulong ito, maaari niyang kalkulahin ang kulay ng vertex batay sa mga katangian ng materyal. Ang huling resulta ay ang kulay ng bawat vertex, na pagkatapos ay inilapat sa bawat tatsulok kasama ang mga kinakalkula na kulay ng iba pang mga vertex. Ang kulay na ito na ginamit ay isasama sa anumang mga pagbabago sa texture na inilalapat namin sa bagay.

Ito ay mukhang medyo nakakatakot, ngunit ito ay talagang hindi na masama. Kailangan nating paganahin ang pag-iilaw at tukuyin ang mga pinagmumulan ng liwanag, materyal na mai-render, at mga normal na vertex (bilang karagdagan sa mga parameter ng vertex na karaniwan nating tutukuyin, gaya ng mga coordinate ng posisyon o texture). Tingnan natin kung paano ito maipapatupad gamit ang OpenGL ES.

Sa practice

Ngayon, gawin natin ang lahat ng mga hakbang na kinakailangan upang gumana sa pag-iilaw gamit ang OpenGL ES. Gumawa tayo ng ilang maliliit na klase ng helper na magpapadali sa pagtatrabaho sa mga light source, at ilagay ang mga ito sa com.badlogi package with.androi dgames.framework.gl.

Pahintulot at pagbabawal sa pag-iilaw

Tulad ng ibang mga estado ng OpenGL ES, kailangan mo munang paganahin ang pinangalanang pagpapagana. Ito ay maaaring gawin tulad ng sumusunod:

Pagkatapos nito, ilalapat ang pag-iilaw sa lahat ng na-render na bagay. Upang makuha ang resulta, kailangan mong tukuyin ang mga pinagmumulan ng liwanag at materyales, pati na rin ang mga normal na vertex. Kapag natapos na namin ang pagguhit ng lahat ng kinakailangang bagay, maaaring patayin ang ilaw:

Pagtukoy sa mga Pinagmumulan ng Liwanag

Nagbibigay ang OpenGL ES ng 4 na uri ng light source: backlight, spot, directional at spotlight. Tingnan natin kung paano matukoy ang unang tatlo. Upang maging mabisa at maganda ang hitsura ng mga luminaire, ang bawat modelo ay dapat na binubuo ng isang malaking bilang ng mga tatsulok. Hindi ito posible para sa maraming kasalukuyang mga mobile device.

Binibigyang-daan ka ng OpenGL ES na tumukoy ng maximum na 8 light source nang sabay-sabay, pati na rin ang isang global light source. Ang bawat isa sa 8 light source ay may identifier, mula GL10.GL LIGHT0 hanggang GL10.GL LIGHT7. Kung kailangan mong baguhin ang mga katangian ng isa sa mga ilaw na ito, magagawa mo ito sa pamamagitan ng pagtukoy sa kaukulang ID.

Maaari mong paganahin ang paggamit ng mga ilaw gamit ang sumusunod na syntax:

Susunod, matatanggap ng OpenGL ES ang mga katangian ng pinagmumulan ng liwanag na ito at ilalapat ang mga ito sa lahat ng na-render na bagay. Kung kailangan naming i-disable ang paggamit ng light source, magagawa namin ito gamit ang sumusunod na pahayag:

Ang highlight ay isang espesyal na kaso dahil wala itong ID. Isang highlight lang ang maaaring umiral sa isang OpenGL ES scene. Tingnan natin ang pinagmumulan ng ilaw na ito.

Backlight

Ang backlight ay isang espesyal na uri ng pag-iilaw. Wala itong posisyon o direksyon, isang kulay lamang na inilalapat sa lahat ng mga bagay na may liwanag na pantay. Binibigyang-daan ka ng OpenGL ES na tukuyin ang pandaigdigang pag-highlight tulad ng sumusunod:

Ang ambi entCol o array ay naglalaman ng mga halaga ng RGBA ng kulay ng backlight, na kinakatawan bilang mga floating point na numero mula 0 hanggang 1. Ang gl LightModel fv method ay tumatagal bilang unang parameter nito ng pare-parehong tumutukoy na gusto naming itakda ang kulay ng background light source, isang array ng floating point numbers , na naglalaman ng source color, at ang offset para sa float array kung saan magsisimula ang paraan sa pagbabasa ng mga halaga ng RGBA. Ilagay natin ang code na lumulutas sa problemang ito sa isang maliit na klase. Ang code nito ay ipinapakita sa Listahan 11.2.

Listahan 11.2. Class AmbientLight.java. simpleng global illumination abstraction ODenGL ES

Ang gagawin lang namin ay iimbak ang kulay ng highlight sa isang float array at magbigay ng dalawang pamamaraan: ang isa ay ginagamit upang itakda ang kulay, at ang isa ay ginagamit upang sabihin sa OpenGL ES na gamitin ang kulay na iyon. Ang default na kulay ay gray.

Ituro ang mga mapagkukunan ng ilaw

Ang mga point light ay may posisyon, gayundin ang background, diffuse, at specular na kulay/intensity (hindi namin isinasaalang-alang ang emissive na kulay/intensity). Tukuyin iba't ibang uri mga kulay tulad ng sumusunod:

Ang unang parameter ay ang light source identifier. Sa kasong ito ginagamit namin ang pang-apat na mapagkukunan. Tinutukoy ng susunod na parameter ang attribute na gusto naming baguhin. Ang ikatlong parameter ay isang hanay ng mga numero ng floating point na naglalaman ng mga halaga ng RGBA, at ang huli ay ang offset sa array na ito. Ang pagtukoy sa posisyon ng pinagmulan ay kasingdali lang:

Muli naming tinukoy ang attribute na gusto naming baguhin (sa kasong ito na posisyon), isang four-element array na naglalaman ng x-, y-, at z-coordinate ng light source sa mundong nilikha. Tandaan na ang ikaapat na elemento ng array ay dapat na katumbas ng isa kung may posisyon ang pinagmumulan ng liwanag. Ilagay natin ito sa isang klase ng katulong. Ang code nito ay nakapaloob sa Listahan 11.3.

Listahan 11.3. Point.Light.java class, isang simpleng abstraction ng OpenGL ES point lights

Ang aming helper class ay naglalaman ng background, diffuse, at specular na bahagi ng kulay ng liwanag, pati na rin ang posisyon (ang ikaapat na elemento ay isa). Bilang karagdagan, iniimbak namin ang huling identifier na ginamit para sa isang partikular na pinagmulan, kaya nagiging posible na gumawa ng paraan ng disableO na papatayin ang ilaw kung kinakailangan. Mayroon din kaming enableO method, na kumukuha ng isang instance ng GL10 class at isang light source identifier (halimbawa GL10.GL LIGHT6). Pinapayagan nitong magamit ang pag-iilaw, itakda ang mga katangian nito, at iimbak ang ginamit na ID. Ang paraan ng disableO ay hindi pinapagana ang paggamit ng pag-iilaw gamit ang 1ast.Ligh.tId na miyembro ng klase na itinakda sa paraan ng pagana.

Gumagamit kami ng mga makatwirang default na halaga para sa background, diffuse, at specular na kulay kapag sinisimulan ang mga array ng miyembro ng klase. Ang ilaw ay magiging puti at hindi lilikha ng anumang liwanag na nakasisilaw dahil ang specular na bahagi nito ay itim.

Mga pinagmumulan ng ilaw sa direksyon

Ang mga pinagmumulan ng ilaw ng direksyon ay halos magkapareho sa mga punto. Ang pinagkaiba lang ay meron silang direksyon sa halip na posisyon. Ang paraan kung saan ang direksyon ay ipinahayag ay medyo nakalilito. Sa halip na gumamit ng vector para magpahiwatig ng direksyon, inaasahan ng OpenGL ES na tutukuyin natin ang isang punto. Ang direksyon ay tutukuyin gamit ang isang vector na nagkokonekta sa puntong ito at sa pinanggalingan. Nagbibigay-daan sa iyo ang sumusunod na snippet na lumikha ng direksyong pinagmumulan ng liwanag na nagmumula sa kanang bahagi ng mundo:

Maaari naming i-convert ito sa isang vector:

Ang iba pang mga katangian, gaya ng background o diffuse na kulay, ay kapareho ng sa isang point light. Ipinapakita ng listahan 11.4 ang code para sa isang maliit na klase ng helper na ginamit upang lumikha ng mga ilaw na direksyon.

Listahan 11.4. Directi onLi class ght.java, isang simpleng abstraction ng directional light sources sa OpenGL ES

Ang helper class na ito ay halos magkapareho sa PointLight class. Ang pagkakaiba lamang ay sa directi sa array ang ikaapat na elemento ay isa. Bilang karagdagan, sa halip na ang setPosition method, ang setDirecti on method ay lumitaw. Pinapayagan ka nitong tukuyin ang direksyon, halimbawa tulad nito: (-1; 0; 0), kung saan ang liwanag ay manggagaling sa kanang bahagi. Sa loob ng pamamaraan, ang lahat ng mga bahagi ng vector ay nagbabago ng kanilang pag-sign, kaya kino-convert namin ang direksyon sa format na inaasahan ng OpenGL ES.

Pagtukoy ng mga materyales

Ang isang materyal ay tinutukoy ng ilang mga katangian. Tulad ng anumang iba pang object ng OpenGL ES, ang materyal ay isang estado na mananatiling aktibo hanggang sa mabago natin itong muli o mawala ang konteksto ng OpenGL ES. Upang itakda ang kasalukuyang mga katangian ng materyal, magagawa natin ang sumusunod:

Gaya ng dati, kailangan nating tukuyin ang background, diffuse at specular na kulay ng RGBA. Magagawa ito sa parehong paraan tulad ng dati - gamit ang mga arrays ng mga numero ng floating point na binubuo ng apat na elemento.

Ang pagsasama-sama ng mga pagkilos na ito sa isang klase ng katulong ay napakasimple. Makikita mo ang resulta sa Listahan 11.5.

Listahan 11.5. Material Java class, isang simpleng abstraction ng mga materyales ng OpenGL ES

Wala rin namang nakakagulat dito. Nag-iimbak lang kami ng tatlong bahagi na naglalarawan sa materyal, at nagbibigay din ng mga function upang itakda ang kanilang mga halaga at isang paraan ng pagpapagana na nagpapasa sa kanila sa OpenGL ES.

May isa pang ace ang OpenGL ES pagdating sa mga materyales. Karaniwan itong gumagamit ng tinatawag na materyal na kulay sa halip na ang glMaterialfvO na pamamaraan. Nangangahulugan ito na sa halip na ang background at diffuse na mga kulay na tinutukoy ng glMateri al fv method, ang OpenGL ES ay kukuha ng kulay ng vertices ng aming mga modelo bilang background at diffuse na kulay ng materyal. Upang paganahin ang tampok na ito, tawagan mo lang ito:

Ito ang kadalasang ginagawa ko dahil madalas pareho ang background at diffuse na kulay. Dahil hindi ako gumagamit ng mga specular na highlight sa karamihan ng aking mga laro at demo, madali kong magagamit ang paraang ito at hindi ko matawagan ang paraan ng glMaterial fv. Aling paraan upang gamitin ito ay nasa iyo na magpasya.

Pagtukoy sa mga normal

Para gumana ang pag-iilaw sa OpenGL ES, kailangan mong tukuyin ang mga vertex normal para sa bawat vertex sa modelo. Ang normal ng isang vertex ay dapat na isang unit vector na tumuturo (karaniwan) sa direksyon kung saan ang ibabaw kung saan kabilang ang vertex ay pinaikot. Sa Fig. Ang Figure 11.5 ay naglalarawan ng vertex normals para sa aming cube.

kanin. 11.5. Normal ang vertex para sa bawat vertex ng aming cube

Ang vertex normal ay isa pang katangian ng isang vertex, tulad ng posisyon o kulay. Upang mapakinabangan ang vertex normals, kailangan nating baguhin muli ang klase ng Verti ces3. Upang sabihin sa OpenGL ES kung saan ito makakahanap ng mga normal para sa bawat vertex, gagamitin namin ang gl Normal PointerO na pamamaraan, tulad ng dati naming ginamit ang gl VertexPointer o gl Col o Pointer na mga pamamaraan. Ipinapakita ng listahan 11.6 ang huling bersyon ng klase ng Vertices3.

Listahan 11.6. Vertices3.Java class, panghuling bersyon na sumusuporta sa mga normal

Ang klase ay may bagong miyembro hasNormal.s na sumusubaybay kung ang mga vertex ay may mga normal.

Tumatanggap na rin ang constructor ng hasNormals parameter. Kailangan pa rin nating baguhin ang kalkulasyon ng miyembro ng vertexSize sa pamamagitan ng pagdaragdag ng tatlong float sa bawat vertex kung posible.

Gaya ng nakikita mo, ang mga pamamaraan ng setVertices at setlndices ay nananatiling hindi nagbabago.

Sa bindO na pamamaraan na ipinakita namin, ginagamit namin ang parehong mga diskarte sa ByteBuffer tulad ng dati, ngunit sa pagkakataong ito ay nagdaragdag kami ng mga normal gamit ang gl Normal Pointer na paraan. Upang kalkulahin ang offset ng normal na pointer, kinakailangang isaalang-alang kung ang texture at mga coordinate ng kulay ay tinukoy.

Tulad ng nakikita mo, ang paraan ng pagguhit ay hindi rin nagbago; lahat ng aksyon ay nangyayari sa bind method O.

Sa wakas, binago namin nang bahagya ang paraan ng unbindO. Hindi namin pinagana ang paggamit ng mga normal na pointer, kung mayroon man, pag-clear sa estado ng OpenGL ES nang naaayon.

Ang paglalapat ng binagong klase ng Verti ces3 ay kasingdali lang ng dati. Tingnan natin ang isang maliit na halimbawa:

Gumagawa kami ng floating point array para mag-imbak ng tatlong vertices, bawat isa ay may posisyon (ang unang tatlong numero sa bawat row) at isang normal (ang huling tatlong numero sa bawat row). Sa kasong ito, tinukoy namin ang isang tatsulok sa xy plane, ang mga normal nito ay tumuturo sa direksyon ng positibong bahagi ng z axis.

Ang kailangan lang nating gawin ay lumikha ng isang halimbawa ng klase ng Vertices3 at itakda ang mga halaga ng vertices. Medyo madali, hindi ba?

Ang lahat ng gawaing pagbubuklod, pagguhit, at pag-unbinding ay eksaktong kapareho ng sa nakaraang bersyon ng klase. Tulad ng dati, maaari tayong magdagdag ng mga kulay ng vertex at mga coordinate ng texture.

Pinagsasama-sama ang lahat

Pagsama-samahin natin ang lahat. Kailangan nating gumuhit ng eksenang mayroong pandaigdigang pag-iilaw, punto at direksyong pinagmumulan ng liwanag. Sila ay magpapailaw sa kubo na matatagpuan sa pinanggalingan. Kailangan din nating tawagan ang gl uLookAt, method. para iposisyon ang camera. Sa Fig. 11.6 ipinapakita hitsura Ang ating mundo.

Tulad ng lahat ng iba pang halimbawa, gumawa tayo ng klase na tinatawag na LightTest, na nagpapalawak sa klase ng GLGame gaya ng dati. Magbabalik ito ng isang instance ng klase ng LightScreen gamit ang getStartScreenO method. Nagmana ang klase ng LightScreen mula sa klase ng GLScreen (Listing 11.7).

kanin. 11.6. Ang aming unang maliwanag na eksena

Listahan 11.7. Mga fragment ng klase ng LightTest.java. paglikha ng ilaw gamit ang OpenGL ES

Magsimula tayo sa paglalarawan ng ilang miyembro ng klase. Ang miyembro ng anggulo ay nag-iimbak ng impormasyon tungkol sa kasalukuyang anggulo ng pag-ikot ng kubo sa paligid ng y-axis. Iniimbak ng miyembro ng Verti ces3 ang vertices ng cube model, na tutukuyin natin sa ilang sandali. Bilang karagdagan, mayroon kaming mga instance ng mga klase ng AmbientLight, PointLight, at Directional Light, pati na rin ang isang instance ng klase ng Material.

Susunod na dumating ang tagabuo. Dito nilikha ang mga vertex ng modelo ng kubo, at na-load ang texture ng kahon. Sinisimulan din namin ang mga ilaw at materyales. Light green ang kulay ng backlight. Ang itinuro na pinagmulan ay pula at matatagpuan sa punto (3; 3; 0) ng ating mundo. Ang directional light source ay may asul na diffuse na kulay, ang liwanag ay bumaba mula sa kaliwa. Para sa materyal na ginagamit namin ang mga default na halaga (medyo background, puti para sa nagkakalat na bahagi at itim para sa specular na bahagi).

Sa pamamaraan ng resume, tinitiyak namin na ang aming texture ay (muling) na-load kung nawala ang konteksto.

Ang paraan ng createCube ay mahalagang hindi nagbabago mula sa mga nakaraang halimbawa. Gayunpaman, sa pagkakataong ito ay nagdaragdag kami ng mga normal sa bawat vertex, tulad ng ipinapakita sa Fig. 11.5. Maliban dito, nananatiling pareho ang lahat.

Sa paraan ng pag-update, pinapataas lang namin ang anggulo ng pag-ikot ng kubo.

Ito ay kung saan ito ay nagiging mas kawili-wili. Ang unang ilang linya ay boilerplate code upang i-clear ang kulay at depth buffer, paganahin ang malalim na pagsubok, at itakda ang saklaw.

Susunod, itinakda namin ang projection matrix na katumbas ng perspective projection matrix gamit ang gl uPerspective method, at ginagamit din ang gl uLookAt method para sa model-view matrix, salamat kung saan gumagana ang camera tulad ng sa Fig. 11.6.

Pagkatapos ay pinapayagan namin ang paggamit ng pag-iilaw. Sa puntong ito, wala pang natukoy na mga ilaw, kaya tinutukoy namin ang mga ito sa susunod na ilang linya sa pamamagitan ng pagtawag sa pamamaraan sa mga ilaw at materyales.

Gaya ng dati, pinapagana din namin ang pagte-text at ibind ang texture ng kahon. Panghuli, tinatawag namin ang gl RotatefC) na paraan upang paikutin ang kubo at pagkatapos ay iguhit ang mga vertices nito gamit ang mga mahusay na inilagay na tawag sa isang halimbawa ng klase ng Verti ces3.

Sa pagtatapos ng pamamaraan, hindi namin pinapagana ang mga spot at directional na ilaw (tandaan, ang backlighting ay isang pandaigdigang estado), pati na rin ang texturing at malalim na pagsubok. Iyon lang para sa pag-iilaw sa OpenGL ES.

Ang natitirang silid-aralan ay walang laman; hindi namin kailangang magsagawa ng anumang mga aksyon kung sakaling ma-pause. Sa Fig. Ipinapakita ng Figure 11.7 ang resulta ng programa.

kanin. 11.7. Ang eksenang ipinakita sa Fig. 11.6, na-render gamit ang OpenGL ES

Ilang tala sa pag-iilaw sa OpenGL ES

Habang ang paggamit ng ilaw ay maaaring magdagdag ng lasa sa iyong laro, mayroon itong mga limitasyon at mga pitfalls. Mayroong ilang mga bagay na dapat mong malaman.

Ang paggamit ng ilaw ay gumagamit ng masyadong maraming mapagkukunan, lalo na kapansin-pansin sa mga mabagal na device. Maingat na gumamit ng ilaw. Ang mas maraming light source na inilalarawan mo, mas maraming kalkulasyon ang kakailanganin para i-render ang eksena.

Ang posisyon/direksyon ng point/directional light source ay dapat matukoy pagkatapos ma-load ang mga camera matrice at bago ang model-view matrix ay i-multiplied sa anumang iba pang matrice upang ilipat at paikutin ang mga bagay. Ito ay kritikal. Kung hindi sinunod ang mga tagubiling ito, maaaring mangyari ang mga hindi maipaliwanag na light artifact.

Kapag ginamit mo ang paraan ng gl Seal ef upang baguhin ang laki ng modelo, ang mga normal nito ay mapapalaki rin. Masama ito dahil inaasahan ng OpenGL ES na ang mga normal ay may mga parameter sa mga ibinigay na unit. Upang malutas ang problemang ito, maaari mong gamitin ang command na glEnable(GL10.GL NORMALIZE) o, sa ilang pagkakataon, gl Enable(GL10 .GL RESCALE N0RMAL). Naniniwala ako na ang unang utos ay dapat gamitin, dahil ang paggamit ng pangalawa ay may mga limitasyon at pitfalls. Ang problema ay ang pag-normalize o pag-rescale ng mga normal ay nangangailangan ng maraming kapangyarihan sa pagproseso. Ang pinakamahusay na solusyon mula sa isang pananaw sa pagganap ay ang hindi sukatin ang mga bagay na may iluminado.

Well, mga ginoo. Medyo marami na kaming natutunan tungkol sa OpenGL kamakailan, kasama na kung paano kontrolin ang camera , gumana sa mga texture, at kasama din mga modelo. Panahon na upang pag-usapan ang isang bagay na mas kawili-wili, lalo na ang pag-iilaw. Ang paksang ito ay kawili-wili dahil walang handa para sa pagtatrabaho sa liwanag sa OpenGL; ang lahat ay kailangang isulat nang nakapag-iisa gamit ang mga shader. Sa post na ito titingnan natin ang Phong lighting. Ito ay isang medyo malaking paksa, kaya eksklusibo namin ang pag-uusapan pag-iilaw. Sa kung paano sila ginawa mga anino, kailangan nating malaman ito sa ibang pagkakataon.

Pag-save at Paggamit ng Normal

Bago tayo direktang lumipat sa pag-iilaw, kailangan natin ng bagay tulad ng mga normal.

Alam na natin na ang mga modelo ay may mga vertex at UV coordinates na naaayon sa mga vertex na ito. Upang lumikha ng pag-iilaw, kailangan namin ng ilang karagdagang impormasyon tungkol sa mga modelo, katulad ng mga normal. Ang normal ay ang unit vector na naaayon sa isang vertex (o, bilang kahalili, isang polygon, ngunit hindi ito ang aming kaso). Malalaman natin kung ano mismo ang papel ng mga normal sa pagpapatupad ng ilaw sa ibaba. Sa ngayon, sapat na upang sabihin na ang mga normal ay talagang napakahalaga. Halimbawa, salamat sa kanila, ang mga ibabaw ay mukhang mas makinis at maaari mong makilala ang isang bola mula sa isang regular na convex polyhedron tulad ng isang icosahedron. At dahil napakahalaga ng mga normal, kailangan nating matutunan kung paano panatilihin ang mga ito kapag nagko-convert ng mga modelo ng Blender sa sarili nating format.

Ang mga kaukulang pagbabago ay medyo walang halaga. Nakukuha namin ang mga normal sa parehong paraan na nakuha namin ang mga coordinate ng vertex at mga coordinate ng UV:

// bahagi ng procedure body importedModelCreate

para sa (unsigned int j = 0 ; j< face.mNumIndices ; ++ j) {
unsigned int index = face.mIndices[ j] ;
aiVector3D pos = mesh->mVertices[ index] ;
aiVector3D uv = mesh-> mTextureCoords[ 0 ] [ index] ;
aiVector3D normal = mesh-> mNormals[ index] ;

VerticesBuffer[ verticesBufferIndex++ ] = pos.x ;
verticesBuffer[ verticesBufferIndex++ ] = pos.y ;
verticesBuffer[ verticesBufferIndex++ ] = pos.z ;
verticesBuffer[ verticesBufferIndex++ ] = normal.x ;
verticesBuffer[ verticesBufferIndex++ ] = normal.y ;
verticesBuffer[ verticesBufferIndex++ ] = normal.z ;
verticesBuffer[ verticesBufferIndex++ ] = uv.x ;
verticesBuffer[ verticesBufferIndex++ ] = 1.0f - uv.y ;
}

Ang pamamaraan ng pag-optimize ng modelo ay nagbabago nang katulad. At sa modelLoad procedure, sa halip na dalawang attribute array, kailangan na natin ngayon ng tatlo:

// bahagi ng katawan ng pamamaraan ng modelLoad

GlBindVertexArray(modelVAO) ;
glEnableVertexAttribArray(0 );
glEnableVertexAttribArray(1) ;
glEnableVertexAttribArray(2) ;

GlBindBuffer(GL_ARRAY_BUFFER, modelVBO) ;
glBufferData(GL_ARRAY_BUFFER, header- > verticesDataSize, verticesPtr,
GL_STATIC_DRAW) ;

GLsizei stride = 8 * sizeof(GLfloat) ;
glVertexAttribPointer(0 , 3 , GL_FLOAT, GL_FALSE, stride, nullptr) ;
glVertexAttribPointer(1 , 3 , GL_FLOAT, GL_FALSE, hakbang,
(const void * ) (3 * sizeof (GLfloat) ) );
glVertexAttribPointer(2 , 2 , GL_FLOAT, GL_FALSE, hakbang,
(const void * ) (6 * sizeof (GLfloat) ) );

Kailangan din namin ng isang pare-parehong variable na may matrix M:

GLint uniformM = getUniformLocation(programId, "M" );

// ...

GlUniformMatrix4fv(uniformM, 1, GL_FALSE, & towerM[ 0 ] [ 0 ] ) ;

... upang iikot nang tama ang normal sa espasyo sa vertex shader:

#bersyon 330 core

Layout(lokasyon = 0 ) sa vec3 vertexPos;
layout(lokasyon = 1 ) sa vec3 vertexNorm;
layout(lokasyon = 2 ) sa vec2 vertexUV;

unipormeng mat4 MVP;
unipormeng banig4 M;

out vec2 fragmentUV;
out vec3 fragmentNormal;
out vec3 fragmentPos;

void main() (
fragmentUV = vertexUV;
fragmentNormal = (M * vec4 (vertexNorm, 0 ) ) . xyz ;
fragmentPos = (M * vec4 (vertexPos, 1 ) ) . xyz ;

gl_Position = MVP * vec4 (vertexPos, 1 );
}

Sa wakas, ang fragment shader ay tumatagal ng isang normal na interpolated sa tatlong vertices:

// ...

void main() (

// ...
}

Sa simpleng paraan na ito nakukuha natin ang mga normal mga fragment.

Ano ang Phong lighting?

Tulad ng nabanggit, ang pag-iilaw sa OpenGL ay nakasulat sa mga shader ng programmer mismo. Malinaw na mayroong higit sa isang paraan upang ipatupad ang pag-iilaw na ito, bawat isa ay may sariling antas ng pagiging totoo at mga kinakailangan sa mapagkukunan. At ang bawat pamamaraan ay maaari pa ring magkaroon ng hindi mabilang na mga partikular na pagpapatupad. Mula sa naiintindihan ko, ang mahusay at makatotohanang real-time na pag-iilaw ay isang lugar pa rin ng aktibong pananaliksik. Para sa post na ito, titingnan natin ang Phong lighting, na parehong medyo makatotohanan at madaling ipatupad.

Mahalagang maunawaan ang pagkakaiba sa pagitan ng mga sumusunod na konsepto:

  • Ang pagtatabing ng gouraud ay kapag kinakalkula mo ang illuminance ng bawat vertex, at ang illuminance ng mga fragment sa pagitan ng mga ito ay interpolated;
  • Phong shading - kapag ang pag-iilaw ay kinakalkula nang hiwalay para sa bawat fragment;
  • Ang Phong lighting o Phong reflection model ay isang partikular na paraan ng pag-iilaw na tinalakay sa artikulong ito at maaaring magamit sa parehong Gouraud at Phong shading;

Hindi nakakagulat na ang Phong shading at Phong lighting ay madalas na nalilito, at sa ilang mga tutorial maaari kang magbasa ng walang kapararakan tulad ng "Ang ideya ng Phong shading ay ang paggamit ng tatlong sangkap..." na agad na nagdududa sa awtoridad ng taong sumulat ng tutorial na ito.

Sa pagkakaintindi ko, sa mga modernong aplikasyon ay halos hindi ginagamit ang gouraud shading, sa halip ay mas gusto ang Phong shading. Sa post na ito, gagamitin din namin ang Phong shading, iyon ay, ang pag-iilaw ay kakalkulahin nang hiwalay para sa bawat fragment. Ang tiyak na paraan ng pag-iilaw na aming gagamitin ay ang Phong lighting. Ang pamamaraang ito ay ang mga sumusunod.

Ang tatlong bahagi ng pag-iilaw ay kinakalkula gamit ang iba't ibang mga formula:

  • Ang ambient lighting ay isang imitasyon ng liwanag na umabot sa isang partikular na punto pagkatapos na maipakita mula sa iba pang mga bagay. Kapag kinakalkula ang background lighting, hindi isinasaalang-alang ang mga normal o ang kasalukuyang posisyon ng camera;
  • Ang diffuse lighting ay liwanag mula sa isang pinagmulan na nakakalat pagkatapos maabot ang isang partikular na punto. Depende sa anggulo kung saan bumagsak ang liwanag, ang pag-iilaw ay nagiging mas malakas o humihina. Isinasaalang-alang nito ang mga normal, ngunit hindi ang posisyon ng camera;
  • Ang specular na pag-iilaw ay liwanag mula sa isang pinagmumulan na makikita pagkatapos maabot ang isang partikular na punto. Ang naaninag na liwanag ay makikita kung ito ay pumasok sa camera. Samakatuwid, ang parehong mga normal at posisyon ng camera ay isinasaalang-alang dito;

Ang mga resulta ay pagkatapos ay summed upang bigyan ang kabuuang pag-iilaw.

Upang gawing mas kawili-wili ang mga bagay, mayroong iba't ibang pinagmumulan ng liwanag. Malinaw, ang araw sa labas at ang isang flashlight sa dilim ay nagbibigay liwanag sa tanawin na ibang-iba. Una, titingnan natin ang pinakasimpleng pinagmulan - ilaw ng direksyon.

Ilaw ng direksyon

Ang ilaw ng direksyon ay isang imitasyon ng isang walang katapusan na malayong pinagmumulan ng liwanag. Kunin natin ang Araw, halimbawa. Napakalayo ng araw sa lupa. Samakatuwid, sa ibabaw ng Earth, ang lahat ng mga sinag ng liwanag mula sa Araw ay maaaring ituring na parallel na may mahusay na katumpakan. Ang ilaw ng direksyon ay nailalarawan sa pamamagitan ng direksyon, kulay, pati na rin ang ilang mga coefficient na kakailanganin natin sa ibaba:

struct DirectionalLight(
direksyon ng vec3;

kulay ng vec3;
float ambientIntensity;
float diffuseIntensity;
float specularIntensity;
} ;

Sa fragment shader code, tutukuyin namin ang isang calcDirectionalLight na pamamaraan na gagamitin tulad nito:

sa vec3 fragmentPos;
unipormeng vec3 cameraPos;
unipormeng DirectionalLight directionalLight;

// ...

void main() (
// dapat itama ang normal pagkatapos ng interpolation
vec3 normal = normalize (fragmentNormal);


ilaw ng direksyon);

// ...
}

Isaalang-alang natin ang pagpapatupad ng pamamaraan.

vec4 calcDirectionalLight(vec3 normal, vec3 fragmentToCamera,
DirectionalLight light) (
vec4 ambientColor = vec4 (light. color, 1) * light. ambientIntensity ;

// ...
}

Una, ang unang bahagi ay kinakalkula - background lighting. Ito ay simpleng kulay ng inilalabas na liwanag na pinarami ng intensity ng background light. Sa ngayon ang lahat ay simple.

// ...

float diffuseFactor = max (0.0 , tuldok (normal, - liwanag. direksyon ) );
vec4 diffuseColor = vec4 (light. color, 1) * light. diffuseIntensity
* diffuseFactor;

// ...

Diffused lighting. Kinakatawan ng diffuseFactor variable ang cosine ng anggulo sa pagitan ng normal hanggang sa fragment at ang vector na nakadirekta mula sa fragment patungo sa light source. Kung ang liwanag ay insidente patayo sa ibabaw, ang anggulo ay zero. Ang cosine ng anggulong ito ay katumbas ng isa at ang pag-iilaw ay pinakamataas (tingnan ang artikulo sa Wikipedia tungkol sa Batas ni Lambert). Habang tumataas ang anggulo, bumababa ang cosine at nagiging katumbas ng zero kung ang liwanag ay parallel sa ibabaw. Kung negatibo ang cosine, ang pinagmumulan ng ilaw ay nasa likod ng ibabaw at hindi ito naiilaw, kaya ginagawa natin ang mga negatibong halaga sa zero gamit ang max(0.0, ...) . Bilang karagdagan sa anggulo kung saan bumagsak ang liwanag, ang diffuseIntensity ng diffused light ay isinasaalang-alang din.

// ...
vec3 lightReflect = normalize(reflect(light. direction, normal));
lumutang specularFactor = pow(
max (0.0 , tuldok (fragmentToCamera, lightReflect) ,
materyalSpecularFactor
) ;
vec4 specularColor = liwanag. specularIntensity * vec4(light.color, 1)
* materyalSpecularIntensity * specularFactor;
// ...

Hindi direktang pag-iilaw. Ang lightReflect variable ay isang unit vector na tumutukoy sa direksyon ng sinasalamin na liwanag. Ang specularFactor variable ay kinakalkula sa katulad na paraan sa diffuseFactor, tanging sa pagkakataong ito ay isinasaalang-alang ang cosine ng anggulo sa pagitan ng direksyon kung saan ang liwanag ay napakita at ang direksyon mula sa fragment patungo sa camera. Kung zero ang anggulong ito, direktang lumilipad ang sinasalamin na liwanag sa camera at ang liwanag na nakasisilaw sa ibabaw ay pinakamataas. Kung ang anggulo ay malaki, pagkatapos ay hindi dapat makita ang liwanag na nakasisilaw. Narito ang materyalSpecularFactor ay isang pare-parehong variable. Kung mas malaki ito, mas maliit ang lugar ng liwanag na nakasisilaw sa ibabaw ng bagay. Ginagamit din ang variable na materialSpecularIntensity upang matukoy ang liwanag ng mga highlight. Tandaan na ang lahat ng ito ay mga katangian ng materyal, hindi ang liwanag. Halimbawa, ang metal ay sumasalamin sa liwanag at samakatuwid ay may liwanag na nakasisilaw. Ngunit ang kahoy ay hindi sumasalamin sa liwanag, at pagkatapos ay hindi ka nakakakita ng liwanag na nakasisilaw sa mga puno (siyempre, kung ang ibabaw ay tuyo, at iba pa).

Sa code sa itaas, ang ilaw ay may specularIntensity property. Ngunit dapat lang itong gamitin para sa mga layunin ng pag-debug upang i-highlight ang mga highlight mula sa isang partikular na pinagmumulan ng liwanag. Sa bersyon ng paglabas ng code, ang koepisyent na ito ay dapat na katumbas ng isa, o ganap na alisin sa code.

Sa wakas, ang tatlong bahagi ay idinagdag at ang resulta ay ibinalik:

// ...

ibalik ang ambientColor + diffuseColor + specularColor;
}

Hindi kaya mahirap, tama?

Point source ng liwanag

Ang isang puntong pinagmumulan ng liwanag ay, halimbawa, isang nasusunog na bombilya. Ang ilaw mula sa bombilya ay nakadirekta sa lahat ng direksyon. Samakatuwid, ang isang point light source ay hindi nailalarawan sa pamamagitan ng direksyon ng liwanag, ngunit nailalarawan sa pamamagitan ng posisyon ng pinagmulan sa espasyo:

struct PointLight(
posisyon ng vec3;

kulay ng vec3;
float ambientIntensity;
float diffuseIntensity;
float specularIntensity; // para sa mga layunin ng pag-debug, dapat itakda sa 1.0
} ;

Ang pag-iilaw mula sa isang point light source ay madaling kalkulahin gamit ang umiiral nang pamamaraan ng calcDirectionalLight:

vec4 calcPointLight(vec3 normal, vec3 fragmentToCamera,
PointLight light) (
vec3 lightDirection = gawing normal (fragmentPos - liwanag. posisyon );
float distance = haba (fragmentPos - liwanag. posisyon );
float pointFactor = 1.0 / (1.0 + pow(distansya, 2));

DirectionalLight tempDirectionalLight = DirectionalLight(
liwanag na Direksyon,
liwanag. kulay,
liwanag. ambientIntensity
liwanag. diffuseIntensity
liwanag. specularIntensity
) ;
return pointFactor * calcDirectionalLight(normal, fragmentToCamera,
tempDirectionalLight);
}

Ang pagkakaroon ng mga coordinate ng fragment at ang pinagmulan ng liwanag, madali mong makalkula ang direksyon ng liwanag sa isang naibigay na fragment sa pamamagitan ng pagkakaiba ng mga vector. Ang pointFactor multiplier ay sumasalamin sa katotohanan na ang liwanag ay lumalabag sa parisukat ng distansya sa pinagmulan nito (alinsunod sa pormula para sa pag-asa ng ibabaw na lugar ng isang globo sa radius). Kapag kinakalkula ang pointFactor, ang isang karagdagang ay idinagdag sa divisor upang maiwasan ang posibilidad ng paghahati sa zero. Pagkatapos nito, ang lahat ay kinakalkula nang eksakto sa parehong paraan tulad ng para sa direksyon na ilaw.

Spot light

Ang isang halimbawa ng pinagmumulan ng liwanag na ito ay isang flashlight. Ito ay katulad ng isang point light source, bukod pa rito ay may direksyon at isang anggulo ng impluwensya (cutoff):

struct SpotLight (
direksyon ng vec3;
posisyon ng vec3;
float cutoff;

kulay ng vec3;
float ambientIntensity;
float diffuseIntensity;
float specularIntensity; // para sa mga layunin ng pag-debug, dapat itakda sa 1.0
} ;

Kaugnay na pamamaraan:

vec4 calcSpotLight(vec3 normal, vec3 fragmentToCamera,
SpotLight light) (
vec3 spotLightDirection = gawing normal (fragmentPos - liwanag. posisyon );
float spotAngleCos = tuldok (spotLightDirection, liwanag. direksyon) ;
float attenuation = (1.0 - 1.0 * (1.0 - spotAngleCos) /
(1.0 - liwanag. cutoff ) );
float spotFactor = float (spotAngleCos > light. cutoff ) * pagpapalambing;

PointLight tempPointLight = PointLight(
liwanag. posisyon
liwanag. kulay,
liwanag. ambientIntensity
liwanag. diffuseIntensity
liwanag. ambientIntensity
) ;
return spotFactor * calcPointLight(normal, fragmentToCamera,
tempPointLight);
}

Ang direksyon ng liwanag ay kinakalkula sa parehong paraan tulad ng para sa isang point source. Pagkatapos ay ang cosine ng anggulo sa pagitan ng direksyon na ito at ang direksyon na tinukoy sa mga katangian ng pinagmulan ng liwanag mismo ay kinakalkula. Gamit ang expression float(spotAngleCos > light.cutoff) ang ilaw ay mahigpit na pinuputol sa tinukoy na anggulo. Attenuation multiplier nagdadagdag makinis pagpapahina ng liwanag habang lumalayo ang mga fragment mula sa direksyon ng liwanag na tinukoy sa mga katangian ng pinagmulan. Pagkatapos nito, ang lahat ng mga kalkulasyon ay nabawasan sa mga kalkulasyon para sa isang point light source.

Pagwawasto ng gamma

Ang buong pangunahing pamamaraan sa fragment shader ay ganito ang hitsura:

void main() (
// dapat itama ang normal pagkatapos ng interpolation
vec3 normal = normalize (fragmentNormal);
vec3 fragmentToCamera = normalize(cameraPos - fragmentPos) ;

vec4 directColor = calcDirectionalLight(normal, fragmentToCamera,
ilaw ng direksyon);
vec4 pointColor = calcPointLight(normal, fragmentToCamera,
pointLight);
vec4 spotColor = calcSpotLight(normal, fragmentToCamera, spotLight) ;
vec4 linearColor = texture(textureSampler, fragmentUV) *
(vec4(materialEmission, 1) + directColor +
pointColor + spotColor);

vec4 gamma = vec4 (vec3 (1.0 / 2.2), 1);
kulay = pow(linearColor, gamma); // kulay na itinama ang gamma
}

Huwag pansinin ang materyalEmission. Ito ay isa pang pag-aari ng materyal na nagdaragdag ng sarili nitong glow. Maraming bagay ang kumikinang sa kanilang sarili. Kunin ang parehong mga bombilya na nagsisilbing ilaw na pinagmumulan ng iba pang mga bagay. Dapat ay nakikita natin sila sa ganap na kadiliman, kahit na ang mga bombilya ay hindi naiilawan ng anumang iba pang pinagmumulan ng liwanag, tama ba?

Ang talagang nararapat pansin ay ang pagwawasto ng gamma, na binubuo ng pagtataas ng lahat ng mga bahagi ng ilaw sa lakas na 1/2.2. Sa ngayon kami ay nagtatrabaho sa linear na espasyo ng kulay, sa ilalim ng pagpapalagay na ang isang kulay na may intensity 1.0 ay dalawang beses na mas maliwanag kaysa sa isang kulay na may intensity 0.5. Ang problema ay hindi nakikita ng mata ng tao ang liwanag nang linearly. Samakatuwid, upang makakuha ng makatotohanang pag-iilaw, kinakailangan na magsagawa ng pagwawasto ng gamma pagkatapos ng lahat ng mga kalkulasyon sa linear space.

Dapat itong isaalang-alang na kapag nagse-save ng isang imahe, ang mga modernong graphic editor ay nagsasagawa rin ng pagwawasto ng gamma. Samakatuwid, bago gumamit ng mga texture, kailangan mong kanselahin ang gamma correction na ito. Sa kabutihang palad, hindi ito mahirap.

Ito ay sapat na upang palitan ang lahat ng mga constants sa texture loading code:

GL_COMPRESSED_RGBA_S3TC_DXT1_EXT
GL_COMPRESSED_RGBA_S3TC_DXT3_EXT
GL_COMPRESSED_RGBA_S3TC_DXT5_EXT

GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT
GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT
GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT

… ayon sa pagkakabanggit. Ipapahiwatig nito na may inilapat na pagwawasto ng gamma sa larawan at kailangang i-undo. Ang OpenGL na ang bahala sa iba.

Sa totoong mga aplikasyon, ang parameter ng gamma (mayroon kaming gamma = 2.2) ay mas mahusay na inilagay sa mga setting ng programa upang ang gumagamit ay maaaring, kung ninanais, bahagyang ayusin ito sa kanyang monitor.

Konklusyon

Panahon na upang tingnan ang mga larawan!

Dito makikita natin ang iba't ibang bahagi ng pag-iilaw. Mula kaliwa hanggang kanan, itaas hanggang ibaba: background, diffuse, reflected, lahat ng tatlo ay magkasama. Gaya ng nakikita mo, isang torus na modelo ang naidagdag sa eksena. Dahil sa kumplikadong paglalagay ng mga normal, ang modelong ito ay inirerekomenda para sa pagsubok sa pag-iilaw.

Iba't ibang pinagmumulan ng liwanag. Mula kaliwa pakanan, itaas hanggang ibaba: puting spot light, pulang spot light, asul na spotlight, lahat ng tatlo ay magkasama.

Hayaan akong tandaan muli na ang parehong paraan ng pag-iilaw ay maaaring magkaroon ng iba't ibang mga pagpapatupad. Halimbawa, maaari mong itakda ang mga materyal na katangian sa ambient, diffuse at specular na kulay, na magbibigay-daan sa iyong gumuhit ng mga pulang bagay na nagkakalat ng berde at may mga asul na highlight. Sa ilang pagpapatupad ng Phong lighting, nakita ko ang background lighting na kinakalkula nang isang beses kaysa sa bawat liwanag. Nakita ko rin ang mga pagpapatupad kung saan ang liwanag mula sa isang point source ay kumupas hindi lamang sa proporsyon sa parisukat ng distansya dito (d * d), ngunit ayon sa isang mas pangkalahatang formula (sa estilo ng A + B*d + C* DD). Ang isang tao ay gumagawa ng ambient intensity at diffuse intensity bilang isang pag-aari hindi lamang ng pinagmumulan ng liwanag, kundi pati na rin ng materyal. Hindi ako sigurado kung magkano ang lahat ng ito ay may kinalaman sa makatotohanang pag-iilaw, bagaman. Ngunit maaari mong paglaruan ang lahat ng ito bilang araling-bahay.

Mga gawa ng taon. Voloshin Maximilian. GALIT NG ISANG MAKATA. 1. I-edit ang tula tulad ng teksto ng isang dispatch sa ibang bansa: Pagkatuyo, kalinawan, presyon - ang bawat salita ay nasa alerto.

Upang putulin ang mga letra sa isang matigas at masikip na bato: Kung mas kakaunti ang mga salita, mas matindi ang kanilang kapangyarihan. Ang volitional charge ng pag-iisip ay katumbas ng mga tahimik na saknong.

Burahin ang mga salitang "Kagandahan", "Inspirasyon" mula sa diksyunaryo - ang karumal-dumal na jargon ng mga rhymer. Sa makata - mga pag-unawa: Katotohanan, disenyo, plano, pagkakapareho, katumpakan at katumpakan. Sa isang matino, mahirap na gawain ay mayroong inspirasyon at karangalan ng isang makata: Upang patalasin ang transendental na pagbabantay sa mga bagay na bingi-pipi. Voloshin M.A. Aklatan: Oryol Regional Scientific Universal Public Library na pinangalanan. I.A. Bunina. - M., ; Mga napiling gawa: Sa 2 volume.

M., ; Pulang Usok: Mga Kwento. - M., ; Gladyshev mula sa kumpanya ng reconnaissance: Mga Kuwento. - M., ; Eselon; Hindi maiiwasan: Mga nobela. Marami siyang ginawang pagsasalin ng mga makatang Mari at Udmurt. Paminsan-minsan ay sinubukan ko rin ang aking kamay sa prosa. Op. Si Maximilian Aleksandrovich Voloshin () ay isa sa mga pinakadakilang makata ng unang ikatlong bahagi ng ika-20 siglo. Siya ay isang mahuhusay na artist, isang multi-faceted lyricist, na naglakbay sa landas mula sa simbolista, esoteric na mga tula hanggang sa civic-journalistic at scientific-philosophical na tula, sa pamamagitan ng anthroposophical predilections - patungo sa "ideal ng Lungsod ng Diyos."

Ang iminungkahing publikasyon ay nagbibigay ng pagkakataon sa mambabasa na maging pamilyar hindi lamang sa pinakamahusay na mga gawang patula ni Voloshin, kundi pati na rin sa kanyang pinaka-kagiliw-giliw na mga gawa sa aesthetics, memoir prose, journalism at mga liham na may kaugnayan sa mga dramatikong kaganapan sa buhay ng mga bansa. May-akda. Voloshin Maximilian. Lahat ng tula ng may akda. Trabaho. Ang kagitingan ng makata. 2. Mga bituin. Lumikha ng mga paboritong koleksyon ng mga may-akda at tula!

Makipag-chat sa mga taong katulad ng pag-iisip! Sumulat ng mga review, lumahok sa mga tunggalian ng tula at mga kumpetisyon! Sumali sa pinakamahusay! Salamat sa pagsali sa Poembook! Ang isang sulat na may data ng pag-access sa account ay ipinadala sa iyong email!

Dapat kang mag-log in sa loob ng 24 na oras. Kung hindi, ang account ay tatanggalin! Nakatanggap ng maraming benepisyo ang mga rehistradong user: Mag-publish ng tula - mapagtanto ang iyong talento! Lumikha ng mga paboritong koleksyon ng mga may-akda at tula! Makipag-chat sa mga taong katulad ng pag-iisip! Sumulat ng mga pagsusuri, lumahok sa mga tunggalian ng tula at mga kumpetisyon!. Maximilian Voloshin. Paglalarawan. Si Maximilian Aleksandrovich Voloshin ay isa sa mga pinakadakilang makata ng unang ikatlong bahagi ng ika-20 siglo.

Siya ay isang mahuhusay na artist, isang multifaceted lyricist, na naglakbay sa landas mula sa simbolista, esoteric na mga tula hanggang sa civic-journalistic at scientific-philosophical na tula, sa pamamagitan ng anthroposophical predilections - patungo sa "ideal ng Lungsod ng Diyos." Ang iminungkahing publikasyon ay nagbibigay ng pagkakataon sa mambabasa na maging pamilyar hindi lamang sa pinakamahusay na mga gawa ng tula ni Voloshin, kundi pati na rin sa kanyang pinaka-kagiliw-giliw na mga gawa sa aesthetics, memoir prose, journalism at mga liham na may kaugnayan sa drama.

Mga piling gawa at liham. M. A. Voloshin. Presyo. kuskusin. Si Maximilian Aleksandrovich Voloshin ay isa sa mga pinakadakilang makata ng unang ikatlong bahagi ng ika-20 siglo. Siya ay isang mahuhusay na artist, isang multifaceted lyricist, na naglakbay sa landas mula sa simbolista, esoteric na mga tula hanggang sa civic-journalistic at scientific-philosophical na tula, sa pamamagitan ng anthroposophical predilections - patungo sa "ideal ng Lungsod ng Diyos."

Voloshin M.A., The Poet’s Valor: Selected Works and Letters. serye: Bagong Aklatan ng Russian Classics: kinakailangang kopya Parade, lungsod, pahina, Paglalarawan ng aklat. Si Maximilian Aleksandrovich Voloshin () ay isa sa mga pinakadakilang makata ng unang ikatlong bahagi ng ika-20 siglo. Siya ay isang mahuhusay na artist, isang multi-faceted lyricist, na naglakbay sa landas mula sa simbolista, esoteric na mga tula hanggang sa civic-journalistic at scientific-philosophical na tula, sa pamamagitan ng anthroposophical predilections - patungo sa "ideal ng Lungsod ng Diyos."

Mga kategorya Mag-post ng nabigasyon

Kung walang pinagmumulan ng liwanag, hindi makikita ang larawan. Upang simulan ang pinagmulan at paganahin ang processor para sa pagkalkula ng epekto ng pinagmulan sa mga bagay, isagawa lamang ang mga command: glEnable(gl_lighting); // paganahin ang lighting analysis mode

GlEnable(gl_light0); // magsama ng tukoy na (zero) na pinagmulan sa eksena, kasama ang mga katangian nito

Upang hindi paganahin ang isang pinagmulan, gamitin ang Disable() function. Bilang default, ang pinagmumulan ng ilaw ay matatagpuan sa espasyo na may mga coordinate (0,0,∞). Maaari kang gumawa ng light source kahit saan sa espasyo ng larawan.

Sinusuportahan ng OpenGl library ang apat na uri ng light source:

  • background lighting (ambient lighting),
  • mga mapagkukunan ng punto,
  • mga spotlight,
  • malayong pinagmumulan ng liwanag (malayong liwanag).
Ang bawat pinagmumulan ng liwanag ay may sariling hanay ng mga katangian.
Ang mga katangian ng pinagmumulan ng liwanag ay tumutugma sa mga parameter ng modelo ng Phong.
Upang magtakda ng mga parameter ng vector, gamitin ang glLightfv() function, na mayroong sumusunod na format:

glLightfv(pinagmulan, parameter, pointer_to_array);

Mayroong apat na mga parameter ng vector na tumutukoy sa posisyon at direksyon ng source ray at ang komposisyon ng kulay ng mga bahagi nito - background, diffuse at specular.
Upang magtakda ng mga scalar parameter sa OpenGL, gamitin ang glLightf() function:

glLightf(pinagmulan, parameter, halaga);

Hayaan, halimbawa, gusto mong isama sa eksena ang pinagmulang GL_LIGHT0, na dapat ay matatagpuan sa punto (1.0, 2.0, 3.0). Ang posisyon ng pinagmulan ay nai-save sa programa bilang isang punto sa magkatulad na mga coordinate:

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

Kung ang ika-apat na bahagi ng puntong ito ay zero, kung gayon ang pinagmulan ng punto ay nagiging isang malayong mapagkukunan, kung saan ang direksyon lamang ng mga sinag ay makabuluhan:

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

Susunod, tinutukoy ang komposisyon ng kulay ng background, pagsasabog at specular na bahagi ng pinagmulan. Kung sa halimbawang isinasaalang-alang ang pinagmulan ay may specular na bahagi ng puting kulay, at ang background at mga bahagi ng pagsasabog ay dapat na pula, kung gayon ang fragment ng programa na bumubuo sa pinagmulan ay ganito ang hitsura:

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, light0_pos);

GlLightfv(GL_LIGHT0, GL_AMBIENT, ambient0);

GlLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse0);

GlLightfv(GL_LIGHT0, GL_SPECULAR, specular0);

Maaari mo ring isama ang pandaigdigang pag-iilaw sa background sa iyong eksena, na hindi nauugnay sa anumang indibidwal na pinagmumulan ng liwanag. Kung, halimbawa, gusto mong madilim na i-highlight ang lahat ng mga bagay sa eksena na may puti, dapat mong isama ang sumusunod na piraso ng code sa programa:

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

GlLightModelfv(GL_LIGHT_MODEL_AMBIENT, global_ambient);

Sa modelo ng pag-iilaw, ang terminong isinasaalang-alang ang distansya sa pinagmulan ay may anyo:

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

At pare-pareho, linear at quadratic na mga bahagi. Ang kaukulang coefficient para sa bawat source ay itinatakda nang isa-isa gamit ang scalar parameter setting function, halimbawa:

GlLightf(GL_LIGHT0, GL_CONSTANT_ATTENATION, a);

Upang i-convert ang isang point source sa isang spotlight, kailangan mong tukuyin ang direksyon ng spotlight beam (GL_SPOT_DIRECTION), ang indicator ng intensity distribution function (GL_SPOT_EXPONENT) at ang beam scattering angle (GL_SPOT_CUTTOF). Ang mga parameter na ito ay itinakda gamit ang glLightf() at glLightfv() function.

Ang mga default na parameter para sa mga light source ay ipinapakita sa Talahanayan 3.

Mga default na setting para sa mga ilaw

Talahanayan 3

Pangalan ng parameter Default na halaga Nilalaman
GL_AMBIENT (0.0, 0.0, 0.0, 1.0) ambient RGBA intensity ng liwanag
GL_DIFFUSE (1.0, 1.0, 1.0, 1.0) nagkakalat ng RGBA intensity ng liwanag
GL_SPECULAR (1.0, 1.0, 1.0, 1.0) specular RGBA intensity ng liwanag
GL_POSITION (0.0, 0.0, 1.0, 0.0) (x, y, z, w) posisyon ng liwanag
GL_SPOT_DIRECTION (0.0, 0.0, -1.0) (x, y, z) direksyon ng spotlight
GL_SPOT_EXPONENT 0.0 spotlight exponent
GL_SPOT_CUTOFF 180.0 anggulo ng cutoff ng spotlight
GL_CONSTANT_ATTENUATION 1.0 pare-pareho ang attenuation factor
GL_LINEAR_ATTENUATION 0.0 linear attenuation factor
GL_QUADRATIC_ATTENUATION 0.0 quadratic attenuation factor